# How can I 'unrotate' a face so it can be drawn in 2d ?

I’m trying to export faces for a package that ‘kind of’ supports 3d…as in 3d postcards, so position, rotation and scale in 3d and that’s about it. faces are drawn in 2d.

If I have a face in 3d, how can I get it’s rotation on x y and z,
‘unrotated’ so that all vertices on one dimension have value 0 ?

I’ve tried to understand this http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_given_an_axis_and_an_angle

but I don’t think I got it, or I don’t use it properly.

Here’s a test
import Blender
from Blender import *
import math

``````
def getRotMatrix(n):
c = cos(0)
s = sin(0)
x2 = n.x*n.x
y2 = n.y*n.y
z2 = n.z*n.z
l1 = x2+(1-x2)*c, n.x*n.y*(1-c)+n.z*s, n.x*n.y*(1-c)-n.y*s
l2 = n.x*n.y*(1-c)-n.z*s,y2+(1-y2)*c,n.x*n.z*(1-c)+n.x*s
l3 = n.x*n.z*(1-c)+n.y*s,n.y*n.z*(1-c)-n.x*s,z2-(1-z2)*c
m = Mathutils.Matrix(l1,l2,l3)
return m

scn = Scene.GetCurrent()
ob = scn.objects.active.getData(mesh=True)#access mesh

out = ob.name+'
'
#face0
f = ob.faces[0]
n = f.v[0].no
out += 'face: ' + str(f)+'
'
out += 'normal: ' + str(n)+'
'

m = getRotMatrix(n)
m.invert()

rvs = []
for v in range(0,len(f.v)):
out += 'original vertex'+str(v)+': ' + str(f.v[v].co) + '
'
rvs.append(m*f.v[v].co)

out += '
'
for v in range(0,len(rvs)):
out += 'rotated vertex'+str(v)+': ' + str(rvs[v]) + '
'

f = open('out.txt','w')
f.write(out)
f.close
``````

And here are a few outputs:

from a default plane with vertices rotated 30 degrees on x axis:

``````Plane.008
face: [MFace (0 3 2 1) 0]
normal: [0.000000, -0.499985, 0.866024](vector)
original vertex0: [1.000000, 0.866025, 0.500000](vector)
original vertex1: [-1.000000, 0.866026, 0.500000](vector)
original vertex2: [-1.000000, -0.866025, -0.500000](vector)
original vertex3: [1.000000, -0.866025, -0.500000](vector)

rotated vertex0: [1.000000, 0.866025, 1.000011](vector)
rotated vertex1: [-1.000000, 0.866026, 1.000012](vector)
rotated vertex2: [-1.000000, -0.866025, -1.000012](vector)
rotated vertex3: [1.000000, -0.866025, -1.000012](vector)
``````

from the first face of suzanne’s face:

``````Suzanne.001
face: [MFace (46 0 2 44) 0]
normal: [0.987976, -0.010102, 0.154088](vector)
original vertex0: [0.468750, 0.242188, 0.757813](vector)
original vertex1: [0.437500, 0.164063, 0.765625](vector)
original vertex2: [0.500000, 0.093750, 0.687500](vector)
original vertex3: [0.562500, 0.242188, 0.671875](vector)

rotated vertex0: [0.468750, 0.242188, -0.795592](vector)
rotated vertex1: [0.437500, 0.164063, -0.803794](vector)
rotated vertex2: [0.500000, 0.093750, -0.721774](vector)
rotated vertex3: [0.562500, 0.242188, -0.705370](vector)
``````

hints ?

why not just use uv unwrap? uv are the 2d cords and the 3d cords are xyz.

that is a very good tip.

the end goal is to reconstruct the mesh in a software that supports ‘3d postcards’
so I can draw the planes/faces using 2d coords, not 3d, but after that’s done
I can rotate the object in 3d.

I could use uv to get normalized 2d vertices, but I would still need to the 3d rotation
for each face, so I can apply it to the plane once it was drawn in 2d.

I was thinking I could use this opportunity to learn a bit of math and understand 3d rotations better, but I need some help

Gimme the face and the angles of rotation (or Euler) and I’ll tell you how to un-rotated it. Based on vertex data you CAN’T understand what should be the rotation for un-rotation action cause verts can be manipulated in EDIT mode some time.

Regards,

@Abidos
The verts I’ve pasted from the output file are manipulated in EDIT mode, that is how meshes are build…you move,rotate, scale vertices around.

I was thinking the face normal points to a direction - the (inverse) rotation of the face, so in theory I could create a rotation matrix from the normal, invert it, and multiply the vertices to it, so I rotate
vertices in the opposite direction, I imagine they would have 0 rotation on x,y,z so I can ignore one dimension, and draw them as 2d. since the rotation matrix stored, I can also output the original rotation of the face and use that to rotate the 2d ‘postcard’.

