Sign in to follow this  
Screamer

Parallax Occlusion Mapping Help

Recommended Posts

Does anyone know why the shader i'm trying to implement isn't displaying correctly? I'm trying to do Terry Welsh's version.

OutputVS PhongDirLtTexVS(float3 posL : POSITION0, float3 normalL : NORMAL0, float2 tex0: TEXCOORD0,
  float3 tangentL  : TANGENT0, float3 binormalL : BINORMAL0)
{
    // Zero out our output.
	OutputVS outVS = (OutputVS)0;
	
	// Build TBN-basis.
	float3x3 TBN;
	TBN[0] = tangentL;
	TBN[1] = binormalL;
	TBN[2] = normalL;
	
	// Matrix transforms from object space to tangent space.
	float3x3 toTangentSpace = transpose(TBN);
		
	// Transform eye position to local space.
	float3 eyePosL = mul(float4(gEyePosW, 1.0f), gWorldInv);
	
	// Transform to-eye vector to tangent space.
	float3 toEyeL = eyePosL - posL;
	outVS.toEyeT = mul(toEyeL, toTangentSpace);
	
	// Transform normal to world space.
	outVS.normalW = mul(float4(normalL, 0.0f), gWorldInvTrans).xyz;
	
	// Transform vertex position to world space.
	outVS.posW  = mul(float4(posL, 1.0f), g_mWorld).xyz;
	
	
	// Transform light direction to tangent space.
	//for directional light
	float3 lightDirL = mul(float4(g_lightArray[0].direction, 0.0f), gWorldInv).xyz;
	outVS.lightDirT  = mul(lightDirL, toTangentSpace);
			
	//for point light
	float3 lightDirPointL = mul(float4(normalize(outVS.posW - g_lightArray[1].position), 0.0f), gWorldInv).xyz;
	outVS.lightDirPointT  = mul(lightDirPointL, toTangentSpace);
	
	//for spot light DIRECTX is dumb so i need to use -position as my light direction
	float3 lightDirSpotL = mul(float4(-g_lightArray[2].position, 0.0f), gWorldInv).xyz;
	outVS.lightDirSpotT  = mul(lightDirSpotL, toTangentSpace);
	
	// Compute the unit vector from the vertex to the eye.
	outVS.toEyeW = gEyePosW - outVS.posW;	
	
	// Transform to homogeneous clip space.
	outVS.posH = mul(float4(posL, 1.0f), g_mWorldViewProjection);
	
	// Pass on texture coordinates to be interpolated in rasterization.
	outVS.tex0 = tex0;

	// Done--return the output.
    return outVS;
}

