You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
224 lines
9.5 KiB
224 lines
9.5 KiB
//---------------------------------------------------------------------------------//
|
|
// Parallax occlusion mapping algorithm implementation. Pixel shader.
|
|
//---------------------------------------------------------------------------------//
|
|
|
|
//..........................................................................................
|
|
// Uniform shader parameters declaration
|
|
//..........................................................................................
|
|
|
|
const float4 g_ParallaxParms : register( c0 );
|
|
|
|
float fShadowSoftening = 0.59f; // fixme: should be a vmt param
|
|
float fHeightMapRange = 0.02f; // fixme: should be a vmt param
|
|
|
|
// unused stuff
|
|
float fSpecularExponent = 100.0f; // fixme: should be a vmt param
|
|
float fDiffuseBrightness = 1.0f;
|
|
float4 cAmbientColor = float4( 1.0f, 1.0f, 1.0f, 1.0f );
|
|
float4 cDiffuseColor = float4( 1.0f, 1.0f, 1.0f, 1.0f );
|
|
float4 cSpecularColor = float4( 1.0f, 1.0f, 1.0f, 1.0f );
|
|
|
|
// texture samplers
|
|
sampler tBaseMap;
|
|
sampler tNormalMap;
|
|
|
|
//..........................................................................................
|
|
// Note: centroid is specified if multisampling is enabled through RenderMonkey's DirectX
|
|
// window preferences settings
|
|
//..........................................................................................
|
|
struct PS_INPUT
|
|
{
|
|
float2 texCoord : TEXCOORD0;
|
|
// float3 vLightTS : TEXCOORD1_centroid; // light vector in tangent space, denormalized
|
|
float3 vViewTS : TEXCOORD2_centroid; // view vector in tangent space, denormalized
|
|
float2 vParallaxOffsetTS : TEXCOORD3_centroid; // Parallax offset vector in tangent space
|
|
float3 vNormalWS : TEXCOORD4_centroid; // Normal vector in world space
|
|
float3 vViewWS : TEXCOORD5_centroid; // View vector in world space
|
|
float4 vDebug : TEXCOORD6;
|
|
};
|
|
|
|
//..........................................................................................
|
|
// Function: ComputeIllumination
|
|
//
|
|
// Description: Computes phong illumination for the given pixel using its attribute textures
|
|
// and a light vector.
|
|
//..........................................................................................
|
|
float4 ComputeIllumination( float2 texCoord, float3 vLightTS, float3 vViewTS, float fOcclusionShadow )
|
|
{
|
|
// Sample the normal from the normal map for the given texture sample:
|
|
float3 vNormalTS = normalize( tex2D( tNormalMap, texCoord ) * 2 - 1 );
|
|
|
|
// Sample base map:
|
|
float4 cBaseColor = tex2D( tBaseMap, texCoord );
|
|
|
|
// Compute diffuse color component:
|
|
float4 cDiffuse = saturate( dot( vNormalTS, vLightTS )) * cDiffuseColor;
|
|
|
|
// Compute specular component:
|
|
float3 vReflectionTS = normalize( 2 * dot( vViewTS, vNormalTS ) * vNormalTS - vViewTS );
|
|
|
|
float fRdotL = dot( vReflectionTS, vLightTS );
|
|
|
|
float4 cSpecular = saturate( pow( fRdotL, fSpecularExponent )) * cSpecularColor;
|
|
|
|
float4 cFinalColor = (( cAmbientColor + cDiffuse ) * cBaseColor + cSpecular ) * fOcclusionShadow;
|
|
|
|
return cFinalColor;
|
|
}
|
|
|
|
//...........................................................................................
|
|
// Function: ps_main
|
|
//
|
|
// Description: Computes pixel illumination result due to applying parallax occlusion mapping
|
|
// to simulation of view-dependent surface displacement for a given height map
|
|
//...........................................................................................
|
|
float4 main( PS_INPUT i ) : COLOR0
|
|
{
|
|
int nMinSamples = g_ParallaxParms.x;
|
|
int nMaxSamples = g_ParallaxParms.y;
|
|
|
|
// Normalize the interpolated vectors:
|
|
float3 vViewTS = normalize( i.vViewTS );
|
|
float3 vViewWS = normalize( i.vViewWS );
|
|
// float3 vLightTS = normalize( i.vLightTS );
|
|
float3 vNormalWS = normalize( i.vNormalWS );
|
|
|
|
float4 cResultColor = float4( 0, 0, 0, 1 );
|
|
|
|
// Compute all the derivatives:
|
|
float2 dx = ddx( i.texCoord );
|
|
float2 dy = ddy( i.texCoord );
|
|
|
|
//===============================================//
|
|
// Parallax occlusion mapping offset computation //
|
|
//===============================================//
|
|
|
|
// Utilize dynamic flow control to change the number of samples per ray
|
|
// depending on the viewing angle for the surface. Oblique angles require
|
|
// smaller step sizes to achieve more accurate precision for computing displacement.
|
|
// We express the sampling rate as a linear function of the angle between
|
|
// the geometric normal and the view direction ray:
|
|
int nNumSteps = (int) lerp( nMaxSamples, nMinSamples, dot( vViewWS, vNormalWS ) );
|
|
|
|
// Intersect the view ray with the height field profile along the direction of
|
|
// the parallax offset ray (computed in the vertex shader. Note that the code is
|
|
// designed specifically to take advantage of the dynamic flow control constructs
|
|
// in HLSL and is very sensitive to specific syntax. When converting to other examples,
|
|
// if still want to use dynamic flow control in the resulting assembly shader,
|
|
// care must be applied.
|
|
//
|
|
// In the below steps we approximate the height field profile as piecewise linear
|
|
// curve. We find the pair of endpoints between which the intersection between the
|
|
// height field profile and the view ray is found and then compute line segment
|
|
// intersection for the view ray and the line segment formed by the two endpoints.
|
|
// This intersection is the displacement offset from the original texture coordinate.
|
|
// See the above paper for more details about the process and derivation.
|
|
//
|
|
float fCurrHeight = 0.0;
|
|
float fStepSize = 1.0 / (float) nNumSteps;
|
|
float fPrevHeight = 1.0;
|
|
float fNextHeight = 0.0;
|
|
|
|
int nStepIndex = 0;
|
|
bool bCondition = true;
|
|
|
|
float2 vTexOffsetPerStep = fStepSize * i.vParallaxOffsetTS;
|
|
float2 vTexCurrentOffset = i.texCoord;
|
|
float fCurrentBound = 1.0;
|
|
float fParallaxAmount = 0.0;
|
|
|
|
float2 pt1 = 0;
|
|
float2 pt2 = 0;
|
|
|
|
float2 texOffset2 = 0;
|
|
|
|
while ( nStepIndex < nNumSteps )
|
|
{
|
|
vTexCurrentOffset -= vTexOffsetPerStep;
|
|
|
|
// Sample height map which in this case is stored in the alpha channel of the normal map:
|
|
fCurrHeight = tex2Dgrad( tNormalMap, vTexCurrentOffset, dx, dy ).a;
|
|
|
|
fCurrentBound -= fStepSize;
|
|
|
|
if ( fCurrHeight > fCurrentBound )
|
|
{
|
|
pt1 = float2( fCurrentBound, fCurrHeight );
|
|
pt2 = float2( fCurrentBound + fStepSize, fPrevHeight );
|
|
|
|
texOffset2 = vTexCurrentOffset - vTexOffsetPerStep;
|
|
|
|
nStepIndex = nNumSteps + 1;
|
|
}
|
|
else
|
|
{
|
|
nStepIndex++;
|
|
fPrevHeight = fCurrHeight;
|
|
}
|
|
} // End of while ( nStepIndex < nNumSteps )
|
|
|
|
float fDelta2 = pt2.x - pt2.y;
|
|
float fDelta1 = pt1.x - pt1.y;
|
|
fParallaxAmount = (pt1.x * fDelta2 - pt2.x * fDelta1 ) / ( fDelta2 - fDelta1 );
|
|
|
|
float2 vParallaxOffset = i.vParallaxOffsetTS * (1 - fParallaxAmount );
|
|
|
|
// The computed texture offset for the displaced point on the pseudo-extruded surface:
|
|
float2 texSample = i.texCoord - vParallaxOffset;
|
|
|
|
// float2 vLightRayTS = vLightTS.xy * fHeightMapRange;
|
|
|
|
// Compute the soft blurry shadows taking into account self-occlusion for features of the height
|
|
// field:
|
|
|
|
// float sh0 = tex2Dgrad( tNormalMap, texSample, dx, dy ).a;
|
|
// float shA = (tex2Dgrad( tNormalMap, texSample + vLightRayTS * 0.88, dx, dy ).a - sh0 - 0.88 ) * 1 * fShadowSoftening;
|
|
// float sh9 = (tex2Dgrad( tNormalMap, texSample + vLightRayTS * 0.77, dx, dy ).a - sh0 - 0.77 ) * 2 * fShadowSoftening;
|
|
// float sh8 = (tex2Dgrad( tNormalMap, texSample + vLightRayTS * 0.66, dx, dy ).a - sh0 - 0.66 ) * 4 * fShadowSoftening;
|
|
// float sh7 = (tex2Dgrad( tNormalMap, texSample + vLightRayTS * 0.55, dx, dy ).a - sh0 - 0.55 ) * 6 * fShadowSoftening;
|
|
// float sh6 = (tex2Dgrad( tNormalMap, texSample + vLightRayTS * 0.44, dx, dy ).a - sh0 - 0.44 ) * 8 * fShadowSoftening;
|
|
// float sh5 = (tex2Dgrad( tNormalMap, texSample + vLightRayTS * 0.33, dx, dy ).a - sh0 - 0.33 ) * 10 * fShadowSoftening;
|
|
// float sh4 = (tex2Dgrad( tNormalMap, texSample + vLightRayTS * 0.22, dx, dy ).a - sh0 - 0.22 ) * 12 * fShadowSoftening;
|
|
|
|
// Compute the actual shadow strength:
|
|
// float fOcclusionShadow = 1 - max( max( max( max( max( max( shA, sh9 ), sh8 ), sh7 ), sh6 ), sh5 ), sh4 );
|
|
|
|
// The previous computation overbrightens the image, let's adjust for that:
|
|
// fOcclusionShadow = fOcclusionShadow * 0.6 + 0.4;
|
|
|
|
// Compute resulting color for the pixel:
|
|
// cResultColor = ComputeIllumination( texSample, vLightTS, vViewTS, fOcclusionShadow );
|
|
|
|
// cResultColor.xyz = ( float )nNumSteps / nMaxSamples;
|
|
//cResultColor.xyz = float3( vTexOffsetPerStep, 0.0f );
|
|
cResultColor.xyz = tex2Dgrad( tNormalMap, texSample, dx, dy ).rgb;
|
|
cResultColor.a = 1.0f;
|
|
|
|
// cResultColor.xyz = float3( vParallaxOffset * 10.0, 0.0f );
|
|
// cResultColor.xyz = ( float3 )fParallaxAmount * .1f;
|
|
// cResultColor.xyz = float3( i.texCoord - ( int2 )i.texCoord, 0.0f );
|
|
// cResultColor.xyz = i.vViewTS;
|
|
// cResultColor.xyz = i.vNormalWS.xyz;
|
|
// cResultColor.xyz = float3( i.vParallaxOffsetTS * 10.0f, 0.0f );
|
|
// cResultColor = i.vDebug;
|
|
// cResultColor.xyz = ( float3 )tex2Dgrad( tNormalMap, texSample, dx, dy ).a;
|
|
// cResultColor.xyz = float3( vTexOffsetPerStep * 10.0f, 0.0f );
|
|
|
|
|
|
// cResultColor = float4( 1.0f, 0.0f, 0.0f, 1.0f );
|
|
|
|
return cResultColor;
|
|
|
|
} // End of float4 ps_main(..)
|
|
|
|
#if 0
|
|
struct PS_INPUT
|
|
{
|
|
float2 texCoord : TEXCOORD0;
|
|
// float3 vLightTS : TEXCOORD1_centroid; // light vector in tangent space, denormalized
|
|
float3 vViewTS : TEXCOORD2_centroid; // view vector in tangent space, denormalized
|
|
float2 vParallaxOffsetTS : TEXCOORD3_centroid; // Parallax offset vector in tangent space
|
|
float3 vNormalWS : TEXCOORD4_centroid; // Normal vector in world space
|
|
float3 vViewWS : TEXCOORD5_centroid; // View vector in world space
|
|
};
|
|
#endif
|