Skip to main content
GameDev.net gamedev.net
🔒 Locked

Computing tangent vector from texture coords

Started by The Rug Feb 4, 2005 at 9:14 AM 4 replies 2.9k views
Original Post
The Rug
The Rug
This is driving me mad, I've been stuck on it for several days... As I understand, (on a textured poly) the tangent is the vector pointing in the direction of the increasing S axis of the texture, is that right? The problem is actually computing this in object space. I can visualise it in my head, but my maths is pretty weak so I have no idea how to go from texture space to object space (or even if thats what I need to do) to get the tangent. I've found only a few articles, and they are usually too maths heavy for me (I prefer to see the actual code, it makes more sense) and cover stuff like finding the tangent at points on parametric surfaces, which isn't any good to me (I don't think). The Google forum search isn't much help either, since it brings up the same threads multiple times, and they don't really help me :'( If anyone can point me to an explanation, in commoners terms, of how to get the tangent of a textured surface using texture coordinates, I'd be really grateful. Code is always a plus. Thankyou.
the rug - funpowered.com
Promit
Promit
This page is the canonical link on the subject.
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
The Rug
The Rug
Thanks, that did help somewhat. I'm still unsure about some things though, I commented the code to try and better understand it, and annotated the confusing bits:

#include "Vector4D.h"struct Triangle{	unsigned short	index[3];};void CalculateTangentArray(const Point3D *vertex, const Vector3D *normal, const Point2D *texcoord,		long triangleCount, const Triangle *triangle, Vector4D *tangent){	Vector3D *tan1 = new Vector3D[vertexCount * 2];	Vector3D *tan2 = tan1 + vertexCount;	ClearMemory(tan1, vertexCount * sizeof(Vector3D) * 2);		for (long a = 0; a < triangleCount; a++)	{		long i1 = triangle->index[0];		long i2 = triangle->index[1];		long i3 = triangle->index[2];				// 3 Points in the triangle		const Point3D& v1 = vertex[i1];		const Point3D& v2 = vertex[i2];		const Point3D& v3 = vertex[i3];				// 3 Points in the texture		const Point2D& w1 = texcoord[i1];		const Point2D& w2 = texcoord[i2];		const Point2D& w3 = texcoord[i3];				// Vectors between points in triangle?		float x1 = v2.x - v1.x;		float x2 = v3.x - v1.x;		float y1 = v2.y - v1.y;		float y2 = v3.y - v1.y;		float z1 = v2.z - v1.z;		float z2 = v3.z - v1.z;				// Vectors between points in texture?		float s1 = w2.x - w1.x;		float s2 = w3.x - w1.x;		float t1 = w2.y - w1.y;		float t2 = w3.y - w1.y;		// Not sure from this point onwards, especially this chunk:		float r = 1.0F / (s1 * t2 - s2 * t1);		Vector3D sdir((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r,				(t2 * z1 - t1 * z2) * r);		Vector3D tdir((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r,				(s1 * z2 - s2 * z1) * r);				// Textures S in object space? (tangent?)                tan1[i1] += sdir;		tan1[i2] += sdir;		tan1[i3] += sdir;				// Textures T in object space? Used for handedness only?		tan2[i1] += tdir;		tan2[i2] += tdir;		tan2[i3] += tdir;				triangle++;	}		long count = vertexCount;	for (long a = 0; a < count; a++)	{		const Vector3D& n = normal[a];		const Vector3D& t = tan1[a];				// Confused by this:		tangent[a] = (t - n * (n * t)).Normalize();				// Calculate handedness		tangent[a].w = (n % t * tan2[a] < 0.0F) ? -1.0F : 1.0F;	}		delete[] tan1;}


Another bit that confuses me is the part commented "Textures S in object space?" confuses me, why are they adding the S direction? Is this to create a kind of average?

Sorry for all the questions, I'm a maths noob so trying to be a graphics coder sucks :/ Nevertheless, I'm determined to do it, if someone can shove me in the right direction [smile]
the rug - funpowered.com
Promit
Promit
Quote:
Original post by The Rug
Another bit that confuses me is the part commented "Textures S in object space?" confuses me, why are they adding the S direction? Is this to create a kind of average?


Yeah, they're doing the exact same thing that you do with normals -- summing over all the triangles that use a vertex, and then normalizing.
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
The Rug
The Rug
Cheers [smile]

Finally if anyone could shed any light on what's going on here:
		float r = 1.0F / (s1 * t2 - s2 * t1);		Vector3D sdir((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r,				(t2 * z1 - t1 * z2) * r);		Vector3D tdir((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r,				(s1 * z2 - s2 * z1) * r);


Those look like cross products, but I'm not sure what they achieve.

Hopefully this will be the last time I bother you with this [grin] Thanks!

(I think I really need a good maths book)
the rug - funpowered.com
Eric Lengyel
Eric Lengyel
Quote:
Original post by The Rug
Cheers [smile]

Finally if anyone could shed any light on what's going on here:
		float r = 1.0F / (s1 * t2 - s2 * t1);		Vector3D sdir((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r,				(t2 * z1 - t1 * z2) * r);		Vector3D tdir((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r,				(s1 * z2 - s2 * z1) * r);


Those look like cross products, but I'm not sure what they achieve.

Hopefully this will be the last time I bother you with this [grin] Thanks!

(I think I really need a good maths book)


This is the heart of the tangent direction calculation. It's derived in Mathematics for 3D Game Programming and Computer Graphics, Section 6.8. The gist of it is that you're solving the following equations for sdir and tdir

Q1 = s1 * sdir + t1 * tdir
Q2 = s2 * sdir + t2 * tdir

where Q1 = (x1, y1, z1) and Q2 = (x2, y2, z2).

The line that you've commented as "Confused by this:" is a Gram-Schmidt orthogonalization of the tangent vector, forcing it to be perpendicular to the normal.

-- Eric Lengyel

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.