# Multiplying tangent and bitangent by scale matrix

• 02-06-2006
psychopath
Multiplying tangent and bitangent by scale matrix
In my dot3 rendering, I noticed that on larger objects (such as a floor in a room), the radiation centre of my light seems to be offset from the lights position. The offset distance seems to increase the farther the light position moves from the object centre.

I did a quick test, and it seems to me, that objects with an XYZ scale of 1 don't have this problem, but scaled objects do (the larger the object, the worse the offset issue). I'm thinking that this is because when I scale an object, the verticies are scaled, but the tangent and bitangent vectors aren't. This would mean that the light on a 20x20x20 cube, is calculated as if the cube is still 1x1x1.

First of all, is what I think is the problem, actually the problem? And if so, how would you scale tangent and bitangent vectors?
• 02-06-2006
loopshot
if your verticies scale is updated i dont think there should be a problem with the calculations.
• 02-07-2006
psychopath
Ok, I tried that and it didn't seem to have any effect on the lighting. Although, as far as I know, multipltying the vectors in that way would just increase the length of the vector (producing unnormalized vectors as you said); but translating the vector to the scaled verticies position would keep the vector length, right?

And since I doubt that would do anything either, what other reasons are there for the offset of the radiation centre?
• 02-07-2006
VirtualAce
Well that is scaling the vectors. That is essentially what the scaling matrix does.

k 0 0 1
0 k 0 1
0 0 k 1
0 0 0 1

If you notice this, this is the same as

Vertex.x*=k,Vertex.y*=k,Vertex.z*=k,Vertex.w*=1.0f ;

A scaling matrix will scale the vertices or vectors. Translating the vectors prob won't help either since lighting is not computed globally, it's computed locally. Tangent space vectors should not need to be translated.

Show me a screenshot of this displacement and perhaps I can tell what is going on.
• 02-07-2006
psychopath
The light position is shown by the red diamond, translated slightly to the left. As you can see, the radiation center moved way beyond it.
• 02-07-2006
VirtualAce
Ok that's definitely strange.

I'm not sure how you are doing this so I may not be much help.

The standard illumination setup is this:

1. Ambient.
2. Diffuse.
3. Specular.

How I do this is derived from several books. First I use vertex shaders to do all the transformation and calculations which are then sent to the pixel shaders. The pixel shaders then alter the color of the output pixel based on the code in the shader.

First is this tangent space bump mapping or object space bump mapping? There is a difference in that in one you do transform the light vector and in the other you do not.

Programming Vertex and Pixel Shaders Charles River Media, pp. 111-16, 2004.

A book that tells you exactly how to compute the tangent vectors is

Mathematics for 3D Game Programing and Computer Graphics - Second Edition Charles River Media, pp. 184-189, 2003.

Following is source code from the first source mentioned for ambient, diffuse, and specular lighting as well as bump mapping.
I do not have the ability to translate these into Cg. The only thing I can do is run these through fxc.exe and then post the disassembly here.

Ambient lighting
Vertex
Code:

```float4x4 matWorldViewProj; struct VS_OUTPUT {   float 4 Pos: POSITION; }; VS_OUTPUT VS(float4 Pos:POSITION) {   VS_OUTPUT Out=(VS_OUTPUT) 0;   Out.Pos=mul(Pos,matWorldviewProj);   return Out; }```
Pixel
Code:

```float 4 PS(): COLOR {   float Aintensity=0.8f;   float4 Acolor=float4(1.0,0.075,0.075,1.0);   return Aintensity*Acolor; }```
Diffuse lighting
Vertex
Code:

```float4x4 matWorldViewProj; float4x4 matInvTransposeWorld; float4 vecLightDir; float4 vDic; struct VS_OUTPUT {   float4 Pos: POSITION;   float3 Light: TEXCOORD0;   float3 Norm: TEXCOORD1; }; VS_OUTPUT VS(float4 Pos: POSITION, float3 Normal: NORMAL) {   VS_OUTPUT Out=(VS_OUTPUT) 0;   Out.Pos=mul(Pos,matWorldViewProj);   Out.Light=normalize(vecLightDir);   Out.Norm=normalize(mul(matInvTransposeWorld,Normal));   return Out; }```
Pixel
Code:

