Tangent attribute in shader

I need a tangent vector in my fragment shader(I am using a .obj model, with no pre-computed tangent map). To my understanding three js does not sent tangent as a default attribute to shader, thus it needs to be calculated.

One suggestion that I came accross is to use -

.computeTangents ( geometry : BufferGeometry ) : null
geometry – A BufferGeometry instance, which must have index, position, normal, and uv attributes.

However normal and uv are not available in js code but in shader.
So how to get the tangent vector?

Vertex tangents and the respective tangent shader attribute can only be used with PBR materials right now. Meaning MeshStandardMaterial and MeshPhysicalMaterial. You have to however set material.vertexTangents to true and provide a normal map so the renderer actually defines the tangent attribute.

1 Like

If normals and UVs are not precalculated then tangents cannot be precalculated. If you generate the first two in the shader then you will also need to write code to define tangents in the shader. Here is the code three.js would normally use to do that — it does assume that the UVs are a vertex attribute but you could change that.

	// Per-Pixel Tangent Space Normal Mapping
	// http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html

	vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm, vec3 mapN ) {

		// Workaround for Adreno 3XX dFd*( vec3 ) bug. See #9988

		vec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );
		vec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );
		vec2 st0 = dFdx( vUv.st );
		vec2 st1 = dFdy( vUv.st );

		float scale = sign( st1.t * st0.s - st0.t * st1.s ); // we do not care about the magnitude

		vec3 S = normalize( ( q0 * st1.t - q1 * st0.t ) * scale );
		vec3 T = normalize( ( - q0 * st1.s + q1 * st0.s ) * scale );
		vec3 N = normalize( surf_norm );

		mat3 tsn = mat3( S, T, N );

		mapN.xy *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );

		return normalize( tsn * mapN );


That said… I’m not sure what kind of UVs one would generate in the shader that would have useful tangents for a normal map? Unless you have something really specific in mind, you might find it easier to open this model in Blender, then export to glTF with the normal and tangent options enabled on export.

1 Like

I have used the UVs provided as default attribute by three js while implementing the above code.
It did work. Thank you !!

Just to confirm, ‘vec3 T’ calculated is in object space?(I just need the tangent vector only for some lighting calculations)

I think so, yes.

1 Like