我正在Maya中从头开始构建Sphere
,而不是使用球体顶点列表创建面,我需要创建一个平面并旋转它以使其与常规球体面相匹配。
我的想法是在水平和垂直方向上获得球体的面顶点之间的中心角。这适用于Y
轴,但只要我应用X
旋转,面部的方向就会丢失。
在图像中,我仔细地旋转了X
轴上的一个球面来说明我需要计算什么样的旋转。实现是用Python编写的,所以如果需要的话我可以访问所有的矢量方法。请注意,这个球体实现是出于另一个目的,所以设置可能看起来有点奇怪!
import pymel.core as pm
import pymel.core.datatypes as dt
import pymel.util as util
degrees = util.arrays.degrees
cos = util.arrays.cos
sin = util.arrays.sin
atan2 = util.math.atan2
acos = util.math.acos
sqrt = util.math.sqrt
PI = util.arrays.pi
TWO_PI = PI * 2
def distance(x1, y1, z1, x2, y2, z2):
return sqrt( (x2 - x1) ** 2 + (y2 - y1) ** 2 + (z2 - z1) ** 2 )
# Sphere class
class Sphere():
# Initialise radius (float), subdivisionsAxis (int), subdivisionsHeight (int)
def __init__(self, radius = 10, subdivisionsAxis = 8, subdivisionsHeight = 8):
# Loop through each subdivision on y axis
for i in range(subdivisionsHeight):
if i == 0 or i == subdivisionsHeight - 1:
# Store the triangle vertices's in this list
data = self.generateSphereData(radius, subdivisionsAxis, subdivisionsHeight, i, 'triangle')
length = len(data) / 11
for j in range(length):
index = j * 11
x1 = data[index]
y1 = data[index + 1]
z1 = data[index + 2]
x2 = data[index + 3]
y2 = data[index + 4]
z2 = data[index + 5]
x3 = data[index + 6]
y3 = data[index + 7]
z3 = data[index + 8]
# Angle y
ay = data[index + 9]
# Angle z
az = data[index + 10]
v1 = dt.FloatVector(x1, y1, z1)
v2 = dt.FloatVector(x2, y2, z2)
v3 = dt.FloatVector(x3, y3, z3)
# Ignore the top and bottom triangles for now...
# pm.polyCreateFacet( p = [ v1, v2, v3 ] )
else:
# Store the quads vertices's in this list
data = self.generateSphereData(radius, subdivisionsAxis, subdivisionsHeight, i, 'quad')
length = len(data) / 14
for j in range(length):
index = j * 14
x1 = data[index]
y1 = data[index + 1]
z1 = data[index + 2]
x2 = data[index + 3]
y2 = data[index + 4]
z2 = data[index + 5]
x3 = data[index + 6]
y3 = data[index + 7]
z3 = data[index + 8]
x4 = data[index + 9]
y4 = data[index + 10]
z4 = data[index + 11]
# Angle y
ay = data[index + 12]
# Angle z
az = data[index + 13]
v1 = dt.FloatVector(x1, y1, z1)
v2 = dt.FloatVector(x2, y2, z2)
v3 = dt.FloatVector(x3, y3, z3)
v4 = dt.FloatVector(x4, y4, z4)
# Calculate centroid
cx = (x1 + x2 + x3 + x4) / 4
cy = (y1 + y2 + y3 + y4) / 4
cz = (z1 + z2 + z3 + z4) / 4
# Calculate the width and height
# Calculate dimensions for facet
tw = distance(x1, y1, z1, x4, y4, z4)
bw = distance(x2, y2, z2, x3, y3, z3)
w = tw if bw < tw else bw
h = distance(x2, y2, z2, x1, y1, z1)
# Calculate rotation of face
centroid = dt.FloatVector(cx, cy, cz)
mesh = pm.polyPlane(width=1, height=1, subdivisionsX=1, subdivisionsY=1, axis=(1, 0, 0))
mesh[0].setTranslation(centroid)
mesh[0].setRotation([0, degrees(-ay), 0])
pm.spaceLocator(p=v1)
pm.spaceLocator(p=v2)
pm.spaceLocator(p=v3)
pm.spaceLocator(p=v4)
# pm.polyCreateFacet( p = [ v1, v2, v3, v4 ] )
# Generate a vertex list of the spheres current subdivision height level
# Arguments: radius (float), subdivisionsAxis (int), subdivisionsHeight (int), index (int), polygonType (string)
def generateSphereData(self, radius, subdivisionsAxis, subdivisionsHeight, index, polygonType):
positions = []
if polygonType == 'triangle':
for i in range(subdivisionsAxis):
# If were generating the top triangles we need the triangle base to
# Be at the previous subdivision level, so change the index to index - 1
if index < subdivisionsHeight:
nextIndex = index + 1
else:
nextIndex = index - 1
if i < subdivisionsAxis - 1:
j = i + 1
else:
j = 0
# Top vertex
r1 = radius * sin(index * (PI / subdivisionsAxis))
x1 = r1 * cos(i * (TWO_PI / subdivisionsAxis))
y1 = radius * cos(index * (PI / subdivisionsHeight))
z1 = r1 * sin(i * (TWO_PI / subdivisionsAxis))
# Left vertex
r2 = radius * sin(nextIndex * (PI / subdivisionsAxis))
x2 = r2 * cos(i * (TWO_PI / subdivisionsAxis))
y2 = radius * cos(nextIndex * (PI / subdivisionsHeight))
z2 = r2 * sin(i * (TWO_PI / subdivisionsAxis))
# Right vertex
x3 = r2 * cos(j * (TWO_PI / subdivisionsAxis))
y3 = radius * cos(nextIndex * (PI / subdivisionsHeight))
z3 = r2 * sin(j * (TWO_PI / subdivisionsAxis))
# Calculate angles
ay = 0
az = 0
positions += [x1, y1, z1, x2, y2, z2, x3, y3, z3, ay, az]
elif polygonType == 'quad':
nextIndex = index + 1
for i in range(subdivisionsAxis):
if i < subdivisionsAxis - 1:
j = i + 1
else:
j = 0
# Bottom y
r1 = radius * sin(index * (PI / subdivisionsAxis))
y1 = radius * cos(index * (PI / subdivisionsHeight))
# Top y
r2 = radius * sin(nextIndex * (PI / subdivisionsAxis))
y2 = radius * cos(nextIndex * (PI / subdivisionsHeight))
# Top left vertex
x1 = r2 * cos(i * (TWO_PI / subdivisionsAxis))
z1 = r2 * sin(i * (TWO_PI / subdivisionsAxis))
# Bottom left vertex
x2 = r1 * cos(i * (TWO_PI / subdivisionsAxis))
z2 = r1 * sin(i * (TWO_PI / subdivisionsAxis))
# Bottom right vertex
x3 = r1 * cos(j * (TWO_PI / subdivisionsAxis))
z3 = r1 * sin(j * (TWO_PI / subdivisionsAxis))
# Top right vertex
x4 = r2 * cos(j * (TWO_PI / subdivisionsAxis))
z4 = r2 * sin(j * (TWO_PI / subdivisionsAxis))
# Calculate angles
ay1 = i * (TWO_PI / subdivisionsAxis)
ay2 = j * (TWO_PI / subdivisionsAxis)
ay = ay1 + ((ay2 - ay1) / 2)
az1 = index * (PI / subdivisionsHeight)
az2 = nextIndex * (PI / subdivisionsHeight)
az = az1 + ((az2 - az1) / 2)
positions += [x1, y2, z1, x2, y1, z2, x3, y1, z3, x4, y2, z4, ay, az]
return positions
Sphere(20, 8, 8)
答案 0 :(得分:1)
好吧,伪代码。怎么样:
planeNormal = cross(plane.firstEdge, plane.secondEdge)
faceNormal = cross(face.firstEdge, face.secondEdge)
normalize(planeNormal)
normalize(faceNormal)
if dot(planeNormal, faceNormal)<0 # if they're more than 90 degrees apart
rotate(plane, plane.firstEdge, pi) # rotate the plane 180 degrees
planeNormal = -planeNormal
axis = cross(planeNormal, faceNormal)
angle = arccos(magnitude(axis))
normalize(axis)
rotate(plane, axis, angle)
答案 1 :(得分:0)
如果我正确地阅读了你的问题,你想对一堆四边形和三角形应用一个旋转,这样它们就可以形成一个球面。我相信你真正想要问的是如何旋转四边形和三元组的集合,以便垂直于形状中心的向量与所需点相交。那个理想的点是你球体的中心。
让我们打破这个!以下是您要执行的操作的伪代码:
for i,shape in enumerate(listOfShapes):
[nc1,nc2] = normal_of_center(shape)
R = rotationFrom2Vecs([nc1,nc2],[s,nc2])
listOfShapes[i] = shape*R
对于每个形状(形状只是3或4个点的列表),您可以计算与形状垂直并以该形状中心为中心的矢量。这个向量只有两点:[nc1,nc2](提示nc2:只是所讨论形状的平均坐标,nc1是放置在由形状定义的平面法线上的任何点)。
我们要做的下一件事是计算此向量与将形状中心(nc2)连接到球体中心的向量之间的旋转矩阵R. But how the heck do I calculate a 3x3 rotation matrix from 2 vectors, you're probably asking yourself?
最后,通过右乘法将此旋转矩阵应用于形状,由于矩阵乘法的规则,这是唯一有效的方法。我不熟悉pymel,我不知道它是否有矩阵乘法程序。如果不是,您将需要使用numpy数组和矩阵,这些数组和矩阵非常简单,方便此类项目。
如果你对整体想法感到困惑,我可以绘制一些快速而肮脏的图表。这是最快的方式吗?不。但它肯定是最清晰的方法。