BlenderCN论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 2011|回复: 2

如何对齐两个 来自不同模型的 点的法线?

[复制链接]
发表于 2012-11-18 21:08:26 | 显示全部楼层 |阅读模式
本帖最后由 nirenyang 于 2012-11-18 23:00 编辑

这个问题困扰我很久了,单个模型里的对齐是没问题的,但是不知道为何两个模型的元素对齐卡这么久。

运行代码,帮我看看,谢谢~

  1. import bpy

  2. import random
  3. from math import degrees, radians
  4. from mathutils import Vector


  5. def MergeMeshSoWeCanCheckTheNormals(context, ob1, ob2):
  6.     context.scene.objects.active = ob2
  7.     ob1.select = ob2.select = True
  8.     bpy.ops.object.join()
  9.     ob = context.active_object
  10.     bpy.ops.object.editmode_toggle()
  11.     return

  12. def MatchPoint0(context, ob1, ob2):
  13.     """
  14.     static = ob1
  15.     dynamic = ob2
  16.     """
  17.     vt1 = ob1.data.vertices[0]
  18.     vt2 = ob2.data.vertices[0]
  19.    
  20.     #location match
  21.     m1 = ob1.matrix_world.copy()
  22.     m2 = ob2.matrix_world.copy()
  23.     loc1 = m1 * vt1.co.copy()
  24.     loc2 = m2 * vt2.co.copy()
  25.     bpy.ops.object.select_all(action='DESELECT')
  26.     context.scene.objects.active = ob2
  27.     ob2.select = True
  28.     bpy.ops.transform.translate(value=loc1 - loc2)
  29.     context.scene.cursor_location = loc1
  30.     bpy.ops.object.origin_set(type='ORIGIN_CURSOR', center='MEDIAN')
  31.    
  32.     #So, We can keep on caculate rotation match
  33.     #Caculate again cuz of ob2 is moved
  34.     m2 = ob2.matrix_world.copy()
  35.     n1 = (m1 * vt1.normal.copy()).normalized()
  36.     print('v1  ::  lNor:%s gNor:%s' % (vt1.normal.copy(), n1))
  37.     n2 = (m2 * vt2.normal.copy()).normalized()
  38.     print('v2  ::  lNor:%s gNor:%s' % (vt2.normal.copy(), n2))
  39.    
  40.     angle = n1.angle(n2)
  41.     cross = n1.cross(n2)
  42.     dot = n1.dot(n2)
  43.    
  44.     print('before::\naxis: %s \nangle: %s \ndot: %s\n' % (cross, angle, dot))
  45.     if dot>0:
  46.         angle *= -1
  47.     #euler = m2.Rotation(angle, 4, cross).to_euler()
  48.     #ob2.rotation_euler = euler
  49.     bpy.ops.transform.rotate(value=angle, axis=cross)
  50.    
  51.     ##############################################################
  52.     m2 = ob2.matrix_world.copy()
  53.     n1 = (m1 * vt1.normal.copy()).normalized()
  54.     n2 = (m2 * vt2.normal.copy()).normalized()
  55.     angle = n1.angle(n2)
  56.     cross = n1.cross(n2)
  57.     dot = n1.dot(n2)
  58.     print('before::\naxis: %s \nangle: %s \ndot: %s' % (cross, angle, dot))
  59.     return

  60. def PrepareMesh(ob):
  61.     """init"""
  62.     bpy.ops.object.editmode_toggle()
  63.     bpy.ops.mesh.select_all(action = 'DESELECT')
  64.     bpy.ops.object.editmode_toggle()
  65.     vt0 = ob.data.vertices[0]
  66.     vt0.select = True
  67.     for i in range(len(vt0.co.copy())):
  68.         vt0.co[i] += random.uniform(0.1, 1)
  69.     ob.data.update()
  70.     ob.data.show_normal_vertex = True
  71.     print('ob Name: %s -vt0- ::\nlocation: %s  \nnormal: %s\n' % (ob.name, vt0.co, vt0.normal))
  72.     return
  73.    
  74. def main(context):
  75.     print('\n\n--->>>')
  76.     # Creating and Preparing
  77.     bpy.ops.mesh.primitive_cube_add(view_align=True, location=(0, 0, 0), rotation=(10, 20, 30))
  78.     ob1 = context.active_object
  79.     PrepareMesh(ob1)
  80.     ob2 = bpy.ops.mesh.primitive_cube_add(view_align=True, location=(3, 0.5, 0), rotation=(40, 50, 60))
  81.     ob2 = context.active_object
  82.     PrepareMesh(ob2)
  83.    
  84.     # Main working
  85.     # static = ob1
  86.     # dynamic = ob2
  87.     context.tool_settings.mesh_select_mode = (True, False, False)
  88.     MatchPoint0(context, ob1, ob2)
  89.     MergeMeshSoWeCanCheckTheNormals(context, ob1, ob2)
  90.     # Goto 3dView check two normals
  91.    



  92. class SimpleOperator(bpy.types.Operator):
  93.     """Tooltip"""
  94.     bl_idname = "object.simple_operator"
  95.     bl_label = "Simple Object Operator"

  96.     def execute(self, context):
  97.         main(context)
  98.         return {'FINISHED'}


  99. def register():
  100.     bpy.utils.register_class(SimpleOperator)


  101. def unregister():
  102.     bpy.utils.unregister_class(SimpleOperator)


  103. if __name__ == "__main__":
  104.     register()

  105.     # test call
  106.     bpy.ops.object.simple_operator()

