I know that I can point a model’s y axis at a certain point, but how would I find a rotation such that its y axis is pointing at one point and its z axis is pointing at another, provided that the two vectors from the model to the points are at right angles to each other?

Hmm… Have you tried the “headsUp” method? Judging by the description, it may do what you want. There also seems to be a version of “lookAt” that takes an “up” vector; I don’t know what the difference is, offhand.

That function seems perfect for my needs, but I wrote some code that was designed to make a rhombic tricontahedron with a coordinate space for each face so that the z axis was perpendicular to the face and the vertices of the face lied on the x and y axises.(axi?)

My method, since a rhombic tricontahedron is basically a dodecahedron( or icosahedron)with its edges switched with faces, is to take a list of dodecahedron vertices and edges, calculate the midpoint of each edge, make a coordinate system to go at each point, and point the y axis at one of it’s dodecahedral vertices, and its z axis along the vector from the center to the midpoint.

But each face seems to be rotated a little ‘off’, and four faces are rotated 90 degrees from where they should be. Am I using the function wrong?

```
self.planet = render.attachNewNode("planet") #the base node for convenience
csys = [self.planet.attachNewNode("coordsystem") for null in xrange(30)] #the coordinate spaces for each face
fundem = [] #list of vertecies
edgeind = [] #list of indecies for edges
s = 2.0 / (1 + sqrt(5)) #1/phi
t = (1 + sqrt(5)) / 2.0 #phi
for z in (-1,1):
for y in (-1,1):
for x in (-1,1):
fundem.append((x,y,z))
for u in (-1,1):
for v in (-1,1):
fundem.append(( (s*u),(t*v),0 ))
fundem.append(( 0 ,(s*u),(t*v) ))
fundem.append(( (t*v),0 ,(s*u) )) #this whole section generates vertecies
edgeind.append((8,14))
edgeind.append((11,17))
edgeind.append((9,15))
edgeind.append((12,18))
edgeind.append((10,16))
edgeind.append((13,19))
edgeind.append((8,0))
edgeind.append((8,4))
edgeind.append((14,1))
edgeind.append((14,5))
edgeind.append((11,2))
edgeind.append((11,6))
edgeind.append((17,3))
edgeind.append((17,7))
edgeind.append((9,0))
edgeind.append((9,1))
edgeind.append((15,2))
edgeind.append((15,3))
edgeind.append((12,4))
edgeind.append((12,5))
edgeind.append((18,6))
edgeind.append((18,7))
edgeind.append((10,0))
edgeind.append((10,2))
edgeind.append((13,1))
edgeind.append((13,3))
edgeind.append((16,4))
edgeind.append((16,6))
edgeind.append((19,5))
edgeind.append((19,7))#put edges in the list
for i,edge in enumerate(edgeind):
cent = ((fundem[edge[0]][0]+fundem[edge[1]][0])/2.0,
(fundem[edge[0]][1]+fundem[edge[1]][1])/2.0,
(fundem[edge[0]][2]+fundem[edge[1]][2])/2.0) #calculate vector from center to midpoint of edge
csys[i].setPos(cent) #set position of coordinate system
csys[i].headsUp(other = self.planet,point=fundem[edge[0]],up=cent) #orient it such that it is pointing towords one vertex and up is away from the center.
vdata = GeomVertexData('pregentiles', GeomVertexFormat.getV3c4(), Geom.UHStatic) #debugging model showing where dodahedral vertecies are and midpoints of edges are
prim = GeomPoints(Geom.UHStatic)
vertex = GeomVertexWriter(vdata, 'vertex')
color = GeomVertexWriter(vdata, 'color')
curind = 0
for vert in fundem:#add dodecahedral vertecies into the thing
vertex.addData3f(vert)
color.addData4f(0,1,0,1)
prim.addVertex(curind)
curind+=1
for coord in csys: #add midpoints into the thing
vertex.addData3f(self.planet.getRelativePoint(coord,(0,0,0)))
color.addData4f(1,1,0,1)
prim.addVertex(curind)
curind += 1
geom = Geom(vdata)
geom.addPrimitive(prim)
node = GeomNode('pregentiles')
node.addGeom(geom)
self.planet.attachNewNode(node).setRenderModeThickness(12)
for duprup in csys: #put rhombus model in each coordinate system
tao = t/2
verts = [(0,tao,0),(.5,0,0),(-.5,0,0),(0,-tao,0)]
vdata = GeomVertexData('sphere',GeomVertexFormat.getV3n3c4(),Geom.UHStatic)
vdata.setNumRows(len(verts))
vertex = GeomVertexWriter(vdata, 'vertex')
normal = GeomVertexWriter(vdata, 'normal')
color = GeomVertexWriter(vdata, 'color')
prim = GeomTriangles(Geom.UHStatic)
for vert in verts:
vertex.addData3f(vert[1],vert[0],vert[2])
normal.addData3f(vert[1],vert[0],vert[2])
color.addData4f(1,0,0,1)
prim.addVertices(1,2,0)
prim.addVertices(1,3,2)
geom = Geom(vdata)
geom.addPrimitive(prim)
node = GeomNode('gnode')
node.addGeom(geom)
nodePath = duprup.attachNewNode(node)
nodePath.setRenderModeWireframe(True)
```

The proper plural is “axes” (pronounced more or less as “ax-ees”), I believe.

Ah, wow. Hum… I’m a little tired, so I haven’t read through that code and the following may well be wrong, but it may at least be a start:

Rotate the relevant NodePath such that one of its axes lined up with the intended vector (by finding the angle between the vectors, then using the cross-product to find the angle around which to rotate, and using those to construct a quaternion rotation which you then apply), then find the angle between the other axis and its intended vector and perform a relative rotation using that value.