PDA

View Full Version : texture-space to object-space

11-03-2009, 10:50 AM
I need to go from texture space to object space.

Having a triangle with vertices p0, p1, p2 and texture coordinates t0, t1, t2, i'm constructing a 3x3 matrix 'A' as:

| v1.x v2.x n.x |
| v1.y v2.y n.y |
| v1.z v2.z n.z |

where v1 and v2 are the vectos lying on the 2 sides of the triangle:

v1 = p0 - p1
v2 = p2 - p1

and n is the normal:

n = |v1 x v2| (normal)

This matrix would go from "triangle-space" to object space.

Then I'm constructing another matrix ('B') as:

| uv1.x uv2.x 0 |
| uv1.y uv2.y 0 |
| uv1.z uv2.z 1 |

Where uv1 is t0-t1 and uv2 is t2-t1 (as before).

This matrix would go from "texture-space" to triangle-space

Finally to convert from texture-space to object-space I'm calculating the final matrix as:

m = B * A

But it doesn't work. What am I doing wrong?

Any help will be appreciated.

DmitryM
11-03-2009, 11:29 AM
As far as I see you want a tangent space basis matrix.

http://www.terathon.com/code/tangent.html
http://jerome.jouvie.free.fr/OpenGl/Lessons/Lesson8.php

11-03-2009, 12:30 PM
Thanks, but I want to understand what I'm doing, and not borrow someone else's code/method.

DmitryM
11-03-2009, 12:52 PM
Ok, but take in account that links provided contain the extensive explanation, not just plain working code.

As far as I see, your B matrix transforms from triangle space to tangent space (inverse of what you are saying). So, assuming that you put the vector to the left of a matrix when multiplying, you need the following matrix in the result:
m = inv(B) * A

11-03-2009, 01:40 PM
I've seen the links, but after posting I realized that for what I want to do what I need is the full transformation (including translation). I need texture points (W=1) in space (and vice-versa), no just vectors (W=0) for tangent-space lighting.

Thus I expanded A to

| v1.x v2.x n.x 0 |
| v1.y v2.y n.y 0 |
| v1.z v2.z n.z 0 |
| p1.x p1.y p1.z 1 |

and B to

| uv1.x uv2.x 0 0 |
| uv1.y uv2.y 0 0 |
| uv1.z uv2.z 1 0 |
| t1.x t1.y t1.z 1 |

Even so, (also with inv(B)) I cannot make it work. I cannot grasp why. After all is two consecutive linear transformations: From texture-space to triangle-space and from triangle-space to object-space...

DmitryM
11-03-2009, 02:51 PM
You are not correct.

==A==:
transform from triangle space to object space:
v' = v.x * v1 + v.y * v2 + v.z * n + p1

So, your matrix should have p1 on the right column instead of bottom row:
| v1.x v2.x n.x p1.x |
| v1.y v2.y n.y p1.y |
| v1.z v2.z n.z p1.z |
| 0 0 0 1 |

==B==:
the same mistake, should be:
| uv1.x uv2.x 0 t1.x |
| uv1.y uv2.y 0 t1.y |
| uv1.z uv2.z 1 t1.z |
| 0 0 0 1 |

11-03-2009, 03:31 PM
You are right. My mistake.
Is wrong in the post, but done right in the code:

c#:

Matrix4f A = new Matrix4f(v0, v1, n, p0);

*****

public Matrix4f(Vector3f xaxis, Vector3f yaxis, Vector3f zaxis, Vector3f pos)
{
m00 = xaxis.X;
m01 = xaxis.Y;
m02 = xaxis.Z;
m03 = 0.0f;
m10 = yaxis.X;
m11 = yaxis.Y;
m12 = yaxis.Z;
m13 = 0.0f;
m20 = zaxis.X;
m21 = zaxis.Y;
m22 = zaxis.Z;
m23 = 0.0f;
m30 = pos.X;
m31 = pos.Y;
m32 = pos.Z;
m33 = 1.0f;
}

DmitryM
11-03-2009, 04:05 PM
I hope you have a correct matrix * vector multiplication.
How do you test the correctness of the tangental space basis?

You should try to use the working equations for the start, just to be sure everything else works correctly.

marshats
11-03-2009, 04:40 PM
DmitryM has the solution:

==A==:
| v1.x v2.x n.x p1.x |
| v1.y v2.y n.y p1.y |
| v1.z v2.z n.z p1.z |
| 0 0 0 1 |

==B==:
| uv1.x uv2.x 0 t1.x |
| uv1.y uv2.y 0 t1.y |
| uv1.z uv2.z 1 t1.z |
| 0 0 0 1 |

Those definitions explicitly mean:

object_coord=A*Triangle_coord
Textre_coord=B*Triangle_coord

so you can solve for Triangle_coord

Triangle_coord=Inverse(B)*Textre_coord

hence

object_coord=A*Triangle_coord
=A*Inverse(B)*Textre_coord

Note the order of operations though!