复制代码

在BA也问了,不过英文实在很菜,沟通起来还是有点别扭。
http://blenderartists.org/forum/showthread.php?272472-How-to-match-two-Normals-direction&p=2243567#post2243567

 楼主| 发表于 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:

  1. import bpy


  2. import random
  3. from math import degrees, radians
  4. from mathutils import Vector




  5. def MergeMeshSoWeCanCheckTheNormals(context, ob1, ob2):
  6.     context.scene.objects.active = ob2
  7.     ob1.select = ob2.select = True
  8.     bpy.ops.object.join()
  9.     ob = context.active_object
  10.     bpy.ops.object.editmode_toggle()
  11.     return


  12. def NormalTransformMatrix(m):
  13.     m_normal = m.inverted().transposed()
  14.     m_normal[0][3] = 0.0
  15.     m_normal[1][3] = 0.0
  16.     m_normal[2][3] = 0.0
  17.    
  18.     return m_normal


  19. def MatchPoint0(context, ob1, ob2):
  20.     """
  21.     static = ob1
  22.     dynamic = ob2
  23.     """
  24.     vt1 = ob1.data.vertices[0]
  25.     vt2 = ob2.data.vertices[0]
  26.    
  27.     #location match
  28.     m1 = ob1.matrix_world.copy()
  29.     m2 = ob2.matrix_world.copy()
  30.     loc1 = m1 * vt1.co.copy()
  31.     loc2 = m2 * vt2.co.copy()
  32.     bpy.ops.object.select_all(action='DESELECT')
  33.     context.scene.objects.active = ob2
  34.     ob2.select = True
  35.     bpy.ops.transform.translate(value=loc1 - loc2)
  36.     context.scene.cursor_location = loc1
  37.     bpy.ops.object.origin_set(type='ORIGIN_CURSOR', center='MEDIAN')
  38.    
  39.     #So, We can keep on caculate rotation match
  40.     #Caculate again cuz of ob2 is moved
  41.     m1 = NormalTransformMatrix(ob1.matrix_world.copy())
  42.     m2 = NormalTransformMatrix(ob2.matrix_world.copy())
  43.     n1 = (m1 * vt1.normal.copy()).normalized()
  44.     print('v1  ::  lNor:%s gNor:%s' % (vt1.normal.copy(), n1))
  45.     n2 = (m2 * vt2.normal.copy()).normalized()
  46.     print('v2  ::  lNor:%s gNor:%s' % (vt2.normal.copy(), n2))
  47.    
  48.     angle = n1.angle(n2)
  49.     cross = n1.cross(n2)
  50.     dot = n1.dot(n2)
  51.    
  52.     print('before::\naxis: %s \nangle: %s \ndot: %s\n' % (cross, angle, dot))
  53.     if dot>0:
  54.         angle *= -1
  55.     #euler = m2.Rotation(angle, 4, cross).to_euler()
  56.     #ob2.rotation_euler = euler
  57.     bpy.ops.transform.rotate(value=angle, axis=cross)
  58.    
  59.     ##############################################################
  60.     m1 = NormalTransformMatrix(ob1.matrix_world.copy())
  61.     m2 = NormalTransformMatrix(ob2.matrix_world.copy())
  62.     n1 = (m1 * vt1.normal.copy()).normalized()
  63.     n2 = (m2 * vt2.normal.copy()).normalized()
  64.     angle = n1.angle(n2)
  65.     cross = n1.cross(n2)
  66.     dot = n1.dot(n2)
  67.     print('before::\naxis: %s \nangle: %s \ndot: %s' % (cross, angle, dot))
  68.     return


  69. def PrepareMesh(ob):
  70.     """init"""
  71.     bpy.ops.object.editmode_toggle()
  72.     bpy.ops.mesh.select_all(action = 'DESELECT')
  73.     bpy.ops.object.editmode_toggle()
  74.     vt0 = ob.data.vertices[0]
  75.     vt0.select = True
  76.     for i in range(len(vt0.co.copy())):
  77.         vt0.co[i] += random.uniform(0.1, 1)
  78.     ob.data.update()
  79.     ob.data.show_normal_vertex = True
  80.     print('ob Name: %s -vt0- ::\nlocation: %s  \nnormal: %s\n' % (ob.name, vt0.co, vt0.normal))
  81.     return
  82.    
  83. def main(context):
  84.     print('\n\n--->>>')
  85.     # Creating and Preparing
  86.     bpy.ops.mesh.primitive_cube_add(view_align=True, location=(0, 0, 0), rotation=(10, 20, 30))
  87.     ob1 = context.active_object
  88.     PrepareMesh(ob1)
  89.     ob2 = bpy.ops.mesh.primitive_cube_add(view_align=True, location=(3, 0.5, 0), rotation=(40, 50, 60))
  90.     ob2 = context.active_object
  91.     PrepareMesh(ob2)
  92.    
  93.     # Main working
  94.     # static = ob1
  95.     # dynamic = ob2
  96.     context.tool_settings.mesh_select_mode = (True, False, False)
  97.     MatchPoint0(context, ob1, ob2)
  98.     MergeMeshSoWeCanCheckTheNormals(context, ob1, ob2)
  99.     # Goto 3dView check two normals
  100.    






  101. class SimpleOperator(bpy.types.Operator):
  102.     """Tooltip"""
  103.     bl_idname = "object.simple_operator"
  104.     bl_label = "Simple Object Operator"


  105.     def execute(self, context):
  106.         main(context)
  107.         return {'FINISHED'}




  108. def register():
  109.     bpy.utils.register_class(SimpleOperator)




  110. def unregister():
  111.     bpy.utils.unregister_class(SimpleOperator)




  112. if __name__ == "__main__":
  113.     register()


  114.     # test call
  115.     bpy.ops.object.simple_operator()
复制代码
By the way, most of the .copy() calls in the code are not needed, though they don't hurt.
回复 支持 反对

使用道具 举报

发表于 2012-11-23 11:56:51 | 显示全部楼层
本帖最后由 么么神人 于 2012-11-23 11:57 编辑

只看懂前面开头定义了三个变量 context, ob1, ob2 后面云里雾绕
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

站长推荐上一条 /1 下一条

Blender最新中文教学视频|Blender头条|小黑屋|手机版|Archiver|Blender中国 ( 蜀ICP备17002929号 )360网站安全检测平台

GMT+8, 2019-12-9 15:12 , Processed in 0.022442 second(s), 17 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表