STEAM GROUP
Blender Source Tools BleST
STEAM GROUP
Blender Source Tools BleST
331
IN-GAME
1,921
ONLINE
Founded
8 November, 2013
All Discussions > Bug Reports > Topic Details
WillZepp 8 Oct, 2018 @ 8:16pm
Minor precision loss on bone positions when exporting animation as .smd
Upon importing an .smd animation and exporting it in the same format (with no changes made whatsoever to it, mind you), I noticed that floating-point precision was lost for some of the bone positions (I don't believe any was lost for the radian angles, peculiarly) in its frames.

Here are some examples:

Original SMD, frame 50: https://pastebin.com/yX6k5gS3
Re-exported SMD, frame 50: https://pastebin.com/NmYkN25Z

Here are some examples of the loss of precision.

Bone #17, original SMD, frame 50:
17 3.698241 0.000000 -0.000000 -0.003276 0.002285 0.091873

Bone #15, original SMD, frame 50:
15 0.000000 4.043968 -0.017929 1.577360 -0.131264 1.576111


Bone #17, reexported SMD, frame 50:
17 3.698244 0.000000 -0.000000 -0.003276 0.002285 0.091873

Bone #15, reexported SMD, frame 50:
15 0.000000 4.043965 -0.017929 1.577360 -0.131264 1.576111

These differences, while obviously minor, are still there, and seem fixable.
< >
Showing 1-3 of 3 comments
Artfunkel 9 Oct, 2018 @ 2:39pm 
They aren't fixable. Floating point rounding errors are a part of life!
WillZepp 27 Oct, 2018 @ 2:38pm 
By the way, I found a fix for this.

First of all, an explanation; in the export_smd file's "writeSMD" function, this is the code used for writing bone positions and angles.

for posebone in self.exportable_bones: parent = posebone.parent while parent and not parent in self.exportable_bones: parent = parent.parent # Get the bone's Matrix from the current pose PoseMatrix = posebone.matrix if self.armature.data.vs.legacy_rotation: PoseMatrix *= mat_BlenderToSMD if parent: parentMat = parent.matrix if self.armature.data.vs.legacy_rotation: parentMat *= mat_BlenderToSMD PoseMatrix = parentMat.inverted() * PoseMatrix else: PoseMatrix = self.armature.matrix_world * PoseMatrix self.smd_file.write("{} {} {}\n".format(self.bone_ids[posebone.name], getSmdVec(PoseMatrix.to_translation()), getSmdVec(PoseMatrix.to_euler())))

The offending functions here are mostly parentMat.inverted(); inverting matrices is done in C, and according to my own tests, some precision is lost in the result.
Finding the bone's matrices is actually completely unnecessary, as Blender already provides a pose bone's correct position/angle on the current animation frame with the bone.location/bone.rotation_euler variable (these variables are what are displayed when you're editing a bone in the Blender menu.) Upon switching out this code with using those variables instead, in my tests everything exports perfectly with no precision errors; positions and angles alike of bones are exactly like in my original .smd.
Last edited by WillZepp; 27 Oct, 2018 @ 2:40pm
Artfunkel 28 Oct, 2018 @ 11:11am 
Unfortunately rotation_euler is only accurate if the bone is configured to use euler angles. It could also store its rotation as a quaternion (the default option) or an axis angle. As soon as you start converting them to eulers you're back to having rounding errors. In any case, it's not worth trying to handle all of those cases for the obscure requirement of making animation values match exactly.

Instead of messing with the exporter, I would suggest a post-process script which snaps values which are very close to the originals. That would work 100% of the time.
< >
Showing 1-3 of 3 comments
Per page: 1530 50

All Discussions > Bug Reports > Topic Details