uniform float4x4 c3d_mtxProjection; uniform float4x4 c3d_mtxModelView; uniform float4x4 c3d_mtxNormal; uniform float4 c3d_v4AmbientLight; uniform float4 c3d_v4MatAmbient; uniform float4 c3d_v4MatEmissive; uniform float4 c3d_v4MatDiffuse; uniform float4 c3d_v4MatSpecular; uniform float c3d_fMatShininess; uniform int c3d_iLightsCount; texture c3d_sLights; sampler2D LightsSampler = sampler_state { Texture = (c3d_sLights); AddressU = clamp; AddressV = clamp; MagFilter = POINT; MinFilter = POINT; Mipfilter = POINT; }; float Depth; float Tile; int LinearSearchSteps = 20; int BinarySearchSteps = 5; texture DiffuseMap; sampler2D DiffuseSampler = sampler_state { Texture = (DiffuseMap); AddressU = clamp; AddressV = clamp; MagFilter = LINEAR; MinFilter = LINEAR; Mipfilter = LINEAR; }; texture NormalMap; sampler2D NormalSampler = sampler_state { Texture = (NormalMap); AddressU = clamp; AddressV = clamp; MagFilter = LINEAR; MinFilter = LINEAR; Mipfilter = LINEAR; }; struct VtxInput { float4 vertex : POSITION0; float3 normal : NORMAL0; float3 tangent : TANGENT; float2 Texture : TEXCOORD0; }; struct VtxOutput { float4 Position : POSITION0; float2 Texture : TEXCOORD0; float3 vertex : NORMAL0; float3 tangent : NORMAL1; float3 binormal : NORMAL2; float3 normal : NORMAL3; }; struct Light { float4 m_v4Ambient; float4 m_v4Diffuse; float4 m_v4Specular; float4 m_v4Position; int m_iType; float3 m_v3Attenuation; float4x4 m_mtx4Orientation; float m_fExponent; float m_fCutOff; }; Light GetLight( int i ) { Light l_lightReturn; l_lightReturn.m_v4Ambient = tex2D( LightsSampler, float2( (i * 0.1) + (0 * 0.01) + 0.005, 0.0 ) ); l_lightReturn.m_v4Diffuse = tex2D( LightsSampler, float2( (i * 0.1) + (1 * 0.01) + 0.005, 0.0 ) ); l_lightReturn.m_v4Specular = tex2D( LightsSampler, float2( (i * 0.1) + (2 * 0.01) + 0.005, 0.0 ) ); float4 l_v4Position = tex2D( LightsSampler, float2( (i * 0.1) + (3 * 0.01) + 0.005, 0.0 ) ); l_lightReturn.m_v3Attenuation = tex2D( LightsSampler, float2( (i * 0.1) + (4 * 0.01) + 0.005, 0.0 ) ).xyz; float4 l_v4A = tex2D( LightsSampler, float2( (i * 0.1) + (5 * 0.01) + 0.005, 0.0 ) ); float4 l_v4B = tex2D( LightsSampler, float2( (i * 0.1) + (6 * 0.01) + 0.005, 0.0 ) ); float4 l_v4C = tex2D( LightsSampler, float2( (i * 0.1) + (7 * 0.01) + 0.005, 0.0 ) ); float4 l_v4D = tex2D( LightsSampler, float2( (i * 0.1) + (8 * 0.01) + 0.005, 0.0 ) ); float2 l_v2Spot = tex2D( LightsSampler, float2( (i * 0.1) + (9 * 0.01) + 0.005, 0.0 ) ).xy; l_lightReturn.m_v4Position = float4( l_v4Position.z, l_v4Position.y, l_v4Position.x, 0.0 ); l_lightReturn.m_iType = int( l_v4Position.w ); l_lightReturn.m_mtx4Orientation = float4x4( l_v4A, l_v4B, l_v4C, l_v4D ); l_lightReturn.m_fExponent = l_v2Spot.x; l_lightReturn.m_fCutOff = l_v2Spot.x; return l_lightReturn; } float RayIntersectRM( in float2 dp, in float2 ds); float length( float3 p_vector) { return sqrt( p_vector.x * p_vector.x + p_vector.y * p_vector.y + p_vector.z * p_vector.z); } VtxOutput mainVx( in VtxInput p_input) { VtxOutput l_output; float3 binormal = cross( p_input.tangent, p_input.normal ); float3x3 l_normalMatrix = (float3x3)c3d_mtxNormal; l_output.tangent = mul( p_input.tangent, l_normalMatrix ); l_output.binormal = mul( binormal, l_normalMatrix ); l_output.normal = mul( p_input.normal, l_normalMatrix ); l_output.vertex = mul( p_input.vertex, c3d_mtxModelView ).xyz; l_output.Texture = p_input.Texture; l_output.Position = mul( p_input.vertex, c3d_mtxProjection * c3d_mtxModelView ); return l_output; } float4 mainPx( in VtxOutput p_input ) : COLOR0 { Light l_light = GetLight( 0 ); float4 l_vAmbient = float4( 0, 0, 0, 0 ); float3 l_vLight = mul( l_light.m_v4Position, c3d_mtxModelView ).xyz; float4 l_vSpecular = float4( 0, 0, 0, 0 ); float4 l_vDiffuse = float4( 0, 0, 0, 0 ); float l_fShine = c3d_fMatShininess; l_vAmbient += c3d_v4MatAmbient * l_light.m_v4Ambient; l_vSpecular += c3d_v4MatSpecular * l_light.m_v4Specular; l_vDiffuse += c3d_v4MatDiffuse * l_light.m_v4Diffuse; float4 l_vTextureRelief; float4 l_vTextureColour; float3 l_vTmp1; float3 l_vTmp2; float3 l_eyeSpaceVertex; float3 l_vLightDirection; float2 l_vUV; float l_fDot; float d; float2 dp, ds; // ray intersect in view direction l_vTmp2 = p_input.vertex; l_eyeSpaceVertex = normalize( l_vTmp2); l_fDot = dot( p_input.normal, -l_eyeSpaceVertex); l_vTmp1 = normalize( float3( dot( l_eyeSpaceVertex, p_input.tangent), dot( l_eyeSpaceVertex, p_input.binormal), l_fDot)); l_vTmp1 *= Depth / l_fDot; dp = p_input.Texture * Tile; ds = l_vTmp1.xy; d = RayIntersectRM( dp, ds); // get rm and color texture points l_vUV = dp + ds * d; l_vTextureRelief = tex2D( NormalSampler, l_vUV); l_vTextureColour = tex2D( DiffuseSampler, l_vUV); // expand normal from normal map in local polygon space l_vTextureRelief.xy = l_vTextureRelief.xy * 2.0 - 1.0; l_vTextureRelief.z = sqrt( 1.0 - dot( l_vTextureRelief.xy, l_vTextureRelief.xy)); l_vTextureRelief.rgb = normalize( l_vTextureRelief.x * p_input.tangent + l_vTextureRelief.y * p_input.binormal + l_vTextureRelief.z * p_input.normal); // compute light direction l_vTmp2 += l_eyeSpaceVertex * d * l_fDot; l_vLightDirection = normalize( l_vTmp2 - l_vLight.xyz); // ray intersect in light direction dp += ds * d; l_fDot = dot( p_input.normal, -l_vLightDirection); l_vTmp1 = normalize( float3( dot( l_vLightDirection, p_input.tangent), dot( l_vLightDirection, p_input.normal), l_fDot)); l_vTmp1 *= Depth / l_fDot; ds = l_vTmp1.xy; dp -= ds * d; float dl = RayIntersectRM( dp, l_vTmp1.xy); float l_fShadow = 1.0; float3 l_vSpecularShadow = l_vSpecular.rgb; if (dl < d - 0.05) // if pixel in shadow { l_fShadow = dot( l_vAmbient.rgb, float3( 1, 1, 1)) * 0.333333; l_vSpecularShadow = float3( 0, 0, 0); } // compute diffuse and specular terms float l_fAttenuation = max( 0.0, dot( -l_vLightDirection, p_input.normal)); float l_fDiffuseTerm = l_fShadow * max( 0.0, dot( -l_vLightDirection, l_vTextureRelief.rgb)); float l_fSpecularTerm = max( 0.0, dot( normalize( -l_vLightDirection - l_eyeSpaceVertex), l_vTextureRelief.rgb)); // compute final color float4 l_vFinalColour; l_vFinalColour.rgb = l_vAmbient.rgb * l_vTextureColour.rgb + l_fAttenuation * (l_vTextureColour.rgb * l_vDiffuse.rgb * l_fDiffuseTerm + l_vSpecularShadow * pow( l_fSpecularTerm, l_fShine)); l_vFinalColour.a = 1; return l_vFinalColour; } float RayIntersectRM( in float2 p_vDP, in float2 p_vDS) { float l_fDepthStep = 1.0 / float( LinearSearchSteps); // current size of search window float l_fSize = l_fDepthStep; // current depth position float l_fDepth = 0.0; // best match found (starts with last position 1.0) float l_fDepthReturn = 1.0; float4 l_vTexColour; int i; // search front to back for first point inside object for (i = 0 ; i < LinearSearchSteps - 1 ; i++) { l_fDepth += l_fSize; l_vTexColour = tex2Dlod( NormalSampler, float4( p_vDP + p_vDS * l_fDepth, 0, 0)); // l_vTexColour = tex2D( NormalSampler, p_vDP + p_vDS * l_fDepth); if (l_fDepthReturn > 0.996) // if no depth found yet { if (l_fDepth >= l_vTexColour.w) { l_fDepthReturn = l_fDepth; // store best depth } } } l_fDepth = l_fDepthReturn; // recurse around first point (l_fDepth) for closest match for (i = 0 ; i < BinarySearchSteps ; i++) { l_fSize *= 0.5; l_vTexColour = tex2Dlod( NormalSampler, float4( p_vDP + p_vDS * l_fDepth, 0, 0)); // l_vTexColour = tex2D( NormalSampler, p_vDP + p_vDS * l_fDepth); if (l_fDepth >= l_vTexColour.w) { l_fDepthReturn = l_fDepth; l_fDepth -= 2.0 * l_fSize; } l_fDepth += l_fSize; } return l_fDepthReturn; } technique RenderPass { pass p0 { CullMode=none; PixelShader = compile ps_3_0 mainPx(); VertexShader = compile vs_3_0 mainVx(); } };