/////////////////////////////////////////////////////////////////////////////// // // ## ###### // ###### ### // ## ############### Shark 3D Engine (www.shark3d.com) // ########## # # # // ######## Copyright (c) 1996-2006 Spinor GmbH. // ######### # # # All rights reserved. // ## ########## // ## // /////////////////////////////////////////////////////////////////////////////// #include \ /////////////////////////////////////////////////////////////////////////////// struct PS_INPUT { float2 mainTexCoord: TEXCOORD0; float3 diffuseDirSurf: TEXCOORD1; float3 specularDirSurf: TEXCOORD2; float3 scaledSurfToLight: TEXCOORD3; #ifdef S3D_PARALLAX_MAPPING float3 camToVertSurf: TEXCOORD4; #endif #ifdef S3D_LIGHT_BRIGHT float4 lightBrightCoord: TEXCOORD5; float4 secPosScr: TEXCOORD6; #endif #ifdef S3D_LIGHT_PROJ float4 lightProjCoord: TEXCOORD5; #endif #ifdef S3D_LIGHT_SHMAP float4 lightShmapCoord: TEXCOORD6; #endif }; /////////////////////////////////////////////////////////////////////////////// sampler mainSamp: register(s0); sampler normalSamp: register(s1); #ifdef S3D_LIGHT_BRIGHT sampler lightBrightSamp: register(s2); #endif #ifdef S3D_LIGHT_PROJ sampler lightProjSamp: register(s2); #endif #ifdef S3D_LIGHT_SHMAP sampler lightShmapSamp: register(s3); #endif /////////////////////////////////////////////////////////////////////////////// const float4 lightAmbient; const float4 lightDiffuse; const float4 lightSpecular; #ifdef S3D_LIGHT_BRIGHT const float4 lightBrightRcpSize; #endif #ifdef S3D_LIGHT_SHMAP const float4 lightShmapSize; const float4 lightShmapRcpSize; #endif /////////////////////////////////////////////////////////////////////////////// #define S3D_INTENS_DISCARD_TRESHOLD 0.001 #define S3D_BRIGHT_EPS 0.01 /////////////////////////////////////////////////////////////////////////////// // Pixelshader // Profile: 2x0 float4 main(PS_INPUT input): COLOR0 { #ifdef S3D_GEOMETRIC_SHADOW // Geometric shadow //clip(input.diffuseDirSurf.z); // ATI Mobility Radeon X1600 workaround: clip(float4(0, 0, 1, 0) * input.diffuseDirSurf); #endif #ifdef S3D_LIGHT_SHMAP float3 clipVal = input.lightShmapCoord.www - abs(2 * input.lightShmapCoord.xyz - input.lightShmapCoord.www); clip(clipVal.xyz); #endif #ifdef S3D_LIGHT_BRIGHT #ifdef S3D_LIGHT_BRIGHT_CARE float4 brightVecMain = tex2Dproj( lightBrightSamp, input.lightBrightCoord); float brightIdent = frac(100.0 * input.secPosScr.z / input.secPosScr.w); float brightDeltaMain = abs(brightVecMain.w - brightIdent); float brightVal = brightVecMain.x; if(brightDeltaMain > S3D_BRIGHT_EPS) { float2 brightOffs = lightBrightRcpSize.xy * input.lightBrightCoord.w; float4 brightCoordX = float4( input.lightBrightCoord.xy + brightOffs, input.lightBrightCoord.zw); float4 brightCoordY = float4( input.lightBrightCoord.xy - brightOffs, input.lightBrightCoord.zw); float4 brightCoordZ = brightCoordX; brightCoordZ.y = brightCoordY.y; float4 brightCoordW = brightCoordY; brightCoordW.y = brightCoordX.y; float4 brightVecX = tex2Dproj(lightBrightSamp, brightCoordX); float4 brightVecY = tex2Dproj(lightBrightSamp, brightCoordY); float4 brightVecZ = tex2Dproj(lightBrightSamp, brightCoordZ); float4 brightVecW = tex2Dproj(lightBrightSamp, brightCoordW); brightVal = min(brightVecMain.x, min(min(brightVecX.x, brightVecY.x), min(brightVecZ.x, brightVecW.x))); } #else // Lookup brightness: float brightVal = tex2Dproj(lightBrightSamp, input.lightBrightCoord).x; #endif // Exit if no light: clip(brightVal - S3D_INTENS_DISCARD_TRESHOLD); #endif #ifdef S3D_LIGHT_SHMAP // Shadow map: float shmapVal = s3d_shmapFilter( lightShmapSamp, input.lightShmapCoord, lightShmapSize, lightShmapRcpSize); clip(shmapVal - S3D_INTENS_DISCARD_TRESHOLD); #endif // Texture coordinates: float2 mainTexCoord = input.mainTexCoord; #ifdef S3D_PARALLAX_MAPPING float3 camToVertSurfNrm = normalize(input.camToVertSurf); float height = tex2D(normalSamp, mainTexCoord).a; float2 offset = S3D_PARALLAX_SCALE * (S3D_PARALLAX_BIAS - height) * camToVertSurfNrm.xy; mainTexCoord = mainTexCoord + offset; #endif // Texture lookups: float4 texCol = tex2D(mainSamp, mainTexCoord); float4 rawNormalView = tex2D(normalSamp, mainTexCoord); float3 normalView = (rawNormalView.xyz - 0.5) * 2; // Calculate range-factor: float rangeFac = max(1.0 - dot(input.scaledSurfToLight, input.scaledSurfToLight), 0.0); // Diffuse direction: float3 diffuseDirSurfNrm = normalize(input.diffuseDirSurf); // Calculate diffuse: float4 diffuse = float4(lightDiffuse.xyz * rangeFac, lightDiffuse.w); diffuse += lightAmbient; float diffDot = dot(normalView, diffuseDirSurfNrm); #ifdef S3D_MILD float diffFac = diffDot * (1 - S3D_MILD) + S3D_MILD; #else float diffFac = diffDot; #endif diffuse *= saturate(diffFac); // Calculate specular: float4 specular = float4(lightSpecular.xyz * rangeFac, lightSpecular.w); float3 specularDirSurfNrm = normalize(input.specularDirSurf); float specDot = dot(normalView, specularDirSurfNrm); float specFac = saturate(pow(saturate(specDot), S3D_SPECULAR_EXP)); specular *= specFac; float4 outCol; outCol.rgb = saturate(diffuse * texCol + specular * texCol.a); // Preserve original opacity from texture. outCol.a = texCol.a; #ifdef S3D_GEOMETRIC_SHADOW // Geometric shadow float geomShadow = saturate(diffuseDirSurfNrm.z * 4); outCol.rgb = saturate(outCol.rgb * geomShadow); #endif #ifdef S3D_LIGHT_BRIGHT // Correct brightness: // The smoothing algorithm generates higher brightness gradients // near 0 and 1 due to sticking to 0 and 1. // This is approximately compensated by using a quadratic function // near 0 and 1. brightVal = 2.0 * brightVal * brightVal * (1.5 - brightVal); // Apply brightness: outCol.rgb = outCol.rgb * brightVal; #endif #ifdef S3D_LIGHT_PROJ float4 texColProjTex = tex2Dproj(lightProjSamp, input.lightProjCoord); outCol *= texColProjTex; #endif #ifdef S3D_LIGHT_SHMAP outCol *= shmapVal; #endif return outCol; } ///////////////////////////////////////////////////////////////////////////////