def export_arms_fix(exportfolderpath, bodyNo): # # first we need to start with arm_LClips1__arm_L_initSource # but this is not done yet, how could I miss this initialization? # on a second thought, to match the body, maybe this should be actually 0 ? game default has a rotation on Y axis of -18/18 degrees # neck_joint01 = bpy.data.objects["_neck_joint01"] wrist_L_joint = bpy.data.objects["_wrist_L_joint"] forearm_L_joint = bpy.data.objects["_forearm_L_joint"] forearm_L_joint = bpy.data.objects["_forearm_L_joint"] arm_R_ikEffector, arm_R_ikHandle = getIKValues("Armature", "elbow_joint.R", "wrist_joint.R") arm_R_ikEffector, arm_R_ikHandle, distance, translation = getClosestPointFromBoneProjection( "Armature", "elbow_joint.R", "wrist_joint.R") arm_L_ikEffector, arm_L_ikHandle, distance, translation = getClosestPointFromBoneProjection( "Armature", "elbow_joint.L", "wrist_joint.L") arms_fix_string = "\n" # #arm_LClips1__arm_L_initSource #those are actually rotations that are applied to the hands, in this case we want to keep the rest pose at 0 snippet = "var :mySplineVector3f :Person\" + :person + \"Anim:Model01:arm_LClips1__arm_L_initSource.Curve[0] ?;" mySplineVectorString = "(" + " {:.6g}f,".format(0) + " {:.6g}f,".format( 0) + " {:.6g}f".format(0) + " )" snippet = snippet + "\n:mySplineVector3f.KeyValue [ " + mySplineVectorString + " , " + mySplineVectorString + " ];" snippet = snippet + "\ndel :mySplineVector3f;" arms_fix_string = arms_fix_string + snippet arms_fix_string = arms_fix_string + "\n" # #arm_RClips1__arm_R_initSource1 (there must be a 1 at the end, is not like arm_RClips1__arm_R_initSource and that is it) snippet = "var :mySplineVector3f :Person\" + :person + \"Anim:Model01:arm_RClips1__arm_R_initSource1.Curve[0] ?;" mySplineVectorString = "(" + " {:.6g}f,".format(0) + " {:.6g}f,".format( 0) + " {:.6g}f".format(0) + " )" snippet = snippet + "\n:mySplineVector3f.KeyValue [ " + mySplineVectorString + " , " + mySplineVectorString + " ];" snippet = snippet + "\ndel :mySplineVector3f;" arms_fix_string = arms_fix_string + snippet arms_fix_string = arms_fix_string + "\n" # # ob = bpy.data.objects.new("_neck_joint01_translated", None) ob.rotation_mode = 'YZX' ob.parent = neck_joint01 ob.matrix_world = neck_joint01.matrix_world ob.matrix_basis = ob.matrix_parent_inverse * ob.matrix_basis ob.matrix_parent_inverse.identity() # Define the translation we want to perform in local space (after rotation) # we actually move down the local Y axis of the ankle joint trans_local = neck_joint01.matrix_world.inverted() * Vector((0, 0, 0)) # Convert the local translation to global with the 3x3 rotation matrix of our object trans_world = ob.matrix_world.to_3x3() * trans_local # Apply the translation ob.matrix_world.translation += trans_world bpy.context.scene.objects.link(ob) neck_joint01_translated = ob # #elbow_LClips1__elbow_L_initSource + elbow_RClips1__elbow_R_initSource elbow_initSource = neck_joint01.matrix_world.inverted() * Vector((0, 0, 0)) snippet = "var :mySplineVector3f :Person\" + :person + \"Anim:Model01:elbow_LClips1__elbow_L_initSource.Curve[0] ?;" mySplineVectorString = "(" + " {:.6g}f,".format( elbow_initSource.y + 0) + " {:.6g}f,".format(-elbow_initSource.z + 0) + " {:.6g}f".format(elbow_initSource.x + 0) + " )" #??? y,-z,x snippet = snippet + "\n:mySplineVector3f.KeyValue [ " + mySplineVectorString + " , " + mySplineVectorString + " ];" snippet = snippet + "\ndel :mySplineVector3f;" arms_fix_string = arms_fix_string + snippet arms_fix_string = arms_fix_string + "\n" snippet = "var :mySplineVector3f :Person\" + :person + \"Anim:Model01:elbow_RClips1__elbow_R_initSource.Curve[0] ?;" mySplineVectorString = "(" + " {:.6g}f,".format( elbow_initSource.y + 0) + " {:.6g}f,".format(-elbow_initSource.z + 0) + " {:.6g}f".format(elbow_initSource.x + 0) + " )" # y,-z,x snippet = snippet + "\n:mySplineVector3f.KeyValue [ " + mySplineVectorString + " , " + mySplineVectorString + " ];" snippet = snippet + "\ndel :mySplineVector3f;" arms_fix_string = arms_fix_string + snippet arms_fix_string = arms_fix_string + "\n" # #effector snippet = ":Person\" + :person + \"Anim:Model01:" snippet = snippet + "arm_L_effector" snippet = snippet + ".SNode? . {\n" snippet = snippet + "\t.ScalingPivot (" + " {:.6f}f,".format( wrist_L_joint.location.y + 0) + " {:.6f}f,".format( wrist_L_joint.location.x + 0) + " {:.6f}f".format( wrist_L_joint.location.z + 0) + " );\n" #here we switch from yzx to yxz snippet = snippet + "\t.RotationPivot (" + " {:.6f}f,".format( wrist_L_joint.location.y + 0) + " {:.6f}f,".format( wrist_L_joint.location.x + 0) + " {:.6f}f".format( wrist_L_joint.location.z + 0) + " );\n" #here we switch from yzx to yxz snippet = snippet + "\t.Translation (" + " {:.6f}f,".format( forearm_L_joint.location.y + 0) + " {:.6f}f,".format( forearm_L_joint.location.z + 0) + " {:.6f}f".format(forearm_L_joint.location.x + 0) + " );\n" #no switch snippet = snippet + "};\n" snippet = snippet + "" arms_fix_string = arms_fix_string + snippet arms_fix_string = arms_fix_string + "\n" #hand_L_target01 snippet = ":Person\" + :person + \"Anim:Model01:" snippet = snippet + "hand_L_target01" snippet = snippet + ".SNode? . {\n" snippet = snippet + "\t.ScalingPivot (" + " {:.6f}f,".format( arm_L_ikHandle.x + 0) + " {:.6f}f,".format(arm_L_ikHandle.z + 0) + " {:.6g}f".format( -arm_L_ikHandle.y + 0) + " );\n" #here we switch to xz -y snippet = snippet + "\t.RotationPivot (" + " {:.6f}f,".format( arm_L_ikHandle.x + 0) + " {:.6f}f,".format(arm_L_ikHandle.z + 0) + " {:.6g}f".format( -arm_L_ikHandle.y + 0) + " );\n" #here we switch to xz -y #old code below #snippet = snippet+ "\t.ScalingPivot (" +" {:.6f}f,".format(wrist_L_joint.matrix_world.to_translation().x+ 0) +" {:.6f}f,".format(wrist_L_joint.matrix_world.to_translation().z+ 0) +" {:.6g}f".format(-wrist_L_joint.matrix_world.to_translation().y+ 0) +" );\n" #here we switch to xz -y #snippet = snippet+ "\t.RotationPivot (" +" {:.6f}f,".format(wrist_L_joint.matrix_world.to_translation().x+ 0) +" {:.6f}f,".format(wrist_L_joint.matrix_world.to_translation().z+ 0) +" {:.6g}f".format(-wrist_L_joint.matrix_world.to_translation().y+ 0) +" );\n" #here we switch to xz -y snippet = snippet + "};\n" snippet = snippet + "" arms_fix_string = arms_fix_string + snippet arms_fix_string = arms_fix_string + "\n" #arm_L_group depends on hand_L_target01_locator_parent because it has a constraint reparent on it snippet = ":Person\" + :person + \"Anim:Model01:" snippet = snippet + "hand_L_target01_locator_parent" snippet = snippet + ".SNode? . {\n" snippet = snippet + "\t.Translation (" + " {:.6f}f,".format( arm_L_ikHandle.x + 0) + " {:.6f}f,".format(arm_L_ikHandle.z + 0) + " {:.6f}f".format(-arm_L_ikHandle.y + 0) + " );\n" #no switch #snippet = snippet+ "\t.Translation (" +" {:.6f}f,".format(wrist_L_joint.matrix_world.to_translation().x+ 0) +" {:.6f}f,".format(wrist_L_joint.matrix_world.to_translation().z+ 0) +" {:.6f}f".format(-wrist_L_joint.matrix_world.to_translation().y+ 0) +" );\n" #no switch snippet = snippet + "};\n" snippet = snippet + "" arms_fix_string = arms_fix_string + snippet arms_fix_string = arms_fix_string + "\n" # #arm_L_locator # fingers_average_location = Vector((0, 0, 0)) fingers_names = [ "_finger01_L_joint01", "_finger02_L_joint01", "_finger03_L_joint01", "_finger04_L_joint01", "_finger05_L_joint01", "_finger01_L_joint02", "_finger02_L_joint02", "_finger03_L_joint02", "_finger04_L_joint02", "_finger05_L_joint02" ] for finger in fingers_names: fingers_average_location += bpy.data.objects[ finger].matrix_world.translation fingers_average_location = fingers_average_location / len(fingers_names) difference = fingers_average_location - arm_L_ikHandle #wrist_L_joint.matrix_world.to_translation() # snippet = ":Person\" + :person + \"Anim:Model01:" snippet = snippet + "arm_L_locator" snippet = snippet + ".SNode? . {\n" snippet = snippet + "\t.Translation (" + " {:.6f}f,".format( difference.x + 0) + " {:.6f}f,".format(difference.z + 0) + " {:.6g}f".format( -difference.y + 0) + " );\n" #here we switch to xz -y snippet = snippet + "\t.Rotation ( 0f, 180f, 0f );\n" snippet = snippet + "};\n" snippet = snippet + "" arms_fix_string = arms_fix_string + snippet arms_fix_string = arms_fix_string + "\n" # # arm_L_base_locator # I think arm_R_offset_locator moves in the center of palm, then it rotates then returns back to wrist loc snippet = ":Person\" + :person + \"Anim:Model01:" snippet = snippet + "arm_L_base_locator" snippet = snippet + ".SNode? . {\n" snippet = snippet + "\t.Translation (" + " {:.6f}f,".format( -difference.x + 0) + " {:.6f}f,".format(-difference.z + 0) + " {:.6g}f".format( difference.y + 0) + " );\n" #here we switch to xz -y snippet = snippet + "};\n" snippet = snippet + "" arms_fix_string = arms_fix_string + snippet arms_fix_string = arms_fix_string + "\n" # #arm_L_ikHandle # this should be maybe all zero ?!?? snippet = ":Person\" + :person + \"Anim:Model01:" snippet = snippet + "arm_L_ikHandle" snippet = snippet + ".SNode? . {\n" snippet = snippet + "\t.Translation (" + " {:.6f}f,".format( 0) + " {:.6f}f,".format(0) + " {:.6g}f".format(0) + " );\n" snippet = snippet + "};\n" snippet = snippet + "" arms_fix_string = arms_fix_string + snippet arms_fix_string = arms_fix_string + "\n" # snippet = ":Person\" + :person + \"Pick:body_hand_L_pick.SNode?.Translation ( -0.096892565f, 0.0010810591f, -0.0056944136f );\n" #:Person" + :person + "Pick:body_hand_L_pick.SNode?.Translation ( -0.096892565f, 0.0010810591f, -0.0056944136f ); arms_fix_string = arms_fix_string + snippet arms_fix_string = arms_fix_string + "\n" # #Selbow_L_group line_b = bpy.data.objects["_elbow_L_joint"].matrix_world.to_translation() # we move it along local Y axis, get the moved vector then move it back to original location bpy.data.objects["_elbow_L_joint"].matrix_basis *= Matrix.Translation( (0.0, -1.0, 0.0)) #for some reason we need to update the scene, otherwise the matrix wont work bpy.data.scenes[0].update() line_a = bpy.data.objects["_elbow_L_joint"].matrix_world.to_translation() bpy.data.objects["_elbow_L_joint"].matrix_basis *= Matrix.Translation( (0.0, 1.0, 0.0)) bpy.data.scenes[0].update() # plane_co = bpy.data.objects[ "_shoulder_L_joint"].matrix_world.to_translation() plane_no = Vector((-1, 0, 0)) calculated_elbow_L_group_world_coordinates = mathutils.geometry.intersect_line_plane( line_a, line_b, plane_co, plane_no) #new code, now we calculate elbow manipulator based on empty _arm_pole_L calculated_elbow_L_group_world_coordinates = bpy.data.objects[ "_arm_pole_L"].matrix_world.to_translation() calculated_elbow_L_group_local_coord = neck_joint01_translated.matrix_world.inverted( ) * calculated_elbow_L_group_world_coordinates snippet = ":Person\" + :person + \"Anim:Model01:" snippet = snippet + "elbow_L_group" snippet = snippet + ".SNode? . {\n" snippet = snippet + "\t.RotationPivot (" + " {:.6f}f,".format( calculated_elbow_L_group_local_coord.y + 0 ) + " {:.6f}f,".format( calculated_elbow_L_group_local_coord.z + 0 ) + " {:.6f}f".format( calculated_elbow_L_group_local_coord.x + 0 ) + " );\n" #here we switch to yzx because we are parented to neck joint #we also need to do RotationPivotTranslation ... #but if we calculated above correctly, then there should be no requirements for RotationPivotTranslation, as this was a bug in original game (location was in world coordinates and they had to fix that back to local) snippet = snippet + "\t.RotationPivotTranslation (" + " {:.6f}f,".format( 0) + " {:.6f}f,".format(0) + " {:.6g}f".format( 0) + " );\n" #here we switch to xz -y snippet = snippet + "};\n" snippet = snippet + "" arms_fix_string = arms_fix_string + snippet arms_fix_string = arms_fix_string + "\n" # #ellbow_L_locator snippet = ":Person\" + :person + \"Anim:Model01:" snippet = snippet + "ellbow_L_locator" snippet = snippet + ".SNode? . {\n" snippet = snippet + "\t.Translation (" + " {:.6f}f,".format( calculated_elbow_L_group_local_coord.y + 0 ) + " {:.6f}f,".format( calculated_elbow_L_group_local_coord.z + 0 ) + " {:.6f}f".format( calculated_elbow_L_group_local_coord.x + 0 ) + " );\n" #here we switch to yzx because we are parented to neck joint snippet = snippet + "};\n" snippet = snippet + "" arms_fix_string = arms_fix_string + snippet arms_fix_string = arms_fix_string + "\n" # # # wrist_R_joint = bpy.data.objects["_wrist_R_joint"] forearm_R_joint = bpy.data.objects["_forearm_R_joint"] elbow_R_joint = bpy.data.objects["_elbow_R_joint"] arm_R_ikEffector, arm_R_ikHandle = getIKValues("Armature", "elbow_joint.R", "wrist_joint.R") arm_R_ikEffector, arm_R_ikHandle, distance, translationAlongY = getClosestPointFromBoneProjection( "Armature", "elbow_joint.R", "wrist_joint.R") localCo, worldCo, distance, translationAlongY = getClosestPointFromBoneProjection( "Armature", "forearm_joint.R", "wrist_joint.R") wrist_R_joint_world_coordinates = wrist_R_joint.matrix_world.to_translation( ) arm_effector = elbow_R_joint.matrix_world.inverted( ) * wrist_R_joint_world_coordinates # snippet = ":Person\" + :person + \"Anim:Model01:" snippet = snippet + "arm_R_effector" snippet = snippet + ".SNode? . {\n" snippet = snippet + "\t.ScalingPivot (" + " {:.6g}f,".format( translationAlongY.x + 0) + " {:.6g}f,".format(translationAlongY.y + 0) + " {:.6g}f".format(translationAlongY.z + 0) + " );\n" #no switch snippet = snippet + "\t.RotationPivot (" + " {:.6g}f,".format( translationAlongY.x + 0) + " {:.6g}f,".format(translationAlongY.y + 0) + " {:.6g}f".format(translationAlongY.z + 0) + " );\n" #no switch #snippet = snippet+ "\t.RotationPivot (" +" {:.6g}f,".format(arm_R_ikEffector.x - forearm_R_joint.location.y+ 0) +" {:.6g}f,".format(arm_R_ikEffector.y - forearm_R_joint.location.z+ 0) +" {:.6g}f".format(arm_R_ikEffector.z - forearm_R_joint.location.x + 0) +" );\n" #no switch #snippet = snippet+ "\t.ScalingPivot (" +" {:.6g}f,".format(arm_R_ikEffector.x - forearm_R_joint.location.y+ 0) +" {:.6g}f,".format(arm_R_ikEffector.y - forearm_R_joint.location.z+ 0) +" {:.6g}f".format(arm_R_ikEffector.z - forearm_R_joint.location.x + 0) +" );\n" #no switch #snippet = snippet+ "\t.ScalingPivot (" +" {:.6f}f,".format(arm_effector.y - forearm_R_joint.location.y + 0) +" {:.6f}f,".format(arm_effector.z - forearm_R_joint.location.z+ 0) +" {:.6g}f".format(arm_effector.x - forearm_R_joint.location.x+ 0) +" );\n" #here we switch from yzx to yxz #snippet = snippet+ "\t.ScalingPivot (" +" {:.6f}f,".format(wrist_R_joint.location.y+ 0) +" {:.6f}f,".format(wrist_R_joint.location.x+ 0) +" {:.6g}f".format(wrist_R_joint.location.z+ 0) +" );\n" #here we switch from yzx to yxz #snippet = snippet+ "\t.RotationPivot (" +" {:.6f}f,".format(wrist_R_joint.location.y+ 0) +" {:.6f}f,".format(wrist_R_joint.location.x+ 0) +" {:.6g}f".format(wrist_R_joint.location.z+ 0) +" );\n" #here we switch from yzx to yxz snippet = snippet + "\t.Translation (" + " {:.6f}f,".format( forearm_R_joint.location.y + 0) + " {:.6f}f,".format( forearm_R_joint.location.z + 0) + " {:.6g}f".format(forearm_R_joint.location.x + 0) + " );\n" #no switch #snippet = snippet+ "\t.Translation (" +" {:.6f}f,".format(arm_effector.x+ 0) +" {:.6f}f,".format(arm_effector.z+ 0) +" {:.6g}f".format(-arm_effector.y+ 0) +" );\n" #no switch snippet = snippet + "};\n" snippet = snippet + "" arms_fix_string = arms_fix_string + snippet arms_fix_string = arms_fix_string + "\n" #arm_R_group depends on hand_R_target01_locator_parent because it has a constraint reparent on it snippet = ":Person\" + :person + \"Anim:Model01:" snippet = snippet + "hand_R_target01_locator_parent" snippet = snippet + ".SNode? . {\n" #snippet = snippet+ "\t.Translation (" +" {:.6f}f,".format(wrist_R_joint.matrix_world.to_translation().x+ 0) +" {:.6f}f,".format(wrist_R_joint.matrix_world.to_translation().z+ 0) +" {:.6g}f".format(-wrist_R_joint.matrix_world.to_translation().y+ 0) +" );\n" #here we switch to xz -y (daz to villa) snippet = snippet + "\t.Translation (" + " {:.6f}f,".format( arm_R_ikHandle.x + 0) + " {:.6f}f,".format(arm_R_ikHandle.z + 0) + " {:.6f}f".format(-arm_R_ikHandle.y + 0) + " );\n" #no switch snippet = snippet + "};\n" snippet = snippet + "" arms_fix_string = arms_fix_string + snippet arms_fix_string = arms_fix_string + "\n" # snippet = ":Person\" + :person + \"Anim:Model01:" snippet = snippet + "hand_R_target01" snippet = snippet + ".SNode? . {\n" snippet = snippet + "\t.ScalingPivot (" + " {:.6f}f,".format( arm_R_ikHandle.x + 0) + " {:.6f}f,".format(arm_R_ikHandle.z + 0) + " {:.6g}f".format( -arm_R_ikHandle.y + 0) + " );\n" #here we switch to xz -y snippet = snippet + "\t.RotationPivot (" + " {:.6f}f,".format( arm_R_ikHandle.x + 0) + " {:.6f}f,".format(arm_R_ikHandle.z + 0) + " {:.6g}f".format( -arm_R_ikHandle.y + 0) + " );\n" #here we switch to xz -y #snippet = snippet+ "\t.ScalingPivot (" +" {:.6f}f,".format(wrist_R_joint.matrix_world.to_translation().x+ 0) +" {:.6f}f,".format(wrist_R_joint.matrix_world.to_translation().z+ 0) +" {:.6g}f".format(-wrist_R_joint.matrix_world.to_translation().y+ 0) +" );\n" #here we switch to xz -y #snippet = snippet+ "\t.RotationPivot (" +" {:.6f}f,".format(wrist_R_joint.matrix_world.to_translation().x+ 0) +" {:.6f}f,".format(wrist_R_joint.matrix_world.to_translation().z+ 0) +" {:.6g}f".format(-wrist_R_joint.matrix_world.to_translation().y+ 0) +" );\n" #here we switch to xz -y snippet = snippet + "};\n" snippet = snippet + "" arms_fix_string = arms_fix_string + snippet arms_fix_string = arms_fix_string + "\n" # #arm_R_locator # fingers_average_location = Vector((0, 0, 0)) fingers_names = [ "_finger01_R_joint01", "_finger02_R_joint01", "_finger03_R_joint01", "_finger04_R_joint01", "_finger05_R_joint01", "_finger01_R_joint02", "_finger02_R_joint02", "_finger03_R_joint02", "_finger04_R_joint02", "_finger05_R_joint02" ] for finger in fingers_names: fingers_average_location += bpy.data.objects[ finger].matrix_world.translation fingers_average_location = fingers_average_location / len(fingers_names) difference = fingers_average_location - wrist_R_joint.matrix_world.to_translation( ) # snippet = ":Person\" + :person + \"Anim:Model01:" snippet = snippet + "arm_R_locator" snippet = snippet + ".SNode? . {\n" snippet = snippet + "\t.Translation (" + " {:.6f}f,".format( difference.x + 0) + " {:.6f}f,".format(difference.z + 0) + " {:.6g}f".format( -difference.y + 0) + " );\n" #here we switch to xz -y snippet = snippet + "};\n" snippet = snippet + "" arms_fix_string = arms_fix_string + snippet arms_fix_string = arms_fix_string + "\n" # # arm_R_base_locator # I think arm_R_offset_locator moves in the center of palm, then it rotates then returns back to wrist loc snippet = ":Person\" + :person + \"Anim:Model01:" snippet = snippet + "arm_R_base_locator" snippet = snippet + ".SNode? . {\n" snippet = snippet + "\t.Translation (" + " {:.6f}f,".format( -difference.x + 0) + " {:.6f}f,".format(-difference.z + 0) + " {:.6g}f".format( difference.y + 0) + " );\n" #here we switch to xz -y snippet = snippet + "\t.Rotation ( 0f, 0f, 180f );\n" snippet = snippet + "};\n" snippet = snippet + "" arms_fix_string = arms_fix_string + snippet arms_fix_string = arms_fix_string + "\n" # #wrist_R_joint_orientConstraint1.OrientOffset wrist_fake_joint_R = bpy.data.objects["_wrist_fake_joint_R"] snippet = ":Person\" + :person + \"Anim:Model01:wrist_R_joint_orientConstraint1.OrientOffset (" + " {:.6f}f,".format( degrees(wrist_fake_joint_R.rotation_euler.y) + 0) + " {:.6f}f,".format( degrees(wrist_fake_joint_R.rotation_euler.z) + 0) + " {:.6g}f".format( degrees(wrist_fake_joint_R.rotation_euler.x) + 0) + " );\n" #here we switch to y z x snippet = snippet + "\n" snippet = snippet + "" arms_fix_string = arms_fix_string + snippet arms_fix_string = arms_fix_string + "\n" #arm_R_ikHandle # this should be maybe all zero ?!?? snippet = ":Person\" + :person + \"Anim:Model01:" snippet = snippet + "arm_R_ikHandle" snippet = snippet + ".SNode? . {\n" snippet = snippet + "\t.Translation (" + " {:.6f}f,".format( 0) + " {:.6f}f,".format(0) + " {:.6g}f".format(0) + " );\n" snippet = snippet + "};\n" snippet = snippet + "" arms_fix_string = arms_fix_string + snippet arms_fix_string = arms_fix_string + "\n" # # #Selbow_R_group line_b = bpy.data.objects["_elbow_R_joint"].matrix_world.to_translation() # we move it along local Y axis, get the moved vector then move it back to original location bpy.data.objects["_elbow_R_joint"].matrix_basis *= Matrix.Translation( (0.0, 1.0, 0.0)) #for some reason we need to update the scene, otherwise the matrix wont work bpy.data.scenes[0].update() line_a = bpy.data.objects["_elbow_R_joint"].matrix_world.to_translation() bpy.data.objects["_elbow_R_joint"].matrix_basis *= Matrix.Translation( (0.0, -1.0, 0.0)) bpy.data.scenes[0].update() # plane_co = bpy.data.objects[ "_shoulder_R_joint"].matrix_world.to_translation() plane_no = Vector((-1, 0, 0)) calculated_elbow_R_group_world_coordinates = mathutils.geometry.intersect_line_plane( line_a, line_b, plane_co, plane_no) ##=new code, now we calculate elbow manipulator based on empty _arm_pole_R calculated_elbow_R_group_world_coordinates = bpy.data.objects[ "_arm_pole_R"].matrix_world.to_translation() calculated_elbow_R_group_local_coord = neck_joint01_translated.matrix_world.inverted( ) * calculated_elbow_R_group_world_coordinates #bpy.context.scene.cursor_location = neck_joint01_translated.matrix_world * calculated_elbow_R_group_local_coord # #neck_joint01_matrix = neck_joint01.matrix_local.copy() #mat_loc = mathutils.Matrix.Translation(calculated_elbow_R_group_local_coord) #mat_rot = neck_joint01_matrix.to_3x3() #new_mat = mat_loc * mat_rot #direction = elbow_initSource.copy() #direction.rotate(neck_joint01.matrix_world) #custom_location = neck_joint01.location + direction # snippet = ":Person\" + :person + \"Anim:Model01:" snippet = snippet + "elbow_R_group" snippet = snippet + ".SNode? . {\n" # .RotationPivot ( 1.412567f, -0.148455f, 0.331618f ); snippet = snippet + "\t.RotationPivot (" + " {:.6f}f,".format( calculated_elbow_R_group_local_coord.y + 0) + " {:.6f}f,".format( calculated_elbow_R_group_local_coord.z + 0) + " {:.6f}f".format(calculated_elbow_R_group_local_coord.x + 0) + " );\n" #here we switch to xz -y #we also need to do RotationPivotTranslation ... #but if we calculated above correctly, then there should be no requirements for RotationPivotTranslation snippet = snippet + "\t.RotationPivotTranslation (" + " {:.6f}f,".format( 0) + " {:.6f}f,".format(0) + " {:.6f}f".format( 0) + " );\n" #here we switch to xz -y snippet = snippet + "};\n" snippet = snippet + "" arms_fix_string = arms_fix_string + snippet arms_fix_string = arms_fix_string + "\n" # #ellbow_R_locator snippet = ":Person\" + :person + \"Anim:Model01:" snippet = snippet + "ellbow_R_locator" snippet = snippet + ".SNode? . {\n" snippet = snippet + "\t.Translation (" + " {:.6f}f,".format( calculated_elbow_R_group_local_coord.y + 0) + " {:.6f}f,".format( calculated_elbow_R_group_local_coord.z + 0) + " {:.6f}f".format(calculated_elbow_R_group_local_coord.x + 0) + " );\n" #here we switch to xz -y snippet = snippet + "};\n" snippet = snippet + "" arms_fix_string = arms_fix_string + snippet arms_fix_string = arms_fix_string + "\n" # arms_fix_string += ":Person\" + :person + \"Anim:Model01:wrist_L_joint.SNode?.RotationAxis (0f, 0f, 0f);\n" print(arms_fix_string) file_path = exportfolderpath + "AcBody" + bodyNo + "Collision.bs" f = open(file_path, 'a') f.write(arms_fix_string) f.flush() f.close()
def objects_to_bmesh(objs, transform=True): """ Merges multiple objects into one bmesh for export """ # CAUTION: Removes/destroys custom layer props # Creates the mesh used to merge the entire scene bm_all = bmesh.new() # Adds the objects" meshes to the bmesh for obj in objs: dprint("Preparing object {} for export...".format(obj.name)) # Creates a bmesh from the supplied object bm = bmesh.new() bm.from_mesh(obj.data) # Makes sure all layers exist so values don't get lost while exporting uv_layer = bm.loops.layers.uv.get("UVMap") tex_layer = bm.faces.layers.tex.get("UVMap") vc_layer = (bm.loops.layers.color.get("Col") or bm.loops.layers.color.new("Col")) env_layer = (bm.loops.layers.color.get("Env") or bm.loops.layers.color.new("Env")) env_alpha_layer = (bm.faces.layers.float.get("EnvAlpha") or bm.faces.layers.float.new("EnvAlpha")) va_layer = (bm.loops.layers.color.get("Alpha") or bm.loops.layers.color.new("Alpha")) texnum_layer = bm.faces.layers.int.get("Texture Number") type_layer = (bm.faces.layers.int.get("Type") or bm.faces.layers.int.new("Type")) material_layer = (bm.faces.layers.int.get("Material") or bm.faces.layers.int.new("Material")) # Removes the parent for exporting and applies transformation parent = obj.parent if parent: mat = obj.matrix_world.copy() old_mat = obj.matrix_basis.copy() obj.parent = None obj.matrix_world = mat spc = obj.matrix_basis bmesh.ops.scale(bm, vec=obj.scale, space=spc, verts=bm.verts) if transform: bmesh.ops.transform(bm, matrix=Matrix.Translation(obj.location), space=spc, verts=bm.verts) bmesh.ops.rotate(bm, cent=obj.location, matrix=obj.rotation_euler.to_matrix(), space=spc, verts=bm.verts) # Restores the parent relationship if parent and not obj.parent: obj.parent = parent obj.matrix_basis = old_mat # Converts the transformed bmesh to mesh new_mesh = bpy.data.meshes.new("ncp_export_temp") bm.to_mesh(new_mesh) # Adds the transformed mesh to the big bmesh bm_all.from_mesh(new_mesh) # Removes unused meshes bpy.data.meshes.remove(new_mesh, do_unlink=True) bm.free() return bm_all
def action_common(self, context, redoing) : try : curve_name = "Curlicue" vertices = [] faces = [] for i in range(self.nr_points) : angle = i / self.nr_points * self.nr_turns * 2 * math.pi if self.curve_type == "linear" : radius = \ ( i / self.nr_points * (self.radius - self.linear_offset) + self.linear_offset ) elif self.curve_type == "log" : radius = \ ( self.radius * self.radius_ratio ** (angle / (2 * math.pi) - self.nr_turns) ) else : raise Failure("SHOULDN’T OCCUR: unrecognized curve type") #end if width = \ ( self.outer_taper * i / self.nr_points + self.inner_taper * (1 - i / self.nr_points) ) to_midpoint = \ ( Matrix.Rotation(angle, 4, "Z") * Matrix.Translation(Vector((radius, 0, 0))) ) orient = math.pi / 2 # ! pt1 = \ ( to_midpoint * Matrix.Rotation(orient + math.pi / 2, 4, "Z") * Matrix.Translation(Vector((width / 2, 0, 0))) * Vector((0, 0, 0)) ) pt2 = \ ( to_midpoint * Matrix.Rotation(orient - math.pi / 2, 4, "Z") * Matrix.Translation(Vector((width / 2, 0, 0))) * Vector((0, 0, 0)) ) vertices.extend([pt1, pt2]) if len(vertices) >= 4 : faces.append(list(len(vertices) + i for i in (-4, -3, -1, -2))) #end if #end for the_curve = bpy.data.meshes.new(curve_name) the_curve.from_pydata(vertices, [], faces) object_utils.object_data_add(context, the_curve, name = curve_name) # all done status = {"FINISHED"} except Failure as why : sys.stderr.write("Failure: {}\n".format(why.msg)) # debug self.report({"ERROR"}, why.msg) status = {"CANCELLED"} #end try return \ status
def view_matrix(self): return Matrix.Translation(Vector((0, 0, 5)))
import bpy from mathutils import Vector, Matrix import math bpy.ops.object.select_all(action='SELECT') bpy.ops.object.delete() x, y, z = 0, 0, 0 for i in range(10): bpy.ops.mesh.primitive_cube_add(location=[x, y, z]) obj = bpy.context.active_object translation = (0, 0, 2 * i) translation_matrix = Matrix.Translation(translation) print("Translation matrix ", translation_matrix) obj.matrix_world *= translation_matrix
def loc_mat(mat): return Matrix.Translation(mat.to_translation()).to_4x4()
def set_bone_transforms(gltf, skin_id, bone, node_id, parent): pyskin = gltf.data.skins[skin_id] pynode = gltf.data.nodes[node_id] obj = bpy.data.objects[pyskin.blender_armature_name] # Set bone bind_pose by inverting bindpose matrix if node_id in pyskin.joints: index_in_skel = pyskin.joints.index(node_id) inverse_bind_matrices = BinaryData.get_data_from_accessor( gltf, pyskin.inverse_bind_matrices) # Needed to keep scale in matrix, as bone.matrix seems to drop it if index_in_skel < len(inverse_bind_matrices): pynode.blender_bone_matrix = Conversion.matrix_gltf_to_blender( inverse_bind_matrices[index_in_skel]).inverted() bone.matrix = pynode.blender_bone_matrix else: gltf.log.error("Error with inverseBindMatrix for skin " + pyskin) else: print('No invBindMatrix for bone ' + str(node_id)) pynode.blender_bone_matrix = Matrix() # Parent the bone if parent is not None and hasattr(gltf.data.nodes[parent], "blender_bone_name"): bone.parent = obj.data.edit_bones[gltf.data.nodes[ parent].blender_bone_name] #TODO if in another scene # Switch to Pose mode bpy.ops.object.mode_set(mode="POSE") obj.data.pose_position = 'POSE' # Set posebone location/rotation/scale (in armature space) # location is actual bone location minus it's original (bind) location bind_location = Matrix.Translation( pynode.blender_bone_matrix.to_translation()) bind_rotation = pynode.blender_bone_matrix.to_quaternion() bind_scale = Conversion.scale_to_matrix( pynode.blender_bone_matrix.to_scale()) location, rotation, scale = Conversion.matrix_gltf_to_blender( pynode.transform).decompose() if parent is not None and hasattr(gltf.data.nodes[parent], "blender_bone_matrix"): parent_mat = gltf.data.nodes[parent].blender_bone_matrix # Get armature space location (bindpose + pose) # Then, remove original bind location from armspace location, and bind rotation final_location = (bind_location.inverted() * parent_mat * Matrix.Translation(location)).to_translation() obj.pose.bones[ pynode.blender_bone_name].location = bind_rotation.inverted( ).to_matrix().to_4x4() * final_location # Do the same for rotation obj.pose.bones[pynode.blender_bone_name].rotation_quaternion = ( bind_rotation.to_matrix().to_4x4().inverted() * parent_mat * rotation.to_matrix().to_4x4()).to_quaternion() obj.pose.bones[pynode.blender_bone_name].scale = ( bind_scale.inverted() * parent_mat * Conversion.scale_to_matrix(scale)).to_scale() else: obj.pose.bones[ pynode.blender_bone_name].location = bind_location.inverted( ) * location obj.pose.bones[ pynode. blender_bone_name].rotation_quaternion = bind_rotation.inverted( ) * rotation obj.pose.bones[ pynode.blender_bone_name].scale = bind_scale.inverted() * scale
def projection(model, cage): model_mat = model.matrix_world.copy() cage_mat = cage.matrix_world.copy() cage_origo = cage_mat * cage.location cage_mesh = cage.data cage_verts = cage_mesh.vertices vertices = [cage_mat * vert.co for vert in cage.data.vertices] i = 0 db = 0 averageDist = 0.0 noIntersectionPoints = [] left_ear = [ 555, 558, 559, 729, 732, 733, 945, 1288, 1291, 1292, 1293, 1480, 1481 ] right_ear = [ 528, 529, 531, 716, 719, 720, 1018, 1019, 1020, 1335, 1390, 1478, 1479 ] #for 3 iter subdiv #left_ear = [2929, 2944, 2947, 2950, 2957, 2958, 2959, 3851, 3860, 3863, 3866, 3873, 3874, 3875, 4769, 5147, 5568, 5575, 5576, 5577, 5578, 5579, 5580, 5581, 5944, 5945] #right_ear = [2784, 2791, 2792, 2793, 2805, 2808, 2811, 3780, 3795, 3798, 3801, 3808, 3809, 3810, 4938, 4939, 4940, 4941, 4942, 4943, 4944, 5357, 5679, 5806, 5942, 5943] for v in vertices: cage_vertex_in_model_system = model_mat.inverted() * v origo_in_model_system = model_mat.inverted() * cage_origo direction = origo_in_model_system - cage_vertex_in_model_system direction.normalize() result, location, normal, index = model.ray_cast( cage_vertex_in_model_system, direction) globalofresult = model_mat * location result_in_cage_system = cage_mat.inverted() * globalofresult if betweentwopoints(cage_vertex_in_model_system, origo_in_model_system, location): translationMatrix = Matrix.Translation( (result_in_cage_system - cage_verts[i].co) / 1.05) cage_verts[i].co = translationMatrix * cage_verts[i].co averageDist = averageDist + numpy.linalg.norm(cage_origo - cage_verts[i].co) db = db + 1 else: noIntersectionPoints.append(i) i = i + 1 averageDist = (averageDist / db) * 1.2 for p in noIntersectionPoints: temp = cage_verts[p].co rate = 1.0 - (averageDist / numpy.linalg.norm(cage_origo - temp)) translationMatrix = Matrix.Translation((cage_origo - temp) * rate) cage_verts[p].co = translationMatrix * cage_verts[p].co cage_details = bounds(model, False) for j in left_ear: temp = Vector((cage_details.x.min, 0, 0)) temp = cage_mat.inverted() * temp cage_verts[j].co.x = temp[0] for j in right_ear: temp = Vector((cage_details.x.max, 0, 0)) temp = cage_mat.inverted() * temp cage_verts[j].co.x = temp[0] return {'FINISHED'}
def make_armature(self, context): bpy.ops.object.add(type='ARMATURE', enter_editmode=True, location=(0,0,0)) armature = context.object armature.name = "skelton" armature.show_in_front = True bone_dic = {} def bone_add(name, head_pos, tail_pos, parent_bone=None): added_bone = armature.data.edit_bones.new(name) added_bone.head = head_pos added_bone.tail = tail_pos if parent_bone is not None: added_bone.parent = parent_bone bone_dic.update({name:added_bone}) return added_bone def x_mirror_bones_add(base_name, right_head_pos, right_tail_pos, parent_bones): left_bone = bone_add(base_name + "_L", right_head_pos, right_tail_pos, parent_bones[0]) right_bone = bone_add(base_name + "_R", [pos*axis for pos, axis in zip(right_head_pos, (-1, 1, 1))], [pos*axis for pos, axis in zip(right_tail_pos, (-1, 1, 1))], parent_bones[1] ) return left_bone,right_bone def x_add(posA, add_x): pos = [pA + _add for pA, _add in zip(posA, [add_x, 0, 0])] return pos def y_add(posA, add_y): pos = [pA + _add for pA, _add in zip(posA, [0, add_y, 0])] return pos def z_add(posA, add_z): pos = [pA+_add for pA,_add in zip(posA,[0,0,add_z])] return pos root = bone_add("root", (0, 0, 0), (0, 0,0.3)) head_size = self.tall / self.head_ratio #down side (前は8頭身の時の股上/股下の股下側割合、後ろは4頭身のときの〃を年齢具合で線形補完)(股上高めにすると破綻する) eight_upside_ratio, four_upside_ratio = 1-self.leg_length_ratio, (2.5/4)*(1-self.aging_ratio)+(1-self.leg_length_ratio)*self.aging_ratio hip_up_down_ratio = eight_upside_ratio * (1 - (8 - self.head_ratio) / 4) + four_upside_ratio * (8 - self.head_ratio) / 4 #チェスト下とチェスト~首の割合 upper_chest_neck_ratio = (1-(8-self.head_ratio)/4)*(1/3) + ((8-self.head_ratio)/4)*0.1 #体幹 neck_len = (1-upper_chest_neck_ratio)*(self.tall*(1-hip_up_down_ratio)/2)/3 upper_chest_len = (self.tall*hip_up_down_ratio - head_size - neck_len)/3 chest_len = upper_chest_len spine_len = chest_len Hips = bone_add("Hips", (0,0, self.tall*(1-hip_up_down_ratio) ), (0,0.1,self.tall*(1-hip_up_down_ratio)),root) Spine = bone_add("Spine",Hips.head,z_add(Hips.head,spine_len),Hips) Chest = bone_add("Chest", Spine.tail, z_add(Spine.tail,chest_len), Spine) upperChest = bone_add("upperChest", Chest.tail, z_add(Chest.tail,upper_chest_len), Chest) Neck = bone_add("Neck", upperChest.tail, z_add(upperChest.tail,neck_len), upperChest) Head = bone_add("Head", (0,0, self.tall-head_size), (0,0, self.tall), Neck) #目 eye_depth = self.eye_depth eyes = x_mirror_bones_add("eye", (head_size / 5, 0, Head.head[2] + head_size / 2), (head_size / 5, eye_depth, Head.head[2] + head_size / 2), (Head, Head)) #足 leg_width = self.leg_width leg_size = self.leg_size leg_bone_lengh =( self.tall*(1-hip_up_down_ratio) - self.tall*0.05 )/2 upside_legs = x_mirror_bones_add("Upper_Leg", x_add(Hips.head, leg_width), z_add(x_add(Hips.head, leg_width), -leg_bone_lengh), (Hips, Hips) ) lower_legs = x_mirror_bones_add("Lower_Leg", upside_legs[0].tail, (leg_width,0,self.tall*0.05), upside_legs ) Foots = x_mirror_bones_add("Foot", lower_legs[0].tail, (leg_width,-leg_size*(2/3),0), lower_legs ) Toes = x_mirror_bones_add("Toes", Foots[0].tail, (leg_width,-leg_size,0), Foots ) #肩~指 shoulder_in_pos = self.shoulder_in_width / 2 shoulders = x_mirror_bones_add("shoulder", x_add(upperChest.tail, shoulder_in_pos), x_add(upperChest.tail, shoulder_in_pos + self.shoulder_width), (upperChest,upperChest)) arm_lengh = head_size * (1*(1-(self.head_ratio-6)/2)+1.5*((self.head_ratio-6)/2)) * self.arm_length_ratio arms = x_mirror_bones_add("Arm", shoulders[0].tail, x_add(shoulders[0].tail,arm_lengh), shoulders) hand_size = self.hand_size forearms = x_mirror_bones_add("forearm", arms[0].tail, #グーにするとパーの半分くらいになる、グーのとき手を含む下腕の長さと上腕の長さが概ね一緒 x_add(arms[0].tail,arm_lengh - hand_size/2), arms) hands = x_mirror_bones_add("hand", forearms[0].tail, x_add(forearms[0].tail,hand_size/2), forearms ) def fingers(finger_name,proximal_pos,finger_len_sum): finger_normalize = 1/(self.finger_1_2_ratio*self.finger_2_3_ratio+self.finger_1_2_ratio+1) proximal_finger_len = finger_len_sum*finger_normalize intermediate_finger_len = finger_len_sum*finger_normalize*self.finger_1_2_ratio distal_finger_len = finger_len_sum*finger_normalize*self.finger_1_2_ratio*self.finger_2_3_ratio proximal_bones = x_mirror_bones_add(f"{finger_name}_proximal",proximal_pos,x_add(proximal_pos,proximal_finger_len),hands) intermediate_bones = x_mirror_bones_add(f"{finger_name}_intermidiate",proximal_bones[0].tail,x_add(proximal_bones[0].tail,intermediate_finger_len),proximal_bones) distal_bones = x_mirror_bones_add(f"{finger_name}_distal",intermediate_bones[0].tail,x_add(intermediate_bones[0].tail,distal_finger_len),intermediate_bones) return proximal_bones,intermediate_bones,distal_bones finger_y_offset = -hand_size/10 thumbs = fingers( "finger_thumbs", y_add(hands[0].head,finger_y_offset - hand_size/5), hand_size/2 ) mats = [thumbs[0][i].matrix.translation for i in [0,1]] mats = [Matrix.Translation(mat) for mat in mats] for j in range(3): for n,angle in enumerate([-45,45]): thumbs[j][n].transform( mats[n].inverted() ) thumbs[j][n].transform( Matrix.Rotation(radians(angle),4,"Z") ) thumbs[j][n].transform( mats[n] ) index_fingers = fingers( "finger_index", y_add(hands[0].tail,-hand_size/5 +finger_y_offset), (hand_size/2)-(1/2.3125)*(hand_size/2)/3 ) middle_fingers = fingers( "finger_middle", y_add(hands[0].tail,finger_y_offset), hand_size/2 ) ring_fingers = fingers( "finger_ring", y_add(hands[0].tail,hand_size/5 +finger_y_offset), (hand_size/2)-(1/2.3125)*(hand_size/2)/3 ) little_fingers = fingers( "finger_little", y_add(hands[0].tail,2*hand_size/5 +finger_y_offset), ((hand_size/2)-(1/2.3125)*(hand_size/2)/3) * ((1/2.3125)+(1/2.3125)*0.75) ) #'s is left,right tupple body_dict = { "hips":Hips.name, "spine":Spine.name, "chest":Chest.name, "upperChest":upperChest.name, "neck":Neck.name, "head":Head.name } left_right_body_dict = { f"{left_right}{bone_name}":bones[lr].name for bone_name,bones in { "Eye":eyes, "UpperLeg":upside_legs, "LowerLeg":lower_legs, "Foot":Foots, "Toes":Toes, "Shoulder":shoulders, "UpperArm":arms, "LowerArm":forearms, "Hand":hands }.items() for lr,left_right in enumerate(["left","right"]) } #VRM finger like name key fingers_dict={ f"{left_right}{finger_name}{position}":finger[i][lr].name for finger_name,finger in zip(["Thumb","Index","Middle","Ring","Little"],[thumbs,index_fingers,middle_fingers,ring_fingers,little_fingers]) for i,position in enumerate(["Proximal","Intermediate","Distal"]) for lr,left_right in enumerate(["left","right"]) } #VRM bone name : blender bone name bone_name_all_dict = {} bone_name_all_dict.update(body_dict) bone_name_all_dict.update(left_right_body_dict) bone_name_all_dict.update(fingers_dict) context.scene.update() bpy.ops.object.mode_set(mode='OBJECT') return armature,bone_name_all_dict
def read_chan(context, filepath, z_up, rot_ord, sensor_width, sensor_height): # get the active object scene = context.scene obj = context.active_object camera = obj.data if obj.type == 'CAMERA' else None # prepare the correcting matrix rot_mat = Matrix.Rotation(radians(90.0), 4, 'X').to_4x4() # read the file filehandle = open(filepath, 'r') # iterate throug the files lines for line in filehandle: # reset the target objects matrix # (the one from whitch one we'll extract the final transforms) m_trans_mat = Matrix() # strip the line data = line.split() # test if the line is not commented out if data and not data[0].startswith("#"): # set the frame number basing on the chan file scene.frame_set(int(data[0])) # read the translation values from the first three columns of line v_transl = Vector((float(data[1]), float(data[2]), float(data[3]))) translation_mat = Matrix.Translation(v_transl) translation_mat.to_4x4() # read the rotations, and set the rotation order basing on the # order set during the export (it's not being saved in the chan # file you have to keep it noted somewhere # the actual objects rotation order doesn't matter since the # rotations are being extracted from the matrix afterwards e_rot = Euler((radians(float(data[4])), radians(float(data[5])), radians(float(data[6])))) e_rot.order = rot_ord mrot_mat = e_rot.to_matrix() mrot_mat.resize_4x4() # merge the rotation and translation m_trans_mat = translation_mat * mrot_mat # correct the world space # (nuke's and blenders scene spaces are different) if z_up: m_trans_mat = rot_mat * m_trans_mat # break the matrix into a set of the coordinates trns = m_trans_mat.decompose() # set the location and the location's keyframe obj.location = trns[0] obj.keyframe_insert("location") # convert the rotation to euler angles (or not) # basing on the objects rotation mode if obj.rotation_mode == 'QUATERNION': obj.rotation_quaternion = trns[1] obj.keyframe_insert("rotation_quaternion") elif obj.rotation_mode == 'AXIS_ANGLE': tmp_rot = trns[1].to_axis_angle() obj.rotation_axis_angle = (tmp_rot[1], ) + tmp_rot[0][:] obj.keyframe_insert("rotation_axis_angle") del tmp_rot else: obj.rotation_euler = trns[1].to_euler(obj.rotation_mode) obj.keyframe_insert("rotation_euler") # check if the object is camera and fov data is present if camera and len(data) > 7: camera.sensor_fit = 'HORIZONTAL' camera.sensor_width = sensor_width camera.sensor_height = sensor_height camera.angle_y = radians(float(data[7])) camera.keyframe_insert("lens") filehandle.close() return {'FINISHED'}
def draw_brick(cm_id, bricksdict, key, loc, seed_keys, bcoll, clear_existing_collection, parent, dimensions, zstep, brick_size, brick_type, split, last_split_model, custom_object1, custom_object2, custom_object3, mat_dirty, custom_data, brick_scale, bricks_created, all_meshes, logo, mats, brick_mats, internal_mat, brick_height, logo_resolution, logo_decimate, build_is_dirty, material_type, custom_mat, random_mat_seed, stud_detail, exposed_underside_detail, hidden_underside_detail, random_rot, random_loc, logo_type, logo_scale, logo_inset, circle_verts, instance_method, rand_s1, rand_s2, rand_s3): brick_d = bricksdict[key] # check exposure of current [merged] brick if brick_d["top_exposed"] is None or brick_d[ "bot_exposed"] is None or build_is_dirty: top_exposed, bot_exposed = set_all_brick_exposures( bricksdict, zstep, key) else: top_exposed, bot_exposed = is_brick_exposed(bricksdict, zstep, key) # get brick material mat = get_material(bricksdict, key, brick_size, zstep, material_type, custom_mat, random_mat_seed, mat_dirty, seed_keys, brick_mats=brick_mats) # set up arguments for brick mesh use_stud = (top_exposed and stud_detail != "NONE") or stud_detail == "ALL" logo_to_use = logo if use_stud else None underside_detail = exposed_underside_detail if bot_exposed else hidden_underside_detail ### CREATE BRICK ### # add brick with new mesh data at original location if brick_d["type"].startswith("CUSTOM"): m = custom_data[int(brick_d["type"][-1]) - 1] else: # get brick mesh m = get_brick_data(brick_d, rand_s3, dimensions, brick_size, brick_type, brick_height, logo_resolution, logo_decimate, circle_verts, underside_detail, logo_to_use, logo_type, logo_scale, logo_inset, use_stud) # duplicate data if not instancing by mesh data m = m if instance_method == "LINK_DATA" else m.copy() # apply random rotation to edit mesh according to parameters random_rot_matrix = get_random_rot_matrix(random_rot, rand_s2, brick_size) # get brick location loc_offset = get_random_loc(random_loc, rand_s2, dimensions["half_width"], dimensions["half_height"]) brick_loc = get_brick_center(bricksdict, key, zstep, loc) + loc_offset if split: brick = bpy.data.objects.get(brick_d["name"]) edge_split = use_edge_split_mod(brick_d, custom_object1, custom_object2, custom_object3) if brick: # NOTE: last brick object is left in memory (faster) # set brick.data to new mesh (resets materials) brick.data = m # add/remove edge split modifier if necessary e_mod = brick.modifiers.get("Edge Split") if not e_mod and edge_split: add_edge_split_mod(brick) elif e_mod and not edge_split: brick.modifiers.remove(e_mod) else: # create new object with mesh data brick = bpy.data.objects.new(brick_d["name"], m) brick.cmlist_id = cm_id # add edge split modifier if edge_split: add_edge_split_mod(brick) # rotate brick by random rotation if random_rot_matrix is not None: # resets rotation_euler in case object is reused brick.rotation_euler = (0, 0, 0) brick.rotation_euler.rotate(random_rot_matrix) # set brick location brick.location = brick_loc # set brick material mat = mat or internal_mat set_material(brick, mat) if mat: keys_in_brick = get_keys_in_brick(bricksdict, brick_size, zstep, loc) for k in keys_in_brick: bricksdict[k]["mat_name"] = mat.name # append to bricks_created bricks_created.append(brick) # set remaining brick info if brick object just created brick.parent = parent if not brick.is_brick: brick.is_brick = True # link bricks to brick collection if clear_existing_collection or brick.name not in bcoll.objects.keys(): bcoll.objects.link(brick) else: # duplicates mesh – prevents crashes in 2.79 (may need to add back if experiencing crashes in b280) if not b280(): m = m.copy() # apply rotation matrices to edit mesh if random_rot_matrix is not None: m.transform(random_rot_matrix) # transform brick mesh to coordinate on matrix m.transform(Matrix.Translation(brick_loc)) # set to internal mat if material not set internal = False if mat is None: mat = internal_mat internal = True # keep track of mats already used if mat in mats: mat_idx = mats.index(mat) elif mat is not None: mats.append(mat) mat_idx = len(mats) - 1 # set material if mat is not None: # set material name in dictionary if not internal: brick_d["mat_name"] = mat.name # point all polygons to target material (index will correspond in all_meshes object) for p in m.polygons: p.material_index = mat_idx # append mesh to all_meshes bmesh object all_meshes.from_mesh(m) # remove mesh in 2.79 (mesh was duplicated above to prevent crashes) if not b280(): bpy.data.meshes.remove(m) # NOTE: The following lines clean up the mesh if not duplicated else: # reset polygon material mapping if mat is not None: for p in m.polygons: p.material_index = 0 # reset transformations for reference mesh m.transform(Matrix.Translation(-brick_loc)) if random_rot_matrix is not None: random_rot_matrix.invert() m.transform(random_rot_matrix) return bricksdict
def __init__(self, cont): # store the owner, mesh, material id, frequency # get sprite size and Vector coordinates from string property "sprites" # convert string property "sequence" to an array of valid id's # get data from string properties "spin", "loop" and "pingpong" # initialize direction, id and offset def get_mesh(self): mesh = self.own.meshes[0] try: base_obj = self.own.scene.objectsInactive[self.own.name] except KeyError: if not self.own["unlink"]: return mesh if not hasattr(logic, "libnews"): logic.libnews = 0 mesh_name = mesh.name new_mesh = logic.LibNew(mesh_name + str(logic.libnews), "Mesh", [mesh_name])[0] self.own.replaceMesh(new_mesh) logic.libnews += 1 return new_mesh def get_mat_id(mesh, identifier="_UV"): # get the material(s) that will be affected # if needed you can change the identifier # if the identifier is not found, all materials on the mesh will be affected for mat_id in range(mesh.numMaterials): if identifier in mesh.getMaterialName(mat_id): return mat_id return -1 def get_sprite_data(self): sprites = [int(i) for i in self.own["sprites"].split(", ")] sprite_size = Vector([1 / sprites[i] for i in range(2)]).to_3d() sprite_coords = [] for y in range(sprites[1]): for x in range(sprites[0]): sprite_coords.append( Vector([x * sprite_size[0], y * sprite_size[1]]).to_3d()) return sprite_coords, sprite_size def get_sequence(string): def digit_in_range(s, len): if not s.isdigit(): return "ValueError" d = int(s) if not d < len: return "IndexError" return d def digits_in_range(l, len): return [digit_in_range(s, len) for s in l] sequence = [] num_sprites = len(self.sprite_coords) for s in [ s for s in string.replace(" ", "").split(",") if s != "" ]: if "-" in s: ds = digits_in_range(s.split("-"), num_sprites) if "ValueError" in ds: self.errors.append(self.err_value + s) elif "IndexError" in ds: self.errors.append(self.err_index + s) else: first, last = ds dir = -1 if first > last else 1 for i in range(first, last + dir, dir): sequence.append(i) elif "*" in s: ds = digits_in_range(s.split("*"), num_sprites) if "ValueError" in ds: self.errors.append(self.err_value + s) elif "IndexError" in ds: self.errors.append(self.err_index + s) else: id, num = ds for i in range(num): sequence.append(id) else: d = digit_in_range(s, num_sprites) if d == "ValueError": self.errors.append(self.err_value + s) elif d == "IndexError": self.errors.append(self.err_index + s) else: sequence.append(d) return sequence def get_properties(self): sequence = get_sequence(self.own["sequence"]) loop = self.own["loop"] pingpong = self.own["pingpong"] return sequence, loop, pingpong self.own = cont.owner self.err_value = "UV Scroll Sequence contains illegal value:\t" self.err_index = "UV Scroll Sequence index is out of range:\t" self.errors = [] self.sprite_coords, self.sprite_size = get_sprite_data(self) self.sequence, self.loop, self.pingpong = get_properties(self) if self.errors: err_msg = "ERROR:\t" + self.own.name for e in self.errors: err_msg += "\n\t-> " + e print(err_msg) return self.mesh = get_mesh(self) self.mat_id = get_mat_id(self.mesh) self.always = cont.sensors[0] self.freq = self.always.skippedTicks self.num_sequence = len(self.sequence) self.extremes = [0, self.num_sequence - 1] self.direction = 1 self.end = False self.id = 0 self.offset = Matrix.Translation( self.sprite_coords[self.sequence[self.id]])
def get_offset(self, next_id): if not self.sequence: return Matrix.Identity(4) current_coords = self.sprite_coords[self.sequence[self.id]] next_coords = self.sprite_coords[self.sequence[next_id]] return Matrix.Translation(next_coords - current_coords)
def main(context, import_filename, options): print("execute amf import") IMPORT_SCALE = options.get_scale_multiplier() print(f"importing at scale {IMPORT_SCALE}") bitmapsDir = ospath.split(import_filename)[0] if len(options.DIRECTORY_BITMAP) > 0: bitmapsDir = options.DIRECTORY_BITMAP reader = FileReader(import_filename) model = AmfModel(reader) arm_obj = None armature = None model_nodes = [] model_materials = [] if options.IMPORT_BONES and len(model.nodes) > 0: print("creating bones") bpy.ops.object.add(type='ARMATURE', enter_editmode=True) arm_obj = context.object armature = arm_obj.data armature.name = model.name + " armature" node_abs_transforms = options.get_node_transforms( model.nodes, 0.5) #why is this getting doubled somehow? for i, node in enumerate(model.nodes): bone = armature.edit_bones.new(options.PREFIX_BONE + node.name) if node.parent_index >= 0: bone.parent = model_nodes[node.parent_index] bone.tail = Vector([1, 0, 0]) * IMPORT_SCALE #'bone.transform' only applies rotation bone.transform(node_abs_transforms[i], scale=False) bone.translate(node_abs_transforms[i].translation) model_nodes.append(bone) bpy.ops.object.mode_set(mode='OBJECT') if options.IMPORT_MARKERS and len(model.markers) > 0: print("creating markers") for mg in model.markers: marker_name = options.PREFIX_MARKER + mg.name node_abs_transforms = options.get_node_transforms(model.nodes) for m in mg.markers: if options.MODE_MARKERS == 'MESH': mesh = bpy.data.meshes.new(marker_name) marker_obj = bpy.data.objects.new(marker_name, mesh) bm = bmesh.new() bmesh.ops.create_uvsphere(bm, u_segments=16, v_segments=16, diameter=IMPORT_SCALE) bm.to_mesh(mesh) bm.free() context.scene.collection.objects.link(marker_obj) else: # MODE_MARKERS == 'EMPTY' #it says 'radius' but it comes out the same size as uvsphere's diameter bpy.ops.object.empty_add(type='SPHERE', radius=IMPORT_SCALE) marker_obj = context.object marker_obj.name = marker_name marker_transform = Matrix.Translation( m.position * IMPORT_SCALE) @ m.rotation.to_matrix().to_4x4() if m.node_index >= 0: marker_transform = node_abs_transforms[ m.node_index] @ marker_transform if options.IMPORT_BONES: marker_obj.parent = arm_obj marker_obj.parent_type = 'BONE' marker_obj.parent_bone = options.PREFIX_BONE + model.nodes[ m.node_index].name marker_obj.hide_render = True marker_obj.matrix_world = marker_transform if options.IMPORT_MATERIALS and len(model.materials) > 0: print("creating materials") for mat in model.materials: material = bpy.data.materials.new(mat.name) material.use_nodes = True bsdf = material.node_tree.nodes["Principled BSDF"] texture = material.node_tree.nodes.new('ShaderNodeTexImage') texture_path = mat.textures[0].get_full_path( bitmapsDir, options.SUFFIX_BITMAP) if not mat.textures[0].is_null and texture_path.exists(): texture.image = bpy.data.images.load(str(texture_path)) if not mat.is_transparent: texture.image.alpha_mode = 'CHANNEL_PACKED' material.node_tree.links.new(bsdf.inputs['Specular'], texture.outputs['Alpha']) material.node_tree.links.new(bsdf.inputs['Base Color'], texture.outputs['Color']) bsdf.location = [0, 300] texture.location = [-300, 300] # texture.repeat_x = mat.textures[0].uv_tiles[0] # texture.repeat_y = mat.textures[0].uv_tiles[1] if not mat.is_terrain and not mat.textures[3].is_null: texture = material.node_tree.nodes.new('ShaderNodeTexImage') texture_path = mat.textures[3].get_full_path( bitmapsDir, options.SUFFIX_BITMAP) if texture_path.exists(): texture.image = bpy.data.images.load(str(texture_path)) texture.image.alpha_mode = 'NONE' texture.image.colorspace_settings.name = 'Non-Color' # inverting green channel is necessary to convert from DirectX coordsys to OpenGL bump = material.node_tree.nodes.new('ShaderNodeNormalMap') split = material.node_tree.nodes.new('ShaderNodeSeparateRGB') invert = material.node_tree.nodes.new('ShaderNodeInvert') merge = material.node_tree.nodes.new('ShaderNodeCombineRGB') texture.location = [-1100, -100] split.location = [-800, -100] invert.location = [-600, -200] merge.location = [-400, -100] bump.location = [-200, -100] material.node_tree.links.new(split.inputs['Image'], texture.outputs['Color']) material.node_tree.links.new(invert.inputs['Color'], split.outputs['G']) material.node_tree.links.new(merge.inputs['R'], split.outputs['R']) material.node_tree.links.new(merge.inputs['G'], invert.outputs['Color']) material.node_tree.links.new(merge.inputs['B'], split.outputs['B']) material.node_tree.links.new(bump.inputs['Color'], merge.outputs['Image']) material.node_tree.links.new(bsdf.inputs['Normal'], bump.outputs['Normal']) model_materials.append(material) if options.IMPORT_MESHES and len(model.regions) > 0: print("creating meshes") instance_lookup = dict() for region in model.regions: for perm in region.permutations: index_buffer = model.index_buffers[perm.face_address] position_buffer = [ v.position for v in model.vertex_buffers[perm.vert_address] ] texcoord_buffer = [ v.texcoords for v in model.vertex_buffers[perm.vert_address] ] normal_buffer = [ v.normal for v in model.vertex_buffers[perm.vert_address] ] node_index_buffer = [ v.indices for v in model.vertex_buffers[perm.vert_address] ] node_weight_buffer = [ v.weights for v in model.vertex_buffers[perm.vert_address] ] for sub_index, sub in enumerate(perm.submeshes): instance_key = f"{perm.vert_address}_{sub_index:03d}" root_obj = instance_lookup.get(instance_key, None) if root_obj is not None: mesh_obj = root_obj.copy() #this makes a deep copy rather than a linked copy #mesh_obj.data = root_obj.data.copy() mesh_obj.matrix_world = options.get_perm_transform( perm) context.scene.collection.objects.link(mesh_obj) if options.MODE_MESHES == 'JOIN': break #skip the rest of the submeshes else: continue if options.MODE_MESHES == 'JOIN': mesh_name = f"{region.name}:{perm.name}" mesh_verts = position_buffer mesh_faces = index_buffer mesh_coords = [ texcoord_buffer[i] for i in itertools.chain(*mesh_faces) ] #blender wants 3 uvs per tri, rather than one per vertex mesh_norms = normal_buffer mesh_nodes = node_index_buffer mesh_weights = node_weight_buffer mat_ranges = [(s.face_start, s.face_count, s.mat_index) for s in perm.submeshes] else: mesh_name = f"{region.name}:{perm.name}.{sub_index:03d}" mesh_faces = [ index_buffer[i] for i in range(sub.face_start, sub.face_start + sub.face_count) ] mesh_coords = [ texcoord_buffer[i] for i in itertools.chain(*mesh_faces) ] #blender wants 3 uvs per tri, rather than one per vertex min_index = min(itertools.chain(*mesh_faces)) max_index = max(itertools.chain(*mesh_faces)) mesh_verts = [ position_buffer[i] for i in range(min_index, max_index + 1) ] #only need verts referenced by the current faces mesh_norms = [ normal_buffer[i] for i in range(min_index, max_index + 1) ] if perm.vert_format > 0: mesh_nodes = [ node_index_buffer[i] for i in range(min_index, max_index + 1) ] mesh_weights = [ node_weight_buffer[i] for i in range(min_index, max_index + 1) ] mat_ranges = [ (0, sub.face_count, sub.mat_index) ] #split meshes are offset to always start at 0 # translate the face indices to start at 0 since we are only using a subset of the vertices now for face in mesh_faces: face[0] -= min_index face[1] -= min_index face[2] -= min_index mesh = bpy.data.meshes.new(mesh_name) mesh.from_pydata(mesh_verts, [], mesh_faces) mesh_obj = bpy.data.objects.new(mesh_name, mesh) mesh.normals_split_custom_set_from_vertices(mesh_norms) mesh.use_auto_smooth = True #required for custom normals to take effect if options.IMPORT_MATERIALS: mat_lookup = dict() for i, mat_index in enumerate( set(t[2] for t in mat_ranges)): mat_lookup[mat_index] = i for i in mat_lookup.keys(): mesh.materials.append(model_materials[i]) for face_start, face_count, mat_index in mat_ranges: for i in range(face_start, face_start + face_count): mesh.polygons[i].material_index = mat_lookup[ mat_index] uvmap = mesh.uv_layers.new() for i in range(len(mesh_coords)): uvmap.data[i].uv = mesh_coords[i] if options.IMPORT_BONES and perm.vert_format > 0: mesh_obj.parent = arm_obj mod = mesh_obj.modifiers.new("armature", 'ARMATURE') mod.object = arm_obj for node in model.nodes: mesh_obj.vertex_groups.new(name=node.name) if perm.node_index != 255: for i in range(len(mesh_verts)): mesh_obj.vertex_groups[perm.node_index].add( [i], 1.0, 'ADD') else: for i in range(len(mesh_nodes)): indices = mesh_nodes[i] weights = mesh_weights[i] for j in range(len(indices)): if weights[j] == 0: continue mesh_obj.vertex_groups[int( indices[j])].add([i], weights[j], 'ADD') if not math.isnan(perm.scale): mesh_obj.matrix_world = options.get_perm_transform( perm) instance_lookup[instance_key] = mesh_obj mesh.transform(Matrix.Scale(IMPORT_SCALE, 4)) context.scene.collection.objects.link(mesh_obj) if options.MODE_MESHES == 'JOIN': break #skip the rest of the submeshes reader.close()
def process(self): # inputs if not (self.inputs['Vertices'].is_linked and self.inputs['Polygons'].is_linked): return if not any( self.outputs[name].is_linked for name in ['Vertices', 'Edges', 'Polygons', 'ExtrudedPolys', 'OtherPolys']): return vertices_s = self.inputs['Vertices'].sv_get() edges_s = self.inputs['Edges'].sv_get(default=[[]]) faces_s = self.inputs['Polygons'].sv_get(default=[[]]) masks_s = self.inputs['Mask'].sv_get(default=[[1]]) heights_s = self.inputs['Height'].sv_get() scales_s = self.inputs['Scale'].sv_get() result_vertices = [] result_edges = [] result_faces = [] result_extruded_faces = [] result_other_faces = [] meshes = match_long_repeat( [vertices_s, edges_s, faces_s, masks_s, heights_s, scales_s]) offset = 0 for vertices, edges, faces, masks, heights, scales in zip(*meshes): fullList(heights, len(faces)) fullList(scales, len(faces)) fullList(masks, len(faces)) bm = bmesh_from_pydata(vertices, edges, faces) extruded_faces = bmesh.ops.extrude_discrete_faces( bm, faces=bm.faces)['faces'] new_extruded_faces = [] for face, mask, height, scale in zip(extruded_faces, masks, heights, scales): if not mask: continue dr = face.normal * height center = face.calc_center_median() translation = Matrix.Translation(center) rotation = face.normal.rotation_difference( (0, 0, 1)).to_matrix().to_4x4() #rotation = autorotate(z, face.normal).inverted() m = translation * rotation bmesh.ops.scale(bm, vec=(scale, scale, scale), space=m.inverted(), verts=face.verts) bmesh.ops.translate(bm, verts=face.verts, vec=dr) new_extruded_faces.append([v.index for v in face.verts]) new_vertices, new_edges, new_faces = pydata_from_bmesh(bm) bm.free() new_other_faces = [ f for f in new_faces if f not in new_extruded_faces ] result_vertices.append(new_vertices) result_edges.append(new_edges) result_faces.append(new_faces) result_extruded_faces.append(new_extruded_faces) result_other_faces.append(new_other_faces) self.outputs['Vertices'].sv_set(result_vertices) if self.outputs['Edges'].is_linked: self.outputs['Edges'].sv_set(result_edges) if self.outputs['Polygons'].is_linked: self.outputs['Polygons'].sv_set(result_faces) if self.outputs['ExtrudedPolys'].is_linked: self.outputs['ExtrudedPolys'].sv_set(result_extruded_faces) if self.outputs['OtherPolys'].is_linked: self.outputs['OtherPolys'].sv_set(result_other_faces)
def load_file(context, filepath, report, fix_parents, game_version, jms_path_a, jms_path_b): jms_a_transform = False jms_b_transform = False jma_file = JMAAsset(filepath, game_version, report) if path.exists(jms_path_a): jms_a_transform = True jms_a_file = import_jms.JMSAsset(jms_path_a, "halo2") if path.exists(jms_path_a) and path.exists(jms_path_b): jms_b_transform = True jms_b_file = import_jms.JMSAsset(jms_path_b, "halo2") collection = bpy.context.collection scene = bpy.context.scene view_layer = bpy.context.view_layer armature = None object_list = list(scene.objects) scene_nodes = [] jma_nodes = [] jms_a_nodes = [] jms_b_nodes = [] for obj in object_list: if armature is None: if obj.type == 'ARMATURE': is_armature_good = False if jma_file.version == 16390: if len(obj.data.bones) == jma_file.node_count: is_armature_good = True else: exist_count = 0 armature_bone_list = list(obj.data.bones) for node in armature_bone_list: for jma_node in jma_file.nodes: if node.name == jma_node.name: scene_nodes.append(node.name) exist_count += 1 if exist_count == len(jma_file.nodes): is_armature_good = True if is_armature_good: armature = obj view_layer.objects.active = armature for jma_node in jma_file.nodes: jma_nodes.append(jma_node.name) if len(scene_nodes) > 0: for jma_node in jma_nodes: if not jma_node in scene_nodes: report({'WARNING'}, "Node '%s' not found in an existing armature" % jma_node) if armature == None: if not jma_file.broken_skeleton: if jma_file.version >= 16392: if jms_a_transform and not jms_b_transform: for jms_node in jms_a_file.nodes: jms_a_nodes.append(jms_node.name) for jms_node_name in jms_a_nodes: if not jms_node_name in jma_nodes: jms_a_transform = False report({ 'WARNING' }, "Node '%s' from JMS skeleton not found in JMA skeleton." % jms_node_name) report({ 'WARNING' }, "No valid armature detected. One will be created and the referenced JMS will be used for the rest position" ) elif jms_a_transform and jms_b_transform: for jms_node in jms_a_file.nodes: jms_a_nodes.append(jms_node.name) for jms_node in jms_b_file.nodes: jms_b_nodes.append(jms_node.name) jms_nodes = jms_a_nodes + jms_b_nodes for jms_node_name in jms_nodes: if not jms_node_name in jma_nodes: jms_a_transform = False report({ 'WARNING' }, "Node '%s' from JMS skeleton not found in JMA skeleton." % jms_node_name) report({ 'WARNING' }, "No valid armature detected. One will be created and the referenced JMS files will be used for the rest position" ) else: report({ 'WARNING' }, "No valid armature detected. One will be created but expect issues with visuals in scene due to no proper rest position" ) pelvis = None thigh0 = None thigh1 = None spine1 = None clavicle0 = None clavicle1 = None armdata = bpy.data.armatures.new('Armature') ob_new = bpy.data.objects.new('Armature', armdata) collection.objects.link(ob_new) armature = ob_new view_layer.objects.active = armature if fix_parents: if game_version == 'halo2': for idx, jma_node in enumerate(jma_file.nodes): if 'pelvis' in jma_node.name: pelvis = idx if 'thigh' in jma_node.name: if thigh0 == None: thigh0 = idx else: thigh1 = idx elif 'spine1' in jma_node.name: spine1 = idx elif 'clavicle' in jma_node.name: if clavicle0 == None: clavicle0 = idx else: clavicle1 = idx first_frame = jma_file.transforms[0] for idx, jma_node in enumerate(jma_file.nodes): bpy.ops.object.mode_set(mode='EDIT') armature.data.edit_bones.new(jma_node.name) armature.data.edit_bones[jma_node.name].tail[2] = 5 parent_idx = jma_node.parent if jms_a_transform: if jma_node.name in jms_a_nodes: node_idx = jms_a_nodes.index(jma_node.name) rest_position = jms_a_file.transforms[0] jms_node = rest_position[node_idx] elif jma_node.name in jms_b_nodes: node_idx = jms_b_nodes.index(jma_node.name) rest_position = jms_b_file.transforms[0] jms_node = rest_position[node_idx] matrix_translate = Matrix.Translation(jms_node.vector) matrix_scale = Matrix.Scale(1, 4, (1, 1, 1)) matrix_rotation = jms_node.rotation.to_matrix().to_4x4( ) else: matrix_translate = Matrix.Translation( first_frame[idx].vector) matrix_scale = Matrix.Scale(1, 4, (1, 1, 1)) matrix_rotation = first_frame[idx].rotation.to_matrix( ).to_4x4() if not parent_idx == -1 and not parent_idx == None: parent = jma_file.nodes[parent_idx].name if 'thigh' in jma_node.name and not pelvis == None and not thigh0 == None and not thigh1 == None: parent = jma_file.nodes[pelvis].name elif 'clavicle' in jma_node.name and not spine1 == None and not clavicle0 == None and not clavicle1 == None: parent = jma_file.nodes[spine1].name bpy.ops.object.mode_set(mode='EDIT') armature.data.edit_bones[ jma_node. name].parent = armature.data.edit_bones[parent] bpy.ops.object.mode_set(mode='POSE') pose_bone = armature.pose.bones[jma_node.name] transform_matrix = matrix_translate @ matrix_rotation @ matrix_scale primary_rest_positions = None secondary_rest_positions = None if jms_a_transform: primary_rest_positions = jms_a_nodes[0] if jms_b_transform: secondary_rest_positions = jms_b_nodes[0] if jma_file.version < 16394 and pose_bone.parent and not jma_node.name == primary_rest_positions and not jma_node.name == secondary_rest_positions: transform_matrix = pose_bone.parent.matrix @ transform_matrix armature.pose.bones[ jma_node.name].matrix = transform_matrix bpy.ops.pose.armature_apply(selected=False) else: report({ 'ERROR' }, "No valid armature detected and not enough information to build valid skeleton due to version. Import will now be aborted" ) return {'CANCELLED'} else: report({ 'ERROR' }, "No valid armature detected and animation graph is invalid. Import will now be aborted" ) return {'CANCELLED'} scene.frame_end = jma_file.frame_count scene.render.fps = jma_file.frame_rate bpy.ops.object.mode_set(mode='POSE') nodes = jma_file.nodes if jma_file.version == 16390: nodes = global_functions.sort_by_layer(list(armature.data.bones), armature, False) for frame_idx, frame in enumerate(jma_file.transforms): scene.frame_set(frame_idx + 1) if jma_file.biped_controller_frame_type != JMAAsset.BipedControllerFrameType.DISABLE: controller_transform = jma_file.biped_controller_transforms[ frame_idx] if jma_file.biped_controller_frame_type & JMAAsset.BipedControllerFrameType.DX: armature.location.x = controller_transform.vector[0] if jma_file.biped_controller_frame_type & JMAAsset.BipedControllerFrameType.DY: armature.location.y = controller_transform.vector[1] if jma_file.biped_controller_frame_type & JMAAsset.BipedControllerFrameType.DZ: armature.location.z = controller_transform.vector[2] if jma_file.biped_controller_frame_type & JMAAsset.BipedControllerFrameType.DYAW: armature.rotation_euler.z = controller_transform.rotation.to_euler( ).z armature.keyframe_insert('location') armature.keyframe_insert('rotation_euler') view_layer.update() for idx, node in enumerate(nodes): pose_bone = armature.pose.bones[node.name] matrix_scale = Matrix.Scale(frame[idx].scale, 4, (1, 1, 1)) matrix_rotation = frame[idx].rotation.to_matrix().to_4x4() transform_matrix = Matrix.Translation( frame[idx].vector) @ matrix_rotation @ matrix_scale if jma_file.version < 16394 and pose_bone.parent: transform_matrix = pose_bone.parent.matrix @ transform_matrix pose_bone.matrix = transform_matrix view_layer.update() pose_bone.keyframe_insert('location') pose_bone.keyframe_insert('rotation_quaternion') pose_bone.keyframe_insert('scale') scene.frame_set(1) bpy.ops.object.mode_set(mode='OBJECT') report({'INFO'}, "Import completed successfully") return {'FINISHED'}
def transform_location( location: Vector, transform: Matrix = Matrix.Identity(4)) -> Vector: """Transform location.""" m = Matrix.Translation(location) m = transform @ m return m.to_translation()
def do_previews(do_objects, do_collections, do_scenes, do_data_intern): import collections # Helpers. RenderContext = collections.namedtuple("RenderContext", ( "scene", "world", "camera", "light", "camera_data", "light_data", "image", # All those are names! "backup_scene", "backup_world", "backup_camera", "backup_light", "backup_camera_data", "backup_light_data", )) RENDER_PREVIEW_SIZE = bpy.app.render_preview_size def render_context_create(engine, objects_ignored): if engine == '__SCENE': backup_scene, backup_world, backup_camera, backup_light, backup_camera_data, backup_light_data = [()] * 6 scene = bpy.context.window.scene exclude_props = {('world',), ('camera',), ('tool_settings',), ('preview',)} backup_scene = tuple(rna_backup_gen(scene, exclude_props=exclude_props)) world = scene.world camera = scene.camera if camera: camera_data = camera.data else: backup_camera, backup_camera_data = [None] * 2 camera_data = bpy.data.cameras.new("TEMP_preview_render_camera") camera = bpy.data.objects.new("TEMP_preview_render_camera", camera_data) camera.rotation_euler = Euler((1.1635528802871704, 0.0, 0.7853981852531433), 'XYZ') # (66.67, 0, 45) scene.camera = camera scene.collection.objects.link(camera) # TODO: add light if none found in scene? light = None light_data = None else: backup_scene, backup_world, backup_camera, backup_light, backup_camera_data, backup_light_data = [None] * 6 scene = bpy.data.scenes.new("TEMP_preview_render_scene") world = bpy.data.worlds.new("TEMP_preview_render_world") camera_data = bpy.data.cameras.new("TEMP_preview_render_camera") camera = bpy.data.objects.new("TEMP_preview_render_camera", camera_data) light_data = bpy.data.lights.new("TEMP_preview_render_light", 'SPOT') light = bpy.data.objects.new("TEMP_preview_render_light", light_data) objects_ignored.add((camera.name, light.name)) scene.world = world camera.rotation_euler = Euler((1.1635528802871704, 0.0, 0.7853981852531433), 'XYZ') # (66.67, 0, 45) scene.camera = camera scene.collection.objects.link(camera) light.rotation_euler = Euler((0.7853981852531433, 0.0, 1.7453292608261108), 'XYZ') # (45, 0, 100) light_data.falloff_type = 'CONSTANT' light_data.spot_size = 1.0471975803375244 # 60 scene.collection.objects.link(light) scene.render.engine = 'CYCLES' scene.render.film_transparent = True # TODO: define Cycles world? scene.render.image_settings.file_format = 'PNG' scene.render.image_settings.color_depth = '8' scene.render.image_settings.color_mode = 'RGBA' scene.render.image_settings.compression = 25 scene.render.resolution_x = RENDER_PREVIEW_SIZE scene.render.resolution_y = RENDER_PREVIEW_SIZE scene.render.resolution_percentage = 100 scene.render.filepath = os.path.join(bpy.app.tempdir, 'TEMP_preview_render.png') scene.render.use_overwrite = True scene.render.use_stamp = False scene.render.threads_mode = 'AUTO' image = bpy.data.images.new("TEMP_render_image", RENDER_PREVIEW_SIZE, RENDER_PREVIEW_SIZE, alpha=True) image.source = 'FILE' image.filepath = scene.render.filepath return RenderContext( scene.name, world.name if world else None, camera.name, light.name if light else None, camera_data.name, light_data.name if light_data else None, image.name, backup_scene, backup_world, backup_camera, backup_light, backup_camera_data, backup_light_data, ) def render_context_delete(render_context): # We use try/except blocks here to avoid crash, too much things can go wrong, and we want to leave the current # .blend as clean as possible! success = True scene = bpy.data.scenes[render_context.scene, None] try: if render_context.backup_scene is None: scene.world = None scene.camera = None if render_context.camera: scene.collection.objects.unlink(bpy.data.objects[render_context.camera, None]) if render_context.light: scene.collection.objects.unlink(bpy.data.objects[render_context.light, None]) bpy.data.scenes.remove(scene, do_unlink=True) scene = None else: rna_backup_restore(scene, render_context.backup_scene) except Exception as e: print("ERROR:", e) success = False if render_context.world is not None: try: world = bpy.data.worlds[render_context.world, None] if render_context.backup_world is None: if scene is not None: scene.world = None world.user_clear() bpy.data.worlds.remove(world) else: rna_backup_restore(world, render_context.backup_world) except Exception as e: print("ERROR:", e) success = False if render_context.camera: try: camera = bpy.data.objects[render_context.camera, None] if render_context.backup_camera is None: if scene is not None: scene.camera = None scene.collection.objects.unlink(camera) camera.user_clear() bpy.data.objects.remove(camera) bpy.data.cameras.remove(bpy.data.cameras[render_context.camera_data, None]) else: rna_backup_restore(camera, render_context.backup_camera) rna_backup_restore(bpy.data.cameras[render_context.camera_data, None], render_context.backup_camera_data) except Exception as e: print("ERROR:", e) success = False if render_context.light: try: light = bpy.data.objects[render_context.light, None] if render_context.backup_light is None: if scene is not None: scene.collection.objects.unlink(light) light.user_clear() bpy.data.objects.remove(light) bpy.data.lights.remove(bpy.data.lights[render_context.light_data, None]) else: rna_backup_restore(light, render_context.backup_light) rna_backup_restore(bpy.data.lights[render_context.light_data, None], render_context.backup_light_data) except Exception as e: print("ERROR:", e) success = False try: image = bpy.data.images[render_context.image, None] image.user_clear() bpy.data.images.remove(image) except Exception as e: print("ERROR:", e) success = False return success def object_bbox_merge(bbox, ob, ob_space, offset_matrix): # Take collections instances into account (including linked one in this case). if ob.type == 'EMPTY' and ob.instance_type == 'COLLECTION': grp_objects = tuple((ob.name, ob.library.filepath if ob.library else None) for ob in ob.instance_collection.all_objects) if (len(grp_objects) == 0): ob_bbox = ob.bound_box else: coords = objects_bbox_calc(ob_space, grp_objects, Matrix.Translation(ob.instance_collection.instance_offset).inverted()) ob_bbox = ((coords[0], coords[1], coords[2]), (coords[21], coords[22], coords[23])) elif ob.bound_box: ob_bbox = ob.bound_box else: ob_bbox = ((-ob.scale.x, -ob.scale.y, -ob.scale.z), (ob.scale.x, ob.scale.y, ob.scale.z)) for v in ob_bbox: v = offset_matrix @ Vector(v) if offset_matrix is not None else Vector(v) v = ob_space.matrix_world.inverted() @ ob.matrix_world @ v if bbox[0].x > v.x: bbox[0].x = v.x if bbox[0].y > v.y: bbox[0].y = v.y if bbox[0].z > v.z: bbox[0].z = v.z if bbox[1].x < v.x: bbox[1].x = v.x if bbox[1].y < v.y: bbox[1].y = v.y if bbox[1].z < v.z: bbox[1].z = v.z def objects_bbox_calc(camera, objects, offset_matrix): bbox = (Vector((1e24, 1e24, 1e24)), Vector((-1e24, -1e24, -1e24))) for obname, libpath in objects: ob = bpy.data.objects[obname, libpath] object_bbox_merge(bbox, ob, camera, offset_matrix) # Our bbox has been generated in camera local space, bring it back in world one bbox[0][:] = camera.matrix_world @ bbox[0] bbox[1][:] = camera.matrix_world @ bbox[1] cos = ( bbox[0].x, bbox[0].y, bbox[0].z, bbox[0].x, bbox[0].y, bbox[1].z, bbox[0].x, bbox[1].y, bbox[0].z, bbox[0].x, bbox[1].y, bbox[1].z, bbox[1].x, bbox[0].y, bbox[0].z, bbox[1].x, bbox[0].y, bbox[1].z, bbox[1].x, bbox[1].y, bbox[0].z, bbox[1].x, bbox[1].y, bbox[1].z, ) return cos def preview_render_do(render_context, item_container, item_name, objects, offset_matrix=None): # Unused. # scene = bpy.data.scenes[render_context.scene, None] if objects is not None: camera = bpy.data.objects[render_context.camera, None] light = bpy.data.objects[render_context.light, None] if render_context.light is not None else None cos = objects_bbox_calc(camera, objects, offset_matrix) depsgraph = bpy.context.evaluated_depsgraph_get() loc, _ortho_scale = camera.camera_fit_coords(depsgraph, cos) camera.location = loc # Set camera clipping accordingly to computed bbox. min_dist = 1e24 max_dist = -1e24 for co in zip(*(iter(cos),) * 3): dist = (Vector(co) - loc).length if dist < min_dist: min_dist = dist if dist > max_dist: max_dist = dist camera.data.clip_start = min_dist / 2 camera.data.clip_end = max_dist * 2 if light: loc, _ortho_scale = light.camera_fit_coords(depsgraph, cos) light.location = loc bpy.context.view_layer.update() bpy.ops.render.render(write_still=True) image = bpy.data.images[render_context.image, None] item = getattr(bpy.data, item_container)[item_name, None] image.reload() preview = item.preview_ensure() preview.image_size = (RENDER_PREVIEW_SIZE, RENDER_PREVIEW_SIZE) preview.image_pixels_float[:] = image.pixels # And now, main code! do_save = True if do_data_intern: bpy.ops.wm.previews_clear(id_type={'SHADING'}) bpy.ops.wm.previews_ensure() render_contexts = {} objects_ignored = set() collections_ignored = set() prev_scenename = bpy.context.window.scene.name if do_objects: prev_shown = {ob.name: ob.hide_render for ob in ids_nolib(bpy.data.objects)} for ob in ids_nolib(bpy.data.objects): if ob in objects_ignored: continue ob.hide_render = True for root in ids_nolib(bpy.data.objects): if root.name in objects_ignored: continue if root.type not in OBJECT_TYPES_RENDER: continue objects = ((root.name, None),) render_context = render_contexts.get('CYCLES', None) if render_context is None: render_context = render_context_create('CYCLES', objects_ignored) render_contexts['CYCLES'] = render_context scene = bpy.data.scenes[render_context.scene, None] bpy.context.window.scene = scene for obname, libpath in objects: ob = bpy.data.objects[obname, libpath] if obname not in scene.objects: scene.collection.objects.link(ob) ob.hide_render = False bpy.context.view_layer.update() preview_render_do(render_context, 'objects', root.name, objects) # XXX Hyper Super Uber Suspicious Hack! # Without this, on windows build, script excepts with following message: # Traceback (most recent call last): # File "<string>", line 1, in <module> # File "<string>", line 451, in <module> # File "<string>", line 443, in main # File "<string>", line 327, in do_previews # OverflowError: Python int too large to convert to C long # ... :( scene = bpy.data.scenes[render_context.scene, None] for obname, libpath in objects: ob = bpy.data.objects[obname, libpath] scene.collection.objects.unlink(ob) ob.hide_render = True for ob in ids_nolib(bpy.data.objects): is_rendered = prev_shown.get(ob.name, ...) if is_rendered is not ...: ob.hide_render = is_rendered if do_collections: for grp in ids_nolib(bpy.data.collections): if grp.name in collections_ignored: continue # Here too, we do want to keep linked objects members of local collection... objects = tuple((ob.name, ob.library.filepath if ob.library else None) for ob in grp.objects) render_context = render_contexts.get('CYCLES', None) if render_context is None: render_context = render_context_create('CYCLES', objects_ignored) render_contexts['CYCLES'] = render_context scene = bpy.data.scenes[render_context.scene, None] bpy.context.window.scene = scene bpy.ops.object.collection_instance_add(collection=grp.name) grp_ob = next(( ob for ob in scene.objects if ob.instance_collection and ob.instance_collection.name == grp.name )) grp_obname = grp_ob.name bpy.context.view_layer.update() offset_matrix = Matrix.Translation(grp.instance_offset).inverted() preview_render_do(render_context, 'collections', grp.name, objects, offset_matrix) scene = bpy.data.scenes[render_context.scene, None] scene.collection.objects.unlink(bpy.data.objects[grp_obname, None]) bpy.context.window.scene = bpy.data.scenes[prev_scenename, None] for render_context in render_contexts.values(): if not render_context_delete(render_context): do_save = False # Do not save file if something went wrong here, we could 'pollute' it with temp data... if do_scenes: for scene in ids_nolib(bpy.data.scenes): has_camera = scene.camera is not None bpy.context.window.scene = scene render_context = render_context_create('__SCENE', objects_ignored) bpy.context.view_layer.update() objects = None if not has_camera: # We had to add a temp camera, now we need to place it to see interesting objects! objects = tuple((ob.name, ob.library.filepath if ob.library else None) for ob in scene.objects if (not ob.hide_render) and (ob.type in OBJECT_TYPES_RENDER)) preview_render_do(render_context, 'scenes', scene.name, objects) if not render_context_delete(render_context): do_save = False bpy.context.window.scene = bpy.data.scenes[prev_scenename, None] if do_save: print("Saving %s..." % bpy.data.filepath) try: bpy.ops.wm.save_mainfile() except Exception as e: # Might fail in some odd cases, like e.g. in regression files we have glsl/ram_glsl.blend which # references an inexistent texture... Better not break in this case, just spit error to console. print("ERROR:", e) else: print("*NOT* Saving %s, because some error(s) happened while deleting temp render data..." % bpy.data.filepath)
def align_to_active(self, active, sel): # get target matrix and decompose amx = active.matrix_world aloc, arot, asca = amx.decompose() # split components into x,y,z axis elements alocx, alocy, alocz = aloc arotx, aroty, arotz = arot.to_euler('XYZ') ascax, ascay, ascaz = asca for obj in sel: # get object matrix and decompose omx = obj.matrix_world oloc, orot, osca = omx.decompose() # split components into x,y,z axis elements olocx, olocy, olocz = oloc orotx, oroty, orotz = orot.to_euler('XYZ') oscax, oscay, oscaz = osca # TRANSLATION # if location is aligned, pick the axis elements based on the loc axis props if self.location: locx = alocx if self.loc_x else olocx locy = alocy if self.loc_y else olocy locz = alocz if self.loc_z else olocz # re-assemble into translation matrix loc = Matrix.Translation(Vector((locx, locy, locz))) # otherwise, just use the object's location component else: loc = Matrix.Translation(oloc) # ROTATION # if rotation is aligned, pick the axis elements based on the rot axis props if self.rotation: rotx = arotx if self.rot_x else orotx roty = aroty if self.rot_y else oroty rotz = arotz if self.rot_z else orotz # re-assemble into rotation matrix rot = Euler((rotx, roty, rotz), 'XYZ').to_matrix().to_4x4() # otherwise, just use the object's rotation component else: rot = orot.to_matrix().to_4x4() # SCALE sca = Matrix() # if scale is aligned, pick the axis elements based on the sca axis props if self.scale: scax = ascax if self.sca_x else oscax scay = ascay if self.sca_y else oscay scaz = ascaz if self.sca_z else oscaz # re-assemble into scale matrix for i in range(3): sca[i][i] = (scax, scay, scaz)[i] # otherwise, just use the object's scale component else: for i in range(3): sca[i][i] = osca[i] # re-combine components into world matrix obj.matrix_world = loc @ rot @ sca
def build_objects(props, grid) -> None: mesh_cells = props.objects.cells.data mesh_walls = props.objects.walls.data cells_corners, cells_faces, stairs_vertex_group, walls_edges = MeshManager.get_mesh_info( grid, props.cell_inset, props.path.force_outside) mesh_cells.clear_geometry() mesh_cells.from_pydata(cells_corners, [], cells_faces) mesh_walls.clear_geometry() mesh_walls.from_pydata(cells_corners, walls_edges, []) bm_cells = bmesh.new() bm_cells.from_mesh(mesh_cells) bm_walls = bmesh.new() bm_walls.from_mesh(mesh_walls) distance_vc = bm_cells.loops.layers.color.new(DISTANCE) group_vc = bm_cells.loops.layers.color.new(GROUP) neighbors_vc = bm_cells.loops.layers.color.new(NEIGHBORS) vg_cells = bm_cells.verts.layers.deform.new() vg_walls = bm_walls.verts.layers.deform.new() random.seed(props.seed_color) groups = grid.groups group_colors = {} max_groups = max(max(grid.groups), 1) for g in groups: val = g / max_groups group_colors[g] = val, val, val, 1 max_neighbors = max(grid.max_links_per_cell, 1) neighbors_colors = {} for n in range(max_neighbors + 1): val = n / max_neighbors neighbors_colors[n] = val, val, val, 1 bm_cells.verts.ensure_lookup_table() bm_walls.verts.ensure_lookup_table() for vg_info, weights in stairs_vertex_group.items(): for v_ind in vg_info: bm_cells_vert = bm_cells.verts[v_ind] bm_cells_vert[vg_cells][0] = weights[0] bm_cells_vert[vg_cells][2] = weights[1] bm_walls_vert = bm_walls.verts[v_ind] bm_walls_vert[vg_walls][0] = weights[0] bm_walls_vert[vg_walls][1] = 1 bm_walls_vert[vg_walls][2] = weights[1] for loop in bm_cells_vert.link_loops: loop[distance_vc] = (weights[0], weights[1], 0, 0) loop[group_vc] = group_colors[weights[2]] loop[neighbors_vc] = neighbors_colors[weights[3]] bm_cells.to_mesh(mesh_cells) bm_walls.to_mesh(mesh_walls) mesh_cells.transform(Matrix.Translation(grid.offset)) mesh_walls.transform(Matrix.Translation(grid.offset)) if props.cell_use_smooth: # Update only when the mesh is supposed to be smoothed, because the default will be unsmoothed MeshManager.update_smooth(props) for mesh in (mesh_cells, mesh_walls): mesh.use_auto_smooth = True mesh.auto_smooth_angle = 0.5
def calc_target_view_matrix(self, start_target, end_target, factor): return Matrix.Translation(Vector((0, 0, 5)))
def get_loc_matrix(location): return Matrix.Translation(location)
def get_object_matrix(self): bound_center = self.calc_bounding_box_center() return self.object.matrix_world * Matrix.Translation(bound_center)
def make_name_plate_notches(self): self.remove_name_plate() x = [ self.location[0] - (0.5 * self.Size_x), self.location[0] + (0.5 * self.Size_x), self.location[0] + (0.25 * self.Size_x) - 1.75, self.location[0] + (0.25 * self.Size_x) + 1.75, self.location[0] + (0.25 * self.Size_x) - 3.5, self.location[0] + (0.25 * self.Size_x) + 3.5, self.location[0] - (0.25 * self.Size_x) - 1.75, self.location[0] - (0.25 * self.Size_x) + 1.75, self.location[0] - (0.25 * self.Size_x) - 3.5, self.location[0] - (0.25 * self.Size_x) + 3.5 ] y = [ self.location[1] + (0.5 * self.Size_y), self.location[1] - (0.5 * self.Size_y), self.location[1] + (0.5 * self.Size_y) - (self.Border_width * 2 / 3) ] z = [ self.location[2] + (0.5 * self.Size_z), self.location[2] - (0.5 * self.Size_z), self.location[2] - (0.5 * self.Size_z) + self.Base_height ] verts = [ Vector((x[0], y[0], z[0])), Vector((x[1], y[0], z[0])), Vector((x[1], y[1], z[0])), Vector((x[0], y[1], z[0])), Vector((x[0], y[0], z[1])), Vector((x[1], y[0], z[1])), Vector((x[1], y[1], z[1])), Vector((x[0], y[1], z[1])), Vector((x[2], y[0], z[1])), Vector((x[3], y[0], z[1])), Vector((x[3], y[2], z[1])), Vector((x[2], y[2], z[1])), Vector((x[4], y[0], z[2])), Vector((x[5], y[0], z[2])), Vector((x[5], y[2], z[2])), Vector((x[4], y[2], z[2])), Vector((x[6], y[0], z[1])), Vector((x[7], y[0], z[1])), Vector((x[7], y[2], z[1])), Vector((x[6], y[2], z[1])), Vector((x[8], y[0], z[2])), Vector((x[9], y[0], z[2])), Vector((x[9], y[2], z[2])), Vector((x[8], y[2], z[2])), ] faces = [(3, 2, 1, 0), (4, 7, 3, 0), (1, 2, 6, 5), (7, 6, 2, 3), (12, 13, 14, 15), (9, 10, 14, 13), (12, 15, 11, 8), (15, 14, 10, 11), (20, 21, 22, 23), (17, 18, 22, 21), (20, 23, 19, 16), (23, 22, 18, 19), (4, 16, 19, 18, 17, 8, 11, 10, 9, 5, 6, 7), (0, 1, 5, 9, 13, 12, 8, 17, 21, 20, 16, 4)] me = bpy.data.meshes.new(self.name_plate_mesh_key) self.name_plate = bpy.data.objects.new(self.name_plate_object_key, me) bpy.context.scene.objects.link(self.name_plate) me.from_pydata(verts, [], faces) me.update() bpy.ops.object.origin_set(type='ORIGIN_CENTER_OF_MASS') R = Matrix.Rotation(math.radians(180), 4, Vector((0, 0, 1))) T = Matrix.Translation(self.location) TRT = T * R * T.inverted() self.name_plate.location = TRT * self.name_plate.location self.name_plate.rotation_euler.rotate(TRT)
def setCharacterPosition(charObject, source, sourceSplinePosition, offsetPosition): characterOffset = sourceSplinePosition - offsetPosition charObject.matrix_world = source.matrix_world * Matrix.Translation( characterOffset)
def _create_blender_armature_from_mod(mod, armature_name, parent=None): armature = bpy.data.armatures.new(armature_name) armature_ob = bpy.data.objects.new(armature_name, armature) armature_ob.parent = parent bpy.context.scene.objects.link(armature_ob) if bpy.context.mode != 'OBJECT': bpy.ops.object.mode_set(mode='OBJECT') # deselect all objects for i in bpy.context.scene.objects: i.select = False bpy.context.scene.objects.active = armature_ob armature_ob.select = True bpy.ops.object.mode_set(mode='EDIT') blender_bones = [] for i, bone in enumerate(mod.bones_array): blender_bone = armature.edit_bones.new(str(i)) blender_bones.append(blender_bone) parents = get_bone_parents_from_mod(bone, mod.bones_array) if not parents: blender_bone.head = Vector( (bone.location_x / 100, bone.location_z * -1 / 100, bone.location_y / 100)) continue chain = [i] + parents wtm = Matrix.Translation((0, 0, 0)) for bi in reversed(chain): b = mod.bones_array[bi] wtm *= Matrix.Translation( (b.location_x / 100, b.location_z / 100 * -1, b.location_y / 100)) blender_bone.head = wtm.to_translation() blender_bone.parent = blender_bones[bone.parent_index] assert len(blender_bones) == len(mod.bones_array) # set tails of bone to their children or make them small if they have none for i, bone in enumerate(blender_bones): children = bone.children_recursive non_mirror_children = [ b for b in children if mod.bones_array[int(b.name)].mirror_index == int(b.name) ] mirror_children = [ b for b in children if mod.bones_array[int(b.name)].mirror_index != int(b.name) ] if mod.bones_array[i].mirror_index == i and non_mirror_children: bone.tail = non_mirror_children[0].head elif mod.bones_array[i].mirror_index != i and mirror_children: bone.tail = mirror_children[0].head else: bone.length = 0.01 # Some very small numbers won't be equal without rounding, but blender will # later treat them as equal, so using rounding here if round(bone.tail[0], 10) == round(bone.head[0], 10): bone.tail[0] += 0.01 if round(bone.tail[1], 10) == round(bone.head[1], 10): bone.tail[1] += 0.01 if round(bone.tail[2], 10) == round(bone.head[2], 10): bone.tail[2] += 0.01 bpy.ops.object.mode_set(mode='OBJECT') assert len(armature.bones) == len(mod.bones_array) return armature_ob
def test_obj_and_cam_blur(self): """ One object ("moving_obj") and the camera ("moving_camera") are moving. Camera and object motion blur are enabled. """ blender_scene = bpy.context.scene # Switch to the moving camera blender_scene.camera = bpy.data.objects["moving_camera"] # Switch to correct frame in case someone messed it up on save blender_scene.frame_set(TEST_FRAME, TEST_SUBFRAME) # Get the object that moves and should be blurred moving_obj = bpy.data.objects["moving_obj"] moving_obj_name = utils.get_luxcore_name(moving_obj, is_viewport_render=False) # Make sure the settings are correct # (can only change if someone messes with the test scene) self.assertIsNotNone(blender_scene.camera) blur_settings = blender_scene.camera.data.luxcore.motion_blur self.assertTrue(blur_settings.enable) self.assertAlmostEqual(blur_settings.shutter, 4.0) self.assertTrue(blur_settings.object_blur) self.assertTrue(blur_settings.camera_blur) self.assertEqual(blur_settings.steps, 2) # Make sure we are at the correct frame self.assertEqual(blender_scene.frame_current, 3) self.assertAlmostEqual(blender_scene.frame_subframe, 0.0) # Export the scene scene_props = export(blender_scene) # Check properties for correctness all_exported_obj_prefixes = scene_props.GetAllUniqueSubNames( "scene.objects") for prefix in all_exported_obj_prefixes: luxcore_name = prefix.split(".")[-1] if luxcore_name == moving_obj_name: test_moving_object(self, scene_props, prefix) # Check if camera shutter settings are correct # Total shutter duration is 4.0 frames, so these should be -2.0 and 2.0 self.assertAlmostEqual( scene_props.Get("scene.camera.shutteropen").GetFloat(), -2.0) self.assertAlmostEqual( scene_props.Get("scene.camera.shutterclose").GetFloat(), 2.0) # Check if camera transformation props are correct # Test the times # step 0. Shutter is 4.0 frames, so this step should be minus half of the shutter value self.assertAlmostEqual( scene_props.Get("scene.camera.motion.0.time").GetFloat(), -2.0) # step 1. This should be half of the shutter value self.assertAlmostEqual( scene_props.Get("scene.camera.motion.1.time").GetFloat(), 2.0) # Test the transformation matrices # step 0. We are at X = 3m, Y = 0, Z = 0m translation = Matrix.Translation([3, 0, 0]) rotation = Matrix.Rotation(math.radians(-90.0), 4, "X") scale = Matrix.Scale(1, 4) expected_step_0 = create_expected_matrix(blender_scene, translation, rotation, scale) # For some reason we need to invert these two... my matrix math is rusty expected_step_0[6] *= -1 expected_step_0[9] *= -1 transformation_step_0 = scene_props.Get( "scene.camera.motion.0.transformation").GetFloats() assertListsAlmostEqual(self, transformation_step_0, expected_step_0) # step 1. We are at X = -3m, Y = 0, Z = 0m translation = Matrix.Translation([-3, 0, 0]) rotation = Matrix.Rotation(math.radians(-90.0), 4, "X") scale = Matrix.Scale(1, 4) expected_step_1 = create_expected_matrix(blender_scene, translation, rotation, scale) # For some reason we need to invert these two... my matrix math is rusty expected_step_1[6] *= -1 expected_step_1[9] *= -1 transformation_step_1 = scene_props.Get( "scene.camera.motion.1.transformation").GetFloats() assertListsAlmostEqual(self, transformation_step_1, expected_step_1)
def execute(self, context): import collections import operator import itertools rotvar = self.rot_var - 1 yvar = self.y_var - 1 app = self.mats.append bpy.ops.mesh.separate(type="LOOSE") bpy.ops.object.origin_set(type="ORIGIN_GEOMETRY", center="MEDIAN") for ob in context.selected_objects: normal_groups = collections.defaultdict(float) for poly in ob.data.polygons: normal_groups[poly.normal.copy().freeze()] += poly.area normals = sorted(normal_groups.items(), key=operator.itemgetter(1), reverse=True) try: normal = normals[rotvar][0] except IndexError: normal = normals[0][0] mat = normal.to_track_quat("Z", "Y").to_matrix().to_4x4() ob.matrix_world @= mat ob.data.transform(mat.inverted()) # Adjust origin # ------------------------------ verts = sorted(ob.data.vertices, key=operator.attrgetter("co.xy.length"), reverse=True)[:8] # Z height co_z_low = min(verts, key=operator.attrgetter("co.z")).co.z if co_z_low != 0.0: mat = Matrix.Translation((0.0, 0.0, co_z_low)) ob.matrix_world @= mat ob.data.transform(mat.inverted()) # Y align if self.y_align: if self.snap_to_edge: cos = [ ( (v1.co.xy + v2.co.xy) / 2, (v1.co.xy - v2.co.xy).length, ) for v1, v2 in itertools.combinations(verts, 2) ] cos.sort(key=operator.itemgetter(1)) try: vec = cos[yvar][0] except IndexError: vec = cos[0][0] else: try: vec = verts[yvar].co.xy except IndexError: vec = verts[0].co.xy vec.negate() vec.resize_3d() mat = vec.to_track_quat("Y", "Z").to_matrix().to_4x4() ob.matrix_world @= mat ob.data.transform(mat.inverted()) # XY center if self.xy_loc != 0: if self.xy_loc == 1: context.view_layer.update() xy_min = min((x[0], x[1]) for x in ob.bound_box) xy_max = max((x[0], x[1]) for x in ob.bound_box) x_loc = (xy_min[0] + xy_max[0]) / 2 y_loc = (xy_min[1] + xy_max[1]) / 2 co_xy = (x_loc, y_loc) elif self.xy_loc == 2: co_xy = min(ob.data.vertices, key=operator.attrgetter("co.z")).co.xy if co_xy[0] != 0.0 or co_xy[1] != 0.0: mat = Matrix.Translation((*co_xy, 0.0)) ob.matrix_world @= mat ob.data.transform(mat.inverted()) # Display axis app(ob.matrix_world.copy()) return {"FINISHED"}
def glsl_draw(self): if GlslDrawObj.myinstance is None and GlslDrawObj.draw_func is None: glsl_draw_obj = GlslDrawObj() glsl_draw_obj.build_scene() else: glsl_draw_obj = GlslDrawObj.myinstance model_offset = Matrix.Translation((glsl_draw_obj.draw_x_offset, 0, 0)) light_pos = [ i + n for i, n in zip(glsl_draw_obj.light.location, [-glsl_draw_obj.draw_x_offset, 0, 0]) ] batches = glsl_draw_obj.batches depth_shader = glsl_draw_obj.depth_shader toon_shader = glsl_draw_obj.toon_shader offscreen = glsl_draw_obj.offscreen # need bone etc changed only update depth_matrix = None light = glsl_draw_obj.light light_lookat = light.rotation_euler.to_quaternion() @ Vector( (0, 0, -1)) # TODO このへん tar = light_lookat.normalized() up = light.rotation_euler.to_quaternion() @ Vector((0, 1, 0)) tmp_bound_len = Vector(glsl_draw_obj.bounding_center).length camera_bias = 0.2 loc = Vector([ glsl_draw_obj.bounding_center[i] + tar[i] * (tmp_bound_len + camera_bias) for i in range(3) ]) loc = model_offset @ loc v_matrix = lookat_cross(loc, tar, up) const_proj = 2 * max(glsl_draw_obj.bounding_size) / 2 p_matrix = ortho_proj_mat(-const_proj, const_proj, -const_proj, const_proj, -const_proj, const_proj) depth_matrix = v_matrix @ p_matrix # reuse in main shader depth_matrix.transpose() # region shader depth path with offscreen.bind(): bgl.glClearColor(10, 10, 10, 1) bgl.glClear(bgl.GL_COLOR_BUFFER_BIT | bgl.GL_DEPTH_BUFFER_BIT) for bat in batches: mat = bat[0] mat.update() depth_bat = bat[2] depth_shader.bind() bgl.glEnable(bgl.GL_BLEND) if mat.alpha_method == "TRANSPARENT": bgl.glBlendFunc(bgl.GL_SRC_ALPHA, bgl.GL_ONE_MINUS_SRC_ALPHA) bgl.glDepthMask(bgl.GL_TRUE) bgl.glEnable(bgl.GL_DEPTH_TEST) elif mat.alpha_method == "OPAQUE": bgl.glBlendFunc(bgl.GL_ONE, bgl.GL_ZERO) bgl.glDepthMask(bgl.GL_TRUE) bgl.glEnable(bgl.GL_DEPTH_TEST) elif mat.alpha_method == "CLIP": bgl.glBlendFunc(bgl.GL_ONE, bgl.GL_ZERO) bgl.glDepthMask(bgl.GL_TRUE) bgl.glEnable(bgl.GL_DEPTH_TEST) if mat.cull_mode == "BACK": bgl.glEnable(bgl.GL_CULL_FACE) bgl.glCullFace(bgl.GL_BACK) else: bgl.glDisable(bgl.GL_CULL_FACE) bgl.glEnable(bgl.GL_CULL_FACE) # そも輪郭線がの影は落ちる? bgl.glCullFace(bgl.GL_BACK) depth_shader.uniform_float("obj_matrix", model_offset) # obj.matrix_world) depth_shader.uniform_float("depthMVP", depth_matrix) depth_bat.draw(depth_shader) # endregion shader depth path # region shader main vp_mat = bpy.context.region_data.perspective_matrix projection_mat = bpy.context.region_data.window_matrix view_dir = bpy.context.region_data.view_matrix[2][:3] view_up = bpy.context.region_data.view_matrix[1][:3] normal_world_to_view_matrix = ( bpy.context.region_data.view_matrix.inverted_safe().transposed()) aspect = bpy.context.area.width / bpy.context.area.height for is_outline in [0, 1]: for bat in batches: toon_bat = bat[1] toon_shader.bind() mat = bat[0] if is_outline == 1 and mat.float_dic["OutlineWidthMode"] == 0: continue # mat.update() #already in depth path bgl.glEnable(bgl.GL_BLEND) bgl.glDepthMask(bgl.GL_TRUE) bgl.glEnable(bgl.GL_DEPTH_TEST) if mat.alpha_method == "TRANSPARENT": bgl.glBlendFunc(bgl.GL_SRC_ALPHA, bgl.GL_ONE_MINUS_SRC_ALPHA) elif mat.alpha_method == "OPAQUE": bgl.glBlendFunc(bgl.GL_ONE, bgl.GL_ZERO) elif mat.alpha_method == "CLIP": bgl.glBlendFunc(bgl.GL_ONE, bgl.GL_ZERO) if is_outline == 0: if mat.cull_mode == "BACK": bgl.glEnable(bgl.GL_CULL_FACE) bgl.glCullFace(bgl.GL_BACK) else: bgl.glDisable(bgl.GL_CULL_FACE) else: bgl.glEnable(bgl.GL_CULL_FACE) bgl.glCullFace(bgl.GL_BACK) toon_shader.uniform_float("obj_matrix", model_offset) # obj.matrix_world) toon_shader.uniform_float("projectionMatrix", projection_mat) toon_shader.uniform_float("viewProjectionMatrix", vp_mat) toon_shader.uniform_float("viewDirection", view_dir) toon_shader.uniform_float("viewUpDirection", view_up) toon_shader.uniform_float("normalWorldToViewMatrix", normal_world_to_view_matrix) toon_shader.uniform_float("depthMVP", depth_matrix) toon_shader.uniform_float("lightpos", light_pos) toon_shader.uniform_float("aspect", aspect) toon_shader.uniform_float("is_outline", is_outline) toon_shader.uniform_float("isDebug", 0.0) toon_shader.uniform_float( "is_cutout", 1.0 if mat.alpha_method == "CLIP" else 0.0) float_keys = [ "CutoffRate", "BumpScale", "ReceiveShadowRate", "ShadeShift", "ShadeToony", "RimLightingMix", "RimFresnelPower", "RimLift", "ShadingGradeRate", "LightColorAttenuation", "IndirectLightIntensity", "OutlineWidth", "OutlineScaleMaxDistance", "OutlineLightingMix", "UV_Scroll_X", "UV_Scroll_Y", "UV_Scroll_Rotation", "OutlineWidthMode", "OutlineColorMode", ] for k in float_keys: toon_shader.uniform_float(k, mat.float_dic[k]) for k, v in mat.vector_dic.items(): toon_shader.uniform_float(k, v) bgl.glActiveTexture(bgl.GL_TEXTURE0) bgl.glBindTexture(bgl.GL_TEXTURE_2D, offscreen.color_texture) bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_WRAP_S, bgl.GL_CLAMP_TO_EDGE) # TODO bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_WRAP_T, bgl.GL_CLAMP_TO_EDGE) toon_shader.uniform_int("depth_image", 0) for i, k in enumerate(mat.texture_dic.keys()): bgl.glActiveTexture(bgl.GL_TEXTURE1 + i) texture = mat.texture_dic[k] bgl.glBindTexture(bgl.GL_TEXTURE_2D, texture.bindcode) bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_WRAP_S, bgl.GL_CLAMP_TO_EDGE) # TODO bgl.glTexParameteri(bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_WRAP_T, bgl.GL_CLAMP_TO_EDGE) toon_shader.uniform_int(k, 1 + i) toon_bat.draw(toon_shader)
def make_humanoid(self, mesh): args = self.args self.bm = bmesh.new() head_size = self.head_size # region body # make neckneck neck_bone = self.get_humanoid_bone("neck") self.make_half_cube([head_size / 2, head_size / 2, neck_bone.length], neck_bone.head_local) # make chest - upper and lower (肋骨の幅の最大値で分割) chest_bone = self.get_humanoid_bone("chest") shoulder_in = args.shoulder_in_width leftUpperArm_bone = self.get_humanoid_bone("leftUpperArm") # upper chest shell self.make_half_trapezoid( [head_size * 3 / 4, leftUpperArm_bone.head_local[0] * 2], [head_size * 3 / 4, shoulder_in], chest_bone.length, chest_bone.matrix_local, ) # lower chest shell spine_bone = self.get_humanoid_bone("spine") self.make_half_trapezoid( [ head_size * 3 / 4, (leftUpperArm_bone.head_local[0] - shoulder_in) * 2 ], [head_size * 3 / 4, leftUpperArm_bone.head_local[0] * 2], spine_bone.length * 3 / 5, spine_bone.matrix_local @ Matrix.Translation( Vector([0, spine_bone.length * 2 / 5, 0])), ) # make spine # make hips hips_bone = self.get_humanoid_bone("hips") hips_size = leftUpperArm_bone.head_local[0] * 2 * 1.2 self.make_half_cube([hips_size, head_size * 3 / 4, hips_bone.length], hips_bone.head_local) # endregion body # region arm left_arm_bones = [ self.get_humanoid_bone(v) for v in HumanBones.left_arm_req + HumanBones.left_arm_def if v in args.armature_obj.data and args.armature_obj.data[v] != "" and args.armature_obj.data[v] in args.armature_obj.data.bones ] left_hand_bone = self.get_humanoid_bone("leftHand") for b in left_arm_bones: base_xz = [ b.head_radius if b != left_hand_bone else args.hand_size / 2, b.head_radius, ] top_xz = [ b.tail_radius if b != left_hand_bone else args.hand_size / 2, b.tail_radius, ] self.make_trapezoid(base_xz, top_xz, b.length, [0, 0, 0], b.matrix_local) # TODO Thumb rotation # endregion arm # region leg # TODO left_leg_bones = [ self.get_humanoid_bone(v) for v in HumanBones.left_leg_req + HumanBones.left_leg_def if v in args.armature_obj.data and args.armature_obj.data[v] != "" and args.armature_obj.data[v] in args.armature_obj.data.bones ] for b in left_leg_bones: bone_name = "" for k, v in self.args.armature_obj.data.items(): if v == b.name: bone_name = k break if bone_name == "": head_x = b.head_radius head_z = b.head_radius tail_x = b.head_radius tail_z = b.head_radius elif "UpperLeg" in bone_name: head_x = hips_size / 2 head_z = hips_size / 2 tail_x = 0.71 * hips_size / 2 tail_z = 0.71 * hips_size / 2 elif "LowerLeg" in bone_name: head_x = 0.71 * hips_size / 2 head_z = 0.71 * hips_size / 2 tail_x = 0.54 * hips_size / 2 tail_z = 0.6 * hips_size / 2 elif "Foot" in bone_name: head_x = 0.54 * hips_size / 2 head_z = 0.6 * hips_size / 2 tail_x = 0.81 * hips_size / 2 tail_z = 0.81 * hips_size / 2 elif "Toes" in bone_name: head_x = 0.81 * hips_size / 2 head_z = 0.81 * hips_size / 2 tail_x = 0.81 * hips_size / 2 tail_z = 0.81 * hips_size / 2 self.make_trapezoid([head_x, head_z], [tail_x, tail_z], b.length, [0, 0, 0], b.matrix_local) # endregion leg self.bm.to_mesh(mesh) self.bm.free() return