def process(self): if not self.outputs['Quaternions'].is_linked: return inputs = self.inputs quaternion_list = [] 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() quaternion_list.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() quaternion_list.append(q) elif self.mode == "EULER": I = [inputs["Angle " + n].sv_get()[0] for n in "XYZ"] params = match_long_repeat(I) # conversion factor from the current angle units to radians au = self.radians_conversion_factor() for angleX, angleY, angleZ in zip(*params): euler = Euler((angleX * au, angleY * au, angleZ * au), self.euler_order) q = euler.to_quaternion() if self.normalize: q.normalize() quaternion_list.append(q) elif self.mode == "AXISANGLE": I = [inputs[n].sv_get()[0] for n in ["Axis", "Angle"]] params = match_long_repeat(I) # conversion factor from the current angle units to radians au = self.radians_conversion_factor() for axis, angle in zip(*params): q = Quaternion(axis, angle * au) if self.normalize: q.normalize() quaternion_list.append(q) elif self.mode == "MATRIX": input_M = inputs["Matrix"].sv_get(default=id_mat) for m in input_M: q = Matrix(m).to_quaternion() if self.normalize: q.normalize() quaternion_list.append(q) self.outputs['Quaternions'].sv_set(quaternion_list)
def transform_rotation( rotation: Quaternion, transform: Matrix = Matrix.Identity(4)) -> Quaternion: """Transform rotation.""" rotation.normalize() m = rotation.to_matrix().to_4x4() m = transform @ m return m.to_quaternion()
def transform_rot(keyframes, matrix): for frame in keyframes.keys(): axis, angle = Quaternion(keyframes[frame]).to_axis_angle() axis.rotate(matrix) quat = Quaternion(axis, angle) quat.normalize() keyframes[frame] = tuple(quat)
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 transform_rotation(rotation: Quaternion, transform: Matrix = Matrix.Identity(4), need_rotation_correction: bool = False) -> Quaternion: """Transform rotation.""" rotation.normalize() correction = Quaternion((2**0.5 / 2, -2**0.5 / 2, 0.0, 0.0)) m = rotation.to_matrix().to_4x4() if need_rotation_correction: m @= correction.to_matrix().to_4x4() m = transform @ m return m.to_quaternion()
def quaternion_from_two_vectors(dir, up): from io_scene_forsaken import forsaken_utils vU1 = dir vU2 = up vU1.normalize() vU2.normalize() vAxis = vU1.cross(vU2) fAxisMag = forsaken_utils.min(math.sqrt(vAxis.x*vAxis.x+vAxis.y*vAxis.y+vAxis.z*vAxis.z), 1.0) fTheta = math.asin(fAxisMag) fTheta_C = math.pi - fTheta if vU1.dot(vU2) < 0.0: fTheta = fTheta_C fTheta_C = math.pi - fTheta fEpsilon = 1e-7 if fTheta < fEpsilon: qRot = Quaternion() qRot.x = 0.0 qRot.y = 0.0 qRot.z = 0.0 qRot.w = 1.0 return qRot if fTheta_C < fEpsilon: vCP = vU1.cross(Vector((1.0, 0.0, 0.0))) fOpposite = vCP.x*vCP.x+vCP.y*vCP.y+vCP.z*vCP.z if fOpposite >= fEpsilon: vAxis = vCP else: vAxis = Vector((0.0, 1.0, 0.0)) vAxis.normalize() qRot = Quaternion() s = math.sin(fTheta * 0.5) c = math.cos(fTheta * 0.5) qRot.x = vAxis.x * s qRot.y = vAxis.y * s qRot.z = vAxis.z * s qRot.w = c qRot.normalize() return qRot
def rotation_to(a, b): """Calculates shortest Quaternion from Vector a to Vector b""" # a - up vector # b - direction to point to # http://stackoverflow.com/questions/1171849/finding-quaternion-representing-the-rotation-from-one-vector-to-another # https://github.com/toji/gl-matrix/blob/f0583ef53e94bc7e78b78c8a24f09ed5e2f7a20c/src/gl-matrix/quat.js#L54 a = a.normalized() b = b.normalized() q = Quaternion() tmpvec3 = Vector() xUnitVec3 = Vector((1, 0, 0)) yUnitVec3 = Vector((0, 1, 0)) dot = a.dot(b) if (dot < -0.999999): # tmpvec3 = cross(xUnitVec3, a) tmpvec3 = xUnitVec3.cross(a) if (tmpvec3.length < 0.000001): tmpvec3 = yUnitVec3.cross(a) tmpvec3.normalize() # q = Quaternion(tmpvec3, Math.PI) q = Quaternion(tmpvec3, math.pi) elif (dot > 0.999999): q.x = 0 q.y = 0 q.z = 0 q.w = 1 else: tmpvec3 = a.cross(b) q.x = tmpvec3[0] q.y = tmpvec3[1] q.z = tmpvec3[2] q.w = 1 + dot q.normalize() return q
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 == "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 _arc_segment(v_1, v_2): ELorigin = bpy.context.scene.objects['ELorigin'] ELground = bpy.context.scene.objects['ELground'] v = v_2 - v_1 d = v.length ELorigin.location = Vector((0, 0, 0)) ELground.location = Vector((0, 0, -d)) v_L = ELground.location - ELorigin.location q = Quaternion() c = Vector.cross(v_L, v) q.x = c.x q.y = c.y q.z = c.z q.w = sqrt((v_L.length ** 2) * (v.length ** 2)) + \ Vector.dot(v_L, v) q.normalize() euler = q.to_euler() bpy.ops.object.runfslg_operator() laALL = bpy.context.scene.objects['laALL'] laALL.name = 'lARC' laALL.rotation_euler = euler laALL.location = v_1 bpy.context.active_object.select = False laALL.select = True bpy.ops.object.transform_apply(location=True, rotation=True, scale=True) laALL.select = False bpy.context.active_object.select = True return laALL
def _arc_segment(v_1, v_2): ELorigin = bpy.context.scene.objects['ELorigin'] ELground = bpy.context.scene.objects['ELground'] v = v_2 - v_1 d = v.length ELorigin.location = Vector((0, 0, 0)) ELground.location = Vector((0, 0, -d)) v_L = ELground.location - ELorigin.location q = Quaternion() c = Vector.cross(v_L, v) q.x = c.x q.y = c.y q.z = c.z q.w = sqrt((v_L.length ** 2) * (v.length ** 2)) + \ Vector.dot(v_L, v) q.normalize() euler = q.to_euler() bpy.ops.object.runfslg_operator() laALL = bpy.context.scene.objects['laALL'] laALL.name = 'lARC' laALL.rotation_euler = euler laALL.location = v_1 bpy.context.active_object.select = False laALL.select = True bpy.ops.object.transform_apply(location=True, rotation=True, scale=True) laALL.select = False bpy.context.active_object.select = True return laALL
def drawBone2(p1, p2, radiuses, material): length = dist(p1,p2) print('length :',length) v = Vector(diffv(p1, p2)) up = Vector((0,0,1)) if v!=-up: rot = up.rotation_difference(v) else: rot = Quaternion((1,0,0),math.pi) s1 = drawEllipsoid((0,0,-0.5*length),radiuses,material) s2 = drawEllipsoid((0,0,0.5*length),radiuses,material) c1 = drawCylinder(zero,radiuses,length,materials.blue) s1.select = True s2.select = True c1.select = True #bpy.ops.transform.translate(value=(0,0,length/2)) #bpy.ops.object.editmode_toggle() bpy.ops.transform.rotate(value=rot.angle, axis=rot.axis) #bpy.ops.object.editmode_toggle() #bpy.ops.transform.translate(value=Vector((0,0,-0.5*length))*rot.to_matrix()) rot.normalize(); bpy.ops.transform.translate(value=Vector((0,0,0.5*length))*rot.to_matrix()) bpy.ops.transform.translate(value=p1) return (s1,s2,c1)
def transform_rotation(rotation: Quaternion, transform: Matrix = Matrix.Identity(4)) -> Quaternion: """Transform rotation.""" rotation.normalize() m = rotation.to_matrix().to_4x4() m = multiply(transform, m) return m.to_quaternion()
def save(operator, context, filepath=""): bpy.ops.object.mode_set(mode='OBJECT') poseLib = None armature = None for object in bpy.data.objects: if object.type == 'ARMATURE': poseLib = object.pose_library armature = object.data break if poseLib == None or armature == None: raise NameError("Cannot export Pose Library %s, there is no armatures" % filepath) numPoses = len(poseLib.groups[0].channels[4].keyframe_points) numBones = len(poseLib.groups) poseArray = [] nameArray = [] print("Exporting") oglBoneArray = [] oglBoneDirectionArray = [] startNodes = [] for i in range(0, len(armature.bones)): bone = armature.bones[i] if bone.parent == None: dupIndex = -1 for j in range(0, len(startNodes)): if bone.head[:] == startNodes[j][:]: dupIndex = j break if dupIndex == -1: baseNode = bone.head_local startNodes.append((baseNode.x, baseNode.y, baseNode.z)) oglBoneArray.append(-1) oglBoneArray.append(i) boneDirection = bone.tail_local - bone.head_local oglBoneDirectionArray.append(boneDirection) for i in range(0, numPoses): nameArray.append(poseLib.pose_markers[i].name) boneArray = [] for j in range(0, len(oglBoneArray)): index = oglBoneArray[j] q = Quaternion() if index == -1: q = Quaternion([1, 0, 0, 0]) else: quat = Quaternion([1, 0, 0, 0]) for k in range(0, 4): quat[k] = poseLib.groups[index].channels[k + 3].keyframe_points[i].co.y axisVector = Vector([0, 1, 0]) boneVector = oglBoneDirectionArray[index] quatBetween = getQuatBetweenVectors(boneVector, axisVector) q = quatBetween.inverted() * quat * quatBetween q.normalize() boneArray.append(tuple([q.w, q.x, q.z, -q.y])) poseArray.append(boneArray) print(filepath) file = open(filepath, 'w') fw = file.write fw("poslib\n") fw("%d %d\n" % (numPoses, len(oglBoneArray))) for i in range(0, numPoses): fw("n " + nameArray[i] + '\n') for j in range(0, len(oglBoneArray)): q = poseArray[i][j] fw("q %f %f %f %f\n" % (q[0], q[1], q[2], q[3])) fw('f\n') file.close() print("Finished Exporting") return {'FINISHED'}
def execute(self, context): print("Export", self.properties.filepath) version = Version() model = Model() texture = Textures() material = Materials() geosets = [] bones = [] pivotpoints = model.PivotPoints() meshcount = 0 file = open(self.properties.filepath, 'w') for obj in bpy.context.scene.objects: if obj.type == 'MESH': # depsgraph = context.evaluated_depsgraph_get() # mesh = bpy.data.meshes.new_from_object(obj.evaluated_get(depsgraph), preserve_all_data_layers=True, depsgraph=depsgraph) mesh = obj.data mesh.transform(obj.matrix_world) geoset = model.Geoset() mesh.calc_loop_triangles() armatures = [] for modifier in obj.modifiers: if modifier.type == 'ARMATURE' and modifier.use_vertex_groups: armatures.append(modifier.object) for armature in armatures: loadarmature(armature,bones,pivotpoints) # bone_names = set(b.name for b in armature.object.data.bones) for vertex in mesh.vertices: geoset.Vertices.append([vertex.co[0]*20,vertex.co[1]*20,vertex.co[2]*20]) geoset.Normals.append([vertex.normal[0],vertex.normal[1],vertex.normal[2]]) vgroups = sorted(vertex.groups[:], key=lambda x:x.weight, reverse=True) if len(vgroups): group = list(list(filter(lambda b: b.Name == obj.vertex_groups[vg.group].name, bones))[0].ObjectId for vg in vgroups if vg.weight > 0.25)[:3] else: group = [0] if group not in geoset.Groups: geoset.Groups.append(group) geoset.VertexGroup.append(geoset.Groups.index(group)) for group in geoset.Groups: for g in group: bones[g].GeosetId = meshcount geoset.TVertices = [[0.0,0.0]] * len(geoset.Vertices) for tri in mesh.loop_triangles: geoset.Faces.append((tri.vertices[0],tri.vertices[1],tri.vertices[2])) for i in range(3): geoset.TVertices[mesh.loops[tri.loops[i]].vertex_index] = [mesh.uv_layers.active.data[tri.loops[i]].uv[0],1 - mesh.uv_layers.active.data[tri.loops[i]].uv[1]] geosets.append(geoset) meshcount += 1 version.FormatVersion = 800 model.Name = "test" model.NumGeosets = meshcount model.BlendTime = 150 model.NumBones = len(bones) version.write(file) model.write(file) texture.write(file) material.write(file) for geoset in geosets: geoset.write(file) for bone in bones: if bone.ParentName: bone.Parent = list(filter(lambda b: b.Name == bone.ParentName, bones))[0].ObjectId for k,frame in bone.Translation.items(): bone.Translation[k] = list(armature.matrix_world @ Vector(frame)) for k,frame in bone.Rotation.items(): axis, angle = Quaternion(frame).to_axis_angle() axis.rotate(armature.matrix_world) quat = Quaternion(axis, angle) quat.normalize() bone.Rotation[k] = [quat[1],quat[2],quat[3],quat[0]] bone.write(file) pivotpoints.write(file) return {'FINISHED'}