|

楼主 |
发表于 2012-11-19 11:37:45
|
显示全部楼层
直接跑到irc的blendercoders频道求人去了,果然有大神帮我了,不过还是不太理解反转矩阵那些部分。
感谢:brecht
The problem is in how you transform the normals. The python API does not make an automatic distinction between position and normal vectors, but they need to be transformed differently by matrices.
For normals the translation component should be ignored (as normals are invariant under translations). That's the cause of the mismatch here. Another issue happens when an object has non-uniform scale, in that case you need to use the inverse transpose.
Here's the modified code that should work, note NormalTransformMatrix:
- import bpy
- import random
- from math import degrees, radians
- from mathutils import Vector
- def MergeMeshSoWeCanCheckTheNormals(context, ob1, ob2):
- context.scene.objects.active = ob2
- ob1.select = ob2.select = True
- bpy.ops.object.join()
- ob = context.active_object
- bpy.ops.object.editmode_toggle()
- return
- def NormalTransformMatrix(m):
- m_normal = m.inverted().transposed()
- m_normal[0][3] = 0.0
- m_normal[1][3] = 0.0
- m_normal[2][3] = 0.0
-
- return m_normal
- def MatchPoint0(context, ob1, ob2):
- """
- static = ob1
- dynamic = ob2
- """
- vt1 = ob1.data.vertices[0]
- vt2 = ob2.data.vertices[0]
-
- #location match
- m1 = ob1.matrix_world.copy()
- m2 = ob2.matrix_world.copy()
- loc1 = m1 * vt1.co.copy()
- loc2 = m2 * vt2.co.copy()
- bpy.ops.object.select_all(action='DESELECT')
- context.scene.objects.active = ob2
- ob2.select = True
- bpy.ops.transform.translate(value=loc1 - loc2)
- context.scene.cursor_location = loc1
- bpy.ops.object.origin_set(type='ORIGIN_CURSOR', center='MEDIAN')
-
- #So, We can keep on caculate rotation match
- #Caculate again cuz of ob2 is moved
- m1 = NormalTransformMatrix(ob1.matrix_world.copy())
- m2 = NormalTransformMatrix(ob2.matrix_world.copy())
- n1 = (m1 * vt1.normal.copy()).normalized()
- print('v1 :: lNor:%s gNor:%s' % (vt1.normal.copy(), n1))
- n2 = (m2 * vt2.normal.copy()).normalized()
- print('v2 :: lNor:%s gNor:%s' % (vt2.normal.copy(), n2))
-
- angle = n1.angle(n2)
- cross = n1.cross(n2)
- dot = n1.dot(n2)
-
- print('before::\naxis: %s \nangle: %s \ndot: %s\n' % (cross, angle, dot))
- if dot>0:
- angle *= -1
- #euler = m2.Rotation(angle, 4, cross).to_euler()
- #ob2.rotation_euler = euler
- bpy.ops.transform.rotate(value=angle, axis=cross)
-
- ##############################################################
- m1 = NormalTransformMatrix(ob1.matrix_world.copy())
- m2 = NormalTransformMatrix(ob2.matrix_world.copy())
- n1 = (m1 * vt1.normal.copy()).normalized()
- n2 = (m2 * vt2.normal.copy()).normalized()
- angle = n1.angle(n2)
- cross = n1.cross(n2)
- dot = n1.dot(n2)
- print('before::\naxis: %s \nangle: %s \ndot: %s' % (cross, angle, dot))
- return
- def PrepareMesh(ob):
- """init"""
- bpy.ops.object.editmode_toggle()
- bpy.ops.mesh.select_all(action = 'DESELECT')
- bpy.ops.object.editmode_toggle()
- vt0 = ob.data.vertices[0]
- vt0.select = True
- for i in range(len(vt0.co.copy())):
- vt0.co[i] += random.uniform(0.1, 1)
- ob.data.update()
- ob.data.show_normal_vertex = True
- print('ob Name: %s -vt0- ::\nlocation: %s \nnormal: %s\n' % (ob.name, vt0.co, vt0.normal))
- return
-
- def main(context):
- print('\n\n--->>>')
- # Creating and Preparing
- bpy.ops.mesh.primitive_cube_add(view_align=True, location=(0, 0, 0), rotation=(10, 20, 30))
- ob1 = context.active_object
- PrepareMesh(ob1)
- ob2 = bpy.ops.mesh.primitive_cube_add(view_align=True, location=(3, 0.5, 0), rotation=(40, 50, 60))
- ob2 = context.active_object
- PrepareMesh(ob2)
-
- # Main working
- # static = ob1
- # dynamic = ob2
- context.tool_settings.mesh_select_mode = (True, False, False)
- MatchPoint0(context, ob1, ob2)
- MergeMeshSoWeCanCheckTheNormals(context, ob1, ob2)
- # Goto 3dView check two normals
-
- class SimpleOperator(bpy.types.Operator):
- """Tooltip"""
- bl_idname = "object.simple_operator"
- bl_label = "Simple Object Operator"
- def execute(self, context):
- main(context)
- return {'FINISHED'}
- def register():
- bpy.utils.register_class(SimpleOperator)
- def unregister():
- bpy.utils.unregister_class(SimpleOperator)
- if __name__ == "__main__":
- register()
- # test call
- bpy.ops.object.simple_operator()
复制代码 By the way, most of the .copy() calls in the code are not needed, though they don't hurt. |
|