I don’t know if it’s the way I’m trying to do this, or the way I do the math that is wrong.

The mat, your math and your logic is not wrong… but in Blender you cannot apply it unless you know the original state cause the orientation issue changes and is not saved anywhere. If you rotate the default cube by 90 degrees on Z in EDIT mode, you’ll never find out the your object needs rotation and what it is based ONLY on verts (mesh) data… If you refer to certain orientation (say, the original one) then you may get it.

Regards,

Can’t you just find the original angle from the face normal?

Something like

``````def lookAt(coords)
x, y, z = coords

roll = r[2]
length = sqrt(x * x + y * y + z * z)

pitch = asin(y / length)
yaw = atan2(x, z)

return [pitch, yaw, roll] #roll will always be 0
``````

When so rotated as described in my posting #6 above, the face’s normals of the cube will have the same angles, but you will find the faces at the other place (because of rotation - 4 such faces) or unchanged (2 such faces). And in the case of that cube you will find something cause you know the original orientation… BUT what about an unknown object with a complicated shape and faces w/o a specific order??? I dont think you will be able to find out anything about the original face’s place/rotation just based on the current mesh data!

Regards,

@Abidos
yes I’m thinking of getting the rotation relative to 0,0,0(original one)

@Écrivain
Thank you!

``````
def lookAt(coords):
x, y, z = coords

roll = 0#r[2]
length = sqrt(x * x + y * y + z * z)

pitch = asin(y / length)
yaw = atan2(x, z)

return [pitch, yaw, roll] #roll will always be 0

``````

I didn’t undertand this:

• what is r[2] and where does it come from ?
• how come roll will always be 0 ?

I printed out some values:

``````
print degrees(lookAt(n)[0])
print degrees(lookAt(n)[1])
print degrees(lookAt(n)[2])

``````

If I have rotation on X,Y, that works, but if I rotate on X,Y,Z, since roll defaults to 0, that messes up the other angles.

Hints ?

Well, guys… here I have a teaser… Two cubes (see the attached .blend file) - please tell (based on certain script of yours) which one faces are rotated and at what degrees around which axis. Please publish the FULL script that finds it out… :evilgrin:

Here’s a pic of the scene too…

Regards,

@Abidos

I’m not sure what you’re trying to prove. If everything was working perfectly, there wouldn’t be so many questions in this post, would there ?

The problem with the lookAt() function is that roll defaults to 0, so if there rotation on X, Y or X and Y, that works well, but if there’s any combination with Z, the 0 will give wrong results.

``````
Scene

Cube_2:
[MFace (0 8 18 7) 0]
rx: 44.3747610295
ry: 34.3943706079
rz: 0.0
[MFace (18 9 1 6) 1]
rx: 0.0
ry: 0.0
rz: 0.0
[MFace (8 2 9 18) 2]
rx: 42.2099678354
ry: -14.0648727044
rz: 0.0
[MFace (13 5 12 19) 3]
rx: -42.2099678354
ry: 14.0648727044
rz: 0.0
[MFace (19 12 4 11) 4]
rx: 0.0
ry: 0.0
rz: 0.0
[MFace (10 19 11 3) 5]
rx: 0.0
ry: 0.0
rz: 0.0
[MFace (0 15 20 7) 6]
rx: 44.3747610295
ry: 34.3943706079
rz: 0.0
[MFace (20 10 3 14) 7]
rx: 14.5108772024
ry: 74.9999353757
rz: 0.0
[MFace (14 3 11 21) 8]
rx: 14.5108772024
ry: 105.000064624
rz: 0.0
[MFace (21 16 4 11) 9]
rx: 0.0
ry: 180.0
rz: 0.0
[MFace (6 21 16 1) 10]
rx: 0.0
ry: 0.0
rz: 0.0
[MFace (16 4 12 22) 11]
rx: 0.0
ry: 180.0
rz: 0.0
[MFace (1 9 22 16) 12]
rx: -28.0198291137
ry: 67.1811422713
rz: 0.0
[MFace (22 12 5 17) 13]
rx: -14.5108772024
ry: -105.000064624
rz: 0.0
[MFace (9 22 17 2) 14]
rx: 0.0
ry: 0.0
rz: 0.0
[MFace (15 0 8 23) 15]
rx: 7.33970228125
ry: -165.06960468
rz: 0.0
[MFace (23 8 2 17) 16]
rx: 54.7356103172
ry: -45.0
rz: 0.0
[MFace (13 5 17 23) 17]
rx: -42.2099678354
ry: 14.0648727044
rz: 0.0
[MFace (7 20 14 24) 18]
rx: 10.3698873803
ry: 43.0789543463
rz: 0.0
[MFace (6 21 14 24) 19]
rx: 0.0
ry: 0.0
rz: 0.0
[MFace (6 24 7 18) 20]
rx: 0.0
ry: 0.0
rz: 0.0
[MFace (13 23 15 25) 21]
rx: -42.2099678354
ry: 14.0648727044
rz: 0.0
[MFace (13 19 10 25) 22]
rx: -42.2099678354
ry: 14.0648727044
rz: 0.0
[MFace (10 25 15 20) 23]
rx: 0.0
ry: 0.0
rz: 0.0