11-03-2009, 05:54 PM
This is craving my brain. It's a small test app in C# using OpenTK:

private void myGLControl1_Paint(object sender, PaintEventArgs e)
{

// Draw triangle with texture

GL.Color3(1.0f, 1.0f, 1.0f);
GL.Enable(EnableCap.Texture2D);
tex.Bind();
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);

GL.Begin(BeginMode.Triangles);

GL.TexCoord2(t0.X, t0.Y);
GL.Vertex3(p0.X, p0.Y, p0.Z);
GL.TexCoord2(t1.X, t1.Y);
GL.Vertex3(p1.X, p1.Y, p1.Z);
GL.TexCoord2(t2.X, t2.Y);
GL.Vertex3(p2.X, p2.Y, p2.Z);

GL.End();

// Draw triangle in wireframe

GL.Color3(1.0f, 1.0f, 0.0f);
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line);
GL.LineWidth(3);
GL.Disable(EnableCap.Texture2D);

GL.Begin(BeginMode.Triangles);

GL.Vertex3(p0.X, p0.Y, p0.Z);
GL.Vertex3(p1.X, p1.Y, p1.Z);
GL.Vertex3(p2.X, p2.Y, p2.Z);

GL.End();

// Compute triangle basis

Vector3f v0 = p1 - p0;
Vector3f v1 = p2 - p0;
Vector3f n = Vector3f.CrossProduct(v0, v1);
//n.Normalize(); // not really needed

Matrix4f A = new Matrix4f(v0, v1, n, p0);

// Point to locate tangent and bitangent origin somewhere outside the triangle

Vector3f temp = A.TransformPoint(new Vector3f(-0.1f, -0.1f, 0.0f));

GL.PointSize(4);
GL.Color3(1.0f, 0.0f, 1.0f);
GL.Begin(BeginMode.Points);
GL.Vertex3(temp.X, temp.Y, temp.Z);
GL.End();

// Texture basis

Vector3f uv0 = t1 - t0;
Vector3f uv1 = t2 - t0;
Vector3f uvn = Vector3f.CrossProduct(uv0, uv1);

Matrix4f B = new Matrix4f(uv0, uv1, uvn);
B.Invert();
//Matrix4f C = A * B;
Matrix4f C = B * A;

// Draw tangent vector

Vector3f tan = C.TransformVector(new Vector3f(1.0f, 0.0f, 0.0f)) * 0.5f;

GL.Color3(1.0f, 0.0f, 0.0f);
GL.Begin(BeginMode.Lines);
GL.Vertex3(temp.X, temp.Y, temp.Z);
GL.Vertex3(temp.X+tan.X, temp.Y+tan.Y, temp.Z+tan.Z);
GL.End();

// Draw bitangent (or binormal)

Vector3f bitan = C.TransformVector(new Vector3f(0.0f, 1.0f, 0.0f)) * 0.5f;

GL.Color3(0.0f, 1.0f, 0.0f);
GL.Begin(BeginMode.Lines);
GL.Vertex3(temp.X, temp.Y, temp.Z);
GL.Vertex3(temp.X + bitan.X, temp.Y + bitan.Y, temp.Z + bitan.Z);
GL.End();

// Overimpose full texture quad over the triangle

Vector3f c0 = C.TransformPoint(new Vector3f(0, 0, 0));
Vector3f c1 = C.TransformPoint(new Vector3f(1, 0, 0));
Vector3f c2 = C.TransformPoint(new Vector3f(1, 1, 0));
Vector3f c3 = C.TransformPoint(new Vector3f(0, 1, 0));

GL.Enable(EnableCap.Blend);
GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
GL.Color4(1.0f, 1.0f, 1.0f, 0.5f);
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);
GL.Enable(EnableCap.Texture2D);

GL.TexCoord2(0, 0);
GL.Vertex3(c0.X, c0.Y, c0.Z);
GL.TexCoord2(1, 0);
GL.Vertex3(c1.X, c1.Y, c1.Z);
GL.TexCoord2(1, 1);
GL.Vertex3(c2.X, c2.Y, c2.Z);
GL.TexCoord2(0, 1);
GL.Vertex3(c3.X, c3.Y, c3.Z);

GL.End();

GL.Disable(EnableCap.Blend);
GL.Disable(EnableCap.Texture2D);

myGLControl1.SwapBuffers();
}

It works perfectly as long as B is identity i.e. tex coords (0,0) (1,0) (0,1)

Matrix multiplication, inversion et al had all been proved good with hierarchical transforms, camera transform (inverse of normal transform) and skinning

11-03-2009, 06:37 PM
Got it!

Matrix4f B = new Matrix4f(uv0, uv1, uvn);

Should have been:

Matrix4f B = new Matrix4f(uv0, uv1, uvn, t0);

Thank you guys!!!

marshats
11-03-2009, 06:41 PM
quick question, which one worked?

Matrix4f C = A * Inverse(B); ?

or

Matrix4f C = Inverse(B) * A; ?