float4 PhongDirLtTexPS(float3 normalW : TEXCOORD0, float3 toEyeW  : TEXCOORD1,
				 float2 tex0 : TEXCOORD2,  float3 posW : POSITION1, float3 toEyeT : TEXCOORD3,
                   float3 lightDirT : TEXCOORD4, float3 lightDirPointT : TEXCOORD5, float3 lightDirSpotT : TEXCOORD6) : COLOR
{
	// Interpolated normals can become unnormal--so normalize.
	//normalW = normalize(normalW);
	//toEyeW  = normalize(toEyeW);
	//toEyeT    = normalize(toEyeT);
	//// Sample normal map.
	float3 normalT = tex2D(NormalMapS, tex0);
	
    
    // Make it a unit vector.
//	normalT = normalize(normalT);
	
	
	float3 color = float3(0,0,0);
	float4 texColor = float4(0,0,0,0);
	
	//pixel OUT;

	float fParallaxLimit = length(toEyeT.xy) / toEyeT.z;	// calculate the parallax offset vector max length
	fParallaxLimit *= fHeightMapScale;						// scale the vector according to height-map scale

	float2 vOffset = normalize( -toEyeT.xy );				// calculate the parallax offset vector direction
	vOffset = vOffset * fParallaxLimit;						// calculate the final maximum offset vector

	float3 E = normalize(toEyeT);
	float3 N = normalize(normalT);

	//int nNumSamples = (int)lerp( nMaxSamples, nMinSamples, dot( E, N ) );	// calculate dynamic number of samples (Tatarchuk's method)
	int nNumSamples = (int)(fParallaxLimit * fTexelsPerSide);				// calculate dynamic number of samples (Zink's method)
	float fStepSize = 1.0 / (float)nNumSamples;								// calculate the texcoord step size
	
	float2 dx, dy;
	dx = ddx( tex0 );	// calculate the texcoord partial derivative in x in screen space for tex2Dgrad
	dy = ddy( tex0 );	// calculate the texcoord partial derivative in y in screen space for tex2Dgrad

	float2 vOffsetStep = fStepSize * vOffset;
	float2 vCurrOffset = float2( 0, 0 );
	float2 vLastOffset = float2( 0, 0 );
	float2 vFinalOffset = float2( 0, 0 );
	
	float4 vCurrSample;
	float4 vLastSample;

	float stepHeight = 1.0;	
	int nCurrSample = 0;

	while ( nCurrSample < nNumSamples )
	{
		vCurrSample = tex2Dgrad( Sampler, tex0 + vCurrOffset, dx, dy );			// sample the current texcoord offset
		if ( vCurrSample.a > stepHeight )
		{
			// calculate the linear intersection point
			float Ua = (vLastSample.a - (stepHeight+fStepSize)) / ( fStepSize + (vCurrSample.a - vLastSample.a));
			vFinalOffset = vLastOffset + Ua * vOffsetStep;

			vCurrSample = tex2Dgrad( Sampler, tex0 + vFinalOffset, dx, dy );		// sample the corrected tex coords
			nCurrSample = nNumSamples + 1;												// exit the while loop
		}
		else
		{
			nCurrSample++;							// increment to the next sample
			stepHeight -= fStepSize;				// change the required height-map height
			vLastOffset = vCurrOffset;				// remember this texcoord offset for next time
			vCurrOffset += vOffsetStep;				// increment to the next texcoord offset
			vLastSample = vCurrSample;
		}
	}

	texColor = vCurrSample;						// return the final sampled color value


	// Expand from [0, 1] compressed interval to true [-1, 1] interval.
    normalT = 2.0f*normalT - 1.0f;

	lightDirPointT = normalize(lightDirPointT);
	float3 lightVecPointT = -lightDirPointT;
	
	// Unit vector from vertex to light source.
	//float3 lightVecWpoint = normalize(g_lightArray[i].position - posW);
	
	// Ambient Light Computation.
	float3 ambient = (gMtrl.ambient*g_lightArray[1].ambient).rgb;

	// Diffuse Light Computation.
	float s = max(dot(normalT, lightVecPointT), 0.00001f);
	float3 diffuse = s*(gMtrl.diffuse*g_lightArray[1].diffuse).rgb;

	// Specular Light Computation.
	//float3 toEyeW   = normalize(gEyePosW - posW);
	float3 r = reflect(lightVecPointT, normalT);
	float t = pow(abs(max(dot(r, toEyeT), 0.00001f)), gMtrl.specPower);
	float3 spec = t*(gMtrl.spec*g_lightArray[1].specular).rgb;

	// Attentuation.
	float d = distance(g_lightArray[1].position, posW);
	float A = g_lightArray[1].attenuation.x + g_lightArray[1].attenuation.y*d + g_lightArray[1].attenuation.z*d*d;

	// Everything together.
	color += ambient + ((diffuse + spec) / A);
	//return float4(color,1.0f);
	

	return float4(color, gMtrl.diffuse.a*texColor.a);

	//return OUT;
	
	
	
	

Thanks a million Screamer

Share this post


Link to post
Share on other sites
Common problems with POM are the input geometry. Have you checked your tangent and bitangent vectors to make sure that they are pointing in the right directions?

I have also found that it helps to go manually through all of the calculations in my shader once to ensure that the math is correct - you can use a matrix multiplier program if you don't want to manually do it. Choose a simple height map and walk through the whole process.

Shameless plug: you can check out my article in the signature below for a guideline and description of how to do POM!

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