Sign in to follow this  
neonkandi

HLSL Phong shader problem

Recommended Posts

neonkandi    142
Hi, recently I have begun to learn HLSL with my first three shaders being an implementation of a Phng shader for directional, point, and spotlight. Next to begin using more advanced methods I tried to implement the same shader using Tangent space coordinates but had problems, hence I stripped out the use of the normal map and tried the shader in rendermonkey using the same technique but using surface normals, the same problem occured. Here is the original basic shader:
//VS

float4x4 matViewProjection;
float4x4 matWorld;
float4   vViewPosition;
float4   vDirLight;

struct VS_OUTPUT 
{
   float4 Pos:    POSITION;
   float3 Norm:   TEXCOORD0;
   float2 Tex:    TEXCOORD1;
   float3 View:   TEXCOORD2;
   float3 Light:  TEXCOORD3;
};

VS_OUTPUT vs_main(    float4 inPos: POSITION,
                      float3 inNorm:NORMAL,
                      float2 inTex: TEXCOORD0   )
{
   VS_OUTPUT Out = (VS_OUTPUT) 0;

   Out.Pos = mul(matViewProjection, inPos);
   
   Out.Light = vDirLight;
   
   Out.Tex = inTex;
   
   float3 vPosWorld = normalize( mul( matWorld, inPos ) );
   
   Out.View = normalize( vViewPosition - vPosWorld );
   
   Out.Norm = normalize( mul( matWorld, inNorm ) );   

   return Out;
}

//PS

float fShinyness;
float4 colDiffuse;
float4 colSpecular;
float4 colAmbient;
float4 lightAmbient;
float4 lightDiffuse;
float4 lightSpecular;
float4 globalAmbient;

sampler Texture0;


float4 ps_main(    float3 inNorm:  TEXCOORD0,
                   float2 inTex:   TEXCOORD1,
                   float3 inView:  TEXCOORD2,
                   float3 inLight: TEXCOORD3   ) : COLOR
{  
   //normalize inputs
   float3 vNormal = normalize(inNorm);
   float3 vLight = -normalize(inLight);
   float3 vView = normalize(inView);
   
   //calc diffuse/specular
   float fNormalDotLight = saturate ( dot(vNormal, vLight) );  
   float3 vLightReflect = 2.0*fNormalDotLight*vNormal - vLight;
   
   float fViewDotReflect = saturate( dot(vView, vLightReflect) );
   float4 fSpecIntensity = pow(fViewDotReflect, fShinyness);
   
   float4 diffuse = fNormalDotLight * colDiffuse * lightDiffuse;
   float4 specular = fSpecIntensity * colSpecular * lightSpecular;
   float4 ambient = ( colAmbient * lightAmbient ) + globalAmbient;
   return (ambient + diffuse) * tex2D(Texture0, inTex) + specular;
}

This shader workes fine:
The following is the shader in tangent space
//VS

float4x4 matViewProjection;
float4x4 matWorld;
float4   vViewPosition;
float4   vDirLight;

struct VS_OUTPUT 
{
   float4 Pos:    POSITION;
   float2 Tex:    TEXCOORD0;
   float3 Norm:   TEXCOORD1;
   float3 Light:  TEXCOORD2;
   float3 View:   TEXCOORD3;
};

VS_OUTPUT vs_main(    float4 inPos: POSITION,
                      float3 inNorm:NORMAL,
                      float2 inTex: TEXCOORD0, 
                      float3 inTang: TANGENT  )
{
   VS_OUTPUT Out = (VS_OUTPUT) 0;

   //output texture and position coordinates
   Out.Pos = mul(matViewProjection, inPos);
   Out.Tex = inTex;
   
   float4 vPosWorld = mul( matWorld, inPos );
   
   //generate tangent space vectors
   float3x3 mToTangent;
   
   mToTangent[0] = mul(inTang, (float3x3)matWorld) ;
   mToTangent[2] = mul(inNorm, (float3x3)matWorld) ;
   mToTangent[1] = cross(mToTangent[0], mToTangent[2]);
   
   //calc light and eye vectors and projectors texture coordinates
   float3 vLight = normalize(vDirLight - vPosWorld);
   Out.Light = mul(mToTangent, vDirLight);
   
   float3 vToEye = normalize(vViewPosition - vPosWorld);
   Out.View = mul(mToTangent, vToEye);
   
   Out.Norm = inNorm;
   
   return Out;
}

//PS

float fShinyness;
float4 colDiffuse;
float4 colSpecular;
float4 colAmbient;
float4 lightAmbient;
float4 lightDiffuse;
float4 lightSpecular;
float4 globalAmbient;

sampler Texture0;
sampler Texture1;


float4 ps_main(   float4 inPos:    POSITION,
                  float2 inTex:    TEXCOORD0,
                  float3 inNorm:   TEXCOORD1,
                  float3 inLight:  TEXCOORD2,
                  float3 inView:   TEXCOORD3   ) : COLOR
{  
   //set inputs
   //float3 vNormal = normalize( tex2D(Texture1, inTex).xyz );
   float3 vNormal = normalize(inNorm);
   float3 vLight = normalize(inLight);
   float3 vView = normalize(inView);
   
   //calc diffuse/specular
   float fNormalDotLight = saturate ( dot(vNormal, vLight) );  
   float3 vLightReflect = 2.0*fNormalDotLight*vNormal - vLight;
   
   float fViewDotReflect = saturate( dot(vView, vLightReflect) );
   float4 fSpecIntensity = pow(fViewDotReflect, fShinyness);
   
   float4 diffuse = fNormalDotLight * colDiffuse * lightDiffuse;
   float4 specular = fSpecIntensity * colSpecular * lightSpecular;
   float4 ambient = ( colAmbient * lightAmbient ) + globalAmbient;
   
   return (ambient + diffuse) * tex2D(Texture0, inTex) + specular;
}

This shader seems to have inaccuracies with the reflection and has problems with the texture coordinates.
Any constructive help would be appreciated. [Edited by - Coder on October 3, 2004 2:23:05 PM]

Share this post


Link to post
Share on other sites
Scoob Droolins    258
The original pixel shader negates the light vector during normalization. Your new version does not (unless that's just a typo?). Plus, you don't really need to pass Position into the pixel shader, and I dont think you need to declare Texture1 as a sampler.

joe
image space

[Edited by - Scoob Droolins on October 4, 2004 11:39:46 AM]

Share this post


Link to post
Share on other sites
neonkandi    142
Hi, Yeah I was aware of the first pixel shader negating the input of the light on the first pixel shader but thanks.

The texture problem seems to be down to the model as I used a different model and that part of the shader worked fine, although I am still getting odd light reflections from the tangent space version of the shader.

Texture1 was for the matching normal map which was since removed to simplify things while I found out what I was doing wrong.

Thanks for the constructive help, too many people seem to use these forums to slag each other off.

Share this post


Link to post
Share on other sites
now    138
In your vertex shader you transform your normal and tangent into world space:

mToTangent[0] = mul(inTang, (float3x3)matWorld) ;
mToTangent[2] = mul(inNorm, (float3x3)matWorld) ;

Why are you doing this?

Another thing you have to transform your inNorm into tangent space or just use (0.0f, 0.0f, 1.0f) in your pixel shader for the normal otherwise you are doing calculations with vectors from different spaces.

Share this post


Link to post
Share on other sites
dhanji    192
I agree, it would make more sense to transform your inNormal to tangent space. Also Im not sure this applies but are you making sure they are both normalized before the cross product?

Share this post


Link to post
Share on other sites
neonkandi    142
Thanks, I think that is the answer I was looking for!

Im finding it hard to find good information on HLSL where everything is explained without you being expected to have a degree in maths (which is my weak point).

Most of the vertex shader was out of a book called ShaderX2 Introduction and tutorials with DirectX9 however that particular chapter does a very poor job of exaplaining a good percentage of the shader(or at least the HLSL version) assuming you already understand more than what I would expect someone reading an introductory book on shaders to know.

The point of the shader was converting the original shader I had written to tangent space so I could then begin to get my head round high resolution normal maps for models but perhaps thats a bit beyond my capabilities at the moment.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this