Hello,
I’m trying to export bone animation rotation value from Blender to Castle Game Engine (CGE).
I use Python script in Blender to export all keyframe values (rotation and translation) of a selected bone into Pascal arrays, then I use those arrays in CGE to manually apply animation to a bone.
but rotation gives incorrect results.
Example:
In Blender, the first keyframe rotation (quaternion) is:
same bone Rotation First keyframe in cge editor is
-0.43393 0.29042 0.85286 deg(174.88354)
Question:
How should I convert or adjust Blender’s quaternion values to match the expected result in CGE?
Do I need to adjust for coordinate system differences (e.g. Z-up vs Y-up), or apply a matrix transformation?
python script get blender keyframe value as pascal code
The script it only copies the generated Pascal code to the clipboard
import bpy
import mathutils
import io
armature = bpy.context.object
pose_bone = bpy.context.active_pose_bone
action = armature.animation_data.action if armature.animation_data else None
if not pose_bone or not action:
print("❌ يجب تحديد عظمة وحركة فعالة")
else:
parent_bone = pose_bone.parent
scene = bpy.context.scene
frame_start = int(action.frame_range[0])
frame_end = int(action.frame_range[1])
key_times = []
key_loc_x = []
key_loc_y = []
key_loc_z = []
key_rot_x = []
key_rot_y = []
key_rot_z = []
key_rot_w = []
for frame in range(frame_start, frame_end + 1):
scene.frame_set(frame)
scene.frame_current = frame
mat = pose_bone.matrix
if parent_bone:
mat = parent_bone.matrix.inverted() @ mat
loc = mat.to_translation()
rot = pose_bone.rotation_quaternion.normalized() # <-- maybe this is the problem?
key_times.append(float(frame))
key_loc_x.append(round(loc.x, 7))
key_loc_y.append(round(loc.y, 7))
key_loc_z.append(round(loc.z, 7))
key_rot_x.append(round(rot.x, 7))
key_rot_y.append(round(rot.y, 7))
key_rot_z.append(round(rot.z, 7))
key_rot_w.append(round(rot.w, 7))
result = io.StringIO()
result.write("const\n")
def write_array(name, values):
result.write(f" {name}: array[0..{len(values)-1}] of Single = (")
result.write(", ".join(str(v) for v in values))
result.write(");\n\n")
write_array("KeyTimes", key_times)
write_array("KeyValues_Location_X", key_loc_x)
write_array("KeyValues_Location_Y", key_loc_y)
write_array("KeyValues_Location_Z", key_loc_z)
write_array("KeyValues_Rotation_X", key_rot_x)
write_array("KeyValues_Rotation_Y", key_rot_y)
write_array("KeyValues_Rotation_Z", key_rot_z)
write_array("KeyValues_Rotation_W", key_rot_w)
bpy.context.window_manager.clipboard = result.getvalue()
print(f"✅ Extracted keyframes for bone '{pose_bone.name}' from action '{action.name}'")
proc to Apply Bone Animation
procedure TViewPlay.ApplyAnimation(const Node: TTransformNode;
var ElapsedTime: Single;
const KeyTimes: array of Single;
const KeyLocX, KeyLocY, KeyLocZ: array of Single;
const KeyRotX, KeyRotY, KeyRotZ, KeyRotW: array of Single
);
var
I: Integer;
Q: TQuaternion;
V: TVector3;
begin
if Length(KeyTimes) = 0 then Exit;
for I := 0 to High(KeyTimes) - 1 do
begin
if (ElapsedTime >= KeyTimes[I]) and (ElapsedTime < KeyTimes[I + 1]) then
begin
Q := Quaternion(
Vector4(KeyValues_Rotation_X[i],
KeyValues_Rotation_Y[i],
KeyValues_Rotation_Z[i],
KeyValues_Rotation_W[i]));
Node.Rotation := Q.Data.Vector4;
V := Vector3(KeyLocX[I], KeyLocY[I], KeyLocZ[I]);
Node.Translation := V;
Exit;
end;
end;
Q := Quaternion(Vector4(KeyValues_Rotation_X[High(KeyTimes)], KeyValues_Rotation_Y[High(KeyTimes)],
KeyValues_Rotation_Z[High(KeyTimes)], KeyValues_Rotation_W[High(KeyTimes)]));
Node.Rotation := Q.Data.Vector4;
V := Vector3(KeyLocX[High(KeyTimes)], KeyLocY[High(KeyTimes)], KeyLocZ[High(KeyTimes)]);
Node.Translation := V;
if ElapsedTime > KeyTimes[High(KeyTimes)] then
ElapsedTime := 0;
end;