获取两点方向并在起点绘圆:解决缩放异常问题
问题:基于两点方向绘制圆时缩放异常的解决方案
需求与问题场景
已知两个顶点s和e,需要以s为圆心,绘制一个与s-e方向垂直的圆。当前实现代码在移动两点时,圆会出现缩放变形的问题。
原实现代码:
import bpy import mathutils obj = bpy.data.objects["Plane"] s = obj.data.vertices[0].co e = obj.data.vertices[1].co v = e-s v = v.normalized() mesh = bpy.data.meshes.new("test") # add the new mesh obj = bpy.data.objects.new(mesh.name, mesh) col = bpy.data.collections["Collection"] col.objects.link(obj) bpy.context.view_layer.objects.active = obj verts = [] edges = [] faces = [] b_0 = mathutils.Vector((0.0000, 0.5000, 0.0000)) b_1 = mathutils.Vector((0.3909, 0.3117, 0.0000)) b_2 = mathutils.Vector((0.4875, -0.1113, 0.0000)) b_3 = mathutils.Vector((0.2169, -0.4505, 0.0000)) b_4 = mathutils.Vector((-0.2169, -0.4505, 0.0000)) b_5 = mathutils.Vector((-0.4875, -0.1113, 0.0000)) b_6 = mathutils.Vector((-0.3909, 0.3117, 0.0000)) v_0 = v.cross(b_0) + s v_1 = v.cross(b_1) + s v_2 = v.cross(b_2) + s v_3 = v.cross(b_3) + s v_4 = v.cross(b_4) + s v_5 = v.cross(b_5) + s v_6 = v.cross(b_6) + s verts.append(v_0) verts.append(v_1) verts.append(v_2) verts.append(v_3) verts.append(v_4) verts.append(v_5) verts.append(v_6) faces.append([0, 1, 2, 3, 4, 5, 6]) mesh.from_pydata(verts, edges, faces)
问题原因
原代码使用向量叉乘v.cross(b_n)生成圆顶点,叉乘结果的模长为|v| * |b_n| * sinθ(θ是v与b_n的夹角)。虽然v已归一化,但两点方向变化时θ会改变,导致sinθ值波动,最终每个顶点到s的距离不一致,圆出现缩放变形。
解决方案
改用矩阵旋转+平移的方式生成圆,确保圆的大小始终稳定:
- 在局部坐标系生成固定半径的标准圆顶点
- 计算旋转矩阵,将局部圆旋转到与
s-e方向垂直的平面 - 通过平移矩阵将圆移动到
s点位置
修正后的代码:
import bpy import math import mathutils def circle(subdivision, r, start, end): # 获取两点方向向量并归一化 v = end - start v = v.normalized() # 创建网格与对象 mesh = bpy.data.meshes.new("test") obj = bpy.data.objects.new(mesh.name, mesh) col = bpy.data.collections["Collection"] col.objects.link(obj) bpy.context.view_layer.objects.active = obj verts = [] edges = [] faces = [] # 生成局部坐标系下的圆顶点 for i in range(subdivision): x = math.cos(2 * math.pi / subdivision * i) * r y = math.sin(2 * math.pi / subdivision * i) * r v_local = mathutils.Vector((x, y, 0)) # 计算旋转矩阵:将局部圆旋转到与v垂直的平面 axis = mathutils.Vector((0.0, 0.0, 1.0)) angle = v.angle(axis, 0.0) mat_rot = mathutils.Matrix.Rotation(angle, 4, axis.cross(v)) # 计算平移矩阵:将圆移动到起点位置 mat_pos = mathutils.Matrix.Translation(start) # 合并旋转与平移矩阵 mat = mat_pos @ mat_rot # 将局部顶点转换到全局坐标系 v_global = mat @ v_local verts.append(v_global) # 创建圆面 face = list(range(subdivision)) faces.append(face) mesh.from_pydata(verts, edges, faces) # 获取平面的两个顶点 obj = bpy.data.objects["Plane"] start = obj.data.vertices[0].co end = obj.data.vertices[1].co # 调用函数生成圆:参数为细分数量、半径、起点、终点 circle(10, 1, start, end)
说明
- 矩阵变换确保了圆的顶点与起点始终保持固定距离,无论两点方向如何变化,圆的大小都不会出现异常缩放
- 可通过调整
subdivision(细分数量)控制圆的平滑度,r控制圆的半径
内容的提问来源于stack exchange,提问作者Christoph Müller
相关产品推荐
相关产品推荐

