I'm building a Sphere
from scratch in Maya, rather than creating faces using the spheres vertex list I need to make a plane and rotate it so it would match a regular spheres face.
My idea was to get the center angle between the Sphere's face vertices's horizontally and vertically. This works for the Y
axis, but as soon as I apply an X
rotation the orientation of the face is lost.
In the image I've deliberatively rotated one of the Sphere faces on the X
axis to illustrate what kind of rotation I need to calculate. The implementation is written in Python so I've got access to all the vector methods if needed. Please note this sphere implementation is for another purpose so the setup may seem a little odd!
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)