[Closed] Rotating vector in Matrix?
Hello, I’m having a bit of trouble with rotating a vector in the matrix of a facenormal. Here is some code of what I’m trying to use use:
facenorm = getFaceNormal obj facenumber
faceTM = matrixFromNormal facenorm
vecTM = matrixFromNormal (normalize (Pos_1-Pos_2))
in coordsys faceTM rotate vecTM (eulerangles 0 0 90)
scrot = vecTM.row3 –should be the rotated direction
This doesn’t work for some reason. Can anybody see any trouble with this code?
The strange thing is that it seems to work when I do it in screenspace instead, like this:
gw.setTransform(Matrix3 1)
Pos_1 = gw.wTranspoint Pos_1 –screenpos
Pos_2 = gw.wTranspoint Pos_2
Pos_1.z = 0 ; Pos_2.z = 0
facenorm = getFaceNormal obj facenumber
faceTM = matrixFromNormal facenorm
vecTM = matrixFromNormal (normalize (Pos_1-Pos_2))
in coordsys faceTM rotate vecTM (eulerangles 0 0 90)
scrot = vecTM.row3
Maybe it has something to do with me setting the Z of the initial positions to 0?
This also works…
[size=2]scrot = (normalize (Pos_1-Pos_2)) * rotateZmatrix 90[/size]
[size=2][/size]
[size=2]but only when Z is pointing straight up…I could really use some help here, thanks[/size]
[size=2][/size]
[size=2]CML
[/size]
You are on the right path here…
Basically, the rotateZmatrix defines a rotation matrix which is relatively to world space.
You JUST have to convert it into the space of the normal’s coordinate system (by multiplying the rotateZmatrix * theNormalMatrix) and multiplying the vector by the resulting matrix which is already transformed into the space of the normal.
Here is a simple example of a teapot which is placed on a vertex of a geosphere and is rotating 360 degrees only using low-level matrix transformations (this is a marketing pitch for my upcoming DVD “The Matrix : Explained” )
resetMaxFile #noPrompt
theGS = geosphere radius:50
theTeapot = Teapot radius:10
theMesh = snapshotasmesh theGS
theIndex = 10
theVertPos = getVert theMesh theIndex
theVertNormal = getNormal theMesh theIndex
theTM = matrixFromNormal theVertNormal --build a matrix with the normal as the Z axis
for i = 0 to 360 do
(
theTeapot.transform = (rotateZMatrix i) * theTM --create a Z rotation matrix, transform into vertex normal's space
theTeapot.pos = theVertPos --set the right translation because both matrices above have translation of 0,0,0
redrawViews() --update to see in the viewport
)
Here is a variation of the same code, might be slightly faster.
Instead of setting the position of the teapot all the time, the translation is already included in the normal’s transformation matrix as row4…
resetMaxFile #noPrompt
theGS = geosphere radius:50
theTeapot = Teapot radius:10
theMesh = snapshotasmesh theGS
theIndex = 10
theVertPos = getVert theMesh theIndex
theVertNormal = getNormal theMesh theIndex
theTM = matrixFromNormal theVertNormal --build a matrix with the normal as the Z axis
theTM.row4 = theVertPos --set the translation to the vertex' position
for i = 0 to 360 do
(
theTeapot.transform = (rotateZMatrix i) * theTM --create a Z rotation matrix, transform into vertex normal matrix space
redrawViews()
)
Hi Bobo, I was hoping you would answer, thank you very much. I’m not sure your example does what I need though. Let me illustrate:
I need to find the direction of the green arrow(doesn’t really matter wich way). So I want to rotate the yellow vector with the facenormals z-axis. I did realise that since the angle I want to rotate is in this case 90 I can use: cross vector facenormal to do it, but I would really like to get this working anyway. Here is what I tried following your example, and it didn’t get me the direction I want:
faceTM = matrixFromNormal (getFaceNormal obj facenum)
vec = normalize (Pos_1 – Pos_2) –start normal
rotTM = (rotateZmatrix 90) * faceTM
[size=2]scrot = vec * rotTM –rotated normal[/size]
[size=2][/size]
[size=2]Can you clear this up?[/size]
[size=2]Looking forward to that dvd. There is a big chance of me getting that. Thanks,[/size]
[size=2]CML
[/size]
maybe its completely wrong, but the first idea i got was:
create a quaternion from the normal and rotate your vector by it
[color=Wheat]quat[/color] <degrees_float> <axis_point3>
<point3> * <quat>
Actually, your code is right. I assume that your face normal is wrong
Where do you get your face normal from? My code expects it to be in world space, but if you are getting it from, say, the .mesh property of an object, you would get the normal in object space and the result will not take the object’s own transformation matrix in account.
So the question is – what is OBJ in your code?
If OBJ was a TriMesh taken using Snapshotasmesh(), the result would be already transformed by the node’s TM. If it is a TriMesh taken using the .mesh property or an EditableMesh base object, it is not, so you would have to transform the resulting vector in world space by multiplying it by the node’s TM first.
Here is my example:
obj = $Plane01 --some plane with an arbitrary orientation in space
spl = $Line01 --some line with two knots to define the vector to rotate
theMesh = snapshotasmesh obj --grab the world state of the mesh
facenum = 1 --use first face
theFaceNormal = getFaceNormal theMesh facenum --get the face normal in world space
/*
--Alternatively, you can say
theMesh = obj.mesh --get the TriMesh in object space
facenum = 1 --use first face
theFaceNormal = getFaceNormal theMesh facenum --get the face normal in object space
--by default, getting a plane's normal in object space will always give you
--the identity matrix (matrix3 [1,0,0] [0,1,0] [0,0,1] [0,0,0]
--because all normals of the plane are pointing up
theFaceNormal *= obj.transform --transform the normal into world space
*/
faceTM = matrixFromNormal theFaceNormal --build the matrix from the world normal
Pos_1 = getKnotPoint spl 1 1 --get first knot of the spline
Pos_2 = getKnotPoint spl 1 2 --get second knot of the spline
vec = normalize (Pos_2 - Pos_1) --start normal
rotTM = (rotateZmatrix 90) * faceTM --rotation matrix
scrot = vec * rotTM --rotated normal
--Visualize the results using some colorful splines:
newSpl = splineShape()
newSpl.name = uniquename "StartVector"
newSpl.wirecolor = green
addNewSpline newSpl
addKnot newSpl 1 #corner #line [0,0,0]
addKnot newSpl 1 #corner #line (vec * 10)
updateShape newSpl
newSpl.pos = Pos_1
newSpl = splineShape()
newSpl.name = uniquename "RotatedVector"
newSpl.wirecolor = red
addNewSpline newSpl
addKnot newSpl 1 #corner #line [0,0,0]
addKnot newSpl 1 #corner #line (scrot * 10)
updateShape newSpl
newSpl.pos = Pos_1
newSpl = splineShape()
newSpl .name = uniquename "NormalVector"
newSpl .wirecolor = blue
addNewSpline newSpl
addKnot newSpl 1 #corner #line [0,0,0]
addKnot newSpl 1 #corner #line ( theFaceNormal * 10)
updateShape newSpl
newSpl.pos = Pos_1
I’m using a normal Editable mesh object to get the facenormal. When the facenormal is pointing straight up it’s working like it should, but not on anything else. It seems strange…I tried your example with the splines (using the top alternative to get the normal) and it worked good when the plane was flat on the ground but when I rotated the plane and ran the code I got this result:
As you see the red line doesn’t point in the right direction at all. Green and blue lines do.
Do you not also get this result?
Thanks for the help,
CML
I’m not entirely sure if this is what you’re after, but this rotates the green (spline) vector around the blue (face normal) vector resulting in the red vector.
(See bottom for changes)
- Martijn
(
obj = $Plane01 --some plane with an arbitrary orientation in space
spl = $Line01 --some line with two knots to define the vector to rotate
theMesh = snapshotasmesh obj --grab the world state of the mesh
facenum = 1 --use first face
theFaceNormal = getFaceNormal theMesh facenum --get the face normal in world space
faceTM = matrixFromNormal theFaceNormal --build the matrix from the world normal
Pos_1 = getKnotPoint spl 1 1 --get first knot of the spline
Pos_2 = getKnotPoint spl 1 2 --get second knot of the spline
vec = normalize (Pos_2 - Pos_1) --start normal
--Visualize the results using some colorful splines:
newSpl = splineShape()
newSpl.name = uniquename "StartVector"
newSpl.wirecolor = green
addNewSpline newSpl
addKnot newSpl 1 #corner #line [0,0,0]
addKnot newSpl 1 #corner #line (vec * 10)
updateShape newSpl
newSpl.pos = Pos_1
newSpl = splineShape()
newSpl .name = uniquename "NormalVector"
newSpl .wirecolor = blue
addNewSpline newSpl
addKnot newSpl 1 #corner #line [0,0,0]
addKnot newSpl 1 #corner #line ( theFaceNormal * 10)
updateShape newSpl
newSpl.pos = Pos_1
newSpl = splineShape()
newSpl.name = uniquename "RotatedVector"
newSpl.wirecolor = red
for i = 15 to 345 by 15 do
(
-- rotate start vector around normal vector
vecTM = matrixFromNormal vec
vecTM *= inverse faceTM
rotatez vecTM i
vecTM *= faceTM
scrot = vecTM.row3
addNewSpline newSpl
addKnot newSpl (numsplines newSpl) #corner #line [0,0,0]
addKnot newSpl (numsplines newSpl) #corner #line (scrot * 5)
)
updateShape newSpl
newSpl.pos = Pos_1
)
Hello Martijn, that works great, thanks for that!
Bobo – I’ll put something together and send, the problem is I’m using a lot of different functions within the script but I’ll try to strip it down. It is also highly confidential PolyDraw stuff! but I think I can trust you;)
CML
Well, I just wanted the scene you took the screenshot from, so I can test using the exactly same mesh as you did. (It worked ok with my meshes and splines, so I wanted to see what is different)
Your script is safe with me, but you shouldn’t have sent that.