def add_object_align_init(context, operator): """ Return a matrix using the operator settings and view context. :arg context: The context to use. :type context: :class:`bpy.types.Context` :arg operator: The operator, checked for location and rotation properties. :type operator: :class:`bpy.types.Operator` :return: the matrix from the context and settings. :rtype: :class:`mathutils.Matrix` """ from mathutils import Matrix, Vector, Euler properties = operator.properties if operator is not None else None space_data = context.space_data if space_data and space_data.type != 'VIEW_3D': space_data = None # location if operator and properties.is_property_set("location"): location = Matrix.Translation(Vector(properties.location)) else: location = Matrix.Translation(context.scene.cursor.location) if operator: properties.location = location.to_translation() # rotation view_align = (context.preferences.edit.object_align == 'VIEW') view_align_force = False if operator: if properties.is_property_set("view_align"): view_align = view_align_force = operator.view_align else: if properties.is_property_set("rotation"): # ugh, 'view_align' callback resets value = properties.rotation[:] properties.view_align = view_align properties.rotation = value del value else: properties.view_align = view_align if operator and (properties.is_property_set("rotation") and not view_align_force): rotation = Euler(properties.rotation).to_matrix().to_4x4() else: if view_align and space_data: rotation = space_data.region_3d.view_matrix.to_3x3().inverted() rotation.resize_4x4() else: rotation = Matrix() # set the operator properties if operator: properties.rotation = rotation.to_euler() return location @ rotation
def __getAxisAngleBasedRotation(self, rotate, translate): euler = Euler(rotate) self.logger.debug("Injecting rotation: '%s'", str(euler)) vector_translate = Vector((translate[0], translate[1], translate[2])) # actually the translation is also needed to be passed here rotate_mtx = Matrix.to_4x4(euler.to_matrix()) translate_mtx = Matrix.Translation(vector_translate) cameraMatrix = translate_mtx * rotate_mtx # global matrix rotate (guess it is for world coordinate system rotating) mtx = Matrix.Rotation(-(math.pi / 2.0), 4, 'X') mtx = mtx * cameraMatrix (loc, quat, _) = mtx.decompose() # get the values the way that in x3d exporter does quat = quat.normalized() # some weird stuff axises = list(quat.axis.to_tuple()) angle = quat.angle orientation = self.__getStringRepresentation(axises) + " " + str(angle) translation = self.__getStringRepresentation(loc) return translation, orientation
def obj_orientation(obj, alpha, beta, gamma): '''Set obj orientation, angle in degrees''' alpha = alpha*pi/180 beta = beta*pi/180 gamma = gamma*pi/180 rot_in_euler = Euler([alpha, beta, gamma]) obj.worldOrientation = rot_in_euler.to_matrix()
def getTransformFromParent(self): rot = Euler((radians(self.alpha.value), radians(self.beta.value), radians(self.gamma.value)), 'XYZ').to_matrix() rot.resize_4x4() transl = Matrix.Translation((self.x.value, self.y.value, self.z.value)) # print("here",transl * rot) return transl * rot
def mapping_node_order_flip(orientation): """ Flip euler order of mapping shader node see: Blender #a1ffb49 """ rot = Euler(orientation) rot.order = 'ZYX' quat = rot.to_quaternion() return quat.to_euler('XYZ')
def process(self): if not self.outputs['Quaternions'].is_linked: return inputs = self.inputs quaternionList = [] if self.mode == "WXYZ": I = [inputs[n].sv_get()[0] for n in "WXYZ"] params = match_long_repeat(I) for wxyz in zip(*params): q = Quaternion(wxyz) if self.normalize: q.normalize() quaternionList.append(q) elif self.mode == "SCALARVECTOR": I = [inputs[n].sv_get()[0] for n in ["Scalar", "Vector"]] params = match_long_repeat(I) for scalar, vector in zip(*params): q = Quaternion([scalar, *vector]) if self.normalize: q.normalize() quaternionList.append(q) elif self.mode == "EULER": I = [inputs["Angle " + n].sv_get()[0] for n in "XYZ"] params = match_long_repeat(I) au = angleConversion[self.angleUnits] for angleX, angleY, angleZ in zip(*params): euler = Euler((angleX * au, angleY * au, angleZ * au), self.eulerOrder) q = euler.to_quaternion() if self.normalize: q.normalize() quaternionList.append(q) elif self.mode == "AXISANGLE": I = [inputs[n].sv_get()[0] for n in ["Axis", "Angle"]] params = match_long_repeat(I) au = angleConversion[self.angleUnits] for axis, angle in zip(*params): q = Quaternion(axis, angle * au) if self.normalize: q.normalize() quaternionList.append(q) elif self.mode == "MATRIX": input_M = inputs["Matrix"].sv_get(default=idMat) for m in input_M: q = Matrix(m).to_quaternion() if self.normalize: q.normalize() quaternionList.append(q) self.outputs['Quaternions'].sv_set([quaternionList])
def eval_planet_rotation(scn_name, obj_name, index=None, time=None): """Evaluate the planets rotation, used by driver. scn_name = Name of a scene which contains the object obj_name = Name of the object to simulate index = index of the rotation channel, usually only z-axis (index=2) changes time = time when to calculate, if not given use current scene time time is in seconds of the simulation returns an Euler in mode ZYX or, if index given, an angle in radians """ scn = bpy.data.scenes.get(scn_name) obj = bpy.data.objects.get(obj_name) if not obj or not scn: errmsg = "DRIVER ERROR: Invalid obj_name ({}) or scn_name ({})" print(errmsg.format(obj_name, scn_name)) return 0 simscn = scn.sssim_scn simrot = obj.sssim_rotation # time = time in seconds, if None use current scene time if time is None: time = simscn.time # rotation_period is also in seconds rotation_period = simrot.rotation_period if rotation_period != 0: rot_z = 2 * pi * time / rotation_period else: # invalid input -> no rotation rot_z = 0 tilt = simrot.axis_tilt planet_rot = Euler((tilt, 0.0, 0.0), 'ZYX') # note that mode is 'ZYX' # rotate around global (not local) z-axis direction = simrot.axis_direction planet_rot.rotate(Euler((0.0, 0.0, direction), 'XYZ')) # rotate around local z-axis # NOTE: we won't use planet_rot.rotate_axis('Z', rot_z) because then # all rotations are between -180 and 180 and for the rotation around # z we need a continous motion with increasing z values planet_rot.z += rot_z if simrot.relative_to_orbit and obj.sssim_obj.object_type == 'PLANET': planet_rot = orbit_rotate(planet_rot, obj.sssim_orbit) if index is None: return planet_rot else: return planet_rot[index]
def main(_self, entity_object, plugin_data): # Restore Euler structure new_orientation = [0, 0, 0] for value in plugin_data: new_orientation[value[1]] = value[0] euler_orientation = Euler(new_orientation) # Interpolate between data and use for extrapolation interpolator = setdefaultdict(entity_object, "interpolate_orientation", interpolate([entity_object.worldOrientation.to_quaternion(), 0.0])) orientation = [euler_orientation.to_quaternion(), time.time()] interpolator.update(orientation) entity_object.worldOrientation = euler_orientation.to_matrix()
def draw_cloud(bm, prefs, translation=(0, 0, 0)): mat = Matrix() mat.translation = translation smin = prefs.lp_Cloud_Scale_Min smax = prefs.lp_Cloud_Scale_Max sx = uniform(smin[0], smax[0]) sy = uniform(smin[1], smax[1]) sz = uniform(smin[2], smax[2]) scale = (sx, sy, sz) mat[0][0], mat[1][1], mat[2][2] = scale[0], scale[1], scale[2] e = Euler((uniform(0, 3.14), uniform(0, 3.14), uniform(0, 3.14)), 'XYZ') mat = mat * e.to_matrix().to_4x4() bmesh.ops.create_icosphere(bm, subdivisions=prefs.lp_Cloud_Subdivisions, diameter=1.0, matrix=mat) return scale
def draw_arc12(x, y, radius, start_angle, end_angle, subdivide): # いずれ削除 # 十二時から時計回りに描画 v = Vector([0, 1, 0]) e = Euler((0, 0, -start_angle)) m = e.to_matrix() v = v * m if end_angle >= start_angle: a = (end_angle - start_angle) / (subdivide + 1) else: a = (end_angle + math.pi * 2 - start_angle) / (subdivide + 1) e = Euler((0, 0, -a)) m = e.to_matrix() bgl.glBegin(bgl.GL_LINE_STRIP) for i in range(subdivide + 2): v1 = v * radius bgl.glVertex2f(x + v1[0], y + v1[1]) v = v * m bgl.glEnd()
def rotation(self, xyz): if len(xyz) != 3: utils.debug("Rotation assignment failed on " + self.obj.name + " object. xyz size != 3.") if isinstance(xyz, (list, tuple)) or len(xyz) == 3: xyz = Euler(xyz, 'XYZ') srt = self.obj.localOrientation.copy() xyz = xyz.to_matrix() for obj in self.transformable: if obj.__class__.__name__ == "KX_GameObject": if obj == self.obj: obj.localOrientation = xyz else: srr = obj.worldOrientation.copy() srr.rotate(xyz) srr = srr.to_euler() obj.localOrientation = srr else: srr = obj.rotation.copy() srr.rotate(xyz) obj.localOrientation = srr obj.rotation = srr self._rotation = self.ProxyRotation()
def createSceneFromXML(scene_file): # parse xml sceneTree = ET.parse(scene_file) root = sceneTree.getroot() # traverse scene xml materialStack.append(createDefaultMaterial()) transformStack.append(Matrix.Identity(4)) rootObject = createObjectFromXML(root, root[0], './sceneRoot', None, True) # create coordinate conversion root sceneObject = bpy.data.objects.new('JReality Scene', None) jrealityToBlender = Euler((math.pi/2, 0.0, math.pi/2), 'XYZ') sceneObject.matrix_local = jrealityToBlender.to_matrix().to_4x4() bpy.context.scene.objects.link(sceneObject) rootObject.parent = sceneObject; # find active camera cameraPath = root.find("scenePaths/path[@name='cameraPath']") if cameraPath != None: cameraPathXpath = resolveReferencePath(root, cameraPath, "./scenePaths/path[@name='cameraPath']") cameraPath = resolveReference(root, cameraPath, "./scenePaths/path[@name='cameraPath']") node = cameraPath.find('node[last()]') camTag = resolveReference(root, node, cameraPathXpath + "/node[last()]") bpy.context.scene.camera = tagToObject[camTag] else: print('WARNING: no camera path set')
def getTransformFromParent(self): alphaMatrix = Euler((radians(self.alpha.value), 0, 0), 'XYZ').to_matrix() alphaMatrix.resize_4x4() thetaMatrix = Euler((0, 0, radians(self.theta.value)), 'XYZ').to_matrix() thetaMatrix.resize_4x4() translation = Matrix.Translation((self.a.value, 0, self.d.value, 1)) return translation * alphaMatrix * thetaMatrix
def _get_bone_channels(scs_root_obj, armature, scs_animation, action, export_scale): """Takes armature and action and returns bone channels. bone_channels structure example: [("Bone", [("_TIME", [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]), ("_MATRIX", [])])]""" bone_channels = [] frame_start = scs_animation.anim_start frame_end = scs_animation.anim_end anim_export_step = action.scs_props.anim_export_step total_frames = (frame_end - frame_start) / anim_export_step # armature matrix stores transformation of armature object against scs root # and has to be added to all bones as they only armature space transformations armature_mat = scs_root_obj.matrix_world.inverted() @ armature.matrix_world invalid_data = False # flag to indicate invalid data state curves_per_bone = OrderedDict( ) # store all the curves we are interested in per bone names for bone in armature.data.bones: for fcurve in action.fcurves: # check if curve belongs to bone if '["' + bone.name + '"]' in fcurve.data_path: data_path = fcurve.data_path array_index = fcurve.array_index if data_path.endswith("location"): curve_type = "location" elif data_path.endswith("rotation_euler"): curve_type = "euler_rotation" elif data_path.endswith("rotation_quaternion"): curve_type = "quat_rotation" elif data_path.endswith("scale"): curve_type = "scale" else: curve_type = None # write only recognized curves if curve_type is not None: if bone.name not in curves_per_bone: curves_per_bone[bone.name] = { "location": {}, "euler_rotation": {}, "quat_rotation": {}, "scale": {} } curves_per_bone[ bone.name][curve_type][array_index] = fcurve for bone_name, bone_curves in curves_per_bone.items(): bone = armature.data.bones[bone_name] pose_bone = armature.pose.bones[bone_name] loc_curves = bone_curves["location"] euler_rot_curves = bone_curves["euler_rotation"] quat_rot_curves = bone_curves["quat_rotation"] sca_curves = bone_curves["scale"] bone_rest_mat = armature_mat @ bone.matrix_local if bone.parent: parent_bone_rest_mat = ( Matrix.Scale(export_scale, 4) @ _convert_utils.scs_to_blend_matrix().inverted() @ armature_mat @ bone.parent.matrix_local) else: parent_bone_rest_mat = Matrix() # GO THOUGH FRAMES actual_frame = frame_start timings_stream = [] matrices_stream = [] while actual_frame <= frame_end: mat_loc = Matrix() mat_rot = Matrix() mat_sca = Matrix() # LOCATION MATRIX if len(loc_curves) > 0: location = Vector() for index in range(3): if index in loc_curves: location[index] = loc_curves[index].evaluate( actual_frame) mat_loc = Matrix.Translation(location) # ROTATION MATRIX if len(euler_rot_curves) > 0: rotation = Euler() for index in range(3): if index in euler_rot_curves: rotation[index] = euler_rot_curves[index].evaluate( actual_frame) mat_rot = Euler(rotation, pose_bone.rotation_mode).to_matrix( ).to_4x4() # calc rotation by pose rotation mode elif len(quat_rot_curves) > 0: rotation = Quaternion() for index in range(4): if index in quat_rot_curves: rotation[index] = quat_rot_curves[index].evaluate( actual_frame) mat_rot = rotation.to_matrix().to_4x4() # SCALE MATRIX if len(sca_curves) > 0: scale = Vector((1.0, 1.0, 1.0)) for index in range(3): if index in sca_curves: scale[index] = sca_curves[index].evaluate(actual_frame) if scale[index] < 0: lprint( str("E Negative scale detected on bone %r:\n\t " "(Action: %r, keyframe no.: %s, SCS Animation: %r)." ), (bone_name, action.name, actual_frame, scs_animation.name)) invalid_data = True mat_sca = Matrix() mat_sca[0] = (scale[0], 0, 0, 0) mat_sca[1] = (0, scale[1], 0, 0) mat_sca[2] = (0, 0, scale[2], 0) mat_sca[3] = (0, 0, 0, 1) # BLENDER FRAME MATRIX mat = mat_loc @ mat_rot @ mat_sca # SCALE REMOVAL MATRIX rest_location, rest_rotation, rest_scale = bone_rest_mat.decompose( ) # print(' BONES rest_scale: %s' % str(rest_scale)) rest_scale = rest_scale * export_scale scale_removal_matrix = Matrix() scale_removal_matrix[0] = (1.0 / rest_scale[0], 0, 0, 0) scale_removal_matrix[1] = (0, 1.0 / rest_scale[1], 0, 0) scale_removal_matrix[2] = (0, 0, 1.0 / rest_scale[2], 0) scale_removal_matrix[3] = (0, 0, 0, 1) # SCALE MATRIX scale_matrix = Matrix.Scale(export_scale, 4) # COMPUTE SCS FRAME MATRIX frame_matrix = (parent_bone_rest_mat.inverted() @ _convert_utils.scs_to_blend_matrix().inverted() @ scale_matrix.inverted() @ bone_rest_mat @ mat @ scale_removal_matrix.inverted()) # print(' actual_frame: %s - value: %s' % (actual_frame, frame_matrix)) timings_stream.append( ("__time__", scs_animation.length / total_frames), ) matrices_stream.append(("__matrix__", frame_matrix.transposed()), ) actual_frame += anim_export_step anim_timing = ("_TIME", timings_stream) anim_matrices = ("_MATRIX", matrices_stream) bone_anim = (anim_timing, anim_matrices) bone_data = (bone_name, bone_anim) bone_channels.append(bone_data) # return empty bone channels if data are invalid if invalid_data: return [] return bone_channels
import bge import time from rift import PyRift from mathutils import Quaternion, Euler, Vector # Functions def poll(): bge.logic.rift.pollSensor() bge.logic.rotation = Quaternion((bge.logic.rift.headPose[3], bge.logic.rift.headPose[4], bge.logic.rift.headPose[5], bge.logic.rift.headPose[6])) bge.logic.position = Vector((bge.logic.rift.headPose[0],bge.logic.rift.headPose[1],bge.logic.rift.headPose[2])) # Main try: eu = bge.logic.rotation.to_euler() fix = Euler((-1.57, 0, 0), 'XYZ') rot = Euler((-eu.z, eu.y, -eu.x), 'XYZ') rot.rotate(fix) bge.logic.prev_orientation = rot; poll() except: bge.logic.rift = PyRift() bge.logic.rift.connect() scene_e = bge.logic.getCurrentScene() cam_e = scene_e.active_camera bge.logic.init_position = Vector((cam_e.localPosition[0],cam_e.localPosition[1],cam_e.localPosition[2])) bge.logic.init_orientation = cam_e.localOrientation.to_euler() eu = Euler()
def modal(self, context, event): if event.type == "TIMER": if context.scene.com_props.prop_running_nav and not context.scene.com_props.prop_paused_nav: last_pose = pc.PathContainer().poses[-1] reached_poses = cnh.Buffer().get_reached_poses() num_reached_poses = len(reached_poses) num_path_poses = len(pc.PathContainer().poses) end_reached = cnh.Buffer().end_reached() if num_reached_poses == num_path_poses and end_reached: context.scene.com_props.prop_running_nav = False context.scene.com_props.prop_paused_nav = False if RUNNING_STATUS in hudWriter.HUDWriterOperator._textos: del hudWriter.HUDWriterOperator._textos[RUNNING_STATUS] if num_reached_poses != num_path_poses and end_reached: self.report({'ERROR'}, "End reached not expected") context.scene.com_props.prop_running_nav = False context.scene.com_props.prop_paused_nav = False capture_started = cnh.Buffer().capture_started() capture_ended = cnh.Buffer().capture_ended() if capture_started: prop_capture_running = context.scene.com_props.prop_capture_running if prop_capture_running: self.report({'ERROR'}, "Capture is already started") else: context.scene.com_props.prop_capture_running = True self.report({'INFO'}, "Capture started") hudWriter.HUDWriterOperator._textos[ CAPTURE_STATUS] = SocketModalOperator.CAPTURE_ON if capture_ended: prop_capture_running = context.scene.com_props.prop_capture_running if not prop_capture_running: self.report({'ERROR'}, "Capture was not started") else: context.scene.com_props.prop_capture_running = False self.report({'INFO'}, "Capture ended") if CAPTURE_STATUS in hudWriter.HUDWriterOperator._textos: del hudWriter.HUDWriterOperator._textos[CAPTURE_STATUS] if not SocketModalOperator.closed and context.scene.com_props.prop_rendering: # Render robot position sel_robot_id = bpy.context.scene.selected_robot_props.prop_robot_id if sel_robot_id < 0: self.report({'ERROR'}, "No robot selected") else: r = robot.RobotSet().getRobot(sel_robot_id) trace = cnh.Buffer().get_last_trace_packet() if trace is not None: pose = trace.pose r.loc = Vector((pose.x, pose.y, 0)) r.rotation = Euler((0, 0, pose.gamma)) if SocketModalOperator.closed: SocketModalOperator.switching = True if SocketModalOperator.error != "": self.report({'ERROR'}, self.error) SocketModalOperator.running = False cnh.ConnectionHandler().remove_socket() else: bpy.context.scene.com_props.prop_last_sent_packet += 1 new_pid = bpy.context.scene.com_props.prop_last_sent_packet new_mode = robot_modes_summary.index("EDITOR_MODE") initial_speed = context.scene.com_props.prop_speed bpy.context.scene.com_props.prop_mode = robot_modes_summary.index( "EDITOR_MODE") if not cnh.ConnectionHandler().send_change_mode( new_pid, new_mode, initial_speed): self.report({ 'ERROR' }, "Changed to editor mode but not in server : ack not received" ) SocketModalOperator.switching = False SocketModalOperator.running = False self.thread.join() # se espera a que acabe el hilo cnh.ConnectionHandler().remove_socket() self.clear_hud(context) return {'FINISHED'} #update_gui() toggle_deactivate_options( robot_modes_summary.index("EDITOR_MODE")) SocketModalOperator.running = False self.thread.join() # se espera a que acabe el hilo cnh.ConnectionHandler().remove_socket() if context.scene.is_cursor_active: bpy.ops.scene.stop_cursor_listener() cnh.Buffer().clear_reached_poses() SocketModalOperator.switching = False self.report({'INFO'}, "Socket closed") context.scene.com_props.prop_running_nav = False context.scene.com_props.prop_paused_nav = False self.clear_hud(context) return {'FINISHED'} return {'PASS_THROUGH'}
def execute(self, context): from .model import SelectModel from .rigid_bodies import SelectGeometry, AssignGeometry from .segments import SelectSegment C = bpy.context D = bpy.data model = C.active_object bone_name = C.active_bone.name axis = C.active_bone.RobotEditor.axis pose_bone = C.active_object.pose.bones[bone_name] parent_bone = pose_bone.parent bone_to_parent = pose_bone.matrix.inverted() * parent_bone.matrix bone_world = model.matrix_world * pose_bone.matrix segment_length = bone_to_parent.translation.length distance_to_children = [ (child.matrix.inverted() * pose_bone.matrix).translation.length for child in pose_bone.children ] self.logger.debug("%s, %s", segment_length, distance_to_children) # if there is no translation to parent, the parent (or its parent) draws the joint if bone_to_parent.translation.length > 0.001: max_length = max(distance_to_children + [segment_length]) # If there is only one children, and its a distance 0, we have a ball joint if len(pose_bone.children ) == 1 and distance_to_children[0] < 0.001: bpy.ops.mesh.primitive_uv_sphere_add(size=segment_length / 15.0) C.active_object.matrix_world = bone_world # if there IS a child, at distance >0 (or more than one child), draw a hinge joint elif len(pose_bone.children): bpy.ops.mesh.primitive_cylinder_add(radius=max_length / 15, depth=max_length / 5) if axis == 'X': m = Euler((0, 0, pi / 4)).to_matrix().to_4x4() elif axis == 'Y': m = Euler((0, 0, pi / 4)).to_matrix().to_4x4() else: m = Matrix() C.active_object.matrix_world = bone_world * m else: bpy.ops.mesh.primitive_cone_add(radius1=segment_length / 10, radius2=segment_length / 10) C.active_object.name = bone_name + '_axis' new_name = C.active_object.name SelectModel.run(model_name=model.name) SelectSegment.run(bone_name) SelectGeometry.run(new_name) AssignGeometry.run() return {'FINISHED'}
def create(cls, object, name): cls.set(object, name, ((0.0, 0.0, 0.0), Euler((0.0, 0.0, 0.0)), (1.0, 1.0, 1.0)))
def bvh_node_dict2armature(context, bvh_name, bvh_nodes, rotate_mode='XYZ', frame_start=1, IMPORT_LOOP=False, global_matrix=None, ): if frame_start < 1: frame_start = 1 # Add the new armature, scene = context.scene for obj in scene.objects: obj.select = False arm_data = bpy.data.armatures.new(bvh_name) arm_ob = bpy.data.objects.new(bvh_name, arm_data) scene.objects.link(arm_ob) arm_ob.select = True scene.objects.active = arm_ob bpy.ops.object.mode_set(mode='OBJECT', toggle=False) bpy.ops.object.mode_set(mode='EDIT', toggle=False) # Get the average bone length for zero length bones, we may not use this. average_bone_length = 0.0 nonzero_count = 0 for bvh_node in bvh_nodes.values(): l = (bvh_node.rest_head_local - bvh_node.rest_tail_local).length if l: average_bone_length += l nonzero_count += 1 # Very rare cases all bones couldbe zero length??? if not average_bone_length: average_bone_length = 0.1 else: # Normal operation average_bone_length = average_bone_length / nonzero_count # XXX, annoying, remove bone. while arm_data.edit_bones: arm_ob.edit_bones.remove(arm_data.edit_bones[-1]) ZERO_AREA_BONES = [] for name, bvh_node in bvh_nodes.items(): # New editbone bone = bvh_node.temp = arm_data.edit_bones.new(name) bone.head = bvh_node.rest_head_world bone.tail = bvh_node.rest_tail_world # Zero Length Bones! (an exceptional case) if (bone.head - bone.tail).length < 0.001: print("\tzero length bone found:", bone.name) if bvh_node.parent: ofs = bvh_node.parent.rest_head_local - bvh_node.parent.rest_tail_local if ofs.length: # is our parent zero length also?? unlikely bone.tail = bone.tail - ofs else: bone.tail.y = bone.tail.y + average_bone_length else: bone.tail.y = bone.tail.y + average_bone_length ZERO_AREA_BONES.append(bone.name) for bvh_node in bvh_nodes.values(): if bvh_node.parent: # bvh_node.temp is the Editbone # Set the bone parent bvh_node.temp.parent = bvh_node.parent.temp # Set the connection state if not bvh_node.has_loc and\ bvh_node.parent and\ bvh_node.parent.temp.name not in ZERO_AREA_BONES and\ bvh_node.parent.rest_tail_local == bvh_node.rest_head_local: bvh_node.temp.use_connect = True # Replace the editbone with the editbone name, # to avoid memory errors accessing the editbone outside editmode for bvh_node in bvh_nodes.values(): bvh_node.temp = bvh_node.temp.name # Now Apply the animation to the armature # Get armature animation data bpy.ops.object.mode_set(mode='OBJECT', toggle=False) pose = arm_ob.pose pose_bones = pose.bones if rotate_mode == 'NATIVE': for bvh_node in bvh_nodes.values(): bone_name = bvh_node.temp # may not be the same name as the bvh_node, could have been shortened. pose_bone = pose_bones[bone_name] pose_bone.rotation_mode = bvh_node.rot_order_str elif rotate_mode != 'QUATERNION': for pose_bone in pose_bones: pose_bone.rotation_mode = rotate_mode else: # Quats default pass context.scene.update() arm_ob.animation_data_create() action = bpy.data.actions.new(name=bvh_name) arm_ob.animation_data.action = action # Replace the bvh_node.temp (currently an editbone) # With a tuple (pose_bone, armature_bone, bone_rest_matrix, bone_rest_matrix_inv) for bvh_node in bvh_nodes.values(): bone_name = bvh_node.temp # may not be the same name as the bvh_node, could have been shortened. pose_bone = pose_bones[bone_name] rest_bone = arm_data.bones[bone_name] bone_rest_matrix = rest_bone.matrix_local.to_3x3() bone_rest_matrix_inv = Matrix(bone_rest_matrix) bone_rest_matrix_inv.invert() bone_rest_matrix_inv.resize_4x4() bone_rest_matrix.resize_4x4() bvh_node.temp = (pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv) # Make a dict for fast access without rebuilding a list all the time. # KEYFRAME METHOD, SLOW, USE IPOS DIRECT # TODO: use f-point samples instead (Aligorith) if rotate_mode != 'QUATERNION': prev_euler = [Euler() for i in range(len(bvh_nodes))] # Animate the data, the last used bvh_node will do since they all have the same number of frames for frame_current in range(len(bvh_node.anim_data) - 1): # skip the first frame (rest frame) # print frame_current # if frame_current==40: # debugging # break scene.frame_set(frame_start + frame_current) # Dont neet to set the current frame for i, bvh_node in enumerate(bvh_nodes.values()): pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv = bvh_node.temp lx, ly, lz, rx, ry, rz = bvh_node.anim_data[frame_current + 1] if bvh_node.has_rot: # apply rotation order and convert to XYZ # note that the rot_order_str is reversed. bone_rotation_matrix = Euler((rx, ry, rz), bvh_node.rot_order_str[::-1]).to_matrix().to_4x4() bone_rotation_matrix = bone_rest_matrix_inv * bone_rotation_matrix * bone_rest_matrix if rotate_mode == 'QUATERNION': pose_bone.rotation_quaternion = bone_rotation_matrix.to_quaternion() else: euler = bone_rotation_matrix.to_euler(pose_bone.rotation_mode, prev_euler[i]) pose_bone.rotation_euler = euler prev_euler[i] = euler if bvh_node.has_loc: pose_bone.location = (bone_rest_matrix_inv * Matrix.Translation(Vector((lx, ly, lz)) - bvh_node.rest_head_local)).to_translation() if bvh_node.has_loc: pose_bone.keyframe_insert("location") if bvh_node.has_rot: if rotate_mode == 'QUATERNION': pose_bone.keyframe_insert("rotation_quaternion") else: pose_bone.keyframe_insert("rotation_euler") for cu in action.fcurves: if IMPORT_LOOP: pass # 2.5 doenst have cyclic now? for bez in cu.keyframe_points: bez.interpolation = 'LINEAR' # finally apply matrix arm_ob.matrix_world = global_matrix bpy.ops.object.transform_apply(rotation=True) return arm_ob
def execute(self, context): os.system("cls") vars = context.scene target = bpy.data.objects[vars.Target] tool = bpy.data.objects[vars.Tool] orig_Euler = target.rotation_euler orig_Location = target.location print('RTL: ', vars.ReturnToLoc) print(orig_Euler) print(orig_Location) return2_eul = rot_eul = [orig_Euler[0],orig_Euler[1],orig_Euler[2]] return2_loc = slide_loc = [orig_Location[0],orig_Location[1],orig_Location[2]] toolRotRads = [radians(vars.MMToolXVal),radians(vars.MMToolYVal),radians(vars.MMToolZVal)] toolSlideUnits = [vars.MMToolXVal,vars.MMToolYVal,vars.MMToolZVal] prestepRotRads = [radians(vars.MMPreStepXVal),radians(vars.MMPreStepYVal),radians(vars.MMPreStepZVal)] prestepSlideUnits = [vars.MMPreStepXVal,vars.MMPreStepYVal,vars.MMPreStepZVal] # print('orig: ',orig_Euler,orig_Location) # print('rot and slide: ',rot_eul,slide_loc) # print('tool: ',toolRotRads,toolSlideUnits) # print('pre: ',prestepRotRads,prestepSlideUnits) for r in range(vars.RepeaterCnt): # print ('rep_cnt: ',r) if (vars.MMPreStep =='Rotate'): rot_eul = Euler([sum(e) for e in zip(rot_eul, prestepRotRads)], "XYZ") target.rotation_euler = rot_eul elif (vars.MMPreStep =='Slide'): slide_loc = Vector([sum(v) for v in zip(slide_loc, prestepSlideUnits)]) target.location = slide_loc # print('rot slide: ',rot_eul,slide_loc) for i in range(vars.NumSteps+1): # print('step: ',i) if (i > 0 ): if (vars.MMMove == 'Rotate'): rot_eul = Euler([sum(z) for z in zip(rot_eul, toolRotRads)], "XYZ") else: # Assumes 'Slide' slide_loc = Vector([sum(z) for z in zip(slide_loc, toolSlideUnits)]) # At step 0 these are the original euler\location (or location after pre-step), else the eul\loc just set target.rotation_euler = rot_eul target.location = slide_loc bpy.ops.object.select_all(action='DESELECT') target.select = True bpy.context.scene.objects.active = target if (i >= vars.StartSteps): # Execute tool action at this step bpy.ops.object.modifier_add(type='BOOLEAN') mod = target.modifiers mod[0].name = "MMTool" if (vars.MMAction == 'Diff'): # print('diff: ',rot_eul, slide_loc) mod[0].operation = 'DIFFERENCE' else: # Assumes 'Union' # print('union: ',rot_eul, slide_loc) mod[0].operation = 'UNION' if (vars.MMAction != 'None'): mod[0].object = tool bpy.ops.object.modifier_apply(apply_as='DATA', modifier=mod[0].name) i += 1 r += 1 if (vars.ReturnToLoc == True): print('Return!!!: ', return2_eul, return2_loc) target.rotation_euler = return2_eul target.location = return2_loc if self.country == '': print('Done') else: print("Don't Make Cuts from %s!" % self.country) return {"FINISHED"}
def get(cls, object, name): paths = tuple(cls.iterSubpropertyPaths(name)) return (Vector(getattr(object, paths[0], (0.0, 0.0, 0.0))), Euler(getattr(object, paths[1], (0.0, 0.0, 0.0)), cls.getRotationOrder(object, name)), Vector(getattr(object, paths[2], (1.0, 1.0, 1.0))))
def extract(properties, *args, **kwargs): """ :returns: { 'resolution': (width, height), 'trackers': { int: (x, y, z), }, 'cameras': { int: { 'filename': str, 'f': float, 'k': (k1, k2, k3), 'c': (x, y, z), # real world coord 't': (x, y, z), # pmvs transformed translation 'R': ((r00, r01, r02), (r10, r11, r12), (r20, r21, r22)), 'trackers': { int: (x, y), } } } } """ filename = bpy.path.abspath(properties.filepath) imagepaths = list(filter(None, bpy.path.abspath(properties.imagepath).split(';'))) data = { 'trackers': {}, 'cameras': {}, } doc = ET.parse(filename) for locator in doc.findall('L'): co = locator.find('P').attrib data['trackers'][int(locator.attrib['i'])] = { 'co': (float(co['x']), float(co['y']), float(co['z'])), 'rgb': (0, 0, 0), } cinfs = {} for cinf in doc.findall('CINF'): cinfs[cinf.attrib['i']] = cinf.attrib # cinf = doc.find('CINF').attrib for shot in doc.findall('SHOT'): cfrm = shot.find('CFRM') # test data indicates frame wasn't matched if cfrm doesn't reference a camera if 'cf' not in cfrm.attrib: continue cinf = cinfs.get(cfrm.attrib['cf'], {}) intrinsics = cfrm.attrib intrinsics.setdefault('rd', cinf.get('rd', 0)) extrinsics = { 'T': cfrm.find('T').attrib, 'R': cfrm.find('R').attrib } extrinsics.update({ 'T': Vector((float(extrinsics['T']['x']), float(extrinsics['T']['y']), float(extrinsics['T']['z']))), 'R': Euler((radians(float(extrinsics['R']['x'])), radians(float(extrinsics['R']['y'])), radians(float(extrinsics['R']['z']))), 'XYZ').to_matrix() }) extrinsics['R'].transpose() # pinhole camera model # https://photo.stackexchange.com/a/41280 # FOV = 2 * atan((sensor_width / 2) / focal_length) # focal_length = (sensor_width / 2) / tan(FOV / 2) f = (float(cinf['fbw']) / 2) / tan(radians(float(intrinsics['fovx']) / 2)) f_pixels = int(shot.attrib['w']) * (f / float(cinf['fbw'])) # find any filename that exists filenames = [fp for fp in [os.path.join(*parts) for parts in zip(imagepaths, [shot.attrib['n'],] * len(imagepaths))] if os.path.exists(fp)] if not filenames: # wasn't in a root path, do we search sub directories? if properties.subdirs: for imagepath in imagepaths: for root, dirs, files in os.walk(imagepath): if shot.attrib['n'] in files: filenames = [os.path.join(root, shot.attrib['n'])] # still didn't find file? if not filenames: raise Exception('Image not found for camera {}: {}'.format(shot.attrib['i'], shot.attrib['n'])) camera = data['cameras'].setdefault(int(shot.attrib['i']), { 'filename': filenames[0], 'f': f_pixels, 'k': (-float(intrinsics['rd']),) * 3, 'c': extrinsics['T'], 'R': tuple(map(tuple, tuple(extrinsics['R']))), 't': tuple(-1 * extrinsics['R'] @ extrinsics['T']), }) if 'resolution' not in data: data.setdefault('resolution', get_image_size(camera['filename'])) trackers = camera.setdefault('trackers', {}) for marker in shot.find('IPLN').find('IFRM').findall('M'): trackers[int(marker.attrib['i'])] = (float(marker.attrib['x']), float(marker.attrib['y'])) return data
def TrajectoryAngle(own, interceptPoint, velocity): try: scene = bge.logic.getCurrentScene() if 'calculate' not in own: own['calculate'] = True if 'trajectoryAngle' not in own: own['trajectoryAngle'] = '' else: try: gravity = scene.gravity.z own['reachable'] = True vec = interceptPoint.getVectTo(own) px = hypot(vec[1].x, vec[1].y) * vec[0] pz = vec[1].z * vec[0] #rumus pertama menggunakan plus berfungsi untuk rumus mortar #rad = atan((velocity**2 + sqrt(velocity**4-gravity*(gravity*px**2 + 2*pz*velocity**2))) / (gravity*px)) #rumus kedua menggunakan minus rad = atan((velocity**2 - sqrt(velocity**4 - gravity * (gravity * px**2 + 2 * pz * velocity**2))) / (gravity * px)) #rad = asin(jarak * gravity / velocity**2) / 2 sRad = sin(rad) cRad = cos(rad) y = cRad * velocity z = sRad * velocity own['cosine'] = str([sRad, cRad]) own['travelTime'] = px / y own['vy'] = y own['vz'] = z own['angle'] = degrees(rad) if own.parent == None: Eul = Euler((rad, 0, 0), 'XYZ') else: parent = own.parent pR = parent.worldOrientation pE = pR.to_euler() Eul = Euler((-rad, pE.y, pE.z), 'XYZ') own.worldOrientation = Eul.to_matrix() own['reachable'] = True own['calculate'] = True except ValueError: own['reachable'] = False if own['calculate'] == True: print("calculate error") own['calculate'] = False except ZeroDivisionError: print('float division by zero') except: checker.getInfo() bge.logic.endGame()
def get_camera_rotation(self, degrees=0): return Euler( (math.radians(90), math.radians(0), math.radians(degrees)), 'XYZ')
def import_motion(reader, context, bonesmap, reported, motions_filter=MOTIONS_FILTER_ALL): bpy_armature = context.armature name = reader.gets() if not motions_filter(name): skip = _skip_motion_rest(reader.getv(), 0) reader.skip(skip) return act = bpy.data.actions.new(name=name) act.use_fake_user = True xray = act.xray reader.getf('II') # range fps, ver = reader.getf('fH') xray.fps = fps if ver < 6: raise AppError('unsupported motions version', log_props(version=ver)) motion = bpy_armature.xray.motions_collection.add() motion.name = act.name if context.use_motion_prefix_name: bpy_armature.xray.use_custom_motion_names = True motion.export_name = name # cut extension filename = context.filename[0:-len(context.filename.split('.')[-1]) - 1] name = '{0}_{1}'.format(filename, name) act.name = name motion.name = name if name != act.name and not context.use_motion_prefix_name: bpy_armature.xray.use_custom_motion_names = True motion.export_name = name xray.flags, xray.bonepart = reader.getf('<BH') xray.speed, xray.accrue, xray.falloff, xray.power = reader.getf('<ffff') for _bone_idx in range(reader.getf('H')[0]): tmpfc = [act.fcurves.new('temp', index=i) for i in range(6)] try: times = {} bname = reader.gets() flags = reader.getf('B')[0] if flags != 0: warn('bone has non-zero flags', bone=bname, flags=flags) for fcurve in tmpfc: behaviors = reader.getf('BB') if (behaviors[0] != 1) or (behaviors[1] != 1): warn('bone has different behaviors', bode=bname, behaviors=behaviors) for _keyframe_idx in range(reader.getf('H')[0]): val = reader.getf('f')[0] time = reader.getf('f')[0] * fps times[time] = True key_frame = fcurve.keyframe_points.insert(time, val) shape = Shape(reader.getf('B')[0]) if shape != Shape.STEPPED: reader.getf('HHH') reader.getf('HHHH') else: key_frame.interpolation = 'CONSTANT' bpy_bone = bpy_armature.data.bones.get(bname, None) if bpy_bone is None: bpy_bone = bonesmap.get(bname.lower(), None) if bpy_bone is None: if bname not in reported: warn('bone is not found', bone=bname) reported.add(bname) continue if bname not in reported: warn('bone\'s reference will be replaced', bone=bname, replacement=bpy_bone.name) reported.add(bname) bname = bpy_bone.name data_path = 'pose.bones["' + bname + '"]' fcs = [ act.fcurves.new(data_path + '.location', index=0, action_group=bname), act.fcurves.new(data_path + '.location', index=1, action_group=bname), act.fcurves.new(data_path + '.location', index=2, action_group=bname), act.fcurves.new(data_path + '.rotation_euler', index=0, action_group=bname), act.fcurves.new(data_path + '.rotation_euler', index=1, action_group=bname), act.fcurves.new(data_path + '.rotation_euler', index=2, action_group=bname) ] xmat = bpy_bone.matrix_local.inverted() real_parent = find_bone_exportable_parent(bpy_bone) if real_parent: xmat = multiply(xmat, real_parent.matrix_local) else: xmat = multiply(xmat, MATRIX_BONE) for time in times: mat = multiply( xmat, Matrix.Translation(( +tmpfc[0].evaluate(time), +tmpfc[1].evaluate(time), -tmpfc[2].evaluate(time), )), Euler(( -tmpfc[4].evaluate(time), -tmpfc[3].evaluate(time), +tmpfc[5].evaluate(time), ), 'ZXY').to_matrix().to_4x4()) trn = mat.to_translation() rot = mat.to_euler('ZXY') for i in range(3): fcs[i + 0].keyframe_points.insert(time, trn[i]) for i in range(3): fcs[i + 3].keyframe_points.insert(time, rot[i]) finally: for fcurve in tmpfc: act.fcurves.remove(fcurve) if ver >= 7: for _bone_idx in range(reader.getf('I')[0]): name = reader.gets_a() reader.skip((4 + 4) * reader.getf('I')[0]) warn('markers are not supported yet', name=name) return act
def save_objects( filepath, objects, rescale_to_max = False, use_head_upscaling_compensation = False, translate_coords = True, recenter_to_origin = False, blender_origin = [0., 0., 0.], generate_texture=True, use_only_exported_object_colors=False, texture_folder="", texture_filename="", export_uvs=True, minify=False, decimal_precision=-1, **kwargs): """Main exporter function. Parses Blender objects into Minecraft cuboid format, uvs, and handles texture read and generation. Will save .json file to output paths. Inputs: - filepath: Output file path name. - object: Iterable collection of Blender objects - rescale_to_max: Scale exported model to max volume allowed. - use_head_upscaling_compensation: Clamp over-sized models to max, but add upscaling in minecraft head slot (experimental, used with animation export, can allow up to 4x max size). Overridden by rescale_to_max (these are incompatible). - translate_coords: Translate into Minecraft [-16, 32] space so origin = (8,8,8) - recenter_to_origin: Recenter model so that its center is at Minecraft origin (8,8,8) - blender_origin: Origin in Blender coordinates (in Blender XYZ space). Use this to translate exported model. - generate_texture: Generate texture from solid material colors. By default, creates a color texture from all materials in file (so all groups of objects can share the same texture file). - use_only_exported_object_colors: Generate texture colors from only exported objects instead of default using all file materials. - texture_folder: Output texture subpath, for typical "item/texture_name" the texture folder would be "item". - texture_file_name: Name of texture file. TODO: auto-parse textures from materials. - export_uvs: Export object uvs. - minify: Minimize output file size (write into single line, remove spaces, ...) - decimal_precision: Number of digits after decimal to keep in numbers. Requires `minify = True`. Set to -1 to disable. """ # output json model model_json = { "texture_size": [16, 16], # default, will be overridden "textures": {}, } elements = [] groups = {} # re-used buffers for every object v_world = np.zeros((3, 8)) v_local = np.zeros((3, 8)) face_normals = np.zeros((3,6)) face_uvs = np.zeros((4,)) face_colors = [None for _ in range(6)] # model bounding box vector # when re-centering to origin, these will clamp to true model bounding box # when not re-centering, bounding box must be relative to blender origin # so model min/max starts at (0,0,0) to account for origin point if recenter_to_origin: model_v_min = np.array([inf, inf, inf]) model_v_max = np.array([-inf, -inf, -inf]) else: model_v_min = np.array([0., 0., 0.,]) model_v_max = np.array([0., 0., 0.,]) # all material colors tuples from all object faces if use_only_exported_object_colors: model_colors = set() else: model_colors = None # all material texture str paths model_textures = set() for obj in objects: mesh = obj.data if not isinstance(mesh, bpy.types.Mesh): continue # object properties origin = np.array(obj.location) mat_world = obj.matrix_world # count number of vertices, ignore if not cuboid num_vertices = len(mesh.vertices) if num_vertices != 8: continue # get world space and local mesh coordinates for i, v in enumerate(mesh.vertices): v_local[0:3,i] = v.co v_world[0:3,i] = mat_world @ v.co # ================================ # first reduce rotation to [-45, 45] by applying all 90 deg # rotations directly to vertices # ================================ rotation = obj.rotation_euler rot_reduced = rotation.copy() rot_to_reduce_x = 0 rot_to_reduce_y = 0 rot_to_reduce_z = 0 # get sign of euler angles rot_x_sign = sign(rotation.x) rot_y_sign = sign(rotation.y) rot_z_sign = sign(rotation.z) eps = 1e-6 # angle error range for floating point precision issues # included sign() in loop condition to avoid cases where angle # overflows to other polarity and infinite loops while abs(rot_reduced.x) > math.pi/4 + eps and sign(rot_reduced.x) == rot_x_sign: angle = rot_x_sign * math.pi/2 rot_reduced.x = round_rotation(rot_reduced.x - angle) rot_to_reduce_x += rot_x_sign while abs(rot_reduced.y) > math.pi/4 + eps and sign(rot_reduced.y) == rot_y_sign: angle = rot_y_sign * math.pi/2 rot_reduced.y = round_rotation(rot_reduced.y - angle) rot_to_reduce_y += rot_y_sign while abs(rot_reduced.z) > math.pi/4 + eps and sign(rot_reduced.z) == rot_z_sign: angle = rot_z_sign * math.pi/2 rot_reduced.z = round_rotation(rot_reduced.z - angle) rot_to_reduce_z += rot_z_sign rot_to_reduce = Euler((rot_to_reduce_x * math.pi/2, rot_to_reduce_y * math.pi/2, rot_to_reduce_z * math.pi/2), "XYZ") mat_rot_reducer = np.array(rot_to_reduce.to_matrix()) v_local_transformed = mat_rot_reducer @ v_local # ================================ # determine best rotation: # 1. transform on all possible minecraft rotations # 2. select rotation with min chamfer distance # ================================ # transform with all possible rotation matrices v_transformed = origin[...,np.newaxis] + MAT_ROTATIONS @ v_local_transformed[np.newaxis, ...] distance_metric = np.array([chamfer_distance(v_transformed[i,:,:], v_world) for i in range(v_transformed.shape[0])]) # get best rotation idx_best_rot = np.argmin(distance_metric) rot_best = ROTATIONS[idx_best_rot] # ================================ # find bounding box edge vertices # of transformed local coordinates # ================================ v_local_transformed_translated = origin[...,np.newaxis] + v_local_transformed v_min = np.amin(v_local_transformed_translated, axis=1) v_max = np.amax(v_local_transformed_translated, axis=1) # ================================ # update global bounding box # -> consider world coords, local coords, origin # ================================ model_v_min = np.amin(np.append(v_world, model_v_min[...,np.newaxis], axis=1), axis=1) model_v_max = np.amax(np.append(v_world, model_v_max[...,np.newaxis], axis=1), axis=1) model_v_min = np.amin(np.append(v_local_transformed_translated, model_v_min[...,np.newaxis], axis=1), axis=1) model_v_max = np.amax(np.append(v_local_transformed_translated, model_v_max[...,np.newaxis], axis=1), axis=1) model_v_min = np.amin(np.append(origin[...,np.newaxis], model_v_min[...,np.newaxis], axis=1), axis=1) model_v_max = np.amax(np.append(origin[...,np.newaxis], model_v_max[...,np.newaxis], axis=1), axis=1) # ================================ # output coordinate values # ================================ # change axis to minecraft y-up axis v_min = to_y_up(v_min) v_max = to_y_up(v_max) origin = to_y_up(origin) rot_best = (to_minecraft_axis(rot_best[0]), rot_best[1]) # ================================ # texture/uv generation # # NOTE: BLENDER VS MINECRAFT UV AXIS # - blender: uvs origin is bottom-left (0,0) to top-right (1, 1) # - minecraft: uvs origin is top-left (0,0) to bottom-right (16, 16) # minecraft uvs: [x1, y1, x2, y2], each value from [0, 16] as proportion of image # as well as 0, 90, 180, 270 degree uv rotation # uv loop to export depends on: # - clockwise/counterclockwise order # - uv starting coordinate (determines rotation) relative to face # vertex loop starting coordinate # # Assume "natural" index order of face vertices and uvs without # any rotations in local mesh space is counterclockwise loop: # 3___2 ^ +y # | | | # |___| ---> +x # 0 1 # # uv, vertex starting coordinate is based on this loop. # Use the uv rotation lookup tables constants to determine rotation. # ================================ # initialize faces faces = { "north": {"uv": [0, 0, 4, 4], "texture": "#0"}, "east": {"uv": [0, 0, 4, 4], "texture": "#0"}, "south": {"uv": [0, 0, 4, 4], "texture": "#0"}, "west": {"uv": [0, 0, 4, 4], "texture": "#0"}, "up": {"uv": [0, 0, 4, 4], "texture": "#0"}, "down": {"uv": [0, 0, 4, 4], "texture": "#0"} } uv_layer = mesh.uv_layers.active.data for i, face in enumerate(mesh.polygons): if i > 5: # should be 6 faces only print(f"WARNING: {obj} has >6 faces") break face_normal = face.normal face_normal_world = mat_rot_reducer @ face_normal # stack + reshape to (6,3) face_normal_stacked = np.transpose(face_normal_world[..., np.newaxis], (1,0)) face_normal_stacked = np.tile(face_normal_stacked, (6,1)) # get face direction string face_direction_index = np.argmax(np.sum(face_normal_stacked * DIRECTION_NORMALS, axis=1), axis=0) d = DIRECTIONS[face_direction_index] face_color = get_object_color(obj, face.material_index) # solid color tuple if isinstance(face_color, tuple) and generate_texture: faces[d] = face_color # replace face with color if model_colors is not None: model_colors.add(face_color) # texture elif isinstance(face_color, str): faces[d]["texture"] = face_color model_textures.add(face_color) if export_uvs: # uv loop loop_start = face.loop_start face_uv_0 = uv_layer[loop_start].uv face_uv_1 = uv_layer[loop_start+1].uv face_uv_2 = uv_layer[loop_start+2].uv face_uv_3 = uv_layer[loop_start+3].uv uv_min_x = min(face_uv_0[0], face_uv_2[0]) uv_max_x = max(face_uv_0[0], face_uv_2[0]) uv_min_y = min(face_uv_0[1], face_uv_2[1]) uv_max_y = max(face_uv_0[1], face_uv_2[1]) uv_clockwise = loop_is_clockwise([face_uv_0, face_uv_1, face_uv_2, face_uv_3]) # vertices loop (using vertices transformed by all 90 deg angles) # project 3d vertex loop onto 2d loop based on face normal, # minecraft uv mapping starting corner experimentally determined verts = [ v_local_transformed[:,v] for v in face.vertices ] #face_normal_world = mat_rot_reducer @ face_normal if face_normal_world[0] > 0.5: # normal = (1, 0, 0) verts = [ (v[1], v[2]) for v in verts ] elif face_normal_world[0] < -0.5: # normal = (-1, 0, 0) verts = [ (-v[1], v[2]) for v in verts ] elif face_normal_world[1] > 0.5: # normal = (0, 1, 0) verts = [ (-v[0], v[2]) for v in verts ] elif face_normal_world[1] < -0.5: # normal = (0, -1, 0) verts = [ (v[0], v[2]) for v in verts ] elif face_normal_world[2] > 0.5: # normal = (0, 0, 1) verts = [ (v[1], -v [0]) for v in verts ] elif face_normal_world[2] < -0.5: # normal = (0, 0, -1) verts = [ (v[1], v[0]) for v in verts ] vert_min_x = min(verts[0][0], verts[2][0]) vert_max_x = max(verts[0][0], verts[2][0]) vert_min_y = min(verts[0][1], verts[2][1]) vert_max_y = max(verts[0][1], verts[2][1]) vert_clockwise = loop_is_clockwise(verts) # get uv, vert loop starting corner index 0..3 in face loop # uv start corner index uv_start_x = face_uv_0[0] uv_start_y = face_uv_0[1] if uv_start_y < uv_max_y: # start coord 0 if uv_start_x < uv_max_x: uv_loop_start_index = 0 # start coord 1 else: uv_loop_start_index = 1 else: # start coord 2 if uv_start_x > uv_min_x: uv_loop_start_index = 2 # start coord 3 else: uv_loop_start_index = 3 # vert start corner index vert_start_x = verts[0][0] vert_start_y = verts[0][1] if vert_start_y < vert_max_y: # start coord 0 if vert_start_x < vert_max_x: vert_loop_start_index = 0 # start coord 1 else: vert_loop_start_index = 1 else: # start coord 2 if vert_start_x > vert_min_x: vert_loop_start_index = 2 # start coord 3 else: vert_loop_start_index = 3 # set uv flip and rotation based on # 1. clockwise vs counterclockwise loop # 2. relative starting corner difference between vertex loop and uv loop # NOTE: if face normals correct, vertices should always be counterclockwise... if uv_clockwise == False and vert_clockwise == False: face_uvs[0] = uv_min_x face_uvs[1] = uv_max_y face_uvs[2] = uv_max_x face_uvs[3] = uv_min_y face_uv_rotation = COUNTERCLOCKWISE_UV_ROTATION_LOOKUP[uv_loop_start_index][vert_loop_start_index] elif uv_clockwise == True and vert_clockwise == False: # invert x face uvs face_uvs[0] = uv_max_x face_uvs[1] = uv_max_y face_uvs[2] = uv_min_x face_uvs[3] = uv_min_y face_uv_rotation = CLOCKWISE_UV_ROTATION_LOOKUP[uv_loop_start_index][vert_loop_start_index] elif uv_clockwise == False and vert_clockwise == True: # invert y face uvs, case should not happen face_uvs[0] = uv_max_x face_uvs[1] = uv_max_y face_uvs[2] = uv_min_x face_uvs[3] = uv_min_y face_uv_rotation = CLOCKWISE_UV_ROTATION_LOOKUP[uv_loop_start_index][vert_loop_start_index] else: # uv_clockwise == True and vert_clockwise == True: # case should not happen face_uvs[0] = uv_min_x face_uvs[1] = uv_max_y face_uvs[2] = uv_max_x face_uvs[3] = uv_min_y face_uv_rotation = COUNTERCLOCKWISE_UV_ROTATION_LOOKUP[uv_loop_start_index][vert_loop_start_index] xmin = face_uvs[0] * 16 ymin = (1.0 - face_uvs[1]) * 16 xmax = face_uvs[2] * 16 ymax = (1.0 - face_uvs[3]) * 16 faces[d]["uv"] = [ xmin, ymin, xmax, ymax ] if face_uv_rotation != 0 and face_uv_rotation != 360: faces[d]["rotation"] = face_uv_rotation if face_uv_rotation >= 0 else 360 + face_uv_rotation # ================================ # get collection # ================================ collection = obj.users_collection[0] if collection is not None: add_to_group(groups, collection.name, len(elements)) # add object to output elements.append({ "name": obj.name, "from": v_min, "to": v_max, "rotation": { "angle": rot_best[1], "axis": rot_best[0].lower(), "origin": origin, }, "faces": faces, }) # tranpose model bbox to minecraft axes model_v_min = to_y_up(model_v_min) model_v_max = to_y_up(model_v_max) model_center = 0.5 * (model_v_min + model_v_max) # get rescaling factors if rescale_to_max: if recenter_to_origin: rescale_factor = np.min(MAX_SIZE / (model_v_max - model_center)) # absolute scale relative to (0,0,0), min scaling of MAX/v_max and -MAX/v_min else: rescale_factor = np.min(np.abs(MAX_SIZE / np.concatenate((-model_v_min - blender_origin, model_v_max - blender_origin)))) # rescaling, but add head display scaling to compensate for downscaling elif use_head_upscaling_compensation: if recenter_to_origin: rescale_factor = np.min(MAX_SIZE / (model_v_max - model_center)) else: rescale_factor = np.min(np.abs(MAX_SIZE / np.concatenate((-model_v_min, model_v_max)))) # clamp if not re-scaling to max if rescale_factor >= 1.0: if rescale_to_max == False: rescale_factor = 1.0 # rescale < 1.0, model too large, inject head display scaling else: display_head_scale = np.clip(1.0 / rescale_factor, 0, 4) model_json["display"] = { "head": { "scale": [display_head_scale, display_head_scale, display_head_scale] } } else: rescale_factor = 1.0 # debug print("RESCALE", rescale_factor) print("BBOX MIN/MAX", model_v_min, "/", model_v_max) print("CENTER", model_center) print("BLENDER ORIGIN", blender_origin) print("") # model post-processing (recenter, rescaling coordinates) minecraft_origin = np.array([8, 8, 8]) # re-center coordinates to minecraft origin and model bounding box center if recenter_to_origin: model_origin_shift = -model_center else: model_origin_shift = -to_y_up(blender_origin) # =========================== # generate texture images # =========================== if generate_texture: # default, get colors from all materials in file if model_colors is None: model_colors = set() for mat in bpy.data.materials: color = get_material_color(mat) if isinstance(color, tuple): model_colors.add(color) tex_pixels, tex_size, color_tex_uv_map, default_color_uv = create_color_texture(model_colors) # texture output filepaths if texture_filename == "": current_dir = os.path.dirname(filepath) filepath_name = os.path.splitext(os.path.basename(filepath))[0] texture_save_path = os.path.join(current_dir, filepath_name + ".png") texture_model_path = posixpath.join(texture_folder, filepath_name) else: current_dir = os.path.dirname(filepath) texture_save_path = os.path.join(current_dir, texture_filename + ".png") texture_model_path = posixpath.join(texture_folder, texture_filename) # create + save texture tex = bpy.data.images.new("tex_colors", alpha=True, width=tex_size, height=tex_size) tex.file_format = "PNG" tex.pixels = tex_pixels tex.filepath_raw = texture_save_path tex.save() # write texture info to output model model_json["texture_size"] = [tex_size, tex_size] model_json["textures"]["0"] = texture_model_path # if not generating texture, just write texture path to json file # TODO: scan materials for textures, then update output size elif texture_filename != "": model_json["texture_size"] = [16, 16] model_json["textures"]["0"] = posixpath.join(texture_folder, texture_filename) # =========================== # process face texture paths # convert blender path names "//folder\tex.png" -> "item/tex" # add textures indices for textures, and create face mappings like "#1" # note: #0 id reserved for generated color texture # =========================== texture_refs = {} # maps blender path name -> #n identifiers texture_id = 1 # texture id in "#1" identifier for texture_path in model_textures: texture_out_path = texture_path if texture_out_path[0:2] == "//": texture_out_path = texture_out_path[2:] texture_out_path = texture_out_path.replace("\\", "/") texture_out_path = os.path.splitext(texture_out_path)[0] texture_refs[texture_path] = "#" + str(texture_id) model_json["textures"][str(texture_id)] = posixpath.join(texture_folder, texture_out_path) texture_id += 1 # =========================== # final object + face processing # 1. recenter/rescale object # 2. map solid color face uv -> location in generated texture # 3. rewrite path textures -> texture name reference # =========================== for obj in elements: # re-center model obj["to"] = model_origin_shift + obj["to"] obj["from"] = model_origin_shift + obj["from"] obj["rotation"]["origin"] = model_origin_shift + obj["rotation"]["origin"] # re-scale objects obj["to"] = rescale_factor * obj["to"] obj["from"] = rescale_factor * obj["from"] obj["rotation"]["origin"] = rescale_factor * obj["rotation"]["origin"] # re-center coordinates to minecraft origin if translate_coords: obj["to"] = minecraft_origin + obj["to"] obj["from"] = minecraft_origin + obj["from"] obj["rotation"]["origin"] = minecraft_origin + obj["rotation"]["origin"] # convert numpy to python list obj["to"] = obj["to"].tolist() obj["from"] = obj["from"].tolist() obj["rotation"]["origin"] = obj["rotation"]["origin"].tolist() faces = obj["faces"] for d, f in faces.items(): if isinstance(f, tuple): color_uv = color_tex_uv_map[f] if f in color_tex_uv_map else default_color_uv faces[d] = { "uv": color_uv, "texture": "#0", } elif isinstance(f, dict): face_texture = f["texture"] if face_texture in texture_refs: f["texture"] = texture_refs[face_texture] else: face_texture = "#0" # =========================== # convert groups # =========================== groups_export = [] for g in groups: groups_export.append({ "name": g, "origin": [0, 0, 0], "children": groups[g], }) # save model_json["elements"] = elements model_json["groups"] = groups_export # minification options to reduce .json file size if minify == True: # go through json dict and replace all float with rounded strings if decimal_precision >= 0: def round_float(x): return round(x, decimal_precision) for elem in model_json["elements"]: elem["from"] = [round_float(x) for x in elem["from"]] elem["to"] = [round_float(x) for x in elem["to"]] elem["rotation"]["origin"] = [round_float(x) for x in elem["rotation"]["origin"]] for face in elem["faces"].values(): face["uv"] = [round_float(x) for x in face["uv"]] # save json with open(filepath, "w") as f: json.dump(model_json, f, separators=(",", ":"))
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 bvh_node_dict2armature(context, bvh_name, bvh_nodes, bvh_frame_time, rotate_mode='XYZ', frame_start=1, IMPORT_LOOP=False, global_matrix=None, use_fps_scale=False, use_frame_step=False, only_rootbone_location=True, rig_only=False, ): ZERO_AREA_BONES = [] scene = context.scene def add_armature(): # Add the new armature, for obj in scene.objects: obj.select = False arm_data = bpy.data.armatures.new(bvh_name) arm_ob = bpy.data.objects.new(bvh_name, arm_data) scene.objects.link(arm_ob) arm_ob.select = True scene.objects.active = arm_ob bpy.ops.object.mode_set(mode='OBJECT', toggle=False) bpy.ops.object.mode_set(mode='EDIT', toggle=False) bvh_nodes_list = sorted_nodes(bvh_nodes) # Get the average bone length for zero length bones, we may not use this. average_bone_length = 0.0 nonzero_count = 0 for bvh_node in bvh_nodes_list: l = (bvh_node.rest_head_local - bvh_node.rest_tail_local).length if l: average_bone_length += l nonzero_count += 1 # Very rare cases all bones could be zero length??? if not average_bone_length: average_bone_length = 0.1 else: # Normal operation average_bone_length = average_bone_length / nonzero_count # XXX, annoying, remove bone. while arm_data.edit_bones: arm_ob.edit_bones.remove(arm_data.edit_bones[-1]) #ZERO_AREA_BONES = [] for bvh_node in bvh_nodes_list: if bvh_node.zero_length: print("ZZZZZZZZZZZZZZZZZZZZZZ", bvh_node) # New editbone bone = bvh_node.temp = arm_data.edit_bones.new(bvh_node.name) bone.head = bvh_node.rest_head_world bone.tail = bvh_node.rest_tail_world # Zero Length Bones! (an exceptional case) if (bone.head - bone.tail).length < 0.001: print("\tzero length bone found:", bone.name) if bvh_node.parent: ofs = bvh_node.parent.rest_head_local - bvh_node.parent.rest_tail_local if ofs.length: # is our parent zero length also?? unlikely bone.tail = bone.tail - ofs else: bone.tail.y = bone.tail.y + average_bone_length else: # HANDLE ZERO LENGTH BONES bone.tail += average_bone_length * Vector((0,1,0)) #bone.tail.y = bone.tail.y + average_bone_length ZERO_AREA_BONES.append(bone.name) for bvh_node in bvh_nodes_list: if bvh_node.zero_length: pass if bvh_node.parent: # bvh_node.temp is the Editbone # Set the bone parent bvh_node.temp.parent = bvh_node.parent.temp # Set the connection state if((not bvh_node.has_loc) and (bvh_node.parent.temp.name not in ZERO_AREA_BONES) and (bvh_node.parent.rest_tail_local == bvh_node.rest_head_local)): bvh_node.temp.use_connect = True # Replace the editbone with the editbone name, # to avoid memory errors accessing the editbone outside editmode for bvh_node in bvh_nodes_list: bvh_node.temp = bvh_node.temp.name return arm_ob, bvh_nodes_list if frame_start < 1: frame_start = 1 arm_ob, bvh_nodes_list = add_armature() # zero length nodes X = [n for n in bvh_nodes_list if n.zero_length] print("ZEROOOOOOO", X) # bone taken out no longer needed #bone = None arm_data = arm_ob.data # Now Apply the animation to the armature # Get armature animation data bpy.ops.object.mode_set(mode='OBJECT', toggle=False) pose = arm_ob.pose pose_bones = pose.bones if rotate_mode == 'NATIVE': for bvh_node in bvh_nodes_list: bone_name = bvh_node.temp # may not be the same name as the bvh_node, could have been shortened. pose_bone = pose_bones[bone_name] if bone_name in ZERO_AREA_BONES: print("ZLB", bone_name) pose_bone["zero"] = True pose_bone.rotation_mode = bvh_node.rot_order_str elif rotate_mode != 'QUATERNION': for pose_bone in pose_bones: pose_bone.rotation_mode = rotate_mode else: # Quats default pass context.scene.update() if rig_only: # fix this to have action part too. arm_ob.matrix_world = global_matrix bpy.ops.object.transform_apply(rotation=True) return arm_ob arm_ob.animation_data_create() action = bpy.data.actions.new(name=bvh_name) arm_ob.animation_data.action = action # Replace the bvh_node.temp (currently an editbone) # With a tuple (pose_bone, armature_bone, bone_rest_matrix, bone_rest_matrix_inv) num_frame = 0 for bvh_node in bvh_nodes_list: bone_name = bvh_node.temp # may not be the same name as the bvh_node, could have been shortened. pose_bone = pose_bones[bone_name] rest_bone = arm_data.bones[bone_name] bone_rest_matrix = rest_bone.matrix_local.to_3x3() bone_rest_matrix_inv = Matrix(bone_rest_matrix) bone_rest_matrix_inv.invert() bone_rest_matrix_inv.resize_4x4() bone_rest_matrix.resize_4x4() #XXXX bone removed from bvh_node.temp bvh_node.temp = (pose_bone, bone_rest_matrix, bone_rest_matrix_inv) if 0 == num_frame: num_frame = len(bvh_node.anim_data) # Choose to skip some frames at the beginning. Frame 0 is the rest pose # used internally by this importer. Frame 1, by convention, is also often # the rest pose of the skeleton exported by the motion capture system. bt = 1.0 / context.scene.render.fps print("FT, BT", bvh_frame_time, bt, floor(bt / bvh_frame_time)) sub_frame_step = 1 if use_frame_step: sub_frame_step = floor(bt / bvh_frame_time) if sub_frame_step == 0: sub_frame_step = 1 skip_frame = 1 if num_frame > skip_frame: num_frame = num_frame - skip_frame # Create a shared time axis for all animation curves. time = [float(frame_start)] * num_frame dt = 0.0 if use_fps_scale: dt = scene.render.fps * bvh_frame_time for frame_i in range(1, num_frame): time[frame_i] += float(frame_i) * dt else: sub_frame_step = 1 for frame_i in range(1, num_frame): time[frame_i] += float(frame_i) frange = range(0, num_frame, sub_frame_step) print("bvh_frame_time = %f, dt = %f, num_frame = %d" % (bvh_frame_time, dt, num_frame)) for i, bvh_node in enumerate(bvh_nodes_list): pose_bone, bone_rest_matrix, bone_rest_matrix_inv = bvh_node.temp #print("FRANGE:", frange) if bvh_node.has_loc: # Not sure if there is a way to query this or access it in the # PoseBone structure. if (pose_bone.parent is None and only_rootbone_location) or not only_rootbone_location: data_path = 'pose.bones["%s"].location' % pose_bone.name location = [(0.0, 0.0, 0.0)] * num_frame for frame_i in range(0, num_frame): bvh_loc = bvh_node.anim_data[frame_i + skip_frame][:3] bone_translate_matrix = Matrix.Translation( Vector(bvh_loc) - bvh_node.rest_head_local) location[frame_i] = (bone_rest_matrix_inv * bone_translate_matrix).to_translation() # For each location x, y, z. for axis_i in range(3): curve = action.fcurves.new(data_path=data_path, index=axis_i) keyframe_points = curve.keyframe_points keyframe_points.add(len(frange)) for i, frame_i in enumerate(frange): keyframe_points[i].co = \ (time[frame_i], location[frame_i][axis_i]) if bvh_node.has_rot: data_path = None rotate = None if 'QUATERNION' == rotate_mode: rotate = [(1.0, 0.0, 0.0, 0.0)] * num_frame data_path = ('pose.bones["%s"].rotation_quaternion' % pose_bone.name) else: rotate = [(0.0, 0.0, 0.0)] * num_frame data_path = ('pose.bones["%s"].rotation_euler' % pose_bone.name) prev_euler = Euler((0.0, 0.0, 0.0)) for frame_i in range(0, num_frame): bvh_rot = bvh_node.anim_data[frame_i + skip_frame][3:] # apply rotation order and convert to XYZ # note that the rot_order_str is reversed. euler = Euler(bvh_rot, bvh_node.rot_order_str[::-1]) bone_rotation_matrix = euler.to_matrix().to_4x4() bone_rotation_matrix = (bone_rest_matrix_inv * bone_rotation_matrix * bone_rest_matrix) if 4 == len(rotate[frame_i]): rotate[frame_i] = bone_rotation_matrix.to_quaternion() else: rotate[frame_i] = bone_rotation_matrix.to_euler( pose_bone.rotation_mode, prev_euler) prev_euler = rotate[frame_i] # For each Euler angle x, y, z (or Quaternion w, x, y, z). for axis_i in range(len(rotate[0])): curve = action.fcurves.new(data_path=data_path, index=axis_i) keyframe_points = curve.keyframe_points keyframe_points.add(len(frange)) for i, frame_i in enumerate(frange): keyframe_points[i].co = \ (time[frame_i], rotate[frame_i][axis_i]) for cu in action.fcurves: if IMPORT_LOOP: pass # 2.5 doenst have cyclic now? for bez in cu.keyframe_points: bez.interpolation = 'LINEAR' # finally apply matrix arm_ob.matrix_world = global_matrix bpy.ops.object.transform_apply(rotation=True) return arm_ob
def get_top_mesh(context, prefs): me = context.blend_data.meshes.new("temp_mesh") bm = bmesh.new() bm.from_mesh(me) mat = Matrix() tt = prefs.lp_Tree_Type if tt == "lp_Tree_Oak": mat.translation = (0, 0, prefs.trunk_depth) tsmin = prefs.lp_Tree_Top_Scale_Min tsmax = prefs.lp_Tree_Top_Scale_Max mat[0][0], mat[1][1], mat[2][2] = ( uniform(tsmin[0], tsmax[0]), uniform(tsmin[1], tsmax[1]), uniform(tsmin[2], tsmax[2]), ) bmesh.ops.create_icosphere(bm, subdivisions=prefs.lp_Tree_Top_Subdivisions, diameter=1.0, matrix=mat) elif tt == "lp_Tree_Pine": segments = get_random(prefs.lp_Tree_Top_Stage_Segments_Min, prefs.lp_Tree_Top_Stage_Segments_Max) stages = get_random(prefs.lp_Tree_Top_Stages_Min, prefs.lp_Tree_Top_Stages_Max) td = prefs.trunk_depth - 0.7 sstep = uniform(prefs.lp_Tree_Top_Stage_Step_Min, prefs.lp_Tree_Top_Stage_Step_Max) ssmin = prefs.lp_Tree_Top_Stage_Size_Min ssmax = prefs.lp_Tree_Top_Stage_Size_Max ssize = (uniform(ssmin[0], ssmax[0]), uniform(ssmin[1], ssmax[1]), uniform(ssmin[2], ssmax[2])) for i in range(0, stages): mult = prefs.lp_Tree_Top_Stage_Shrink_Multiplier * (i / 4) sc = (1 - i * prefs.lp_Tree_Top_Stage_Shrink * mult) * 0.9 if sc < 0.01: sc = 0.01 mat[0][0], mat[1][1], mat[2][2] = (sc * ssize[0], sc * ssize[1], sc * ssize[2]) mat.translation = (0, 0, (td + ((ssize[2] - 1) / 2) + i * sstep) * 0.85) if prefs.lp_Tree_Top_Rotate_Stages: e = Euler((0, 0, uniform(0, 3.14)), "XYZ") mat = mat * e.to_matrix().to_4x4() bmesh.ops.create_cone( bm, cap_ends=True, cap_tris=True, segments=segments, diameter1=(prefs.lp_Tree_Top_Stage_Diameter), diameter2=0, depth=(0.85), matrix=mat, ) mat = Matrix() elif tt == "lp_Tree_Palm": trunk_length = prefs.palm_stage_length * prefs.palm_stages leaf_length = get_random(prefs.lp_Tree_Palm_Top_Leaf_Length_Min, prefs.lp_Tree_Palm_Top_Leaf_Length_Max) leaf_size = uniform(prefs.lp_Tree_Palm_Top_Leaf_Size_Min, prefs.lp_Tree_Palm_Top_Leaf_Size_Max) mat.translation = (0, 0, trunk_length) leaves = get_random(prefs.lp_Tree_Palm_Top_Leaves_Min, prefs.lp_Tree_Palm_Top_Leaves_Max) bmesh.ops.create_cone( bm, cap_ends=True, cap_tris=True, segments=leaves, diameter1=leaf_size, diameter2=leaf_size, depth=0.1, matrix=mat, ) faces = bm.faces[:] for face in faces: nor = face.normal # Asume normalized normal dir = (nor.x * 0.3, nor.y * 0.3, -0.12) if nor.z == 0: for i in range(0, leaf_length): r = bmesh.ops.extrude_discrete_faces(bm, faces=[face]) bmesh.ops.translate(bm, vec=dir, verts=r["faces"][0].verts) face = r["faces"][0] dir = (dir[0], dir[1], dir[2] - 0.08) # Align last face verts mid = [0, 0, 0] for v in face.verts: mid[0] += v.co.x mid[1] += v.co.y mid[2] += v.co.z mid[0] /= len(face.verts) mid[1] /= len(face.verts) mid[2] /= len(face.verts) for v in face.verts: v.co.x, v.co.y, v.co.z = mid[0], mid[1], mid[2] bm.to_mesh(me) return me
faces = [(0, 1, 2, 3), (4, 5, 6, 7)] mesh = bpy.data.meshes.new("Xpos") obj = bpy.data.objects.new("Xpos", mesh) bpy.context.scene.objects.link(obj) mesh.from_pydata(verts, [], faces) mesh.update(calc_edges=True) bpy.data.objects["Xpos"].data.materials.append( material_options["wall"][randint(0, len(material_options["wall"]) - 1)]) # place corridor Y+ bpy.ops.object.select_all(action="DESELECT") bpy.data.objects["Xpos"].select = True bpy.ops.object.duplicate() bpy.data.objects["Xpos.001"].name = "Ypos" bpy.data.objects["Ypos"].rotation_euler = Euler((0, 0, math.radians(90))) # place corridor X- bpy.ops.object.select_all(action="DESELECT") bpy.data.objects["Xpos"].select = True bpy.ops.object.duplicate() bpy.data.objects["Xpos.001"].name = "Xneg" bpy.data.objects["Xneg"].rotation_euler = Euler((0, 0, math.radians(180))) # place corridor Y- bpy.ops.object.select_all(action="DESELECT") bpy.data.objects["Xpos"].select = True bpy.ops.object.duplicate() bpy.data.objects["Xpos.001"].name = "Yneg" bpy.data.objects["Yneg"].rotation_euler = Euler((0, 0, math.radians(-90)))
def _get_bone_channels(scs_root_obj, armature, scs_animation, action, export_scale): """Takes armature and action and returns bone channels. bone_channels structure example: [("Bone", [("_TIME", [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]), ("_MATRIX", [])])]""" bone_channels = [] frame_start = scs_animation.anim_start frame_end = scs_animation.anim_end anim_export_step = action.scs_props.anim_export_step total_frames = (frame_end - frame_start) / anim_export_step # armature matrix stores transformation of armature object against scs root # and has to be added to all bones as they only armature space transformations armature_mat = scs_root_obj.matrix_world.inverted() * armature.matrix_world invalid_data = False # flag to indicate invalid data state curves_per_bone = {} # store all the curves we are interested in per bone names for bone in armature.data.bones: for fcurve in action.fcurves: # check if curve belongs to bone if '["' + bone.name + '"]' in fcurve.data_path: data_path = fcurve.data_path array_index = fcurve.array_index if data_path.endswith("location"): curve_type = "location" elif data_path.endswith("rotation_euler"): curve_type = "euler_rotation" elif data_path.endswith("rotation_quaternion"): curve_type = "quat_rotation" elif data_path.endswith("scale"): curve_type = "scale" else: curve_type = None # write only recognized curves if curve_type is not None: if bone.name not in curves_per_bone: curves_per_bone[bone.name] = { "location": {}, "euler_rotation": {}, "quat_rotation": {}, "scale": {} } curves_per_bone[bone.name][curve_type][array_index] = fcurve for bone_name, bone_curves in curves_per_bone.items(): bone = armature.data.bones[bone_name] pose_bone = armature.pose.bones[bone_name] loc_curves = bone_curves["location"] euler_rot_curves = bone_curves["euler_rotation"] quat_rot_curves = bone_curves["quat_rotation"] sca_curves = bone_curves["scale"] bone_rest_mat = armature_mat * bone.matrix_local if bone.parent: parent_bone_rest_mat = (Matrix.Scale(export_scale, 4) * _convert_utils.scs_to_blend_matrix().inverted() * armature_mat * bone.parent.matrix_local) else: parent_bone_rest_mat = Matrix() # GO THOUGH FRAMES actual_frame = frame_start timings_stream = [] matrices_stream = [] while actual_frame <= frame_end: mat_loc = Matrix() mat_rot = Matrix() mat_sca = Matrix() # LOCATION MATRIX if len(loc_curves) > 0: location = Vector() for index in range(3): if index in loc_curves: location[index] = loc_curves[index].evaluate(actual_frame) mat_loc = Matrix.Translation(location) # ROTATION MATRIX if len(euler_rot_curves) > 0: rotation = Euler() for index in range(3): if index in euler_rot_curves: rotation[index] = euler_rot_curves[index].evaluate(actual_frame) mat_rot = Euler(rotation, pose_bone.rotation_mode).to_matrix().to_4x4() # calc rotation by pose rotation mode elif len(quat_rot_curves) > 0: rotation = Quaternion() for index in range(4): if index in quat_rot_curves: rotation[index] = quat_rot_curves[index].evaluate(actual_frame) mat_rot = rotation.to_matrix().to_4x4() # SCALE MATRIX if len(sca_curves) > 0: scale = Vector((1.0, 1.0, 1.0)) for index in range(3): if index in sca_curves: scale[index] = sca_curves[index].evaluate(actual_frame) if scale[index] < 0: lprint(str("E Negative scale detected on bone %r:\n\t " "(Action: %r, keyframe no.: %s, SCS Animation: %r)."), (bone_name, action.name, actual_frame, scs_animation.name)) invalid_data = True mat_sca = Matrix() mat_sca[0] = (scale[0], 0, 0, 0) mat_sca[1] = (0, scale[2], 0, 0) mat_sca[2] = (0, 0, scale[1], 0) mat_sca[3] = (0, 0, 0, 1) # BLENDER FRAME MATRIX mat = mat_loc * mat_rot * mat_sca # SCALE REMOVAL MATRIX rest_location, rest_rotation, rest_scale = bone_rest_mat.decompose() # print(' BONES rest_scale: %s' % str(rest_scale)) rest_scale = rest_scale * export_scale scale_removal_matrix = Matrix() scale_removal_matrix[0] = (1.0 / rest_scale[0], 0, 0, 0) scale_removal_matrix[1] = (0, 1.0 / rest_scale[1], 0, 0) scale_removal_matrix[2] = (0, 0, 1.0 / rest_scale[2], 0) scale_removal_matrix[3] = (0, 0, 0, 1) # SCALE MATRIX scale_matrix = Matrix.Scale(export_scale, 4) # COMPUTE SCS FRAME MATRIX frame_matrix = (parent_bone_rest_mat.inverted() * _convert_utils.scs_to_blend_matrix().inverted() * scale_matrix.inverted() * bone_rest_mat * mat * scale_removal_matrix.inverted()) # print(' actual_frame: %s - value: %s' % (actual_frame, frame_matrix)) timings_stream.append(("__time__", scs_animation.length / total_frames), ) matrices_stream.append(("__matrix__", frame_matrix.transposed()), ) actual_frame += anim_export_step anim_timing = ("_TIME", timings_stream) anim_matrices = ("_MATRIX", matrices_stream) bone_anim = (anim_timing, anim_matrices) bone_data = (bone_name, bone_anim) bone_channels.append(bone_data) # return empty bone channels if data are invalid if invalid_data: return [] return bone_channels
def draw_callback_px(self, context): font_id = 0 region = context.region UIColor = (0.992, 0.5518, 0.0, 1.0) # Cut Type RECTANGLE = 0 LINE = 1 CIRCLE = 2 self.carver_prefs = context.preferences.addons[__package__].preferences # Color color1 = (1.0, 1.0, 1.0, 1.0) color2 = UIColor #The mouse is outside the active region if not self.in_view_3d: color1 = color2 = (1.0, 0.2, 0.1, 1.0) # Primitives type PrimitiveType = "Rectangle" if self.CutType == CIRCLE: PrimitiveType = "Circle" if self.CutType == LINE: PrimitiveType = "Line" # Width screen overlap = context.preferences.system.use_region_overlap t_panel_width = 0 if overlap: for region in context.area.regions: if region.type == 'TOOLS': t_panel_width = region.width # Initial position region_width = int(region.width / 2.0) y_txt = 10 # Draw the center command from bottom to top # Get the size of the text text_size = 18 if region.width >= 850 else 12 blf.size(0, int(round(text_size * bpy.context.preferences.view.ui_scale, 0)), 72) # Help Display if (self.ObjectMode is False) and (self.ProfileMode is False): # Depth Cursor TypeStr = "Cursor Depth [" + self.carver_prefs.Key_Depth + "]" BoolStr = "(ON)" if self.snapCursor else "(OFF)" help_txt = [[TypeStr, BoolStr]] # Close poygonal shape if self.CreateMode and self.CutType == LINE: TypeStr = "Close [" + self.carver_prefs.Key_Close + "]" BoolStr = "(ON)" if self.Closed else "(OFF)" help_txt += [[TypeStr, BoolStr]] if self.CreateMode is False: # Apply Booleans TypeStr = "Apply Operations [" + self.carver_prefs.Key_Apply + "]" BoolStr = "(OFF)" if self.dont_apply_boolean else "(ON)" help_txt += [[TypeStr, BoolStr]] #Auto update for bevel TypeStr = "Bevel Update [" + self.carver_prefs.Key_Update + "]" BoolStr = "(ON)" if self.Auto_BevelUpdate else "(OFF)" help_txt += [[TypeStr, BoolStr]] # Circle subdivisions if self.CutType == CIRCLE: TypeStr = "Subdivisions [" + self.carver_prefs.Key_Subrem + "][" + self.carver_prefs.Key_Subadd + "]" BoolStr = str((int(360 / self.stepAngle[self.step]))) help_txt += [[TypeStr, BoolStr]] if self.CreateMode: help_txt += [["Type [Space]", PrimitiveType]] else: help_txt += [["Cut Type [Space]", PrimitiveType]] else: # Instantiate TypeStr = "Instantiate [" + self.carver_prefs.Key_Instant + "]" BoolStr = "(ON)" if self.Instantiate else "(OFF)" help_txt = [[TypeStr, BoolStr]] # Random rotation if self.alt: TypeStr = "Random Rotation [" + self.carver_prefs.Key_Randrot + "]" BoolStr = "(ON)" if self.RandomRotation else "(OFF)" help_txt += [[TypeStr, BoolStr]] # Thickness if self.BrushSolidify: TypeStr = "Thickness [" + self.carver_prefs.Key_Depth + "]" if self.ProfileMode: BoolStr = str( round(self.ProfileBrush.modifiers["CT_SOLIDIFY"].thickness, 2)) if self.ObjectMode: BoolStr = str( round(self.ObjectBrush.modifiers["CT_SOLIDIFY"].thickness, 2)) help_txt += [[TypeStr, BoolStr]] # Brush depth if (self.ObjectMode): TypeStr = "Carve Depth [" + self.carver_prefs.Key_Depth + "]" BoolStr = str(round(self.ObjectBrush.data.vertices[0].co.z, 2)) help_txt += [[TypeStr, BoolStr]] TypeStr = "Brush Depth [" + self.carver_prefs.Key_BrushDepth + "]" BoolStr = str(round(self.BrushDepthOffset, 2)) help_txt += [[TypeStr, BoolStr]] help_txt, bloc_height, max_option, max_key, comma = get_text_info( self, context, help_txt) xCmd = region_width - (max_option + max_key + comma) / 2 draw_string(self, color1, color2, xCmd, y_txt, help_txt, max_option, divide=2) # Separator (Line) LineWidth = (max_option + max_key + comma) / 2 if region.width >= 850: LineWidth = 140 LineWidth = (max_option + max_key + comma) coords = [(int(region_width - LineWidth/2), y_txt + bloc_height + 8), \ (int(region_width + LineWidth/2), y_txt + bloc_height + 8)] draw_shader(self, UIColor, 1, 'LINES', coords, self.carver_prefs.LineWidth) # Command Display if self.CreateMode and ((self.ObjectMode is False) and (self.ProfileMode is False)): BooleanMode = "Create" else: if self.ObjectMode or self.ProfileMode: BooleanType = "Difference) [T]" if self.BoolOps == self.difference else "Union) [T]" BooleanMode = \ "Object Brush (" + BooleanType if self.ObjectMode else "Profil Brush (" + BooleanType else: BooleanMode = \ "Difference" if (self.shift is False) and (self.ForceRebool is False) else "Rebool" # Display boolean mode text_size = 40 if region.width >= 850 else 20 blf.size(0, int(round(text_size * bpy.context.preferences.view.ui_scale, 0)), 72) draw_string(self, color2, color2, region_width - (blf.dimensions(0, BooleanMode)[0]) / 2, \ y_txt + bloc_height + 16, BooleanMode, 0, divide = 2) if region.width >= 850: if self.AskHelp is False: # "H for Help" text blf.size(0, int(round(13 * bpy.context.preferences.view.ui_scale, 0)), 72) help_txt = "[" + self.carver_prefs.Key_Help + "] for help" txt_width = blf.dimensions(0, help_txt)[0] txt_height = (blf.dimensions(0, "gM")[1] * 1.45) # Draw a rectangle and put the text "H for Help" xrect = 40 yrect = 40 rect_vertices = [(xrect - 5, yrect - 5), (xrect + txt_width + 5, yrect - 5), \ (xrect + txt_width + 5, yrect + txt_height + 5), (xrect - 5, yrect + txt_height + 5)] draw_shader(self, (0.0, 0.0, 0.0), 0.3, 'TRI_FAN', rect_vertices, self.carver_prefs.LineWidth) draw_string(self, color1, color2, xrect, yrect, help_txt, 0) else: #Draw the help text xHelp = 30 + t_panel_width yHelp = 10 if self.ObjectMode or self.ProfileMode: if self.ProfileMode: help_txt = [["Object Mode", self.carver_prefs.Key_Brush]] else: help_txt = [["Cut Mode", self.carver_prefs.Key_Brush]] else: help_txt =[ ["Profil Brush", self.carver_prefs.Key_Brush],\ ["Move Cursor", "Ctrl + LMB"] ] if (self.ObjectMode is False) and (self.ProfileMode is False): if self.CreateMode is False: help_txt +=[ ["Create geometry", self.carver_prefs.Key_Create],\ ] else: help_txt +=[ ["Cut", self.carver_prefs.Key_Create],\ ] if self.CutMode == RECTANGLE: help_txt +=[ ["Dimension", "MouseMove"],\ ["Move all", "Alt"],\ ["Validate", "LMB"],\ ["Rebool", "Shift"] ] elif self.CutMode == CIRCLE: help_txt +=[ ["Rotation and Radius", "MouseMove"],\ ["Move all", "Alt"],\ ["Subdivision", self.carver_prefs.Key_Subrem + " " + self.carver_prefs.Key_Subadd],\ ["Incremental rotation", "Ctrl"],\ ["Rebool", "Shift"] ] elif self.CutMode == LINE: help_txt +=[ ["Dimension", "MouseMove"],\ ["Move all", "Alt"],\ ["Validate", "Space"],\ ["Rebool", "Shift"],\ ["Snap", "Ctrl"],\ ["Scale Snap", "WheelMouse"],\ ] else: # ObjectMode help_txt +=[ ["Difference", "Space"],\ ["Rebool", "Shift + Space"],\ ["Duplicate", "Alt + Space"],\ ["Scale", self.carver_prefs.Key_Scale],\ ["Rotation", "LMB + Move"],\ ["Step Angle", "CTRL + LMB + Move"],\ ] if self.ProfileMode: help_txt += [[ "Previous or Next Profile", self.carver_prefs.Key_Subadd + " " + self.carver_prefs.Key_Subrem ]] help_txt +=[ ["Create / Delete rows", chr(8597)],\ ["Create / Delete cols", chr(8596)],\ ["Gap for rows or columns", self.carver_prefs.Key_Gapy + " " + self.carver_prefs.Key_Gapx] ] blf.size(0, int(round(15 * bpy.context.preferences.view.ui_scale, 0)), 72) help_txt, bloc_height, max_option, max_key, comma = get_text_info( self, context, help_txt) draw_string(self, color1, color2, xHelp, yHelp, help_txt, max_option) if self.ProfileMode: xrect = region.width - t_panel_width - 80 yrect = 80 coords = [(xrect, yrect), (xrect + 60, yrect), (xrect + 60, yrect - 60), (xrect, yrect - 60)] # Draw rectangle background in the lower right draw_shader(self, (0.0, 0.0, 0.0), 0.3, 'TRI_FAN', coords, size=self.carver_prefs.LineWidth) # Use numpy to get the vertices and indices of the profile object to draw WidthProfil = 50 location = Vector((region.width - t_panel_width - WidthProfil, 50, 0)) ProfilScale = 20.0 coords = [] mesh = bpy.data.meshes[self.Profils[self.nProfil][0]] mesh.calc_loop_triangles() vertices = np.empty((len(mesh.vertices), 3), 'f') indices = np.empty((len(mesh.loop_triangles), 3), 'i') mesh.vertices.foreach_get("co", np.reshape(vertices, len(mesh.vertices) * 3)) mesh.loop_triangles.foreach_get( "vertices", np.reshape(indices, len(mesh.loop_triangles) * 3)) for idx, vals in enumerate(vertices): coords.append([ vals[0] * ProfilScale + location.x, vals[1] * ProfilScale + location.y, vals[2] * ProfilScale + location.z ]) #Draw the silhouette of the mesh draw_shader(self, UIColor, 0.5, 'TRIS', coords, size=self.carver_prefs.LineWidth, indices=indices) if self.CutMode: if len(self.mouse_path) > 1: x0 = self.mouse_path[0][0] y0 = self.mouse_path[0][1] x1 = self.mouse_path[1][0] y1 = self.mouse_path[1][1] # Cut rectangle if self.CutType == RECTANGLE: coords = [ (x0 + self.xpos, y0 + self.ypos), (x1 + self.xpos, y0 + self.ypos), \ (x1 + self.xpos, y1 + self.ypos), (x0 + self.xpos, y1 + self.ypos) ] indices = ((0, 1, 2), (2, 0, 3)) self.rectangle_coord = coords draw_shader(self, UIColor, 1, 'LINE_LOOP', coords, size=self.carver_prefs.LineWidth) #Draw points draw_shader(self, UIColor, 1, 'POINTS', coords, size=3) if self.shift or self.CreateMode: draw_shader(self, UIColor, 0.5, 'TRIS', coords, size=self.carver_prefs.LineWidth, indices=indices) # Draw grid (based on the overlay options) to show the incremental snapping if self.ctrl: mini_grid(self, context, UIColor) # Cut Line elif self.CutType == LINE: coords = [] indices = [] top_grid = False for idx, vals in enumerate(self.mouse_path): coords.append([vals[0] + self.xpos, vals[1] + self.ypos]) indices.append([idx]) # Draw lines if self.Closed: draw_shader(self, UIColor, 1.0, 'LINE_LOOP', coords, size=self.carver_prefs.LineWidth) else: draw_shader(self, UIColor, 1.0, 'LINE_STRIP', coords, size=self.carver_prefs.LineWidth) # Draw points draw_shader(self, UIColor, 1.0, 'POINTS', coords, size=3) # Draw polygon if (self.shift) or (self.CreateMode and self.Closed): draw_shader(self, UIColor, 0.5, 'TRI_FAN', coords, size=self.carver_prefs.LineWidth) # Draw grid (based on the overlay options) to show the incremental snapping if self.ctrl: mini_grid(self, context, UIColor) # Circle Cut elif self.CutType == CIRCLE: # Create a circle using a tri fan tris_coords, indices = draw_circle(self, x0, y0) # Remove the vertex in the center to get the outer line of the circle line_coords = tris_coords[1:] draw_shader(self, UIColor, 1.0, 'LINE_LOOP', line_coords, size=self.carver_prefs.LineWidth) if self.shift or self.CreateMode: draw_shader(self, UIColor, 0.5, 'TRIS', tris_coords, size=self.carver_prefs.LineWidth, indices=indices) if (self.ObjectMode or self.ProfileMode) and len(self.CurrentSelection) > 0: if self.ShowCursor: region = context.region rv3d = context.space_data.region_3d if self.ObjectMode: ob = self.ObjectBrush if self.ProfileMode: ob = self.ProfileBrush mat = ob.matrix_world # 50% alpha, 2 pixel width line bgl.glEnable(bgl.GL_BLEND) bbox = [mat @ Vector(b) for b in ob.bound_box] objBBDiagonal = objDiagonal(self.CurrentSelection[0]) if self.shift: gl_size = 4 UIColor = (0.5, 1.0, 0.0, 1.0) else: gl_size = 2 UIColor = (1.0, 0.8, 0.0, 1.0) line_coords = [] idx = 0 CRadius = ((bbox[7] - bbox[0]).length) / 2 for i in range(int(len(self.CLR_C) / 3)): vector3d = (self.CLR_C[idx * 3] * CRadius + self.CurLoc.x, \ self.CLR_C[idx * 3 + 1] * CRadius + self.CurLoc.y, \ self.CLR_C[idx * 3 + 2] * CRadius + self.CurLoc.z) vector2d = bpy_extras.view3d_utils.location_3d_to_region_2d( region, rv3d, vector3d) if vector2d is not None: line_coords.append((vector2d[0], vector2d[1])) idx += 1 if len(line_coords) > 0: draw_shader(self, UIColor, 1.0, 'LINE_LOOP', line_coords, size=gl_size) # Object display if self.quat_rot is not None: ob.location = self.CurLoc v = Vector() v.x = v.y = 0.0 v.z = self.BrushDepthOffset ob.location += self.quat_rot @ v e = Euler() e.x = 0.0 e.y = 0.0 e.z = self.aRotZ / 25.0 qe = e.to_quaternion() qRot = self.quat_rot @ qe ob.rotation_mode = 'QUATERNION' ob.rotation_quaternion = qRot ob.rotation_mode = 'XYZ' if self.ProfileMode: if self.ProfileBrush is not None: self.ProfileBrush.location = self.CurLoc self.ProfileBrush.rotation_mode = 'QUATERNION' self.ProfileBrush.rotation_quaternion = qRot self.ProfileBrush.rotation_mode = 'XYZ' # Opengl defaults bgl.glLineWidth(1) bgl.glDisable(bgl.GL_BLEND)
def bvh_node_dict2armature( context, bvh_name, bvh_nodes, rotate_mode='XYZ', frame_start=1, IMPORT_LOOP=False, global_matrix=None, ): if frame_start < 1: frame_start = 1 # Add the new armature, scene = context.scene for obj in scene.objects: obj.select = False arm_data = bpy.data.armatures.new(bvh_name) arm_ob = bpy.data.objects.new(bvh_name, arm_data) scene.objects.link(arm_ob) arm_ob.select = True scene.objects.active = arm_ob bpy.ops.object.mode_set(mode='OBJECT', toggle=False) bpy.ops.object.mode_set(mode='EDIT', toggle=False) # Get the average bone length for zero length bones, we may not use this. average_bone_length = 0.0 nonzero_count = 0 for bvh_node in bvh_nodes.values(): l = (bvh_node.rest_head_local - bvh_node.rest_tail_local).length if l: average_bone_length += l nonzero_count += 1 # Very rare cases all bones couldbe zero length??? if not average_bone_length: average_bone_length = 0.1 else: # Normal operation average_bone_length = average_bone_length / nonzero_count # XXX, annoying, remove bone. while arm_data.edit_bones: arm_ob.edit_bones.remove(arm_data.edit_bones[-1]) ZERO_AREA_BONES = [] for name, bvh_node in bvh_nodes.items(): # New editbone bone = bvh_node.temp = arm_data.edit_bones.new(name) bone.head = bvh_node.rest_head_world bone.tail = bvh_node.rest_tail_world # Zero Length Bones! (an exceptional case) if (bone.head - bone.tail).length < 0.001: print("\tzero length bone found:", bone.name) if bvh_node.parent: ofs = bvh_node.parent.rest_head_local - bvh_node.parent.rest_tail_local if ofs.length: # is our parent zero length also?? unlikely bone.tail = bone.tail - ofs else: bone.tail.y = bone.tail.y + average_bone_length else: bone.tail.y = bone.tail.y + average_bone_length ZERO_AREA_BONES.append(bone.name) for bvh_node in bvh_nodes.values(): if bvh_node.parent: # bvh_node.temp is the Editbone # Set the bone parent bvh_node.temp.parent = bvh_node.parent.temp # Set the connection state if not bvh_node.has_loc and\ bvh_node.parent and\ bvh_node.parent.temp.name not in ZERO_AREA_BONES and\ bvh_node.parent.rest_tail_local == bvh_node.rest_head_local: bvh_node.temp.use_connect = True # Replace the editbone with the editbone name, # to avoid memory errors accessing the editbone outside editmode for bvh_node in bvh_nodes.values(): bvh_node.temp = bvh_node.temp.name # Now Apply the animation to the armature # Get armature animation data bpy.ops.object.mode_set(mode='OBJECT', toggle=False) pose = arm_ob.pose pose_bones = pose.bones if rotate_mode == 'NATIVE': for bvh_node in bvh_nodes.values(): bone_name = bvh_node.temp # may not be the same name as the bvh_node, could have been shortened. pose_bone = pose_bones[bone_name] pose_bone.rotation_mode = bvh_node.rot_order_str elif rotate_mode != 'QUATERNION': for pose_bone in pose_bones: pose_bone.rotation_mode = rotate_mode else: # Quats default pass context.scene.update() arm_ob.animation_data_create() action = bpy.data.actions.new(name=bvh_name) arm_ob.animation_data.action = action # Replace the bvh_node.temp (currently an editbone) # With a tuple (pose_bone, armature_bone, bone_rest_matrix, bone_rest_matrix_inv) for bvh_node in bvh_nodes.values(): bone_name = bvh_node.temp # may not be the same name as the bvh_node, could have been shortened. pose_bone = pose_bones[bone_name] rest_bone = arm_data.bones[bone_name] bone_rest_matrix = rest_bone.matrix_local.to_3x3() bone_rest_matrix_inv = Matrix(bone_rest_matrix) bone_rest_matrix_inv.invert() bone_rest_matrix_inv.resize_4x4() bone_rest_matrix.resize_4x4() bvh_node.temp = (pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv) # Make a dict for fast access without rebuilding a list all the time. # KEYFRAME METHOD, SLOW, USE IPOS DIRECT # TODO: use f-point samples instead (Aligorith) if rotate_mode != 'QUATERNION': prev_euler = [Euler() for i in range(len(bvh_nodes))] # Animate the data, the last used bvh_node will do since they all have the same number of frames for frame_current in range(len(bvh_node.anim_data) - 1): # skip the first frame (rest frame) # print frame_current # if frame_current==40: # debugging # break scene.frame_set(frame_start + frame_current) # Dont neet to set the current frame for i, bvh_node in enumerate(bvh_nodes.values()): pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv = bvh_node.temp lx, ly, lz, rx, ry, rz = bvh_node.anim_data[frame_current + 1] if bvh_node.has_rot: # apply rotation order and convert to XYZ # note that the rot_order_str is reversed. bone_rotation_matrix = Euler( (rx, ry, rz), bvh_node.rot_order_str[::-1]).to_matrix().to_4x4() bone_rotation_matrix = bone_rest_matrix_inv * bone_rotation_matrix * bone_rest_matrix if rotate_mode == 'QUATERNION': pose_bone.rotation_quaternion = bone_rotation_matrix.to_quaternion( ) else: euler = bone_rotation_matrix.to_euler( pose_bone.rotation_mode, prev_euler[i]) pose_bone.rotation_euler = euler prev_euler[i] = euler if bvh_node.has_loc: pose_bone.location = ( bone_rest_matrix_inv * Matrix.Translation( Vector((lx, ly, lz)) - bvh_node.rest_head_local)).to_translation() if bvh_node.has_loc: pose_bone.keyframe_insert("location") if bvh_node.has_rot: if rotate_mode == 'QUATERNION': pose_bone.keyframe_insert("rotation_quaternion") else: pose_bone.keyframe_insert("rotation_euler") for cu in action.fcurves: if IMPORT_LOOP: pass # 2.5 doenst have cyclic now? for bez in cu.keyframe_points: bez.interpolation = 'LINEAR' # finally apply matrix arm_ob.matrix_world = global_matrix bpy.ops.object.transform_apply(rotation=True) return arm_ob
def vrot(self, r): random.seed(self.ran + r) return Euler((radians(self.rotx) + gauss(0, self.var2 / 3), radians(self.roty) + gauss(0, self.var2 / 3), radians(self.rotz) + gauss(0, self.var2 / 3)), 'XYZ')
def save(operator, context, filepath, debug_report=True): print("Exporting scene to DTS") scene = context.scene dsq = DsqFile() # Create a DTS node for every armature/empty in the scene node_ob = {} export_all_nodes(node_ob, dsq, filter(lambda o: not o.parent, scene.objects)) # Figure out if we should create our own root node if "NodeOrder" in bpy.data.texts: order = bpy.data.texts["NodeOrder"].as_string().split("\n") order_key = {name: i for i, name in enumerate(order)} try: dsq.nodes = list(sorted(dsq.nodes, key=lambda n: order_key[n])) except KeyError as e: return fail( operator, "Node '{}' is missing from the 'NodeOrder' text block. This means that you may have added nodes to a skeleton when you shouldn't have, or that you forgot to remove the 'NodeOrder' text block. It is automatically created by the \"Import node order\" option when importing a DTS file. Perhaps you forgot to press Ctrl+N after you imported?" .format(e.args[0])) shape_node_names = set(dsq.nodes) missing_nodes = tuple(filter(lambda n: n not in dsq.nodes, order)) if missing_nodes: return fail( operator, "The following nodes were found in the 'NodeOrder' text block but do not exist in the shape. This means that you may have removed nodes from a skeleton when you shouldn't have, or that you forgot to remove the 'NodeOrder' text block:\n{}" .format(", ".join(missing_nodes))) node_index = {node_ob[name]: i for i, name in enumerate(dsq.nodes)} animated_nodes = [] for node in dsq.nodes: ob = node_ob[node] data = ob.animation_data if data and data.action and len(data.action.fcurves): animated_nodes.append(ob) for bobj in scene.objects: if bobj.type != "MESH": continue if bobj.users_group and bobj.users_group[0].name == "__ignore__": continue if not bobj.parent: if not auto_root_index: if "NodeOrder" in bpy.data.texts and "__auto_root__" not in order_key: return fail( operator, "The mesh '{}' does not have a parent. Normally, the exporter would create a temporary parent for you to fix this, but you have a specified NodeOrder (may be created by previously importing a DTS file and not pressing Ctrl+N after you're done with it), which does not have the '__auto_root__' entry (name used for the automatic parent)." .format(bobj.name)) dsq.nodes.append("__auto_root__") sequences = {} for marker in context.scene.timeline_markers: if ":" not in marker.name: continue name, what = marker.name.rsplit(":", 1) if name not in sequences: sequences[name] = {} if what in sequences[name]: print( "Warning: Got duplicate '{}' marker for sequence '{}' at frame {} (first was at frame {}), ignoring" .format(what, name, marker.frame, sequences[name][what].frame)) continue sequences[name][what] = marker sequence_flags_strict = False sequence_flags = {} sequence_missing = set() if "Sequences" in bpy.data.texts: for line in bpy.data.texts["Sequences"].as_string().split("\n"): line = line.strip() if not line: continue if line == "strict": sequence_flags_strict = True continue if ":" not in line: print("Invalid line in 'Sequences':", line) continue name, flags = line.split(":", 1) if flags.lstrip(): flags = tuple(map(lambda f: f.strip(), flags.split(","))) else: flags = () sequence_flags[name] = flags sequence_missing.add(name) for name, markers in sequences.items(): print("Exporting sequence", name) if "start" not in markers: return fail(operator, "Missing start marker for sequence '{}'".format(name)) if "end" not in markers: return fail(operator, "Missing end marker for sequence '{}'".format(name)) seq = Sequence() seq.name = name seq.flags = Sequence.AlignedScale if name in sequence_flags: for part in sequence_flags[name]: flag, *data = part.split(" ", 1) if data: data = data[0] if flag == "cyclic": seq.flags |= Sequence.Cyclic elif flag == "blend": seq.flags |= Sequence.Blend seq.priority = int(data) else: print("Warning: Unknown flag '{}' (used by sequence '{}')". format(flag, name)) sequence_missing.remove(name) elif sequence_flags_strict: return fail( operator, "Missing 'Sequences' line for sequence '{}'".format(name)) frame_start = markers["start"].frame frame_end = markers["end"].frame frame_range = frame_end - frame_start + 1 frame_step = 1 # TODO: GCD of keyframe spacings seq.toolBegin = frame_start seq.duration = frame_range * (context.scene.render.fps_base / context.scene.render.fps) seq.numKeyframes = int(math.ceil(float(frame_range) / frame_step)) seq.firstGroundFrame = len(dsq.ground_translations) seq.baseRotation = len(dsq.rotations) seq.baseTranslation = len(dsq.translations) seq.baseScale = len(dsq.aligned_scales) seq.baseObjectState = 0 seq.baseDecalState = 0 seq.firstTrigger = len(dsq.triggers) seq.rotationMatters = [False] * len(dsq.nodes) seq.translationMatters = [False] * len(dsq.nodes) seq.scaleMatters = [False] * len(dsq.nodes) seq.decalMatters = [False] * len(dsq.nodes) seq.iflMatters = [False] * len(dsq.nodes) seq.visMatters = [False] * len(dsq.nodes) seq.frameMatters = [False] * len(dsq.nodes) seq.matFrameMatters = [False] * len(dsq.nodes) dsq.sequences.append(seq) seq_curves_rotation = [] seq_curves_translation = [] seq_curves_scale = [] for ob in animated_nodes: index = node_index[ob] fcurves = ob.animation_data.action.fcurves if ob.rotation_mode == "QUATERNION": curves_rotation = array_from_fcurves(fcurves, "rotation_quaternion", 4) elif ob.rotation_mode == "XYZ": curves_rotation = array_from_fcurves(fcurves, "rotation_euler", 3) else: return fail( operator, "Animated node '{}' uses unsupported rotation_mode '{}'". format(ob.name, ob.rotation_mode)) curves_translation = array_from_fcurves(fcurves, "location", 3) curves_scale = array_from_fcurves(fcurves, "scale", 3) if curves_rotation and fcurves_keyframe_in_range( curves_rotation, frame_start, frame_end): print("rotation matters for", ob.name) seq_curves_rotation.append((curves_rotation, ob.rotation_mode)) seq.rotationMatters[index] = True if curves_translation and fcurves_keyframe_in_range( curves_translation, frame_start, frame_end): print("translation matters for", ob.name) seq_curves_translation.append(curves_translation) seq.translationMatters[index] = True if curves_scale and fcurves_keyframe_in_range( curves_scale, frame_start, frame_end): print("scale matters for", ob.name) seq_curves_scale.append(curves_scale) seq.scaleMatters[index] = True frame_indices = [] frame_current = frame_start while frame_current <= frame_end: frame_indices.append(frame_current) if frame_current == frame_end: break frame_current = min(frame_end, frame_current + frame_step) for (curves, mode) in seq_curves_rotation: for frame in frame_indices: if mode == "QUATERNION": r = evaluate_all(curves, frame) elif mode == "XYZ": r = Euler(evaluate_all(curves, frame), "XYZ").to_quaternion() else: assert false, "unknown rotation_mode after finding matters" dsq.rotations.append(Quaternion(r[1], r[2], r[3], -r[0])) for curves in seq_curves_translation: for frame in frame_indices: dsq.translations.append(Vector(evaluate_all(curves, frame))) for curves in seq_curves_scale: for frame in frame_indices: dsq.aligned_scales.append(Vector(evaluate_all(curves, frame))) for name in sequence_missing: print( "Warning: Sequence '{}' exists in flags file, but no markers were found" .format(name)) with open(filepath, "wb") as fd: dsq.write(fd) with open(filepath + ".txt", "w") as fd: dsq.write_dump(fd) return {"FINISHED"}
def nrot(self, n): return Euler((radians(self.nrotx) * n[0], radians(self.nroty) * n[1], radians(self.nrotz) * n[2]), 'XYZ')
def _get_bone_channels(bone_list, action, export_scale): """Takes a bone list and action and returns bone channels. bone_channels structure example: [("Bone", [("_TIME", [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]), ("_MATRIX", [])])]""" bone_channels = [] frame_start = action.frame_range[0] frame_end = action.frame_range[1] total_time = action.scs_props.action_length anim_export_step = action.scs_props.anim_export_step total_frames = (frame_end - frame_start) / anim_export_step # print(' -- action: %r' % str(action)) for bone in bone_list: # print(' oo bone: %r' % str(bone)) if bone: # print(' -- bone_name: %r' % bone.name) bone_name = bone.name bone_rest_mat = bone.matrix_local if bone.parent: parent_bone_rest_mat = Matrix.Scale(export_scale, 4) * _convert_utils.scs_to_blend_matrix().inverted() * bone.parent.matrix_local else: parent_bone_rest_mat = Matrix() for group in action.groups: if group.name == bone_name: # print(' -- group: %r' % str(group)) # GET CHANELS' CURVES loc_curves = {} euler_rot_curves = {} quat_rot_curves = {} sca_curves = {} rot_mode = '' for channel in group.channels: data_path = channel.data_path array_index = channel.array_index # channel_start = channel.range()[0] # channel_end = channel.range()[1] # print(' channel: %r (%s) [%s - %s]' % (data_path, array_index, channel_start, channel_end)) if data_path.endswith("location"): loc_curves[array_index] = channel elif data_path.endswith("rotation_euler"): euler_rot_curves[array_index] = channel rot_mode = 'euler' elif data_path.endswith("rotation_quaternion"): quat_rot_curves[array_index] = channel rot_mode = 'quat' elif data_path.endswith("scale"): sca_curves[array_index] = channel # GO THOUGH FRAMES actual_frame = frame_start timings_stream = [] matrices_stream = [] while actual_frame <= frame_end: mat_loc = Matrix() mat_rot = Matrix() mat_sca = Matrix() # LOCATION MATRIX if len(loc_curves) > 0: location = Vector() for index in range(3): if index in loc_curves: location[index] = loc_curves[index].evaluate(actual_frame) mat_loc = Matrix.Translation(location) # ROTATION MATRIX if rot_mode == 'euler' and len(euler_rot_curves) > 0: rotation = Euler() for index in range(3): if index in euler_rot_curves: rotation[index] = euler_rot_curves[index].evaluate(actual_frame) mat_rot = Euler(rotation, 'XYZ').to_matrix().to_4x4() # TODO: Solve the other rotation modes. if rot_mode == 'quat' and len(quat_rot_curves) > 0: rotation = Quaternion() for index in range(4): if index in quat_rot_curves: rotation[index] = quat_rot_curves[index].evaluate(actual_frame) mat_rot = rotation.to_matrix().to_4x4() # SCALE MATRIX if len(sca_curves) > 0: scale = Vector((1.0, 1.0, 1.0)) for index in range(3): if index in sca_curves: scale[index] = sca_curves[index].evaluate(actual_frame) mat_sca = Matrix() mat_sca[0] = (scale[0], 0, 0, 0) mat_sca[1] = (0, scale[2], 0, 0) mat_sca[2] = (0, 0, scale[1], 0) mat_sca[3] = (0, 0, 0, 1) # BLENDER FRAME MATRIX mat = mat_loc * mat_rot * mat_sca # SCALE REMOVAL MATRIX rest_location, rest_rotation, rest_scale = bone_rest_mat.decompose() # print(' BONES rest_scale: %s' % str(rest_scale)) rest_scale = rest_scale * export_scale scale_removal_matrix = Matrix() scale_removal_matrix[0] = (1.0 / rest_scale[0], 0, 0, 0) scale_removal_matrix[1] = (0, 1.0 / rest_scale[1], 0, 0) scale_removal_matrix[2] = (0, 0, 1.0 / rest_scale[2], 0) scale_removal_matrix[3] = (0, 0, 0, 1) # SCALE MATRIX scale_matrix = Matrix.Scale(export_scale, 4) # COMPUTE SCS FRAME MATRIX frame_matrix = (parent_bone_rest_mat.inverted() * _convert_utils.scs_to_blend_matrix().inverted() * scale_matrix.inverted() * bone_rest_mat * mat * scale_removal_matrix.inverted()) # print(' actual_frame: %s - value: %s' % (actual_frame, frame_matrix)) timings_stream.append(("__time__", total_time / total_frames), ) matrices_stream.append(("__matrix__", frame_matrix.transposed()), ) actual_frame += anim_export_step anim_timing = ("_TIME", timings_stream) anim_matrices = ("_MATRIX", matrices_stream) bone_anim = (anim_timing, anim_matrices) bone_data = (bone_name, bone_anim) bone_channels.append(bone_data) else: lprint('W bone %r is not part of the actual Armature!', bone.name) # print(' -- bone.name: %r' % (bone.name)) return bone_channels
def getRotation(cls, object, name): path = '["AN*Transforms*Rotation*%s"]' % name return Euler(getattr(object, paths, (0.0, 0.0, 0.0)), cls.getRotationOrder(object, name))
def checkFire(self, tembak): now = datetime.datetime.now() jarak = now - self.lastTimeOfFire if tembak == 2: #print("trying to fire weapon {0} with time a : {1} and time b : {2}".format(self.name, str(jarak.seconds), str(self.reloadTime))) if self.mag > -1: if self.ammo > 0: interval = rTimeLeft(jarak, self.interval) if interval <= 0: projectile = None if self.shootOneByOne == False: for barrel in self.barrelsDeviation: if self.hideBarrelAfterShot == True: barrel.parent.visible = False #print("dp scene ialah " + self.scene.name + " dengan objek " + self.self.name) #ator dp deviation nx = random.random() * self.deviation nx = nx - self.deviation / 2 nz = random.random() * self.deviation nz = nz - self.deviation / 2 deviation = Euler((nx, 0.0, nz)) #print([nx, ny, nz, self.deviation]) na = barrel.parent.worldOrientation #na.rotate(deviation) eul = Vector(na.to_euler()) + Vector(deviation) eul = Euler(eul) barrel.worldOrientation = eul.to_matrix() #cek = deviation, na.to_euler(), barrel.worldOrientation.to_euler() #print(cek) projectile = self.scene.addObject( self.shell, barrel, self.timeToLive) else: barrel = self.barrelsDeviation[ self.currentBarrelIndex] if self.hideBarrelAfterShot == True: barrel.parent.visible = False nx = random.random() * self.deviation nx = nx - self.deviation / 2 nz = random.random() * self.deviation nz = nz - self.deviation / 2 deviation = Euler((nx, 0.0, nz)) na = barrel.parent.worldOrientation eul = Vector(na.to_euler()) + Vector(deviation) eul = Euler(eul) barrel.worldOrientation = eul.to_matrix() #print("dp scene ialah " + self.scene.name + " dengan objek " + self.self.name) projectile = self.scene.addObject( self.shell, barrel, self.timeToLive) ''' if 'type' in projectile: if projectile['type'] == "heatSeekingMissile": projectile = KX_SeekingMissile(projectile) else: projectile = KX_Projectile(projectile) else: projectile = KX_Projectile(projectile) self.ammo -= 1 #print('dp putput = ' + str(self.output)) #print("dp velocity = " + str(self.velocity)) projectile.localLinearVelocity = Vector((self.output.x * self.velocity + self.heldBy.localLinearVelocity.x, self.output.y * self.velocity + self.heldBy.localLinearVelocity.y, self.output.z * self.velocity + self.heldBy.localLinearVelocity.z)) #print('projectile has been shot with speed = {0}'.format(projectile.localLinearVelocity)) self.lastTimeOfFire = datetime.datetime.now() projectile.shotWith = self.name projectile.shotBy = self.heldBy projectile.scaling = Vector(self.scale) projectile.target = self.target ''' pb = len(self.barrelsDeviation) if pb > 1: self.currentBarrelIndex += 1 if self.currentBarrelIndex > pb - 1: self.currentBarrelIndex = 0 #rint(self.currentBarrelIndex) if projectile != None: if 'type' in projectile: if projectile['type'] == "heatSeekingMissile": projectile = gameobjects.KX_SeekingMissile( projectile) projectile.target = self.lockedTo projectile.lockOnStatus = self.lockOnStatus else: projectile = gameobjects.KX_Projectile( projectile) else: projectile = gameobjects.KX_Projectile( projectile) self.ammo -= 1 projectile.localLinearVelocity += Vector( (self.output.x * self.velocity + self.heldBy.localLinearVelocity.x, self.output.y * self.velocity + self.heldBy.localLinearVelocity.y, self.output.z * self.velocity + self.heldBy.localLinearVelocity.z)) #print('projectile has been shot with speed = {0}'.format(projectile.localLinearVelocity)) projectile.lastVelocity = projectile.worldLinearVelocity self.lastTimeOfFire = datetime.datetime.now() projectile.shotWith = self.name projectile.shotBy = self.heldBy projectile.scaling = Vector(self.scale) self.shootCount += 1 if self.ammo == 0: if self.reloadStatus == "standBy": self.reloadStatus = "gonnaReload" if self.reloadStatus == "awal": self.mag -= 1 self.reloadStatus = "standBy" if self.reloadStatus == "gonnaReload": self.lastTimeOfFire = datetime.datetime.now() jarak = now - self.lastTimeOfFire self.reloadTimeLeft = rTimeLeft(jarak, self.reloadTime) self.reloadStatus = "isReloading" if self.reloadStatus == "isReloading": jarak = now - self.lastTimeOfFire self.reloadTimeLeft = rTimeLeft(jarak, self.reloadTime) if self.reloadTimeLeft <= 0.0: self.reloadStatus = "reloaded" if self.reloadStatus == "reloaded": if self.mag > 0: self.mag -= 1 self.ammo = self.ammoSize if self.mag == 0 and self.ammo == 0: self.reloadStatus = "abis" else: self.reloadStatus = "standBy" if self.hideBarrelAfterShot == True: for barrel in self.barrels: barrel.visible = True
def main(): # time logging global start_time start_time = time.time() import argparse # parse commandline arguments log_message(sys.argv) parser = argparse.ArgumentParser( description='Generate synth dataset images.') parser.add_argument('--idx', type=int, help='idx of the requested sequence') parser.add_argument('--name', type=str, help='name of the requested sequence') parser.add_argument('--ishape', type=int, help='requested cut, according to the stride') parser.add_argument('--stride', type=int, help='stride amount, default 50') parser.add_argument('--direction', type=str, help='subject direction, default forward') parser.add_argument('--subject_id', type=int, help='local subject id, default 0') args = parser.parse_args(sys.argv[sys.argv.index("---") + 1:]) idx = args.idx name = args.name ishape = args.ishape stride = args.stride direction = args.direction subject_id = args.subject_id log_message("input idx: %d" % idx) log_message("input name: %s" % name) log_message("input ishape: %d" % ishape) log_message("input stride: %d" % stride) log_message("Subject direction: %s" % direction) log_message("Local subject id: %d" % subject_id) if idx == None: exit(1) if ishape == None: exit(1) if stride == None: log_message("WARNING: stride not specified, using default value 50") stride = 50 # import idx info (name, split) idx_info = load(open("pkl/idx_info.pickle", 'rb')) # get runpass (runpass, idx) = divmod(idx, len(idx_info)) log_message("runpass: %d" % runpass) log_message("output idx: %d" % idx) for dic in idx_info: if dic['name'] == name: idx_info = dic break else: idx_info = idx_info[idx] log_message("sequence: %s" % idx_info['name']) log_message("nb_frames: %f" % idx_info['nb_frames']) # import configuration log_message("Importing configuration") import config params = config.load_file('config', 'SYNTH_DATA') smpl_data_folder = params['smpl_data_folder'] smpl_data_filename = params['smpl_data_filename'] bg_path = params['bg_path'] resy = params['resy'] resx = params['resx'] clothing_option = params['clothing_option'] # grey, nongrey or all tmp_path = params['tmp_path'] output_path = params['output_path'] output_types = params['output_types'] stepsize = params['stepsize'] clipsize = params['clipsize'] openexr_py2_path = params['openexr_py2_path'] # compute number of cuts nb_ishape = max( 1, int(np.ceil( (idx_info['nb_frames'] - (clipsize - stride)) / stride))) log_message("Max ishape: %d" % (nb_ishape - 1)) if ishape == None: exit(1) assert (ishape < nb_ishape) # name is set given idx name = idx_info['name'] output_path = join(output_path, 'run%d' % runpass, name.replace(" ", "")) params['output_path'] = output_path tmp_path = join( tmp_path, 'run%d_%s_c%04d' % (runpass, name.replace(" ", ""), (ishape + 1))) params['tmp_path'] = tmp_path # check if already computed # + clean up existing tmp folders if any if exists(tmp_path) and tmp_path != "" and tmp_path != "/": os.system('rm -rf %s' % tmp_path) rgb_vid_filename = "%s_c%04d.mp4" % (join(output_path, name.replace( ' ', '')), (ishape + 1)) # create tmp directory if not exists(tmp_path): mkdir_safe(tmp_path) # >> don't use random generator before this point << # initialize RNG with seeds from sequence id import hashlib s = "synth_data:%d:%d:%d" % (idx, runpass, ishape) seed_number = int(hashlib.sha1(s.encode('utf-8')).hexdigest(), 16) % (10** 8) log_message("GENERATED SEED %d from string '%s'" % (seed_number, s)) random.seed(seed_number) np.random.seed(seed_number) if (output_types['vblur']): vblur_factor = np.random.normal(0.5, 0.5) params['vblur_factor'] = vblur_factor log_message("Setup Blender") # create copy-spher.harm. directory if not exists sh_dir = join(tmp_path, 'spher_harm') if not exists(sh_dir): mkdir_safe(sh_dir) sh_dst = join(sh_dir, 'sh_%02d_%05d.osl' % (runpass, idx)) os.system('cp spher_harm/sh.osl %s' % sh_dst) genders = {0: 'male', 1: 'female'} # pick random gender gender = genders[subject_id % 2] #choice(genders) scene = bpy.data.scenes['Scene'] scene.render.engine = 'CYCLES' bpy.data.materials['Material'].use_nodes = True scene.cycles.shading_system = True scene.use_nodes = True log_message("Listing background images") #bg_names = join(bg_path, '%s_img.txt' % idx_info['use_split']) bg_names = join(bg_path, 'bg.txt') nh_txt_paths = [] with open(bg_names) as f: for line in f: nh_txt_paths.append(join(bg_path, line)) # grab clothing names log_message("clothing: %s" % clothing_option) with open(join(smpl_data_folder, 'textures', '%s_train.txt' % gender)) as f: txt_paths = f.read().splitlines() # if using only one source of clothing if clothing_option == 'nongrey': txt_paths = [k for k in txt_paths if 'nongrey' in k] elif clothing_option == 'grey': txt_paths = [k for k in txt_paths if 'nongrey' not in k] # random clothing texture cloth_img_name = txt_paths[subject_id] #choice(txt_paths) cloth_img_name = join(smpl_data_folder, cloth_img_name) cloth_img = bpy.data.images.load(cloth_img_name) # random background bg_img_name = choice(nh_txt_paths)[:-1] bg_img = bpy.data.images.load(bg_img_name) log_message("Loading parts segmentation") beta_stds = np.load(join(smpl_data_folder, ('%s_beta_stds.npy' % gender))) log_message("Building materials tree") mat_tree = bpy.data.materials['Material'].node_tree create_sh_material(mat_tree, sh_dst, cloth_img) res_paths = create_composite_nodes(scene.node_tree, params, img=bg_img, idx=idx) log_message("Loading smpl data") smpl_data = np.load(join(smpl_data_folder, smpl_data_filename)) log_message("Initializing scene") camera_distance = 11.0 #np.random.normal(8.0, 1) params['camera_distance'] = camera_distance ob, obname, arm_ob, cam_ob = init_scene(scene, params, gender) setState0() ob.select = True bpy.context.scene.objects.active = ob segmented_materials = True #True: 0-24, False: expected to have 0-1 bg/fg log_message("Creating materials segmentation") # create material segmentation if segmented_materials: materials = create_segmentation(ob, params) prob_dressed = { 'leftLeg': .5, 'leftArm': .9, 'leftHandIndex1': .01, 'rightShoulder': .8, 'rightHand': .01, 'neck': .01, 'rightToeBase': .9, 'leftShoulder': .8, 'leftToeBase': .9, 'rightForeArm': .5, 'leftHand': .01, 'spine': .9, 'leftFoot': .9, 'leftUpLeg': .9, 'rightUpLeg': .9, 'rightFoot': .9, 'head': .01, 'leftForeArm': .5, 'rightArm': .5, 'spine1': .9, 'hips': .9, 'rightHandIndex1': .01, 'spine2': .9, 'rightLeg': .5 } else: materials = {'FullBody': bpy.data.materials['Material']} prob_dressed = {'FullBody': .6} orig_pelvis_loc = None random_zrot = 0 if direction == 'forward': random_zrot = -np.pi / 2 orig_pelvis_loc = ( arm_ob.matrix_world.copy() * arm_ob.pose.bones[obname + '_Pelvis'].head.copy()) - Vector( (-1., 0.65, -1.15)) elif direction == 'backward': random_zrot = np.pi / 2 orig_pelvis_loc = ( arm_ob.matrix_world.copy() * arm_ob.pose.bones[obname + '_Pelvis'].head.copy()) - Vector( (-1., 0.65, 2.9)) orig_cam_loc = cam_ob.location.copy() print("CAM LOC:", orig_cam_loc, type(orig_cam_loc)) # unblocking both the pose and the blendshape limits for k in ob.data.shape_keys.key_blocks.keys(): bpy.data.shape_keys["Key"].key_blocks[k].slider_min = -10 bpy.data.shape_keys["Key"].key_blocks[k].slider_max = 10 log_message("Loading body data") cmu_parms, fshapes, name = load_body_data(smpl_data, ob, obname, name, gender=gender) log_message("Loaded body data for %s" % name) nb_fshapes = len(fshapes) #if idx_info['use_split'] == 'train': # fshapes = fshapes[:int(nb_fshapes*0.8)] #elif idx_info['use_split'] == 'test': # fshapes = fshapes[int(nb_fshapes*0.8):] # pick random real body shape shape = fshapes[ subject_id] #choice(fshapes) #+random_shape(.5) can add noise #shape = random_shape(3.) # random body shape # example shapes #shape = np.zeros(10) #average #shape = np.array([ 2.25176191, -3.7883464 , 0.46747496, 3.89178988, 2.20098416, 0.26102114, -3.07428093, 0.55708514, -3.94442258, -2.88552087]) #fat ndofs = 10 scene.objects.active = arm_ob orig_trans = np.asarray(arm_ob.pose.bones[obname + '_Pelvis'].location).copy() # create output directory if not exists(output_path): mkdir_safe(output_path) # spherical harmonics material needs a script to be loaded and compiled scs = [] for mname, material in materials.items(): scs.append(material.node_tree.nodes['Script']) scs[-1].filepath = sh_dst scs[-1].update() rgb_dirname = name.replace(" ", "") + '_c%04d.mp4' % (ishape + 1) rgb_path = join(tmp_path, rgb_dirname) data = cmu_parms[name] fbegin = ishape * stepsize * stride fend = min(ishape * stepsize * stride + stepsize * clipsize, len(data['poses'])) log_message("Computing how many frames to allocate") N = len(data['poses'][fbegin:fend:stepsize]) log_message("Allocating %d frames in mat file" % N) # force recomputation of joint angles unless shape is all zeros curr_shape = np.zeros_like(shape) nframes = len(data['poses'][::stepsize]) matfile_info = join( output_path, name.replace(" ", "") + "_c%04d_info.mat" % (ishape + 1)) log_message('Working on %s' % matfile_info) # allocate dict_info = {} dict_info['bg'] = np.zeros((N, ), dtype=np.object) # background image path dict_info['camLoc'] = np.empty(3) # (1, 3) dict_info['clipNo'] = ishape + 1 dict_info['cloth'] = np.zeros( (N, ), dtype=np.object) # clothing texture image path dict_info['gender'] = np.empty(N, dtype='uint8') # 0 for male, 1 for female dict_info['joints2D'] = np.empty( (2, 24, N), dtype='float32') # 2D joint positions in pixel space dict_info['joints3D'] = np.empty( (3, 24, N), dtype='float32') # 3D joint positions in world coordinates dict_info['light'] = np.empty((9, N), dtype='float32') dict_info['pose'] = np.empty( (data['poses'][0].size, N), dtype='float32') # joint angles from SMPL (CMU) dict_info['sequence'] = name.replace(" ", "") + "_c%04d" % (ishape + 1) dict_info['shape'] = np.empty((ndofs, N), dtype='float32') dict_info['zrot'] = np.empty(N, dtype='float32') dict_info['camDist'] = camera_distance dict_info['stride'] = stride if name.replace(" ", "").startswith('h36m'): dict_info['source'] = 'h36m' else: dict_info['source'] = 'cmu' if (output_types['vblur']): dict_info['vblur_factor'] = np.empty(N, dtype='float32') # for each clipsize'th frame in the sequence get_real_frame = lambda ifr: ifr reset_loc = False batch_it = 0 curr_shape = reset_joint_positions(orig_trans, shape, ob, arm_ob, obname, scene, cam_ob, smpl_data['regression_verts'], smpl_data['joint_regressor']) arm_ob.animation_data_clear() cam_ob.animation_data_clear() # create a keyframe animation with pose, translation, blendshapes and camera motion # LOOP TO CREATE 3D ANIMATION for seq_frame, (pose, trans) in enumerate( zip(data['poses'][fbegin:fend:stepsize], data['trans'][fbegin:fend:stepsize])): iframe = seq_frame scene.frame_set(get_real_frame(seq_frame)) # apply the translation, pose and shape to the character apply_trans_pose_shape(Vector(trans), pose, shape, ob, arm_ob, obname, scene, cam_ob, get_real_frame(seq_frame)) dict_info['shape'][:, iframe] = shape[:ndofs] dict_info['pose'][:, iframe] = pose dict_info['gender'][iframe] = list(genders)[list( genders.values()).index(gender)] if (output_types['vblur']): dict_info['vblur_factor'][iframe] = vblur_factor arm_ob.pose.bones[obname + '_root'].rotation_quaternion = Quaternion( Euler((0, 0, random_zrot), 'XYZ')) arm_ob.pose.bones[obname + '_root'].keyframe_insert( 'rotation_quaternion', frame=get_real_frame(seq_frame)) dict_info['zrot'][iframe] = random_zrot scene.update() # Bodies centered only in each minibatch of clipsize frames if seq_frame == 0 or reset_loc: reset_loc = False new_pelvis_loc = arm_ob.matrix_world.copy() * arm_ob.pose.bones[ obname + '_Pelvis'].head.copy() cam_ob.location = orig_cam_loc.copy() + (new_pelvis_loc.copy() - orig_pelvis_loc.copy()) cam_ob.keyframe_insert('location', frame=get_real_frame(seq_frame)) dict_info['camLoc'] = np.array(cam_ob.location) scene.node_tree.nodes['Image'].image = bg_img for part, material in materials.items(): material.node_tree.nodes['Vector Math'].inputs[1].default_value[:2] = ( 0, 0) # random light sh_coeffs = .7 * (2 * np.random.rand(9) - 1) sh_coeffs[0] = .5 + .9 * np.random.rand( ) # Ambient light (first coeff) needs a minimum is ambient. Rest is uniformly distributed, higher means brighter. sh_coeffs[1] = -.7 * np.random.rand() for ish, coeff in enumerate(sh_coeffs): for sc in scs: sc.inputs[ish + 1].default_value = coeff # iterate over the keyframes and render # LOOP TO RENDER for seq_frame, (pose, trans) in enumerate( zip(data['poses'][fbegin:fend:stepsize], data['trans'][fbegin:fend:stepsize])): scene.frame_set(get_real_frame(seq_frame)) iframe = seq_frame dict_info['bg'][iframe] = bg_img_name dict_info['cloth'][iframe] = cloth_img_name dict_info['light'][:, iframe] = sh_coeffs scene.render.use_antialiasing = False scene.render.filepath = join( rgb_path, 'Image%04d.png' % get_real_frame(seq_frame)) log_message("Rendering frame %d" % seq_frame) # disable render output logfile = '/dev/null' open(logfile, 'a').close() old = os.dup(1) sys.stdout.flush() os.close(1) os.open(logfile, os.O_WRONLY) # Render bpy.ops.render.render(write_still=True) # disable output redirection os.close(1) os.dup(old) os.close(old) # bone locations should be saved after rendering so that the bones are updated bone_locs_2D, bone_locs_3D = get_bone_locs(obname, arm_ob, scene, cam_ob) dict_info['joints2D'][:, :, iframe] = np.transpose(bone_locs_2D) dict_info['joints3D'][:, :, iframe] = np.transpose(bone_locs_3D) reset_loc = (bone_locs_2D.max(axis=-1) > 256).any() or (bone_locs_2D.min(axis=0) < 0).any() arm_ob.pose.bones[obname + '_root'].rotation_quaternion = Quaternion( (1, 0, 0, 0)) # save a .blend file for debugging: # bpy.ops.wm.save_as_mainfile(filepath=join(tmp_path, 'pre.blend')) # save RGB data with ffmpeg (if you don't have h264 codec, you can replace with another one and control the quality with something like -q:v 3) cmd_ffmpeg = 'ffmpeg -y -r 30 -i ' '%s' ' -c:v h264 -pix_fmt yuv420p -crf 23 ' '%s_c%04d.mp4' '' % ( join(rgb_path, 'Image%04d.png'), join(output_path, name.replace(' ', '')), (ishape + 1)) log_message("Generating RGB video (%s)" % cmd_ffmpeg) os.system(cmd_ffmpeg) if (output_types['vblur']): cmd_ffmpeg_vblur = 'ffmpeg -y -r 30 -i ' '%s' ' -c:v h264 -pix_fmt yuv420p -crf 23 -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" ' '%s_c%04d.mp4' '' % ( join(res_paths['vblur'], 'Image%04d.png'), join(output_path, name.replace(' ', '') + '_vblur'), (ishape + 1)) log_message("Generating vblur video (%s)" % cmd_ffmpeg_vblur) os.system(cmd_ffmpeg_vblur) if (output_types['fg']): cmd_ffmpeg_fg = 'ffmpeg -y -r 30 -i ' '%s' ' -c:v h264 -pix_fmt yuv420p -crf 23 ' '%s_c%04d.mp4' '' % ( join(res_paths['fg'], 'Image%04d.png'), join(output_path, name.replace(' ', '') + '_fg'), (ishape + 1)) log_message("Generating fg video (%s)" % cmd_ffmpeg_fg) os.system(cmd_ffmpeg_fg) cmd_tar = 'tar -czvf %s/%s.tar.gz -C %s %s' % (output_path, rgb_dirname, tmp_path, rgb_dirname) log_message("Tarballing the images (%s)" % cmd_tar) os.system(cmd_tar) # save annotation excluding png/exr data to _info.mat file import scipy.io scipy.io.savemat(matfile_info, dict_info, do_compression=True)
def generate(ds_name, tags_list): start_time = time.time() #check if folder exists in render, if not, create folder try: os.mkdir("render/" + ds_name) except Exception: pass data_storage_path = os.getcwd() + "/render/" + ds_name # switch to correct scene bpy.context.window.scene = bpy.data.scenes['Real'] # remove all animation for obj in bpy.context.scene.objects: obj.animation_data_clear() # set up file outputs output_node = bpy.data.scenes['Render'].node_tree.nodes["File Output"] output_node.base_path = data_storage_path np.random.seed(5) waypoints_dict = { 'distance': [#0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5 6, 3, 1, 3, 6, 3, 1 ] , 'offset': [ (0.25, 0.25), (0.5, 0.5), (0.75, 0.75), (0.7, 0.3), (0.5, 0.25), (0.35, 0.5), (0.25, 0.5) ], 'background': [ (0, -90, 0), (0, -105, 15), (0, -120, 30), (0, -120, 15), (0, -120, 0), (0, -105, 0), (0, -90, 0) ], 'pose': np.random.rand(7, 3) * 360, 'lighting': np.random.rand(7, 3) * 360 } waypoints = [] for vals in zip(*waypoints_dict.values()): d = dict(zip(waypoints_dict.keys(), vals)) waypoints.append(starfish.Frame( distance=nm_to_bu(d['distance']), offset=d['offset'], background=Euler(list(map(deg_to_rad, d['background']))), pose=Euler(list(map(deg_to_rad, d['pose']))), lighting=Euler(list(map(deg_to_rad, d['lighting']))) )) counts = [300] * 7 for scene in bpy.data.scenes: scene.unit_settings.scale_length = 1 / SCALE for i, frame in enumerate(starfish.Sequence.interpolated(waypoints, counts)): bpy.context.scene.frame_set(0) frame.setup(bpy.data.scenes['Real'], bpy.data.objects["Gateway"], bpy.data.objects["Camera"], bpy.data.objects["Sun"]) #create name for the current image (unique to that image) name = str(i).zfill(5) output_node.file_slots[0].path = "image_" + "#" + str(name) output_node.file_slots[1].path = "mask_" + "#" + str(name) # render bpy.ops.render.render(scene="Render") # Tag the pictures frame.tags = tags_list # add metadata to frame frame.sequence_name = ds_name mask_filepath = os.path.join(output_node.base_path, "mask_0" + str(name) + ".png") meta_filepath = os.path.join(output_node.base_path, "meta_0" + str(name) + ".json") # run color normalization with labels plus black background postprocessing.normalize_mask_colors(mask_filepath, list(LABEL_MAP.values()) + [(0, 0, 0)]) # get bbox and centroid and add them to metadata frame.bboxes = postprocessing.get_bounding_boxes_from_mask(mask_filepath, LABEL_MAP) frame.centroids = postprocessing.get_centroids_from_mask(mask_filepath, LABEL_MAP) with open(meta_filepath, "w") as f: f.write(frame.dumps()) print("===========================================" + "\r") time_taken = time.time() - start_time print("------Time Taken: %s seconds----------" %(time_taken) + "\r") print("Data stored at: " + data_storage_path) bpy.ops.wm.quit_blender()
def createPencil(name, co, segs=12, tipDepth=.1, height=1, diameter=.033, endTipPerc=15, endTipDia=0.0033, sharpCutOffset=0.01, tilt=45, group=None): def createMaterialNode(obj, colorVal, matName): if (bpy.data.materials.get(matName) == None): mat = bpy.data.materials.new(matName) if (bpy.context.scene.render.engine == 'CYCLES'): mat.use_nodes = True defNode = mat.node_tree.nodes[1] defNode.inputs[0].default_value = colorVal elif (bpy.context.scene.render.engine == 'BLENDER_EEVEE'): mat.diffuse_color = colorVal else: mat = bpy.data.materials[matName] obj.data.materials.append(mat) return mat bm = bmesh.new() bmesh.ops.create_cone(bm, cap_ends=True, segments=segs, depth=tipDepth * (100 - endTipPerc) / 100, diameter1=endTipDia, diameter2=diameter) up = Vector((0, 0, 1)) bm.normal_update() topFace = [f for f in bm.faces if f.normal.angle(up) < radians(3)][0] oldFaces = [f for f in bm.faces] info = bmesh.ops.extrude_face_region(bm, geom=[topFace]) bmesh.ops.translate( bm, vec=Vector((0, 0, height)), verts=[v for v in info["geom"] if isinstance(v, bmesh.types.BMVert)]) for f in bm.faces: if (f not in oldFaces): f.material_index = 0 else: f.material_index = 1 oldFaces = [f for f in bm.faces] offsetVerts = [v for i, v in enumerate(topFace.verts) if i % 2 == 0] bmesh.ops.translate(bm, vec=(0, 0, sharpCutOffset), verts=offsetVerts) info = bmesh.ops.create_cone(bm, cap_ends=True, segments=segs * 2, depth=tipDepth * endTipPerc / 100, diameter1=0, diameter2=endTipDia) bmesh.ops.translate(bm, vec=(0, 0, -tipDepth * .5), verts=info['verts']) for f in bm.faces: if (f not in oldFaces): f.material_index = 2 mesh = bpy.data.meshes.new(name) pObj = bpy.data.objects.new(name, mesh) # ~ bpy.context.scene.collection.objects.link(pObj) #In 2.8 add to group only # ~ bpy.context.scene.update() depsgraph = bpy.context.evaluated_depsgraph_get() depsgraph.update() bm.to_mesh(mesh) bodyColor = [0.00, 0.35, 0.44, 1.00] sharpenedTipColor = [0.80, 0.55, 0.09, 1.00] endTipColor = [0.00, 0.00, 0.00, 1.00] createMaterialNode(pObj, bodyColor, NEW_DATA_PREFIX + 'BodyMat') createMaterialNode(pObj, sharpenedTipColor, NEW_DATA_PREFIX + 'Tip1Mat') createMaterialNode(pObj, endTipColor, NEW_DATA_PREFIX + 'Tip2Mat') #pObj.data.uv_textures.new() # 2.8 Changed? for vert in mesh.vertices: vert.co.z += (tipDepth + tipDepth * endTipPerc / 100) / 2 pObj.rotation_euler = Euler((radians(tilt), 0, 0), 'XYZ') if (group != None): group.objects.link(pObj) return pObj
def __init__(self, name, root, length, chord, incidence, twist, taper, sweep, dihedral): # transform angles to rad sweep *= DEG2RAD twist *= DEG2RAD dihedral *= DEG2RAD incidence *=DEG2RAD # find out if it's a symetric element self.is_symetric = not name.startswith("YASim_vstab") # create the wing mesh object # the wing is first created at ORIGIN w/o incidence/dihedral base = ORIGIN basefore = ORIGIN + 0.5 * chord * X baseaft = ORIGIN - 0.5 * chord * X tip = ORIGIN + (math.cos(sweep) * length * Y) - (math.sin(sweep) * length * X) tipfore = tip + (0.5 * taper * chord * math.cos(twist) * X) + (0.5 * taper * chord * math.sin(twist) * Z) tipaft = tip + tip - tipfore # <1--0--2 # \ | / # 4-3-5 wing_obj = mesh_create(name, ORIGIN, [base, basefore, baseaft, tip, tipfore, tipaft], [], [(0, 1, 4, 3), (2, 0, 3, 5)]) # now transform the mesh # set the created object active !!!!!!! bpy.context.scene.objects.active = wing_obj # get the active mesh mesh = bpy.context.object.data # create a rotation matrix, for dihedral and incidence rotation e = Euler((dihedral, -incidence, 0)) m1 = e.to_matrix() m = m1.to_4x4() # rotate it mesh.transform(m) mesh.update() # position the object #wing_obj.location = root # use the matrix to position it wing_obj.matrix_world = Matrix.Translation(root) # assign materials if self.is_symetric: Item.set_material('tgreen-1', (0.0,0.5,0.0), 0.5) Symetric.list_append(wing_obj) else: Item.set_material('tred-1', (0.5,0.0,0.0), 0.5) # write out the vars for the flaps self.baseaft = baseaft self.tipaft = tipaft self.base = base self.wing_obj = wing_obj self.mesh_matrix = m
#obj_backup.hide = False bpy.context.scene.objects.active = obj_backup obj = obj_backup.copy() # duplicate linked obj.data = obj_backup.data.copy( ) # optional: make this a real duplicate (not linked) obj.name = 'new_2k' obj.hide = False obj.hide_render = False bpy.context.scene.objects.link(obj) # add to scene # obj.parent.pose.bones['Bone.001'].rotation_quaternion = Euler((np.random.uniform(-180,180),np.random.uniform(-180,180),np.random.uniform(-180,180))).to_quaternion() # obj.parent.pose.bones['Bone.005'].location = loc + Vector((np.random.uniform(-3,3),np.random.uniform(-3,3),np.random.uniform(-5,-3))) # bpy.data.objects['Armature'].pose.bones['Bone.005'].location = Vector((def_a, d, def_c)) obj.parent.pose.bones["Bone.001"].rotation_mode = 'XYZ' obj.parent.pose.bones['Bone.001'].rotation_euler = Euler( (np.deg2rad(alpha_range[j, 0]), np.deg2rad(alpha_range[j, 1]), np.deg2rad(alpha_range[j, 2]))) # break applyArmModifier(obj) obj.parent.pose.bones['Bone.001'].location = loc obj.parent = None obj.location = Vector((0, 0, 0)) rotateTranslate(obj, a, b, g, x, y, z) #1.5, 2)#4, 10)#std=3 # break #select and load background image bpy.context.scene.render.filepath = outdir + '{}_{:04}.png'.format( filename, j)