```float4 PS(float3 Light: TEXCOORD0,float3 Norm: TEXCOORD1) : COLOR {   float4 A={0.f,0.0,0.0,1.0};   return A+vDic*saturate(dot(Light,Normal)); }```
Specular (pure Phong, not Blinn)
Vertex
Code:

```float4x4 matWorldViewProj; float4x4 matWorld; float4 vecLightDir; float4 vecEye; float4 vDIC; float4 vSpecIC; struct VS_OUTPUT VS(float4 Pos: POSITION,float 4 Normal:NORMAL) {   VS_OUTPUT Out= (VS_OUTPUT) 0;   Out.Pos=mul(Pos,matWorldViewProj);   Out.Norm=mul(Normal,matWorld);   float4 PosWorld=mul(Pos,matWorld);   Out.Light=vecLightDir;   Out.View=vecEye-PosWorld;   return Out; }```
Pixel
Code:

```float4 PS(float3 Light: TEXCOORD0,float3 Norm:TEXCOORD1,float3 View:TEXCOORD2):COLOR {   float4 A={0.1f,.0.0f,0.0f,1.0f};   float3 Normal=normalize(Norm);   float3 LightDir=normalize(Light);   float3 ViewDir=normalize(View);     float Diff=saturate((dot(Normal,LightDir));   float3 Reflect=normalize(2*Diff*Normal*LightDir);   float Specular=pow(saturate(dot(Reflect,ViewDir)),8);   return A+vDIC*Diff+vSpecIC*Specular; }```
Bump mapping
Vertex
Code:

```float4x4 matWorldViewProj; float4x4 matWorld; float4 vecLightDir; float4 vecEye; struct VS_OUTPUT {   float4 Pos: POSITION;   float2 Tex:TEXCOORD0;   float3 Light: TEXCOORD1;   float3 Vew:TEXCOORD2; }; VS_OUTPUT VS(float4 Pos:POSITION,float2 Tex:TEXCOORD0,float3 Normal:NORMAL,float3 Tangent:TANGENT) {   VS_OUTPUT Out= (VS_OUTPUT) 0;   Out.Pos=mul(Pos,matWorldViewProj);   //Transform world space to tangent space   float3x3 worldToTangentSpace;   worldToTangentSpace[0]=mul(Tangent,matWorld);   worldToTangentSpace[1]=mul(cross(Tangent,normal),matWorld);   worldToTangentSpace[2]=mul(Normal,matWorld);   Out.Tex=Tex;   float4 PosWorld=mul(Pos,matWorld);   Out.Light=mul(worldToTangentSpace,vecLightDir);   Out.View=mul(worldToTangentSpace,vecEye*PosWorld);   return Out; }```
Pixel
Code:

```texture ColorMap; sampler ColorMapSampler=sampler_state {   Texture=<ColorMap>;   MinFilter=Linear;      MagFilter=Linear;    MipFilter=Linear;   AddressU=Clamp;   AddressV=Clamp; }; texture BumpMap; sampler BumpMapSampler=sampler_state {   Texture=<BumpMap>;   MinFilter=Linear;   MagFilter=Linear;   MipFilter=Linear;   AddressU=Clamp;   AddressV=Clamp; }; float4 PS(float2 Tex:TEXCOORD0,float3 Light:TEXCOORD1,float3 View:TEXCOORD2):COLOR {   float4 Color=tex2D(ColorMapSampler,Tex);   float3 Normal=(2*(tex2D(BumpMapSampler,Tex)))-1.0;   float3 LightDir=normalize(Light);   float3 ViewDir=normalize(View);   float Diffuse=saturate(dot(Normal,LightDir));   float3 Reflect=normalize(2*Diffuse*Normal-LightDir);     float Specular=min(pow(saturate(dot(Reflect,ViewDir)),3),Color.w);   return 0.2*Color+Color*Diffuse+Specular; }```
Perhaps the transform from world space to tangent space may help.
• 02-08-2006
psychopath
I'm doing all the calculations in tangent space already. I'm not using shaders at the moment(I've had alot of trouble getting it working properly with shaders). I'm using OpenGL dot3 extensions, so the lighting is should be standard(it's basicly like doing bumpmapping in fixed-function mode).

It seems that the only way to get this working correctly, is to try and get my shader bumpmapping working correctly. However, that would mean the fallback for cards that don't support OpenGL 2.0 still wouldn't work properly....which means I need to get both working..argh.