Я создаю Sphere
с нуля в Maya, вместо того, чтобы создавать грани, используя список вершин сфер, мне нужно сделать плоскость и повернуть ее, чтобы она соответствовала обычной грани сфер.
Моя идея состояла в том, чтобы получить центральный угол между вершинами грани Сферы по горизонтали и вертикали. Это работает для оси 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)