PDA

View Full Version : texture-space to object-space



AdrianPi
11-03-2009, 11: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, 12:29 PM
As far as I see you want a tangent space basis matrix.
Instead of looking for the error in your code, I'll provide some links with working code.

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

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

DmitryM
11-03-2009, 01: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

AdrianPi
11-03-2009, 02: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, 03: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 |

AdrianPi
11-03-2009, 04: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, 05: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, 05: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!

AdrianPi
11-03-2009, 06: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)
{
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

// 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.Begin(BeginMode.Quads);

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

AdrianPi
11-03-2009, 07: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, 07:41 PM
quick question, which one worked?



Matrix4f C = A * Inverse(B); ?

or

Matrix4f C = Inverse(B) * A; ?

AdrianPi
11-03-2009, 07:43 PM
http://i35.tinypic.com/x3fvh5.png

AdrianPi
11-03-2009, 07:50 PM
Well, I it will ever depend on how matrix multiplication was written. In my case the latter. For a standard "scale, rotate, translate" I write M = S * R * T

You both where right. Thanks again.