Cube_1:
[MFace (6 3 7 8) 0]
rx: -0.0874302352923
ry: -179.669511621
rz: 0.0
[MFace (0 4 8 7) 1]
rx: -44.4290105269
ry: -145.363850588
rz: 0.0
[MFace (2 6 8 5) 2]
rx: 27.7727858176
ry: -114.644150419
rz: 0.0
[MFace (5 8 4 1) 3]
rx: 41.4049424556
ry: -166.335243459
rz: 0.0
[MFace (24 5 2 13) 4]
rx: 74.9751975156
ry: -93.428647804
rz: 0.0
[MFace (24 17 1 5) 5]
rx: 74.9751975156
ry: -93.428647804
rz: 0.0
[MFace (22 4 1 17) 6]
rx: -14.9988385517
ry: -90.5304174955
rz: 0.0
[MFace (0 4 22 18) 7]
rx: -44.4290105269
ry: -145.363850588
rz: 0.0
[MFace (0 18 25 7) 8]
rx: -44.4290105269
ry: -145.363850588
rz: 0.0
[MFace (25 15 3 7) 9]
rx: -74.9751975156
ry: 86.571352196
rz: 0.0
[MFace (21 6 3 15) 10]
rx: 14.5072409006
ry: 74.9403661547
rz: 0.0
[MFace (21 6 2 13) 11]
rx: 14.5072409006
ry: 74.9403661547
rz: 0.0
[MFace (24 13 10 19) 12]
rx: 74.9751975156
ry: -93.428647804
rz: 0.0
[MFace (24 19 12 17) 13]
rx: 74.9751975156
ry: -93.428647804
rz: 0.0
[MFace (22 17 12 16) 14]
rx: -14.9988385517
ry: -90.5304174955
rz: 0.0
[MFace (22 16 11 18) 15]
rx: -14.9988385517
ry: -90.5304174955
rz: 0.0
[MFace (25 18 11 20) 16]
rx: -74.9751975156
ry: 86.571352196
rz: 0.0
[MFace (25 20 9 15) 17]
rx: -74.9751975156
ry: 86.571352196
rz: 0.0
[MFace (21 15 9 14) 18]
rx: 14.5072409006
ry: 74.9403661547
rz: 0.0
[MFace (21 14 10 13) 19]
rx: 14.5072409006
ry: 74.9403661547
rz: 0.0
[MFace (23 19 10 14) 20]
rx: 0.0
ry: 180.0
rz: 0.0
[MFace (23 14 9 20) 21]
rx: 0.0
ry: 180.0
rz: 0.0
[MFace (23 20 11 16) 22]
rx: 0.0
ry: 180.0
rz: 0.0
[MFace (23 16 12 19) 23]
rx: 0.0
ry: 180.0
rz: 0.0

``````

@ orgicus - For your amusement, there where NO rotations of the whole objects Cube_1 (selected on the pic) and Cube_2. Starting from the default cube with 1 level of subdivision, rotation of the middle layer of verts at 30 degrees on Z and changing positions of 2 verts + inverting some of the normals to breaking the logic of potential scripts => Cube_2 has been produced. While the Cube_1 was produced ONLY by using data for verts position from Cube_2… I.e. practically ZERO rotations at any face of Cube_1 nor at any ot its verts has been applied…

Now… if you use (somehow) the data stripped by your script and apply it on the Cube_1 => you will get a quite different object from the original one!

Which proves what I;ve been trying to say several times here - it is NOT possible to determine anything about the original mesh basing ONLY on the mesh data (either local or global).

Regards,

Oops! I stripped the function from a script I’m working on that has an additional argument r that contains the original rotation and forgot to remove that, but it wasn’t working right anyway.
All this function does is returns an euler XYZ rotation looking towards a point in space from (0, 0, 0) so you don’t need roll, it’s just needed to prevent twisting.

These ‘spikes’ were generated with that function (and some others.) As you can see the rotation along the normal is perfect, so all you have to do is rotate the vertices the opposite way about MeshFace.center.