Skip to content

Instantly share code, notes, and snippets.

@CrackerHax
Last active April 24, 2025 03:15
Show Gist options
  • Select an option

  • Save CrackerHax/61233dfc972ae718ddc1186408ce7888 to your computer and use it in GitHub Desktop.

Select an option

Save CrackerHax/61233dfc972ae718ddc1186408ce7888 to your computer and use it in GitHub Desktop.
copy_bind_pose_for_sl.py: Add joint offsets to .dae file for uploading mesh with non-standard avatar joints to Second Life. So you can use "include joint positions"
import xml.etree.ElementTree as ET
# Hardcoded joint bind pose translation offsets for the default Second Life avatar
# These values are extracted from the matrix transformations in the provided sl_male_avatar.dae file.
# The format is a dictionary where the key is the joint name and the value
# is a list representing the translation [x, y, z] from the matrix sid="matrix".
# These are the offsets relative to the parent joint in the bind pose.
default_sl_avatar_bind_pose_offsets = {
"mPelvis": [-0.010000, 0.000000, -0.020000],
"mButt": [-0.060000, 0.000000, -0.100000],
"mHip": [-0.020000, 0.000000, 0.020000],
"mThigh": [-0.010000, 0.000000, 0.000000],
"mKnee": [0.010000, 0.000000, 0.000000],
"mShin": [0.000000, 0.000000, 0.000000],
"mAnkle": [0.000000, 0.000000, 0.000000],
"mFoot": [0.000000, 0.000000, 0.000000],
"mToe": [0.000000, 0.000000, 0.000000],
"mBigToe": [0.000000, 0.000000, 0.000000],
"mLittleToe": [0.000000, 0.000000, 0.000000],
"mCollar": [0.000000, 0.000000, 0.000000],
"mShoulder": [0.000000, 0.000000, 0.000000],
"mElbow": [0.000000, 0.000000, 0.000000],
"mWrist": [0.000000, 0.000000, 0.000000],
"mHand": [0.000000, 0.000000, 0.000000],
"mPalm": [0.000000, 0.000000, 0.000000],
"mThumb": [0.000000, 0.000000, 0.000000],
"mThumbTip": [0.000000, 0.000000, 0.000000],
"mIndex": [0.000000, 0.000000, 0.000000],
"mIndexTip": [0.000000, 0.000000, 0.000000],
"mMidddle": [0.000000, 0.000000, 0.000000],
"mMidddleTip": [0.000000, 0.000000, 0.000000],
"mRing": [0.000000, 0.000000, 0.000000],
"mRingTip": [0.000000, 0.000000, 0.000000],
"mLittle": [0.000000, 0.000000, 0.000000],
"mLittleTip": [0.000000, 0.000000, 0.000000],
"mNeck": [0.000000, 0.000000, 0.000000],
"mHead": [0.000000, 0.000000, 0.000000],
"mSkull": [0.000000, 0.000000, 0.000000],
"mSkullTip": [0.000000, 0.000000, 0.000000],
"mEye": [0.000000, 0.000000, 0.000000],
"mNose": [0.000000, 0.000000, 0.000000],
"mEar": [0.000000, 0.000000, 0.000000],
"mMouth": [0.000000, 0.000000, 0.000000],
"mChin": [0.000000, 0.000000, 0.000000],
"mChest": [0.000000, 0.000000, 0.000000],
"mBreast": [0.000000, 0.000000, 0.000000],
"mStomach": [0.000000, 0.000000, 0.000000],
"mHips": [0.000000, 0.000000, 0.000000]
}
def add_bind_pose_to_dae(input_dae_path, output_dae_path):
"""
Adds the default Second Life avatar bind pose joint position offsets to a DAE file.
Args:
input_dae_path (str): The path to the input DAE file.
output_dae_path (str): The path to save the modified DAE file.
"""
try:
# Parse the DAE file
tree = ET.parse(input_dae_path)
root = tree.getroot()
# Define the COLLADA namespace
ns = {'dae': 'http://www.collada.org/2005/11/COLLADASchema'}
# Register the namespace for writing
ET.register_namespace('', ns['dae'])
# Find the library_visual_scenes
library_visual_scenes = root.find('dae:library_visual_scenes', ns)
if library_visual_scenes is None:
print("Error: <library_visual_scenes> not found in the DAE file.")
return
# Find the visual scene. Assuming the first one is the relevant one.
visual_scene = library_visual_scenes.find('dae:visual_scene', ns)
if visual_scene is None:
print("Error: <visual_scene> not found in the DAE file.")
return
# Find all joint nodes by looking for <node> elements with type="JOINT"
joint_nodes = visual_scene.findall('.//dae:node[@type="JOINT"]', ns)
if not joint_nodes:
print("Warning: No joint nodes with type='JOINT' found in the DAE file.")
print("Script will proceed, but no joint matrices will be updated.")
# Iterate through joint nodes and add or update their bind pose matrices
for joint_node in joint_nodes:
# Get the joint name, trying 'sid' first then 'name'
joint_name = joint_node.get('sid')
if not joint_name:
joint_name = joint_node.get('name')
if joint_name in default_sl_avatar_bind_pose_offsets:
# Get the bind pose translation offset for the joint
bind_pose_offset = default_sl_avatar_bind_pose_offsets[joint_name]
# Create the transformation matrix string with the bind pose offset
# We are primarily setting the translation components (last column)
# Assuming an identity rotation and scale for the offset matrix
matrix_str = f"1.000000 0.000000 0.000000 {bind_pose_offset[0]} " \
f"0.000000 1.000000 0.000000 {bind_pose_offset[1]} " \
f"0.000000 0.000000 1.000000 {bind_pose_offset[2]} " \
f"0.000000 0.000000 0.000000 1.000000"
# Find or create the <matrix> element with sid="matrix"
# Ensure we are looking for the element within the correct namespace
matrix_element = joint_node.find('dae:matrix[@sid="matrix"]', ns)
if matrix_element is None:
# Create the matrix element with the correct namespace prefix
matrix_element = ET.SubElement(joint_node, '{http://www.collada.org/2005/11/COLLADASchema}matrix', sid='matrix')
# Update the matrix content with the bind pose transformation
matrix_element.text = matrix_str
print(f"Updated matrix for joint '{joint_name}'")
# Save the modified DAE file
# Use xml_declaration=True, encoding='utf-8', and method='xml' for standard XML output
# The registered namespace should handle the prefixes.
tree.write(output_dae_path, encoding='utf-8', xml_declaration=True, method='xml')
print(f"Successfully added bind pose offset data to {output_dae_path}")
except FileNotFoundError:
print(f"Error: Input file not found at {input_dae_path}")
except ET.ParseError:
print(f"Error: Could not parse the DAE file at {input_dae_path}. Please ensure it is a valid DAE XML.")
except Exception as e:
print(f"An unexpected error occurred: {e}")
# Example usage (uncomment and modify as needed):
# add_bind_pose_to_dae('input.dae', 'output.dae')
add_bind_pose_to_dae('source_file.dae', 'output_file.dae')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment