You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

获取两点方向并在起点绘圆:解决缩放异常问题

问题:基于两点方向绘制圆时缩放异常的解决方案

需求与问题场景

已知两个顶点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的距离不一致,圆出现缩放变形。

解决方案

改用矩阵旋转+平移的方式生成圆,确保圆的大小始终稳定:

  1. 在局部坐标系生成固定半径的标准圆顶点
  2. 计算旋转矩阵,将局部圆旋转到与s-e方向垂直的平面
  3. 通过平移矩阵将圆移动到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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 03:25:29