Re: Fw: [script] normal vector to xyz rotation?

Date : Mon, 5 Sep 2005 22:40:28 +0200
To : <XSI(at)Softimage.COM>
From : "peterb" <peter_b(at)skynet.be>
Subject : Re: Fw: [script] normal vector to xyz rotation?
yes,
as it seems the formula for arccos below is correct.
(i've found several sources that confirm)
however, in case of a 1 you get a division by zero.
but... the arccos of 1 is 0, and the arccos of -1 is PI
so thats quickly added into the script with a condition, and yet a few more lines. where the simple "arccos" should be all :-(
 
so I got my 2 scripts running (hurrah!), but the version with the arccos isnt giving proper results.
could be my math, could be my script... or both
 
I've added them at the bottom of this mail, if anyone wants to look, see whats wrong
(or laugh at my scripting :-)
 
 
peter
 
That would be correct (cos always returns a value between -1 and 1) - if you've got a dot product greater than that your vectors weren't unit vectors (normalized).

Hope this helps.

Cheers,

Alan.

On 9/5/05, peterb <peter_b(at)skynet.be> wrote:

>hm I m not gonna switch languages because of a math function now?
>thats like deciding to switch to japanese because you feel there's some characters missing in our alphabet. (yeah its a flawed comparison)
>
>now I did work it out with the acos, and I ll be needing this,
>since I wanna do this on particles, and they dont have a transform matrix.
>
>btw it ran MUCH faster that way, but there can be some other things that are influencing it.
>right now I have one version, with the matrix method, to place nulls on points,
>and another version using the arccos method, to place particles on points, the second being more performant.
>
>however, it seems that the formula is flawed, I get 'division by zero' errors.
>and its quite obvious: if X=1 then (x*x + 1) gives zero.
>Arccos(X) = Atn(-X / Sqr(-X * X + 1)) + 2 * Atn(1)
 
apparently the arccos function only accepts numbers between -1 and 1 at the input...
 
 
>
>I'll have to try and find a better arccos formula somewhere..
 
,

Glad you got it sorted - microsoft's acos solution truly is elegant ;-) A google seems to provide strange results - some places mention a math object in VBScript though doesn't seem to work for me.

If your other solution is working then I'd go with that - at least until you shift languages

Cheers,

Alan.



On 9/5/05, peterb <peter_b(at)skynet.be> wrote:
 
Hi Alan, seems like your answer was on right on the spot.
 
but on kims suggestion I found back the thread on xsibase:
 
I got it working with Rafaelle's method, that doesnt involve dot product, nor inverse cosine.
just cross product, normalize and putting it into a matrix that goes straight to an object's transform.
 
on the bottom of the page there is a method by Andrea, that is pretty much exactly what you suggested.
this uses the inverse cosine of the dot product and so on:
...
var angle = Math.acos(upVec.dot(polyNormal)); 
...
 
cant find one in vbscript though.
 
what I did come up with is
where inverse cosine is made up like this:
Arccos(X) = Atn(-X / Sqr(-X * X + 1)) + 2 * Atn(1)
 
microsoft helps to keep things simple :-)
if anyone knows of an inverse cosine function in vbscript, I'd love to know.
 
 
peter
 
 
Excuse my laziness I didn't real through all your code so I've no idea how you're tackling this, but here's a simple approach I'd recommend anyway (I'll explain the math rather than coding it out.)

Take the direction you want to be "up" on your object (probably the y axis I guess so 0,1,0). Get the cross product of that with the normal you want it to rotate to. The result is the axis you want to rotate your object around. To get the angle you want to rotate your object get the dot product of the up axis and the normal. Then get the inverse cosine of this and that will be the angle in radians you want to rotate it. The only problem you'll probably come into this way is defining how it rotates around the normal. You may want to look at doing this with a direction vector which could be global or using the U and V directions or whatever.

Cheers,
 
'this is the script that is working fine, based on rafaelle's suggested method
'select a mesh and run, it creates nulls, aligned to the mesh's points
'---------------------------------------------------
option explicit
dim sel, oGeometry, oPoints, pnt, oNull
Dim V1, V2, vUP, oMatrix, vNORM, transfo
set V1 = XSIMath.CreateVector3
set V2 = XSIMath.CreateVector3
set vUP = XSImath.CreateVector3
set oMatrix = XSIMath.CreateMatrix3
set vNORM = XSImath.CreateVector3
set transfo = XSIMath.CreateTransform
vUP.set 0.0,1.0,0.0
set sel = selection(0)
set oGeometry = sel.activeprimitive.geometry
set oPoints = oGeometry.Points
for each pnt in oPoints
vNORM.set pnt.normal.x,pnt.normal.y,pnt.normal.z
MatrixFromNormal (vNORM)
 
transfo.setRotationFromMatrix3 oMatrix
transfo.SetTranslationFromValues pnt.position.x, pnt.position.y, pnt.position.z
set ("name" & pnt.index)
oNull.Kinematics.local.transform = transfo
next
Function MatrixFromNormal (norm)
V1.cross norm,vUP
V2.cross V1,norm
V1.normalizeInPlace
V2.normalizeInPlace
norm.normalizeInPlace
oMatrix.set V1.x, V1.y, V1.z,_
norm.x, norm.y, norm.z,_
V2.x, V2.y, V2.z
set MatrixFromNormal = oMatrix
end Function
 
'----------------------------------------------------
'this is the script that is not working fine, based on the math  method
'the nulls are not properly aligned...
'---------------------------------------------------
set sel = selection(0)
set oGeometry = sel.activeprimitive.geometry
set oPointer = oGeometry.Points
set rot = XSIMath.CreateRotation
set vUP = XSIMath.CreateVector3
set axis = XSIMath.CreateVector3
set vNORM = XSIMath.CreateVector3
set vPos = XSIMath.CreateVector3
set vRot = XSIMath.CreateVector3
vUP.set 0,1,0
for i = 0 to oPointer.count-1
set oPoint = oGeometry.Points(i)
 
set vPos = oPoint.Position
set vNORM = oPoint.Normal
RotationFromNormal (vNORM)
rot.GetXYZAngles vRot
 
set ("name" & i)
oNull.Kinematics.local.parameters("posx").value = vPos.x
oNull.Kinematics.local.parameters("posy").value = vPos.y
oNull.Kinematics.local.parameters("posz").value = vPos.z
oNull.Kinematics.global.parameters("rotx").value = xsimath.radianstodegrees(vRot.x)
oNull.Kinematics.global.parameters("roty").value = xsimath.radianstodegrees(vRot.y)
oNull.Kinematics.global.parameters("rotz").value = xsimath.radianstodegrees(vRot.z)
next
Function RotationFromNormal (norm)
axis.cross vUP, norm
DOT = vUP.dot(norm)
if DOT => 1 then
angle = 0
elseif DOT <= -1 then
angle = XSIMath.PI
else
angle = 2*atn(1) - atn(DOT/sqr(1-DOT*DOT))
end if
rot.SetFromAxisAngle axis, angle
set RotationFromNormal = rot
end Function

'----------------------------------------------------------------

 

 

Search the XSI List archives here or use the advanced search form to search across mailing lists. Searching help is available.
This site supposedly brought to you by Benjamin Grosser and the Imaging Technology Group.