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
from math import sin,cos,radians,degrees


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 :slight_smile:

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!
I’ve used your function with minor adjustments:


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…

http://www.opendrive.com/files/6692297_mW8cH/2010-07-19_211334.jpg

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 ? :slight_smile:

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.

For your amusement, here’s a print from your scene:


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.

http://pasteall.org/pic/show.php?id=4592

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.