//-------------------------------------------------------------------------------------- // File: effectChaff.fx // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbConstant { static const float CycleRate = 3.7; static const float NoiseScale = 2.00; static const float SpecleAmount = 0.5; }; cbuffer cbGlobal { float g_TimeNow; float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; }; Texture2D g_MaterialTexture; SamplerState g_TextureSampler { Filter = MIN_POINT_MAG_LINEAR_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float4 diffuse : COLOR; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float4 diffuse : COLOR0; float4 pos_w : COLOR1; //xyz = world space pos, w = fogdist float3 uv : TEXCOORD; //xy = uv, z = spec float4 pos : SV_POSITION; }; struct PS_INPUT { float4 diffuse : COLOR0; float4 pos_w : COLOR1; //xyz = world space pos, w = fogdist float3 uv : TEXCOORD; //xy = uv, z = spec }; //-------------------------------------------------------------------------------------- float4 add_fog_fade_alpha(float4 Color, float FogDist, float FogZ) { float4 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, float4(g_FogColor, 0.0f), fog); return (output); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space output.pos = mul(P, g_mViewProj); output.diffuse = input.diffuse; output.uv.xy = input.uv; output.uv.z = max(0.0f, sin(float(CycleRate*g_TimeNow + NoiseScale*(P.x - P.y)))); output.pos_w.xyz = P.xyz; const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output = g_MaterialTexture.Sample(g_TextureSampler, input.uv.xy); output = input.diffuse * output; output.rgb += (input.uv.z * float3(SpecleAmount, SpecleAmount, SpecleAmount)); output = add_fog_fade_alpha(output, input.pos_w.w, input.pos_w.z); return (output); } //-------------------------------------------------------------------------------------- // Techniques //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: effectColor1Add.fx // Copyright (c) 2010 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float g_LightLevel; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; }; Texture2D g_MaterialTexture; SamplerState g_LinearSampler { Filter = MIN_MAG_MIP_LINEAR; AddressU = Wrap; AddressV = Wrap; }; struct VS_INPUT { float3 pos : POSITION; float4 diffuse : COLOR; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float4 diffuse : COLOR; float4 pos_w : COLOR1; //xyz = world space pos, w = fogdist float2 uv : TEXCOORD; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 diffuse : COLOR; float4 pos_w : COLOR1; //xyz = world space pos, w = fogdist float2 uv : TEXCOORD; }; //-------------------------------------------------------------------------------------- float4 multiply_fog(float4 Color, float FogDist, float FogZ) { float4 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } output *= (1.0 - clamp(0.0, 1.0, fog)); return (output); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space output.pos = mul(P, g_mViewProj); output.uv = input.uv; output.diffuse = input.diffuse; output.pos_w.xyz = P.xyz; const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output = input.diffuse * g_MaterialTexture.Sample(g_LinearSampler, input.uv); if (output.a > 0.0) { output = multiply_fog(output, input.pos_w.w, input.pos_w.z); } return (output); } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: effectFire.fx // Copyright (c) 2009 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- cbuffer cbConstant { static const float g_Brightness = 2.0f; ///static const float g_Brightness = 2.0f; } //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; }; Texture2D g_MaterialTexture; SamplerState g_TextureSampler { Filter = MIN_MAG_MIP_LINEAR; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float4 diffuse : COLOR; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float4 diffuse : COLOR0; float4 pos_w : COLOR1; //xyz = world space pos, w = fogdist float2 uv : TEXCOORD; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 diffuse : COLOR0; float4 pos_w : COLOR1; //xyz = world space pos, w = fogdist float2 uv : TEXCOORD; }; struct PS_OUTPUT { float4 color : SV_Target0; float4 bright : SV_Target1; }; //-------------------------------------------------------------------------------------- float4 multiply_fog2(float4 Color, float FogDist, float FogZ) { float4 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } output *= (1.0 - clamp(0.0, 1.0, fog*fog)); ///output *= (1.0 - clamp(0.0, 1.0, fog*fog)); return (output); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space output.pos = mul(P, g_mViewProj); output.uv = input.uv; output.diffuse = input.diffuse; output.pos_w.xyz = P.xyz; const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- PS_OUTPUT PS( PS_INPUT input ) { PS_OUTPUT output; output.color = input.diffuse * g_MaterialTexture.Sample(g_TextureSampler, input.uv); if (output.color.a > 0.0) { output.color = multiply_fog2(output.color, input.pos_w.w, input.pos_w.z); output.bright = float4(g_Brightness * output.color.a, 0.0f, 0.0f, output.color.a); ///output.bright = float4(g_Brightness * output.color.a, 0.0f, 0.0f, output.color.a); } return (output); } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: effectLightAdd.fx // Copyright (c) 2010 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float g_LightLevel; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; }; Texture2D g_MaterialTexture; SamplerState g_LinearSampler { Filter = MIN_MAG_MIP_LINEAR; AddressU = Wrap; AddressV = Wrap; }; struct VS_INPUT { float3 pos : POSITION; float4 diffuse : COLOR; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float4 diffuse : COLOR; float4 pos_w : COLOR1; //xyz = world space pos, w = fogdist float2 uv : TEXCOORD; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 diffuse : COLOR; float4 pos_w : COLOR1; //xyz = world space pos, w = fogdist float2 uv : TEXCOORD; }; //-------------------------------------------------------------------------------------- float4 multiply_fog2(float4 Color, float FogDist, float FogZ) { float4 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } output *= (1.0 - clamp(0.0, 1.0, fog*fog)); return (output); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space output.pos = mul(P, g_mViewProj); output.uv = input.uv; output.diffuse = input.diffuse; output.pos_w.xyz = P.xyz; const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output = input.diffuse * g_MaterialTexture.Sample(g_LinearSampler, input.uv); if (output.a > 0.0) { output = multiply_fog2(output, input.pos_w.w, input.pos_w.z); } return (output); } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: effectLightLevel.fx // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- // for color vertices that use constant light level //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float g_LightLevel; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; }; Texture2D g_MaterialTexture; SamplerState g_LinearSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; struct VS_INPUT { float3 pos : POSITION; float4 diffuse : COLOR; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float4 diffuse : COLOR0; float4 pos_w : COLOR1; //xyz = world space pos, w = fogdist float2 uv : TEXCOORD; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 diffuse : COLOR0; float4 pos_w : COLOR1; //xyz = world space pos, w = fogdist float2 uv : TEXCOORD; }; //-------------------------------------------------------------------------------------- float4 add_fog_fade_alpha(float4 Color, float FogDist, float FogZ) { float4 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, float4(g_FogColor, 0.0f), fog); return (output); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space output.pos = mul(P, g_mViewProj); output.uv = input.uv; output.diffuse = input.diffuse;// * g_LightLevel; TODO when we remove DX9 output.pos_w.xyz = P.xyz; const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output = input.diffuse * g_MaterialTexture.Sample(g_LinearSampler, input.uv); if (output.a > 0.0) { output = add_fog_fade_alpha(output, input.pos_w.w, input.pos_w.z); } return (output); } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: effectLightLevelAdd.fx // Copyright (c) 2010 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- // for color vertices that use constant light level //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float g_LightLevel; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; }; Texture2D g_MaterialTexture; SamplerState g_LinearSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; struct VS_INPUT { float3 pos : POSITION; float4 diffuse : COLOR; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float4 diffuse : COLOR0; float4 pos_w : COLOR1; //xyz = world space pos, w = fogdist float2 uv : TEXCOORD; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 diffuse : COLOR0; float4 pos_w : COLOR1; //xyz = world space pos, w = fogdist float2 uv : TEXCOORD; }; //-------------------------------------------------------------------------------------- float4 multiply_fog(float4 Color, float FogDist, float FogZ) { float4 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } output *= (1.0 - clamp(0.0, 1.0, fog)); return (output); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space output.pos = mul(P, g_mViewProj); output.uv = input.uv; output.diffuse = input.diffuse;// * g_LightLevel; TODO when we remove DX9 output.pos_w.xyz = P.xyz; const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output = input.diffuse * g_MaterialTexture.Sample(g_LinearSampler, input.uv); if (output.a > 0.0) { output = multiply_fog(output, input.pos_w.w, input.pos_w.z); } return (output); } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: ENVCLOUDLAYER.FX // Copyright (c) 2009 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; }; Texture2D g_MaterialTexture; SamplerState g_LinearSampler { Filter = MIN_MAG_MIP_LINEAR; AddressU = Wrap; AddressV = Wrap; }; struct VS_INPUT { float3 pos : POSITION; float4 diffuse : COLOR; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float4 diffuse : COLOR0; float2 uv : TEXCOORD; float fogdist : COLOR1; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 diffuse : COLOR0; float2 uv : TEXCOORD; float fogdist : COLOR1; }; //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space output.pos = mul(P, g_mViewProj); output.uv = input.uv; output.diffuse = input.diffuse; const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.fogdist = Pv.z; return output; } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist) { float3 output = Color; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { const float fog = (fd * g_FogDistance.z); output = lerp(output, g_FogColor, fog); } return (output); } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float3 output; if (input.fogdist < g_FogDistance.y) { output = g_MaterialTexture.Sample(g_LinearSampler, input.uv).rgb; output *= input.diffuse.rgb; output = add_fog(output, input.fogdist); } else { output.rgb = g_FogColor; } return (float4(output, input.diffuse.a)); } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: ENVCLOUDS.FX // Copyright (c) 2009 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; }; Texture2D g_MaterialTexture; SamplerState g_LinearSampler { Filter = MIN_MAG_MIP_LINEAR; AddressU = Wrap; AddressV = Wrap; }; struct VS_INPUT { float3 pos : POSITION; float4 diffuse : COLOR; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float4 diffuse : COLOR0; float2 uv : TEXCOORD; float fogdist : COLOR1; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 diffuse : COLOR0; float2 uv : TEXCOORD; float fogdist : COLOR1; }; //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space output.pos = mul(P, g_mViewProj); output.uv = input.uv; output.diffuse = input.diffuse; const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.fogdist = Pv.z; return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (input.fogdist < g_FogDistance.y) { output = g_MaterialTexture.Sample(g_LinearSampler, input.uv); output *= input.diffuse; float fog = 0.0f; const float fd = input.fogdist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); output.rgb = (1.0 - fog) * output.rgb + fog * g_FogColor; } } else { output = float4(g_FogColor, 0.0f); } return (output); } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: ENVHORIZON.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mViewProj; float g_InvFarClip; }; cbuffer cbPerMesh { float3 g_MeshOffsetPos; }; Texture2D g_MaterialTexture; SamplerState g_LinearSampler { Filter = MIN_MAG_MIP_LINEAR; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float4 diffuse : COLOR; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float4 diffuse : COLOR; float2 uv : TEXCOORD; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 diffuse : COLOR; float2 uv : TEXCOORD; }; //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = float4((input.pos + g_MeshOffsetPos), 1.0); // position, world-space output.pos = mul(P, g_mViewProj); output.uv = input.uv; output.diffuse = input.diffuse; return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output = g_MaterialTexture.Sample(g_LinearSampler, input.uv); return (input.diffuse * output); } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: ENVMOON.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float g_InvScreenWidth; float g_InvScreenHeight; float2 g_ViewportTopLeft; }; Texture2D g_MaterialTexture; SamplerState g_TextureSampler { Filter = MIN_MAG_MIP_LINEAR; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float4 pos : POSITION; float4 diffuse : COLOR; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float4 diffuse : COLOR; float2 uv : TEXCOORD; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 diffuse : COLOR; float2 uv : TEXCOORD; }; //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; //convert from screen coordinates to clip space coordinates output.pos.x = (input.pos.x - g_ViewportTopLeft.x) * 2.0f * g_InvScreenWidth - 1.0f; output.pos.y = 1.0f - (input.pos.y - g_ViewportTopLeft.y) * 2.0f * g_InvScreenHeight; output.pos.zw = input.pos.zw; output.diffuse = input.diffuse; output.uv = input.uv; return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; output = g_MaterialTexture.Sample(g_TextureSampler, input.uv); output.a *= input.diffuse.a; return (output); } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: ENVRAIN.FX // Copyright (c) 2009 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; }; struct VS_INPUT { float3 pos : POSITION; float4 diffuse : COLOR; }; struct VS_OUTPUT { float4 diffuse : COLOR0; float4 pos_w : COLOR1; //xyz = world space pos, w = fogdist float4 pos : SV_POSITION; }; struct PS_INPUT { float4 diffuse : COLOR0; float4 pos_w : COLOR1; //xyz = world space pos, w = fogdist }; //-------------------------------------------------------------------------------------- float4 add_fog_fade_alpha(float4 Color, float FogDist, float FogZ) { float4 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, float4(g_FogColor, 0.0f), fog); return (output); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space output.pos = mul(P, g_mViewProj); output.diffuse = input.diffuse;// * g_LightLevel; TODO when we remove DX9 output.pos_w.xyz = P.xyz; const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output = input.diffuse; // fade it out with distance, say 2 km? output.a *= (1.0 - smoothstep(0.0f, 2000.0f, input.pos_w.w)); // TK TODO add some specular here? if (output.a > 0.0) { output = add_fog_fade_alpha(output, input.pos_w.w, input.pos_w.z); } return (output); } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: ENVSKY.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mViewProj; float g_InvFarClip; }; cbuffer cbPerMesh { float3 g_MeshOffsetPos; }; struct VS_INPUT { float3 pos : POSITION; float4 diffuse : COLOR; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float4 diffuse : COLOR; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 diffuse : COLOR; }; //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = float4((input.pos + g_MeshOffsetPos), 1.0); // position, world-space output.pos = mul(P, g_mViewProj); output.diffuse = input.diffuse; return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { return (input.diffuse); } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: ENVSTAR.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float g_InvScreenWidth; float g_InvScreenHeight; float2 g_ViewportTopLeft; }; Texture2D g_MaterialTexture; SamplerState g_TextureSampler { Filter = MIN_POINT_MAG_LINEAR_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float4 pos : POSITION; float4 diffuse : COLOR; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float4 diffuse : COLOR; float2 uv : TEXCOORD; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 diffuse : COLOR; float2 uv : TEXCOORD; }; //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; //convert from screen coordinates to clip space coordinates output.pos.x = (input.pos.x - g_ViewportTopLeft.x) * 2.0f * g_InvScreenWidth - 1.0f; output.pos.y = 1.0f - (input.pos.y - g_ViewportTopLeft.y) * 2.0f * g_InvScreenHeight; output.pos.zw = input.pos.zw; output.diffuse = input.diffuse; output.uv = input.uv; return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; output = input.diffuse * g_MaterialTexture.Sample(g_TextureSampler, input.uv); return (output); } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: ENVSUN.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- cbuffer cbConstant { static const float g_Brightness = 400.0f; static const float g_HDRThreshold = 0.95f; static const float g_HDRMultiplier = 100.0f; } //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float g_InvScreenWidth; float g_InvScreenHeight; float2 g_ViewportTopLeft; }; Texture2D g_MaterialTexture; SamplerState g_TextureSampler { Filter = MIN_MAG_MIP_LINEAR; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float4 pos : POSITION; float4 diffuse : COLOR; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float4 diffuse : COLOR; float2 uv : TEXCOORD; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 diffuse : COLOR; float2 uv : TEXCOORD; }; struct PS_OUTPUT { float4 color : SV_Target0; float4 bright : SV_Target1; }; //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; //convert from screen coordinates to clip space coordinates output.pos.x = (input.pos.x - g_ViewportTopLeft.x) * 2.0f * g_InvScreenWidth - 1.0f; output.pos.y = 1.0f - (input.pos.y - g_ViewportTopLeft.y) * 2.0f * g_InvScreenHeight; output.pos.zw = input.pos.zw; output.diffuse = input.diffuse; output.uv = input.uv; return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- PS_OUTPUT PS( PS_INPUT input ) { PS_OUTPUT output; output.color = g_MaterialTexture.Sample(g_TextureSampler, input.uv); if (output.color.a >= g_HDRThreshold) { output.color.rgb *= (1.0f + (input.diffuse.a * g_HDRMultiplier * (output.color.a - g_HDRThreshold))); } output.color.a *= input.diffuse.a; output.bright = float4(g_Brightness * output.color.a, 0.0f, 0.0f, output.color.a); return (output); } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: ENVSUNFLARE.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float g_InvScreenWidth; float g_InvScreenHeight; float2 g_ViewportTopLeft; }; Texture2D g_MaterialTexture; SamplerState g_TextureSampler { Filter = MIN_MAG_MIP_LINEAR; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float4 pos : POSITION; float4 diffuse : COLOR; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float4 diffuse : COLOR; float2 uv : TEXCOORD; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 diffuse : COLOR; float2 uv : TEXCOORD; }; //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; //convert from screen coordinates to clip space coordinates output.pos.x = (input.pos.x - g_ViewportTopLeft.x) * 2.0f * g_InvScreenWidth - 1.0f; output.pos.y = 1.0f - (input.pos.y - g_ViewportTopLeft.y) * 2.0f * g_InvScreenHeight; output.pos.z = input.pos.z; output.pos.w = input.pos.w; output.diffuse = input.diffuse; output.uv = input.uv; return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; output = g_MaterialTexture.Sample(g_TextureSampler, input.uv); output.a *= input.diffuse.a; return (output); } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: FLTDTVFILTER.FX // Copyright (c) 2009 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- Texture2D g_RenderedScene; SamplerState PointSampler { Filter = MIN_MAG_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; SamplerState LinearSampler { Filter = MIN_MAG_MIP_LINEAR; AddressU = Clamp; AddressV = Clamp; }; //-------------------------------------------------------------------------------------- // color space conversion functions //-------------------------------------------------------------------------------------- float3 GetYxyFromRGB(uniform float3 vRGB) { // RGB -> XYZ conversion ( http://www.w3.org/Graphics/Color/sRGB ) const float3x3 RGB2XYZ = { 0.5141f, 0.3239f, 0.1604f, 0.2651f, 0.6702f, 0.0641f, 0.0241f, 0.1228f, 0.8444f }; const float3 vXYZ = mul(RGB2XYZ, vRGB); // XYZ -> Yxy conversion: X = Y, x = X / (X + Y + Z), y = Y / (X + Y + Z) const float inv_XYZ = 1.0f / (vXYZ.r + vXYZ.g + vXYZ.b + 0.0001f); return ( float3(vXYZ.g, vXYZ.r * inv_XYZ, vXYZ.g * inv_XYZ) ); }; float3 GetRGBFromYxy(uniform float3 vYxy) { float3 vRGB = float3(0.0f, 0.0f, 0.0f); // make sure intesity is positive if (vYxy.r > 0.0f) { // Yxy -> XYZ conversion const float inv_Yxy = 1.0f / (vYxy.b + 0.0001f); const float3 vXYZ = float3( vYxy.r * vYxy.g * inv_Yxy, vYxy.r, vYxy.r * (1.0f - vYxy.g - vYxy.b) * inv_Yxy ); // XYZ -> RGB conversion const float3x3 XYZ2RGB = { 2.5651f,-1.1665f,-0.3986f, -1.0217f, 1.9777f, 0.0439f, 0.0753f,-0.2543f, 1.1892f }; vRGB = max(0, mul(XYZ2RGB, vXYZ)); // make sure rbg values are positive! } return (vRGB); }; //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- struct VS_INPUT { float4 pos : POSITION; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float2 uv : TEXCOORD; float4 pos : SV_POSITION; }; struct PS_INPUT { float2 uv : TEXCOORD; }; //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; output.uv = input.uv; output.pos = input.pos; return output; } //-------------------------------------------------------------------------------------- // Pixel Shaders //-------------------------------------------------------------------------------------- //g_RenderedScene: rendered scene texture float PS ( PS_INPUT input ) : SV_TARGET { const float3 RGB2Lum = { 0.2125f, 0.7154f, 0.0721f }; float4 output; float3 vColor = g_RenderedScene.Sample( PointSampler, input.uv ); float fLum = dot( vColor, RGB2Lum ); output.r = float4( fLum, fLum, fLum, 1.0f ); return (output); } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: FLTGUNSIGHT.FX // Copyright (c) 2011 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mViewProj; float g_InvFarClip; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; }; Texture2D g_MaterialTexture; SamplerState g_LinearSampler { Filter = MIN_MAG_MIP_LINEAR; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float4 diffuse : COLOR; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float4 diffuse : COLOR; float2 uv : TEXCOORD; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 diffuse : COLOR; float2 uv : TEXCOORD; }; //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space output.pos = mul(P, g_mViewProj); output.uv = input.uv; output.diffuse = input.diffuse; return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output = g_MaterialTexture.Sample(g_LinearSampler, input.uv); return (input.diffuse * output); } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: FLTHUD.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float g_InvScreenWidth; float g_InvScreenHeight; float2 g_ViewportTopLeft; }; cbuffer cbPerMaterial { int g_bClampTexture; }; Texture2D g_MaterialTexture; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float4 pos : POSITION; float4 diffuse : COLOR; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float4 diffuse : COLOR; float2 uv : TEXCOORD; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 diffuse : COLOR; float2 uv : TEXCOORD; }; //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; //convert from screen coordinates to clip space coordinates output.pos.x = (input.pos.x - g_ViewportTopLeft.x) * 2.0f * g_InvScreenWidth - 1.0f; output.pos.y = 1.0f - (input.pos.y - g_ViewportTopLeft.y) * 2.0f * g_InvScreenHeight; output.pos.z = input.pos.z; output.pos.w = input.pos.w; output.diffuse = input.diffuse; output.uv = input.uv; return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bClampTexture) { output = g_MaterialTexture.Sample(g_TextureWrapSampler, input.uv); } else { output = g_MaterialTexture.Sample(g_TextureClampSampler, input.uv); } return (input.diffuse * output); } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHDECAL1.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; float3 g_CameraPos; int g_bInReflection; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3 N, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float h_dot_n = dot(H, N); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(H)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; output.norm_w = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space output.uv0 = input.uv0; output.uv1 = input.uv1; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { if (g_bInReflection) { clip(input.pos_w.z + g_CameraPos.z); } float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); } if (output.a > 0.0) { // do lightsourcing before decals so specular can only affect the base texture float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); if (g_bLightEnabled) { const float3 N = normalize(input.norm_w); // do per-pixel light sourcing diffuse = compute_per_pixel_ambient_diffuse(N, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(N, input.pos_w.xyz); output.rgb += specular; // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { specular *= (0.4f / g_SpecularLevel); } } // decals at 1 float4 decal = g_MaterialTexture1.Sample(g_TextureClampSampler, input.uv1); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHDECAL1BUMP.FX // Copyright (c) 2009 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; float3 g_CameraPos; int g_bInReflection; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color float g_BumpAmount; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_BumpNormalTexture; Texture2D g_MaterialTexture2; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; SamplerState g_BumpWrapSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_BumpClampSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; }; //-------------------------------------------------------------------------------------- float3x3 compute_tangent_frame(float3 N, float3 P, float2 uv) { // get edge vectors of the pixel triangle const float3 dp1 = ddx(P); const float3 dp2 = ddy(P); const float2 duv1 = ddx(uv); const float2 duv2 = ddy(uv); // solve the linear system const float2x3 M = float2x3(dp1, dp2); const float3 T = mul(float2(duv1.x, duv2.x), M); const float3 B = mul(float2(duv1.y, duv2.y), M); // construct tangent frame float3 bT = normalize( cross(N, T) ); const float3 nT = cross(bT, N); if (dot(bT, B) < 0) { bT *= -1.0f; } return float3x3( nT, bT, N); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3x3 TangentFrame, float3 Nt, float3 P) { const float3 light_t = mul(TangentFrame, -g_DirLight.dir); float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(Nt, light_t)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return saturate(diffuse); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3x3 TangentFrame, float3 Nt, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float3 Ht = mul(TangentFrame, H); const float h_dot_n = dot(Ht, Nt); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(Ht)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; output.norm_w = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space output.uv0 = input.uv0; output.uv2 = input.uv2; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { if (g_bInReflection) { clip(input.pos_w.z + g_CameraPos.z); } float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 Np; if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); Np = g_BumpNormalTexture.Sample(g_BumpWrapSampler, input.uv0).xyz * 2.0 - 1.0; } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); Np = g_BumpNormalTexture.Sample(g_BumpClampSampler, input.uv0).xyz * 2.0 - 1.0; } if (output.a > 0.0) { float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); // do lightsourcing before decals so specular can only affect the base texture if (g_bLightEnabled) { // do per-pixel light sourcing const float3 N0 = normalize(input.norm_w); const float3x3 tangent_frame = compute_tangent_frame(N0, input.pos_w.xyz, input.uv0); float3 Nt = lerp(float3(0.0,0.0,1.0), Np, g_BumpAmount); Nt = normalize(Nt); diffuse = compute_per_pixel_ambient_diffuse(tangent_frame, Nt, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(tangent_frame, Nt, input.pos_w.xyz); output.rgb += specular; // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { specular *= (0.4f / g_SpecularLevel); } } // decals at 2 float4 decal = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv2); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHDECAL1BUMPSPEC.FX // Copyright (c) 2010 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; float3 g_CameraPos; int g_bInReflection; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color float g_BumpAmount; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; SamplerState g_BumpWrapSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_BumpClampSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv3 : TEXCOORD1; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv3 : TEXCOORD1; }; //-------------------------------------------------------------------------------------- float3x3 compute_tangent_frame(float3 N, float3 P, float2 uv) { // get edge vectors of the pixel triangle const float3 dp1 = ddx(P); const float3 dp2 = ddy(P); const float2 duv1 = ddx(uv); const float2 duv2 = ddy(uv); // solve the linear system const float2x3 M = float2x3(dp1, dp2); const float3 T = mul(float2(duv1.x, duv2.x), M); const float3 B = mul(float2(duv1.y, duv2.y), M); // construct tangent frame float3 bT = normalize( cross(N, T) ); const float3 nT = cross(bT, N); if (dot(bT, B) < 0) { bT *= -1.0f; } return float3x3( nT, bT, N); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3x3 TangentFrame, float3 Nt, float3 P) { const float3 light_t = mul(TangentFrame, -g_DirLight.dir); float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(Nt, light_t)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return saturate(diffuse); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3x3 TangentFrame, float3 Nt, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float3 Ht = mul(TangentFrame, H); const float h_dot_n = dot(Ht, Nt); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(Ht)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; output.norm_w = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space output.uv0 = input.uv0; output.uv3 = input.uv3; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { if (g_bInReflection) { clip(input.pos_w.z + g_CameraPos.z); } float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 Np; float3 sm; if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); Np = g_MaterialTexture1.Sample(g_BumpWrapSampler, input.uv0).xyz * 2.0 - 1.0; sm = g_MaterialTexture2.Sample(g_TextureWrapSampler, input.uv0); } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); Np = g_MaterialTexture1.Sample(g_BumpClampSampler, input.uv0).xyz * 2.0 - 1.0; sm = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv0); } if (output.a > 0.0) { float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); // do lightsourcing before decals so specular can only affect the base texture if (g_bLightEnabled) { // do per-pixel light sourcing const float3 N0 = normalize(input.norm_w); const float3x3 tangent_frame = compute_tangent_frame(N0, input.pos_w.xyz, input.uv0); float3 Nt = lerp(float3(0.0,0.0,1.0), Np, g_BumpAmount); Nt = normalize(Nt); diffuse = compute_per_pixel_ambient_diffuse(tangent_frame, Nt, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(tangent_frame, Nt, input.pos_w.xyz); output.rgb += (specular * sm); // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { float3 max_decal_sm = min(g_SpecularLevel * sm, float3(0.4f,0.4f,0.4f)); specular *= (max_decal_sm / g_SpecularLevel); } } // decals at 3 float4 decal = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHDECAL1SPEC.FX // Copyright (c) 2010 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; float3 g_CameraPos; int g_bInReflection; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3 N, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float h_dot_n = dot(H, N); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(H)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; output.norm_w = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space output.uv0 = input.uv0; output.uv2 = input.uv2; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { if (g_bInReflection) { clip(input.pos_w.z + g_CameraPos.z); } float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 sm; if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); sm = g_MaterialTexture1.Sample(g_TextureWrapSampler, input.uv0); } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); sm = g_MaterialTexture1.Sample(g_TextureClampSampler, input.uv0); } if (output.a > 0.0) { // do lightsourcing before decals so specular can only affect the base texture float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); if (g_bLightEnabled) { const float3 N = normalize(input.norm_w); // do per-pixel light sourcing diffuse = compute_per_pixel_ambient_diffuse(N, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(N, input.pos_w.xyz); output.rgb += (specular * sm); // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { float3 max_decal_sm = min(g_SpecularLevel * sm, float3(0.4f,0.4f,0.4f)); specular *= (max_decal_sm / g_SpecularLevel); } } // decals at 2 at max 40% specular float4 decal = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv2); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHDECAL2.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3 N, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float h_dot_n = dot(H, N); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(H)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; output.norm_w = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space output.uv0 = input.uv0; output.uv1 = input.uv1; output.uv2 = input.uv2; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); } if (output.a > 0.0) { // do lightsourcing before decals so specular can only affect the base texture float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); if (g_bLightEnabled) { const float3 N = normalize(input.norm_w); // do per-pixel light sourcing diffuse = compute_per_pixel_ambient_diffuse(N, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(N, input.pos_w.xyz); output.rgb += specular; // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { specular *= (0.4f / g_SpecularLevel); } } // decals at 1,2 float4 decal = g_MaterialTexture1.Sample(g_TextureClampSampler, input.uv1); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv2); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHDECAL2BUMP.FX // Copyright (c) 2009 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color float g_BumpAmount; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_BumpNormalTexture; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; SamplerState g_BumpWrapSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_BumpClampSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; }; //-------------------------------------------------------------------------------------- float3x3 compute_tangent_frame(float3 N, float3 P, float2 uv) { // get edge vectors of the pixel triangle const float3 dp1 = ddx(P); const float3 dp2 = ddy(P); const float2 duv1 = ddx(uv); const float2 duv2 = ddy(uv); // solve the linear system const float2x3 M = float2x3(dp1, dp2); const float3 T = mul(float2(duv1.x, duv2.x), M); const float3 B = mul(float2(duv1.y, duv2.y), M); // construct tangent frame float3 bT = normalize( cross(N, T) ); const float3 nT = cross(bT, N); if (dot(bT, B) < 0) { bT *= -1.0f; } return float3x3( nT, bT, N); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3x3 TangentFrame, float3 Nt, float3 P) { const float3 light_t = mul(TangentFrame, -g_DirLight.dir); float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(Nt, light_t)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return saturate(diffuse); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3x3 TangentFrame, float3 Nt, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float3 Ht = mul(TangentFrame, H); const float h_dot_n = dot(Ht, Nt); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(Ht)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; output.norm_w = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space output.uv0 = input.uv0; output.uv2 = input.uv2; output.uv3 = input.uv3; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 Np; if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); Np = g_BumpNormalTexture.Sample(g_BumpWrapSampler, input.uv0).xyz * 2.0 - 1.0; } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); Np = g_BumpNormalTexture.Sample(g_BumpClampSampler, input.uv0).xyz * 2.0 - 1.0; } if (output.a > 0.0) { float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); // do lightsourcing before decals so specular can only affect the base texture if (g_bLightEnabled) { // do per-pixel light sourcing const float3 N0 = normalize(input.norm_w); const float3x3 tangent_frame = compute_tangent_frame(N0, input.pos_w.xyz, input.uv0); float3 Nt = lerp(float3(0.0,0.0,1.0), Np, g_BumpAmount); Nt = normalize(Nt); diffuse = compute_per_pixel_ambient_diffuse(tangent_frame, Nt, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(tangent_frame, Nt, input.pos_w.xyz); output.rgb += specular; // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { specular *= (0.4f / g_SpecularLevel); } } // decals at 2,3 float4 decal = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv2); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHDECAL2BUMPSPEC.FX // Copyright (c) 2010 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color float g_BumpAmount; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; Texture2D g_MaterialTexture4; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; SamplerState g_BumpWrapSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_BumpClampSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv3 : TEXCOORD1; float2 uv4 : TEXCOORD2; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv3 : TEXCOORD1; float2 uv4 : TEXCOORD2; }; //-------------------------------------------------------------------------------------- float3x3 compute_tangent_frame(float3 N, float3 P, float2 uv) { // get edge vectors of the pixel triangle const float3 dp1 = ddx(P); const float3 dp2 = ddy(P); const float2 duv1 = ddx(uv); const float2 duv2 = ddy(uv); // solve the linear system const float2x3 M = float2x3(dp1, dp2); const float3 T = mul(float2(duv1.x, duv2.x), M); const float3 B = mul(float2(duv1.y, duv2.y), M); // construct tangent frame float3 bT = normalize( cross(N, T) ); const float3 nT = cross(bT, N); if (dot(bT, B) < 0) { bT *= -1.0f; } return float3x3( nT, bT, N); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3x3 TangentFrame, float3 Nt, float3 P) { const float3 light_t = mul(TangentFrame, -g_DirLight.dir); float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(Nt, light_t)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return saturate(diffuse); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3x3 TangentFrame, float3 Nt, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float3 Ht = mul(TangentFrame, H); const float h_dot_n = dot(Ht, Nt); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(Ht)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; output.norm_w = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space output.uv0 = input.uv0; output.uv3 = input.uv3; output.uv4 = input.uv4; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 Np; float3 sm; if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); Np = g_MaterialTexture1.Sample(g_BumpWrapSampler, input.uv0).xyz * 2.0 - 1.0; sm = g_MaterialTexture2.Sample(g_TextureWrapSampler, input.uv0); } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); Np = g_MaterialTexture1.Sample(g_BumpClampSampler, input.uv0).xyz * 2.0 - 1.0; sm = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv0); } if (output.a > 0.0) { float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); // do lightsourcing before decals so specular can only affect the base texture if (g_bLightEnabled) { // do per-pixel light sourcing const float3 N0 = normalize(input.norm_w); const float3x3 tangent_frame = compute_tangent_frame(N0, input.pos_w.xyz, input.uv0); float3 Nt = lerp(float3(0.0,0.0,1.0), Np, g_BumpAmount); Nt = normalize(Nt); diffuse = compute_per_pixel_ambient_diffuse(tangent_frame, Nt, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(tangent_frame, Nt, input.pos_w.xyz); output.rgb += (specular * sm); // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { float3 max_decal_sm = min(g_SpecularLevel * sm, float3(0.4f,0.4f,0.4f)); specular *= (max_decal_sm / g_SpecularLevel); } } // decals at 3,4 float4 decal = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture4.Sample(g_TextureClampSampler, input.uv4); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHDECAL2SPEC.FX // Copyright (c) 2010 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3 N, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float h_dot_n = dot(H, N); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(H)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; output.norm_w = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space output.uv0 = input.uv0; output.uv2 = input.uv2; output.uv3 = input.uv3; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 sm; if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); sm = g_MaterialTexture1.Sample(g_TextureWrapSampler, input.uv0); } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); sm = g_MaterialTexture1.Sample(g_TextureClampSampler, input.uv0); } if (output.a > 0.0) { // do lightsourcing before decals so specular can only affect the base texture float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); if (g_bLightEnabled) { const float3 N = normalize(input.norm_w); // do per-pixel light sourcing diffuse = compute_per_pixel_ambient_diffuse(N, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(N, input.pos_w.xyz); output.rgb += (specular * sm); // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { float3 max_decal_sm = min(g_SpecularLevel * sm, float3(0.4f,0.4f,0.4f)); specular *= (max_decal_sm / g_SpecularLevel); } } // decals at 2,3 at max 40% specular float4 decal = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv2); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHDECAL3.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3 N, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float h_dot_n = dot(H, N); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(H)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; output.norm_w = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space output.uv0 = input.uv0; output.uv1 = input.uv1; output.uv2 = input.uv2; output.uv3 = input.uv3; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); } if (output.a > 0.0) { // do lightsourcing before decals so specular can only affect the base texture float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); if (g_bLightEnabled) { const float3 N = normalize(input.norm_w); // do per-pixel light sourcing diffuse = compute_per_pixel_ambient_diffuse(N, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(N, input.pos_w.xyz); output.rgb += specular; // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { specular *= (0.4f / g_SpecularLevel); } } // decals at 1,2,3 float4 decal = g_MaterialTexture1.Sample(g_TextureClampSampler, input.uv1); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv2); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHDECAL3BUMP.FX // Copyright (c) 2009 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color float g_BumpAmount; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_BumpNormalTexture; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; Texture2D g_MaterialTexture4; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; SamplerState g_BumpWrapSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_BumpClampSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float2 uv4 : TEXCOORD3; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float2 uv4 : TEXCOORD3; }; //-------------------------------------------------------------------------------------- float3x3 compute_tangent_frame(float3 N, float3 P, float2 uv) { // get edge vectors of the pixel triangle const float3 dp1 = ddx(P); const float3 dp2 = ddy(P); const float2 duv1 = ddx(uv); const float2 duv2 = ddy(uv); // solve the linear system const float2x3 M = float2x3(dp1, dp2); const float3 T = mul(float2(duv1.x, duv2.x), M); const float3 B = mul(float2(duv1.y, duv2.y), M); // construct tangent frame float3 bT = normalize( cross(N, T) ); const float3 nT = cross(bT, N); if (dot(bT, B) < 0) { bT *= -1.0f; } return float3x3( nT, bT, N); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3x3 TangentFrame, float3 Nt, float3 P) { const float3 light_t = mul(TangentFrame, -g_DirLight.dir); float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(Nt, light_t)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return saturate(diffuse); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3x3 TangentFrame, float3 Nt, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float3 Ht = mul(TangentFrame, H); const float h_dot_n = dot(Ht, Nt); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(Ht)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; output.norm_w = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space output.uv0 = input.uv0; output.uv2 = input.uv2; output.uv3 = input.uv3; output.uv4 = input.uv4; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 Np; if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); Np = g_BumpNormalTexture.Sample(g_BumpWrapSampler, input.uv0).xyz * 2.0 - 1.0; } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); Np = g_BumpNormalTexture.Sample(g_BumpClampSampler, input.uv0).xyz * 2.0 - 1.0; } if (output.a > 0.0) { float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); // do lightsourcing before decals so specular can only affect the base texture if (g_bLightEnabled) { // do per-pixel light sourcing const float3 N0 = normalize(input.norm_w); const float3x3 tangent_frame = compute_tangent_frame(N0, input.pos_w.xyz, input.uv0); float3 Nt = lerp(float3(0.0,0.0,1.0), Np, g_BumpAmount); Nt = normalize(Nt); diffuse = compute_per_pixel_ambient_diffuse(tangent_frame, Nt, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(tangent_frame, Nt, input.pos_w.xyz); output.rgb += specular; // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { specular *= (0.4f / g_SpecularLevel); } } // decals at 2,3,4 float4 decal = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv2); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture4.Sample(g_TextureClampSampler, input.uv4); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHDECAL3BUMPSPEC.FX // Copyright (c) 2010 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color float g_BumpAmount; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; Texture2D g_MaterialTexture4; Texture2D g_MaterialTexture5; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; SamplerState g_BumpWrapSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_BumpClampSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv3 : TEXCOORD1; float2 uv4 : TEXCOORD2; float2 uv5 : TEXCOORD3; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv3 : TEXCOORD1; float2 uv4 : TEXCOORD2; float2 uv5 : TEXCOORD3; }; //-------------------------------------------------------------------------------------- float3x3 compute_tangent_frame(float3 N, float3 P, float2 uv) { // get edge vectors of the pixel triangle const float3 dp1 = ddx(P); const float3 dp2 = ddy(P); const float2 duv1 = ddx(uv); const float2 duv2 = ddy(uv); // solve the linear system const float2x3 M = float2x3(dp1, dp2); const float3 T = mul(float2(duv1.x, duv2.x), M); const float3 B = mul(float2(duv1.y, duv2.y), M); // construct tangent frame float3 bT = normalize( cross(N, T) ); const float3 nT = cross(bT, N); if (dot(bT, B) < 0) { bT *= -1.0f; } return float3x3( nT, bT, N); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3x3 TangentFrame, float3 Nt, float3 P) { const float3 light_t = mul(TangentFrame, -g_DirLight.dir); float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(Nt, light_t)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return saturate(diffuse); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3x3 TangentFrame, float3 Nt, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float3 Ht = mul(TangentFrame, H); const float h_dot_n = dot(Ht, Nt); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(Ht)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; output.norm_w = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space output.uv0 = input.uv0; output.uv3 = input.uv3; output.uv4 = input.uv4; output.uv5 = input.uv5; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 Np; float3 sm; if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); Np = g_MaterialTexture1.Sample(g_BumpWrapSampler, input.uv0).xyz * 2.0 - 1.0; sm = g_MaterialTexture2.Sample(g_TextureWrapSampler, input.uv0); } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); Np = g_MaterialTexture1.Sample(g_BumpClampSampler, input.uv0).xyz * 2.0 - 1.0; sm = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv0); } if (output.a > 0.0) { float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); // do lightsourcing before decals so specular can only affect the base texture if (g_bLightEnabled) { // do per-pixel light sourcing const float3 N0 = normalize(input.norm_w); const float3x3 tangent_frame = compute_tangent_frame(N0, input.pos_w.xyz, input.uv0); float3 Nt = lerp(float3(0.0,0.0,1.0), Np, g_BumpAmount); Nt = normalize(Nt); diffuse = compute_per_pixel_ambient_diffuse(tangent_frame, Nt, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(tangent_frame, Nt, input.pos_w.xyz); output.rgb += (specular * sm); // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { float3 max_decal_sm = min(g_SpecularLevel * sm, float3(0.4f,0.4f,0.4f)); specular *= (max_decal_sm / g_SpecularLevel); } } // decals at 3,4,5 float4 decal = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture4.Sample(g_TextureClampSampler, input.uv4); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture5.Sample(g_TextureClampSampler, input.uv5); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHDECAL3SPEC.FX // Copyright (c) 2010 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; Texture2D g_MaterialTexture4; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float2 uv4 : TEXCOORD3; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float2 uv4 : TEXCOORD3; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3 N, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float h_dot_n = dot(H, N); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(H)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; output.norm_w = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space output.uv0 = input.uv0; output.uv2 = input.uv2; output.uv3 = input.uv3; output.uv4 = input.uv4; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 sm; if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); sm = g_MaterialTexture1.Sample(g_TextureWrapSampler, input.uv0); } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); sm = g_MaterialTexture1.Sample(g_TextureClampSampler, input.uv0); } if (output.a > 0.0) { // do lightsourcing before decals so specular can only affect the base texture float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); if (g_bLightEnabled) { const float3 N = normalize(input.norm_w); // do per-pixel light sourcing diffuse = compute_per_pixel_ambient_diffuse(N, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(N, input.pos_w.xyz); output.rgb += (specular * sm); // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { float3 max_decal_sm = min(g_SpecularLevel * sm, float3(0.4f,0.4f,0.4f)); specular *= (max_decal_sm / g_SpecularLevel); } } // decals at 2,3,4 at max 40% specular float4 decal = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv2); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture4.Sample(g_TextureClampSampler, input.uv4); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHDECAL4.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; Texture2D g_MaterialTexture4; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3 N, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float h_dot_n = dot(H, N); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(H)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; output.norm_w = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space output.uv0 = input.uv0; output.uv1 = input.uv1; output.uv2 = input.uv2; output.uv3 = input.uv3; output.uv4 = input.uv4; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); } if (output.a > 0.0) { // do lightsourcing before decals so specular can only affect the base texture float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); if (g_bLightEnabled) { const float3 N = normalize(input.norm_w); // do per-pixel light sourcing diffuse = compute_per_pixel_ambient_diffuse(N, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(N, input.pos_w.xyz); output.rgb += specular; // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { specular *= (0.4f / g_SpecularLevel); } } // decals at 1,2,3,4 at 50% specular float4 decal = g_MaterialTexture1.Sample(g_TextureClampSampler, input.uv1); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv2); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture4.Sample(g_TextureClampSampler, input.uv4); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHDECAL4BUMP.FX // Copyright (c) 2009 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color float g_BumpAmount; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_BumpNormalTexture; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; Texture2D g_MaterialTexture4; Texture2D g_MaterialTexture5; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; SamplerState g_BumpWrapSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_BumpClampSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float2 uv4 : TEXCOORD3; float2 uv5 : TEXCOORD4; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float2 uv4 : TEXCOORD3; float2 uv5 : TEXCOORD4; }; //-------------------------------------------------------------------------------------- float3x3 compute_tangent_frame(float3 N, float3 P, float2 uv) { // get edge vectors of the pixel triangle const float3 dp1 = ddx(P); const float3 dp2 = ddy(P); const float2 duv1 = ddx(uv); const float2 duv2 = ddy(uv); // solve the linear system const float2x3 M = float2x3(dp1, dp2); const float3 T = mul(float2(duv1.x, duv2.x), M); const float3 B = mul(float2(duv1.y, duv2.y), M); // construct tangent frame float3 bT = normalize( cross(N, T) ); const float3 nT = cross(bT, N); if (dot(bT, B) < 0) { bT *= -1.0f; } return float3x3( nT, bT, N); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3x3 TangentFrame, float3 Nt, float3 P) { const float3 light_t = mul(TangentFrame, -g_DirLight.dir); float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(Nt, light_t)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return saturate(diffuse); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3x3 TangentFrame, float3 Nt, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float3 Ht = mul(TangentFrame, H); const float h_dot_n = dot(Ht, Nt); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(Ht)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; output.norm_w = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space output.uv0 = input.uv0; output.uv2 = input.uv2; output.uv3 = input.uv3; output.uv4 = input.uv4; output.uv5 = input.uv5; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 Np; if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); Np = g_BumpNormalTexture.Sample(g_BumpWrapSampler, input.uv0).xyz * 2.0 - 1.0; } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); Np = g_BumpNormalTexture.Sample(g_BumpClampSampler, input.uv0).xyz * 2.0 - 1.0; } if (output.a > 0.0) { float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); // do lightsourcing before decals so specular can only affect the base texture if (g_bLightEnabled) { // do per-pixel light sourcing const float3 N0 = normalize(input.norm_w); const float3x3 tangent_frame = compute_tangent_frame(N0, input.pos_w.xyz, input.uv0); float3 Nt = lerp(float3(0.0,0.0,1.0), Np, g_BumpAmount); Nt = normalize(Nt); diffuse = compute_per_pixel_ambient_diffuse(tangent_frame, Nt, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(tangent_frame, Nt, input.pos_w.xyz); output.rgb += specular; // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { specular *= (0.4f / g_SpecularLevel); } } // decals at 2,3,4,5 at 50% specular float4 decal = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv2); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture4.Sample(g_TextureClampSampler, input.uv4); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture5.Sample(g_TextureClampSampler, input.uv5); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHDECAL4BUMPSPEC.FX // Copyright (c) 2010 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color float g_BumpAmount; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; Texture2D g_MaterialTexture4; Texture2D g_MaterialTexture5; Texture2D g_MaterialTexture6; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; SamplerState g_BumpWrapSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_BumpClampSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv3 : TEXCOORD1; float2 uv4 : TEXCOORD2; float2 uv5 : TEXCOORD3; float2 uv6 : TEXCOORD4; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv3 : TEXCOORD1; float2 uv4 : TEXCOORD2; float2 uv5 : TEXCOORD3; float2 uv6 : TEXCOORD4; }; //-------------------------------------------------------------------------------------- float3x3 compute_tangent_frame(float3 N, float3 P, float2 uv) { // get edge vectors of the pixel triangle const float3 dp1 = ddx(P); const float3 dp2 = ddy(P); const float2 duv1 = ddx(uv); const float2 duv2 = ddy(uv); // solve the linear system const float2x3 M = float2x3(dp1, dp2); const float3 T = mul(float2(duv1.x, duv2.x), M); const float3 B = mul(float2(duv1.y, duv2.y), M); // construct tangent frame float3 bT = normalize( cross(N, T) ); const float3 nT = cross(bT, N); if (dot(bT, B) < 0) { bT *= -1.0f; } return float3x3( nT, bT, N); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3x3 TangentFrame, float3 Nt, float3 P) { const float3 light_t = mul(TangentFrame, -g_DirLight.dir); float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(Nt, light_t)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return saturate(diffuse); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3x3 TangentFrame, float3 Nt, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float3 Ht = mul(TangentFrame, H); const float h_dot_n = dot(Ht, Nt); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(Ht)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; output.norm_w = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space output.uv0 = input.uv0; output.uv3 = input.uv3; output.uv4 = input.uv4; output.uv5 = input.uv5; output.uv6 = input.uv6; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 Np; float3 sm; if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); Np = g_MaterialTexture1.Sample(g_BumpWrapSampler, input.uv0).xyz * 2.0 - 1.0; sm = g_MaterialTexture2.Sample(g_TextureWrapSampler, input.uv0); } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); Np = g_MaterialTexture1.Sample(g_BumpClampSampler, input.uv0).xyz * 2.0 - 1.0; sm = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv0); } if (output.a > 0.0) { float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); // do lightsourcing before decals so specular can only affect the base texture if (g_bLightEnabled) { // do per-pixel light sourcing const float3 N0 = normalize(input.norm_w); const float3x3 tangent_frame = compute_tangent_frame(N0, input.pos_w.xyz, input.uv0); float3 Nt = lerp(float3(0.0,0.0,1.0), Np, g_BumpAmount); Nt = normalize(Nt); diffuse = compute_per_pixel_ambient_diffuse(tangent_frame, Nt, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(tangent_frame, Nt, input.pos_w.xyz); output.rgb += (specular * sm); // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { float3 max_decal_sm = min(g_SpecularLevel * sm, float3(0.4f,0.4f,0.4f)); specular *= (max_decal_sm / g_SpecularLevel); } } // decals at 3,4,5,6 at 50% specular float4 decal = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture4.Sample(g_TextureClampSampler, input.uv4); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture5.Sample(g_TextureClampSampler, input.uv5); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture6.Sample(g_TextureClampSampler, input.uv6); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHDECAL4SPEC.FX // Copyright (c) 2010 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; Texture2D g_MaterialTexture4; Texture2D g_MaterialTexture5; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float2 uv4 : TEXCOORD3; float2 uv5 : TEXCOORD4; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float2 uv4 : TEXCOORD3; float2 uv5 : TEXCOORD4; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3 N, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float h_dot_n = dot(H, N); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(H)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; output.norm_w = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space output.uv0 = input.uv0; output.uv2 = input.uv2; output.uv3 = input.uv3; output.uv4 = input.uv4; output.uv5 = input.uv5; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 sm; if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); sm = g_MaterialTexture1.Sample(g_TextureWrapSampler, input.uv0); } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); sm = g_MaterialTexture1.Sample(g_TextureClampSampler, input.uv0); } if (output.a > 0.0) { // do lightsourcing before decals so specular can only affect the base texture float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); if (g_bLightEnabled) { const float3 N = normalize(input.norm_w); // do per-pixel light sourcing diffuse = compute_per_pixel_ambient_diffuse(N, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(N, input.pos_w.xyz); output.rgb += (specular * sm); // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { float3 max_decal_sm = min(g_SpecularLevel * sm, float3(0.4f,0.4f,0.4f)); specular *= (max_decal_sm / g_SpecularLevel); } } // decals at 2,3,4,5 at max 40% specular float4 decal = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv2); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture4.Sample(g_TextureClampSampler, input.uv4); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture5.Sample(g_TextureClampSampler, input.uv5); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHDECAL5.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; Texture2D g_MaterialTexture4; Texture2D g_MaterialTexture5; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3 N, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float h_dot_n = dot(H, N); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(H)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; output.norm_w = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space output.uv0 = input.uv0; output.uv1 = input.uv1; output.uv2 = input.uv2; output.uv3 = input.uv3; output.uv4 = input.uv4; output.uv5 = input.uv5; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); } if (output.a > 0.0) { // do lightsourcing before decals so specular can only affect the base texture float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); if (g_bLightEnabled) { const float3 N = normalize(input.norm_w); // do per-pixel light sourcing diffuse = compute_per_pixel_ambient_diffuse(N, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(N, input.pos_w.xyz); output.rgb += specular; // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { specular *= (0.4f / g_SpecularLevel); } } // decals at 1,2,3,4,5 float4 decal = g_MaterialTexture1.Sample(g_TextureClampSampler, input.uv1); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv2); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture4.Sample(g_TextureClampSampler, input.uv4); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture5.Sample(g_TextureClampSampler, input.uv5); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHDECAL5BUMP.FX // Copyright (c) 2009 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color float g_BumpAmount; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_BumpNormalTexture; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; Texture2D g_MaterialTexture4; Texture2D g_MaterialTexture5; Texture2D g_MaterialTexture6; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; SamplerState g_BumpWrapSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_BumpClampSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float2 uv4 : TEXCOORD3; float2 uv5 : TEXCOORD4; float2 uv6 : TEXCOORD5; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float2 uv4 : TEXCOORD3; float2 uv5 : TEXCOORD4; float2 uv6 : TEXCOORD5; }; //-------------------------------------------------------------------------------------- float3x3 compute_tangent_frame(float3 N, float3 P, float2 uv) { // get edge vectors of the pixel triangle const float3 dp1 = ddx(P); const float3 dp2 = ddy(P); const float2 duv1 = ddx(uv); const float2 duv2 = ddy(uv); // solve the linear system const float2x3 M = float2x3(dp1, dp2); const float3 T = mul(float2(duv1.x, duv2.x), M); const float3 B = mul(float2(duv1.y, duv2.y), M); // construct tangent frame float3 bT = normalize( cross(N, T) ); const float3 nT = cross(bT, N); if (dot(bT, B) < 0) { bT *= -1.0f; } return float3x3( nT, bT, N); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3x3 TangentFrame, float3 Nt, float3 P) { const float3 light_t = mul(TangentFrame, -g_DirLight.dir); float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(Nt, light_t)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return saturate(diffuse); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3x3 TangentFrame, float3 Nt, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float3 Ht = mul(TangentFrame, H); const float h_dot_n = dot(Ht, Nt); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(Ht)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; output.norm_w = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space output.uv0 = input.uv0; output.uv2 = input.uv2; output.uv3 = input.uv3; output.uv4 = input.uv4; output.uv5 = input.uv5; output.uv6 = input.uv6; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 Np; if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); Np = g_BumpNormalTexture.Sample(g_BumpWrapSampler, input.uv0).xyz * 2.0 - 1.0; } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); Np = g_BumpNormalTexture.Sample(g_BumpClampSampler, input.uv0).xyz * 2.0 - 1.0; } if (output.a > 0.0) { float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); // do lightsourcing before decals so specular can only affect the base texture if (g_bLightEnabled) { // do per-pixel light sourcing const float3 N0 = normalize(input.norm_w); const float3x3 tangent_frame = compute_tangent_frame(N0, input.pos_w.xyz, input.uv0); float3 Nt = lerp(float3(0.0,0.0,1.0), Np, g_BumpAmount); Nt = normalize(Nt); diffuse = compute_per_pixel_ambient_diffuse(tangent_frame, Nt, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(tangent_frame, Nt, input.pos_w.xyz); output.rgb += specular; // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { specular *= (0.4f / g_SpecularLevel); } } // decals at 2,3,4,5,6 float4 decal = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv2); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture4.Sample(g_TextureClampSampler, input.uv4); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture5.Sample(g_TextureClampSampler, input.uv5); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture6.Sample(g_TextureClampSampler, input.uv6); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHDECAL5BUMPSPEC.FX // Copyright (c) 2010 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color float g_BumpAmount; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; Texture2D g_MaterialTexture4; Texture2D g_MaterialTexture5; Texture2D g_MaterialTexture6; Texture2D g_MaterialTexture7; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; SamplerState g_BumpWrapSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_BumpClampSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv3 : TEXCOORD1; float2 uv4 : TEXCOORD2; float2 uv5 : TEXCOORD3; float2 uv6 : TEXCOORD4; float2 uv7 : TEXCOORD5; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv3 : TEXCOORD1; float2 uv4 : TEXCOORD2; float2 uv5 : TEXCOORD3; float2 uv6 : TEXCOORD4; float2 uv7 : TEXCOORD5; }; //-------------------------------------------------------------------------------------- float3x3 compute_tangent_frame(float3 N, float3 P, float2 uv) { // get edge vectors of the pixel triangle const float3 dp1 = ddx(P); const float3 dp2 = ddy(P); const float2 duv1 = ddx(uv); const float2 duv2 = ddy(uv); // solve the linear system const float2x3 M = float2x3(dp1, dp2); const float3 T = mul(float2(duv1.x, duv2.x), M); const float3 B = mul(float2(duv1.y, duv2.y), M); // construct tangent frame float3 bT = normalize( cross(N, T) ); const float3 nT = cross(bT, N); if (dot(bT, B) < 0) { bT *= -1.0f; } return float3x3( nT, bT, N); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3x3 TangentFrame, float3 Nt, float3 P) { const float3 light_t = mul(TangentFrame, -g_DirLight.dir); float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(Nt, light_t)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return saturate(diffuse); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3x3 TangentFrame, float3 Nt, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float3 Ht = mul(TangentFrame, H); const float h_dot_n = dot(Ht, Nt); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(Ht)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; output.norm_w = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space output.uv0 = input.uv0; output.uv3 = input.uv3; output.uv4 = input.uv4; output.uv5 = input.uv5; output.uv6 = input.uv6; output.uv7 = input.uv7; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 Np; float3 sm; if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); Np = g_MaterialTexture1.Sample(g_BumpWrapSampler, input.uv0).xyz * 2.0 - 1.0; sm = g_MaterialTexture2.Sample(g_TextureWrapSampler, input.uv0); } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); Np = g_MaterialTexture1.Sample(g_BumpClampSampler, input.uv0).xyz * 2.0 - 1.0; sm = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv0); } if (output.a > 0.0) { float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); // do lightsourcing before decals so specular can only affect the base texture if (g_bLightEnabled) { // do per-pixel light sourcing const float3 N0 = normalize(input.norm_w); const float3x3 tangent_frame = compute_tangent_frame(N0, input.pos_w.xyz, input.uv0); float3 Nt = lerp(float3(0.0,0.0,1.0), Np, g_BumpAmount); Nt = normalize(Nt); diffuse = compute_per_pixel_ambient_diffuse(tangent_frame, Nt, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(tangent_frame, Nt, input.pos_w.xyz); output.rgb += (specular * sm); // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { float3 max_decal_sm = min(g_SpecularLevel * sm, float3(0.4f,0.4f,0.4f)); specular *= (max_decal_sm / g_SpecularLevel); } } // decals at 3,4,5,6,7 float4 decal = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture4.Sample(g_TextureClampSampler, input.uv4); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture5.Sample(g_TextureClampSampler, input.uv5); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture6.Sample(g_TextureClampSampler, input.uv6); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture7.Sample(g_TextureClampSampler, input.uv7); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHDECAL5SPEC.FX // Copyright (c) 2010 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; Texture2D g_MaterialTexture4; Texture2D g_MaterialTexture5; Texture2D g_MaterialTexture6; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float2 uv4 : TEXCOORD3; float2 uv5 : TEXCOORD4; float2 uv6 : TEXCOORD5; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float2 uv4 : TEXCOORD3; float2 uv5 : TEXCOORD4; float2 uv6 : TEXCOORD5; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3 N, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float h_dot_n = dot(H, N); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(H)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; output.norm_w = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space output.uv0 = input.uv0; output.uv2 = input.uv2; output.uv3 = input.uv3; output.uv4 = input.uv4; output.uv5 = input.uv5; output.uv6 = input.uv6; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 sm; if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); sm = g_MaterialTexture1.Sample(g_TextureWrapSampler, input.uv0); } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); sm = g_MaterialTexture1.Sample(g_TextureClampSampler, input.uv0); } if (output.a > 0.0) { // do lightsourcing before decals so specular can only affect the base texture float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); if (g_bLightEnabled) { const float3 N = normalize(input.norm_w); // do per-pixel light sourcing diffuse = compute_per_pixel_ambient_diffuse(N, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(N, input.pos_w.xyz); output.rgb += (specular * sm); // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { float3 max_decal_sm = min(g_SpecularLevel * sm, float3(0.4f,0.4f,0.4f)); specular *= (max_decal_sm / g_SpecularLevel); } } // decals at 2,3,4,5,6 at max 40% specular float4 decal = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv2); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture4.Sample(g_TextureClampSampler, input.uv4); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture5.Sample(g_TextureClampSampler, input.uv5); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture6.Sample(g_TextureClampSampler, input.uv6); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHDECAL6.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; Texture2D g_MaterialTexture4; Texture2D g_MaterialTexture5; Texture2D g_MaterialTexture6; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3 N, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float h_dot_n = dot(H, N); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(H)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; output.norm_w = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space output.uv0 = input.uv0; output.uv1 = input.uv1; output.uv2 = input.uv2; output.uv3 = input.uv3; output.uv4 = input.uv4; output.uv5 = input.uv5; output.uv6 = input.uv6; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); } if (output.a > 0.0) { // do lightsourcing before decals so specular can only affect the base texture float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); if (g_bLightEnabled) { const float3 N = normalize(input.norm_w); // do per-pixel light sourcing diffuse = compute_per_pixel_ambient_diffuse(N, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(N, input.pos_w.xyz); output.rgb += specular; // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { specular *= (0.4f / g_SpecularLevel); } } // decals at 1,2,3,4,5,6 float4 decal = g_MaterialTexture1.Sample(g_TextureClampSampler, input.uv1); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv2); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture4.Sample(g_TextureClampSampler, input.uv4); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture5.Sample(g_TextureClampSampler, input.uv5); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture6.Sample(g_TextureClampSampler, input.uv6); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHDECAL6BUMP.FX // Copyright (c) 2009 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color float g_BumpAmount; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_BumpNormalTexture; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; Texture2D g_MaterialTexture4; Texture2D g_MaterialTexture5; Texture2D g_MaterialTexture6; Texture2D g_MaterialTexture7; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; SamplerState g_BumpWrapSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_BumpClampSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float2 uv4 : TEXCOORD3; float2 uv5 : TEXCOORD4; float2 uv6 : TEXCOORD5; float2 uv7 : TEXCOORD6; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float2 uv4 : TEXCOORD3; float2 uv5 : TEXCOORD4; float2 uv6 : TEXCOORD5; float2 uv7 : TEXCOORD6; }; //-------------------------------------------------------------------------------------- float3x3 compute_tangent_frame(float3 N, float3 P, float2 uv) { // get edge vectors of the pixel triangle const float3 dp1 = ddx(P); const float3 dp2 = ddy(P); const float2 duv1 = ddx(uv); const float2 duv2 = ddy(uv); // solve the linear system const float2x3 M = float2x3(dp1, dp2); const float3 T = mul(float2(duv1.x, duv2.x), M); const float3 B = mul(float2(duv1.y, duv2.y), M); // construct tangent frame float3 bT = normalize( cross(N, T) ); const float3 nT = cross(bT, N); if (dot(bT, B) < 0) { bT *= -1.0f; } return float3x3( nT, bT, N); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3x3 TangentFrame, float3 Nt, float3 P) { const float3 light_t = mul(TangentFrame, -g_DirLight.dir); float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(Nt, light_t)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return saturate(diffuse); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3x3 TangentFrame, float3 Nt, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float3 Ht = mul(TangentFrame, H); const float h_dot_n = dot(Ht, Nt); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(Ht)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; output.norm_w = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space output.uv0 = input.uv0; output.uv2 = input.uv2; output.uv3 = input.uv3; output.uv4 = input.uv4; output.uv5 = input.uv5; output.uv6 = input.uv6; output.uv7 = input.uv7; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 Np; if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); Np = g_BumpNormalTexture.Sample(g_BumpWrapSampler, input.uv0).xyz * 2.0 - 1.0; } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); Np = g_BumpNormalTexture.Sample(g_BumpClampSampler, input.uv0).xyz * 2.0 - 1.0; } if (output.a > 0.0) { float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); // do lightsourcing before decals so specular can only affect the base texture if (g_bLightEnabled) { // do per-pixel light sourcing const float3 N0 = normalize(input.norm_w); const float3x3 tangent_frame = compute_tangent_frame(N0, input.pos_w.xyz, input.uv0); float3 Nt = lerp(float3(0.0,0.0,1.0), Np, g_BumpAmount); Nt = normalize(Nt); diffuse = compute_per_pixel_ambient_diffuse(tangent_frame, Nt, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(tangent_frame, Nt, input.pos_w.xyz); output.rgb += specular; // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { specular *= (0.4f / g_SpecularLevel); } } // decals at 2,3,4,5,6 float4 decal = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv2); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture4.Sample(g_TextureClampSampler, input.uv4); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture5.Sample(g_TextureClampSampler, input.uv5); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture6.Sample(g_TextureClampSampler, input.uv6); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture7.Sample(g_TextureClampSampler, input.uv7); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHDECAL6SPEC.FX // Copyright (c) 2010 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; Texture2D g_MaterialTexture4; Texture2D g_MaterialTexture5; Texture2D g_MaterialTexture6; Texture2D g_MaterialTexture7; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float2 uv4 : TEXCOORD3; float2 uv5 : TEXCOORD4; float2 uv6 : TEXCOORD5; float2 uv7 : TEXCOORD6; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float2 uv4 : TEXCOORD3; float2 uv5 : TEXCOORD4; float2 uv6 : TEXCOORD5; float2 uv7 : TEXCOORD6; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3 N, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float h_dot_n = dot(H, N); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(H)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; output.norm_w = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space output.uv0 = input.uv0; output.uv2 = input.uv2; output.uv3 = input.uv3; output.uv4 = input.uv4; output.uv5 = input.uv5; output.uv6 = input.uv6; output.uv7 = input.uv7; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 sm; if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); sm = g_MaterialTexture1.Sample(g_TextureWrapSampler, input.uv0); } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); sm = g_MaterialTexture1.Sample(g_TextureClampSampler, input.uv0); } if (output.a > 0.0) { // do lightsourcing before decals so specular can only affect the base texture float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); if (g_bLightEnabled) { const float3 N = normalize(input.norm_w); // do per-pixel light sourcing diffuse = compute_per_pixel_ambient_diffuse(N, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(N, input.pos_w.xyz); output.rgb += (specular * sm); // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { float3 max_decal_sm = min(g_SpecularLevel * sm, float3(0.4f,0.4f,0.4f)); specular *= (max_decal_sm / g_SpecularLevel); } } // decals at 2,3,4,5,6,7 at max 40% specular float4 decal = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv2); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture4.Sample(g_TextureClampSampler, input.uv4); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture5.Sample(g_TextureClampSampler, input.uv5); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture6.Sample(g_TextureClampSampler, input.uv6); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture7.Sample(g_TextureClampSampler, input.uv7); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHDECAL7.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; Texture2D g_MaterialTexture4; Texture2D g_MaterialTexture5; Texture2D g_MaterialTexture6; Texture2D g_MaterialTexture7; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3 N, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float h_dot_n = dot(H, N); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(H)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; output.norm_w = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space output.uv0 = input.uv0; output.uv1 = input.uv1; output.uv2 = input.uv2; output.uv3 = input.uv3; output.uv4 = input.uv4; output.uv5 = input.uv5; output.uv6 = input.uv6; output.uv7 = input.uv7; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); } if (output.a > 0.0) { // do lightsourcing before decals so specular can only affect the base texture float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); if (g_bLightEnabled) { const float3 N = normalize(input.norm_w); // do per-pixel light sourcing diffuse = compute_per_pixel_ambient_diffuse(N, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(N, input.pos_w.xyz); output.rgb += specular; // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { specular *= (0.4f / g_SpecularLevel); } } // decals at 1,2,3,4,5,6,7 float4 decal = g_MaterialTexture1.Sample(g_TextureClampSampler, input.uv1); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv2); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture4.Sample(g_TextureClampSampler, input.uv4); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture5.Sample(g_TextureClampSampler, input.uv5); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture6.Sample(g_TextureClampSampler, input.uv6); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture7.Sample(g_TextureClampSampler, input.uv7); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHNOTEXTURE.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bFogEnabled; int g_bLightEnabled; float3 g_DiffuseColor; int g_bSpecularEnabled; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3 N, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float h_dot_n = dot(H, N); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(H)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; output.norm_w = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output = float4(g_DiffuseColor, 1.0); if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { if (g_bLightEnabled) { const float3 N = normalize(input.norm_w); // do per-pixel light sourcing output.rgb *= compute_per_pixel_ambient_diffuse(N, input.pos_w.xyz); output.rgb += compute_per_pixel_specular(N, input.pos_w.xyz); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } else { output.rgb = g_FogColor; } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHNOTEXTUREALPHA.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color float g_Transparency; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3 N, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float h_dot_n = dot(H, N); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(H)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; output.norm_w = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output = float4(1.0, 1.0, 1.0, g_Transparency); if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { if (g_bLightEnabled) { const float3 N = normalize(input.norm_w); // do per-pixel light sourcing output.rgb *= compute_per_pixel_ambient_diffuse(N, input.pos_w.xyz); output.rgb += compute_per_pixel_specular(N, input.pos_w.xyz); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } else { output.rgb = g_FogColor; } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHNOTEXTUREREFLECTION.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bFogEnabled; int g_bLightEnabled; float3 g_DiffuseColor; int g_bSpecularEnabled; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv : TEXCOORD; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv : TEXCOORD; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3 N, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float h_dot_n = dot(H, N); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(H)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; // calculate spherical reflection coordidates const float3 N = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space const float3 Nv = mul(N, (float3x3)g_mWorldToView); // normal, view-space output.norm_w = N; output.uv.x = 0.5 * Nv.x + 0.5; output.uv.y = -0.5 * Nv.y + 0.5; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position, view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output = float4(g_DiffuseColor, 1.0); if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { const float4 reflec = g_MaterialTexture.Sample(g_TextureWrapSampler, input.uv); output.rgb = lerp(output.rgb, reflec.rgb, reflec.a); if (g_bLightEnabled) { const float3 N = normalize(input.norm_w); // do per-pixel light sourcing output.rgb *= compute_per_pixel_ambient_diffuse(N, input.pos_w.xyz); output.rgb += compute_per_pixel_specular(N, input.pos_w.xyz); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } else { output.rgb = g_FogColor; } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHREFLECTION.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; float3 g_CameraPos; int g_bInReflection; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; int g_NumSpotLights; PointLight g_aPointLights[8]; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3 N, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float h_dot_n = dot(H, N); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(H)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; // calculate spherical reflection coordidates const float3 N = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space const float3 Nv = mul(N, (float3x3)g_mWorldToView); // normal, view-space output.norm_w = N; output.uv0 = input.uv0; output.uv1.x = 0.5 * Nv.x + 0.5; output.uv1.y = -0.5 * Nv.y + 0.5; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position, view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { if (g_bInReflection) { clip(input.pos_w.z + g_CameraPos.z); } float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); } if (output.a > 0) { const float4 reflec = g_MaterialTexture1.Sample(g_TextureClampSampler, input.uv1); output.rgb = lerp(output.rgb, reflec.rgb, reflec.a); if (g_bLightEnabled) { const float3 N = normalize(input.norm_w); // do per-pixel light sourcing output.rgb *= compute_per_pixel_ambient_diffuse(N, input.pos_w.xyz); output.rgb += compute_per_pixel_specular(N, input.pos_w.xyz); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHREFLECTIONBUMP.FX // Copyright (c) 2009 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; float3 g_CameraPos; int g_bInReflection; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color float g_BumpAmount; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; int g_NumSpotLights; PointLight g_aPointLights[8]; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_BumpNormalTexture; Texture2D g_MaterialTexture2; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; SamplerState g_BumpWrapSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_BumpClampSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; }; //-------------------------------------------------------------------------------------- float3x3 compute_tangent_frame(float3 N, float3 P, float2 uv) { // get edge vectors of the pixel triangle const float3 dp1 = ddx(P); const float3 dp2 = ddy(P); const float2 duv1 = ddx(uv); const float2 duv2 = ddy(uv); // solve the linear system const float2x3 M = float2x3(dp1, dp2); const float3 T = mul(float2(duv1.x, duv2.x), M); const float3 B = mul(float2(duv1.y, duv2.y), M); // construct tangent frame float3 bT = normalize( cross(N, T) ); const float3 nT = cross(bT, N); if (dot(bT, B) < 0) { bT *= -1.0f; } return float3x3( nT, bT, N); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3x3 TangentFrame, float3 Nt, float3 P) { const float3 light_t = mul(TangentFrame, -g_DirLight.dir); float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(Nt, light_t)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return saturate(diffuse); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3x3 TangentFrame, float3 Nt, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float3 Ht = mul(TangentFrame, H); const float h_dot_n = dot(Ht, Nt); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(Ht)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; // calculate spherical reflection coordidates const float3 N = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space const float3 Nv = mul(N, (float3x3)g_mWorldToView); // normal, view-space output.norm_w = N; output.uv0 = input.uv0; output.uv2.x = 0.5 * Nv.x + 0.5; output.uv2.y = -0.5 * Nv.y + 0.5; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position, view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { if (g_bInReflection) { clip(input.pos_w.z + g_CameraPos.z); } float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 Np; if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); Np = g_BumpNormalTexture.Sample(g_BumpWrapSampler, input.uv0).xyz * 2.0 - 1.0; } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); Np = g_BumpNormalTexture.Sample(g_BumpClampSampler, input.uv0).xyz * 2.0 - 1.0; } if (output.a > 0) { const float4 reflec = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv2); output.rgb = lerp(output.rgb, reflec.rgb, reflec.a); float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); if (g_bLightEnabled) { // do per-pixel light sourcing const float3 N0 = normalize(input.norm_w); const float3x3 tangent_frame = compute_tangent_frame(N0, input.pos_w.xyz, input.uv0); float3 Nt = lerp(float3(0.0,0.0,1.0), Np, g_BumpAmount); Nt = normalize(Nt); output.rgb *= compute_per_pixel_ambient_diffuse(tangent_frame, Nt, input.pos_w.xyz); output.rgb += compute_per_pixel_specular(tangent_frame, Nt, input.pos_w.xyz); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHREFLECTIONBUMPSPEC.FX // Copyright (c) 2010 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; float3 g_CameraPos; int g_bInReflection; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color float g_BumpAmount; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; int g_NumSpotLights; PointLight g_aPointLights[8]; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; SamplerState g_BumpWrapSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_BumpClampSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv3 : TEXCOORD1; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv3 : TEXCOORD1; }; //-------------------------------------------------------------------------------------- float3x3 compute_tangent_frame(float3 N, float3 P, float2 uv) { // get edge vectors of the pixel triangle const float3 dp1 = ddx(P); const float3 dp2 = ddy(P); const float2 duv1 = ddx(uv); const float2 duv2 = ddy(uv); // solve the linear system const float2x3 M = float2x3(dp1, dp2); const float3 T = mul(float2(duv1.x, duv2.x), M); const float3 B = mul(float2(duv1.y, duv2.y), M); // construct tangent frame float3 bT = normalize( cross(N, T) ); const float3 nT = cross(bT, N); if (dot(bT, B) < 0) { bT *= -1.0f; } return float3x3( nT, bT, N); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3x3 TangentFrame, float3 Nt, float3 P) { const float3 light_t = mul(TangentFrame, -g_DirLight.dir); float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(Nt, light_t)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return saturate(diffuse); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3x3 TangentFrame, float3 Nt, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float3 Ht = mul(TangentFrame, H); const float h_dot_n = dot(Ht, Nt); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(Ht)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; // calculate spherical reflection coordidates const float3 N = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space const float3 Nv = mul(N, (float3x3)g_mWorldToView); // normal, view-space output.norm_w = N; output.uv0 = input.uv0; output.uv3.x = 0.5 * Nv.x + 0.5; output.uv3.y = -0.5 * Nv.y + 0.5; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position, view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { if (g_bInReflection) { clip(input.pos_w.z + g_CameraPos.z); } float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 Np; float3 sm; if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); Np = g_MaterialTexture1.Sample(g_BumpWrapSampler, input.uv0).xyz * 2.0 - 1.0; sm = g_MaterialTexture2.Sample(g_TextureWrapSampler, input.uv0).rgb; } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); Np = g_MaterialTexture1.Sample(g_BumpClampSampler, input.uv0).xyz * 2.0 - 1.0; sm = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv0).rgb; } if (output.a > 0) { // TK TODO add reflection component? use color b for now if (sm.b >= 0.5f) { float sr = clamp(0.0, 1.0, (sm.b - 0.5f) * 2.0f); // 0 at 0-0.5, 0-1 at 0.5 to 1 const float4 reflec = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); output.rgb = lerp(output.rgb, reflec.rgb, (reflec.a * sr)); } if (g_bLightEnabled) { // do per-pixel light sourcing const float3 N0 = normalize(input.norm_w); const float3x3 tangent_frame = compute_tangent_frame(N0, input.pos_w.xyz, input.uv0); float3 Nt = lerp(float3(0.0,0.0,1.0), Np, g_BumpAmount); Nt = normalize(Nt); output.rgb *= compute_per_pixel_ambient_diffuse(tangent_frame, Nt, input.pos_w.xyz); output.rgb += (compute_per_pixel_specular(tangent_frame, Nt, input.pos_w.xyz) * sm); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHREFLECTIONDECAL1.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; float3 g_CameraPos; int g_bInReflection; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3 N, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float h_dot_n = dot(H, N); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(H)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; // calculate spherical reflection coordidates const float3 N = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space const float3 Nv = mul(N, (float3x3)g_mWorldToView); // normal, view-space output.norm_w = N; output.uv0 = input.uv0; output.uv1.x = 0.5 * Nv.x + 0.5; output.uv1.y = -0.5 * Nv.y + 0.5; output.uv2 = input.uv2; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { if (g_bInReflection) { clip(input.pos_w.z + g_CameraPos.z); } float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); } if (output.a > 0.0) { const float4 reflec = g_MaterialTexture1.Sample(g_TextureClampSampler, input.uv1); output.rgb = lerp(output.rgb, reflec.rgb, reflec.a); // do lightsourcing before decals so specular can only affect the base texture float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); if (g_bLightEnabled) { const float3 N = normalize(input.norm_w); // do per-pixel light sourcing diffuse = compute_per_pixel_ambient_diffuse(N, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(N, input.pos_w.xyz); output.rgb += specular; // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { specular *= (0.4f / g_SpecularLevel); } } // decals at 2 float4 decal = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv2); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHREFLECTIONDECAL1BUMP.FX // Copyright (c) 2009 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; float3 g_CameraPos; int g_bInReflection; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color float g_BumpAmount; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_BumpNormalTexture; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; SamplerState g_BumpWrapSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_BumpClampSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; }; //-------------------------------------------------------------------------------------- float3x3 compute_tangent_frame(float3 N, float3 P, float2 uv) { // get edge vectors of the pixel triangle const float3 dp1 = ddx(P); const float3 dp2 = ddy(P); const float2 duv1 = ddx(uv); const float2 duv2 = ddy(uv); // solve the linear system const float2x3 M = float2x3(dp1, dp2); const float3 T = mul(float2(duv1.x, duv2.x), M); const float3 B = mul(float2(duv1.y, duv2.y), M); // construct tangent frame float3 bT = normalize( cross(N, T) ); const float3 nT = cross(bT, N); if (dot(bT, B) < 0) { bT *= -1.0f; } return float3x3( nT, bT, N); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3x3 TangentFrame, float3 Nt, float3 P) { const float3 light_t = mul(TangentFrame, -g_DirLight.dir); float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(Nt, light_t)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return saturate(diffuse); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3x3 TangentFrame, float3 Nt, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float3 Ht = mul(TangentFrame, H); const float h_dot_n = dot(Ht, Nt); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(Ht)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; // calculate spherical reflection coordidates const float3 N = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space const float3 Nv = mul(N, (float3x3)g_mWorldToView); // normal, view-space output.norm_w = N; output.uv0 = input.uv0; output.uv2.x = 0.5 * Nv.x + 0.5; output.uv2.y = -0.5 * Nv.y + 0.5; output.uv3 = input.uv3; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { if (g_bInReflection) { clip(input.pos_w.z + g_CameraPos.z); } float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 Np; if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); Np = g_BumpNormalTexture.Sample(g_BumpWrapSampler, input.uv0).xyz * 2.0 - 1.0; } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); Np = g_BumpNormalTexture.Sample(g_BumpClampSampler, input.uv0).xyz * 2.0 - 1.0; } if (output.a > 0.0) { const float4 reflec = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv2); output.rgb = lerp(output.rgb, reflec.rgb, reflec.a); float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); // do lightsourcing before decals so specular can only affect the base texture if (g_bLightEnabled) { // do per-pixel light sourcing const float3 N0 = normalize(input.norm_w); const float3x3 tangent_frame = compute_tangent_frame(N0, input.pos_w.xyz, input.uv0); float3 Nt = lerp(float3(0.0,0.0,1.0), Np, g_BumpAmount); Nt = normalize(Nt); diffuse = compute_per_pixel_ambient_diffuse(tangent_frame, Nt, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(tangent_frame, Nt, input.pos_w.xyz); output.rgb += specular; // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { specular *= (0.4f / g_SpecularLevel); } } // decals at 3 float4 decal = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHREFLECTIONDECAL1BUMPSPEC.FX // Copyright (c) 2010 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; float3 g_CameraPos; int g_bInReflection; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color float g_BumpAmount; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; Texture2D g_MaterialTexture4; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; SamplerState g_BumpWrapSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_BumpClampSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv3 : TEXCOORD1; float2 uv4 : TEXCOORD2; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv3 : TEXCOORD1; float2 uv4 : TEXCOORD2; }; //-------------------------------------------------------------------------------------- float3x3 compute_tangent_frame(float3 N, float3 P, float2 uv) { // get edge vectors of the pixel triangle const float3 dp1 = ddx(P); const float3 dp2 = ddy(P); const float2 duv1 = ddx(uv); const float2 duv2 = ddy(uv); // solve the linear system const float2x3 M = float2x3(dp1, dp2); const float3 T = mul(float2(duv1.x, duv2.x), M); const float3 B = mul(float2(duv1.y, duv2.y), M); // construct tangent frame float3 bT = normalize( cross(N, T) ); const float3 nT = cross(bT, N); if (dot(bT, B) < 0) { bT *= -1.0f; } return float3x3( nT, bT, N); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3x3 TangentFrame, float3 Nt, float3 P) { const float3 light_t = mul(TangentFrame, -g_DirLight.dir); float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(Nt, light_t)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return saturate(diffuse); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3x3 TangentFrame, float3 Nt, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float3 Ht = mul(TangentFrame, H); const float h_dot_n = dot(Ht, Nt); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(Ht)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; // calculate spherical reflection coordidates const float3 N = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space const float3 Nv = mul(N, (float3x3)g_mWorldToView); // normal, view-space output.norm_w = N; output.uv0 = input.uv0; output.uv3.x = 0.5 * Nv.x + 0.5; output.uv3.y = -0.5 * Nv.y + 0.5; output.uv4 = input.uv4; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { if (g_bInReflection) { clip(input.pos_w.z + g_CameraPos.z); } float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 Np; float3 sm; if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); Np = g_MaterialTexture1.Sample(g_BumpWrapSampler, input.uv0).xyz * 2.0 - 1.0; sm = g_MaterialTexture2.Sample(g_TextureWrapSampler, input.uv0).rgb; } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); Np = g_MaterialTexture1.Sample(g_BumpClampSampler, input.uv0).xyz * 2.0 - 1.0; sm = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv0).rgb; } if (output.a > 0.0) { // TK TODO add reflection component? use color b for now if (sm.b >= 0.5f) { float sr = clamp(0.0, 1.0, (sm.b - 0.5f) * 2.0f); // 0 at 0-0.5, 0-1 at 0.5 to 1 const float4 reflec = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); output.rgb = lerp(output.rgb, reflec.rgb, (reflec.a * sr)); } float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); // do lightsourcing before decals so specular can only affect the base texture if (g_bLightEnabled) { // do per-pixel light sourcing const float3 N0 = normalize(input.norm_w); const float3x3 tangent_frame = compute_tangent_frame(N0, input.pos_w.xyz, input.uv0); float3 Nt = lerp(float3(0.0,0.0,1.0), Np, g_BumpAmount); Nt = normalize(Nt); diffuse = compute_per_pixel_ambient_diffuse(tangent_frame, Nt, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(tangent_frame, Nt, input.pos_w.xyz); output.rgb += (specular * sm); // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { float3 max_decal_sm = min(g_SpecularLevel * sm, float3(0.4f,0.4f,0.4f)); specular *= (max_decal_sm / g_SpecularLevel); } } // decals at 4 float4 decal = g_MaterialTexture4.Sample(g_TextureClampSampler, input.uv4); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHREFLECTIONDECAL1SPEC.FX // Copyright (c) 2010 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; float3 g_CameraPos; int g_bInReflection; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3 N, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float h_dot_n = dot(H, N); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(H)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; // calculate spherical reflection coordidates const float3 N = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space const float3 Nv = mul(N, (float3x3)g_mWorldToView); // normal, view-space output.norm_w = N; output.uv0 = input.uv0; output.uv2.x = 0.5 * Nv.x + 0.5; output.uv2.y = -0.5 * Nv.y + 0.5; output.uv3 = input.uv3; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { if (g_bInReflection) { clip(input.pos_w.z + g_CameraPos.z); } float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 sm; if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); sm = g_MaterialTexture1.Sample(g_TextureWrapSampler, input.uv0).rgb; } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); sm = g_MaterialTexture1.Sample(g_TextureClampSampler, input.uv0).rgb; } if (output.a > 0.0) { // TK TODO add reflection component? use color b for now if (sm.b >= 0.5f) { float sr = clamp(0.0, 1.0, (sm.b - 0.5f) * 2.0f); // 0 at 0-0.5, 0-1 at 0.5 to 1 const float4 reflec = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv2); output.rgb = lerp(output.rgb, reflec.rgb, (reflec.a * sr)); } // do lightsourcing before decals so specular can only affect the base texture float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); if (g_bLightEnabled) { const float3 N = normalize(input.norm_w); // do per-pixel light sourcing diffuse = compute_per_pixel_ambient_diffuse(N, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(N, input.pos_w.xyz); output.rgb += (specular * sm); // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { float3 max_decal_sm = min(g_SpecularLevel * sm, float3(0.4f,0.4f,0.4f)); specular *= (max_decal_sm / g_SpecularLevel); } } // decals at 3 at max 40% specular float4 decal = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHREFLECTIONDECAL2.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3 N, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float h_dot_n = dot(H, N); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(H)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; // calculate spherical reflection coordidates const float3 N = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space const float3 Nv = mul(N, (float3x3)g_mWorldToView); // normal, view-space output.norm_w = N; output.uv0 = input.uv0; output.uv1.x = 0.5 * Nv.x + 0.5; output.uv1.y = -0.5 * Nv.y + 0.5; output.uv2 = input.uv2; output.uv3 = input.uv3; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); } if (output.a > 0.0) { const float4 reflec = g_MaterialTexture1.Sample(g_TextureClampSampler, input.uv1); output.rgb = lerp(output.rgb, reflec.rgb, reflec.a); // do lightsourcing before decals so specular can only affect the base texture float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); if (g_bLightEnabled) { const float3 N = normalize(input.norm_w); // do per-pixel light sourcing diffuse = compute_per_pixel_ambient_diffuse(N, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(N, input.pos_w.xyz); output.rgb += specular; // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { specular *= (0.4f / g_SpecularLevel); } } // decals at 2,3 float4 decal = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv2); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHREFLECTIONDECAL2BUMP.FX // Copyright (c) 2009 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color float g_BumpAmount; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_BumpNormalTexture; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; Texture2D g_MaterialTexture4; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; SamplerState g_BumpWrapSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_BumpClampSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float2 uv4 : TEXCOORD3; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float2 uv4 : TEXCOORD3; }; //-------------------------------------------------------------------------------------- float3x3 compute_tangent_frame(float3 N, float3 P, float2 uv) { // get edge vectors of the pixel triangle const float3 dp1 = ddx(P); const float3 dp2 = ddy(P); const float2 duv1 = ddx(uv); const float2 duv2 = ddy(uv); // solve the linear system const float2x3 M = float2x3(dp1, dp2); const float3 T = mul(float2(duv1.x, duv2.x), M); const float3 B = mul(float2(duv1.y, duv2.y), M); // construct tangent frame float3 bT = normalize( cross(N, T) ); const float3 nT = cross(bT, N); if (dot(bT, B) < 0) { bT *= -1.0f; } return float3x3( nT, bT, N); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3x3 TangentFrame, float3 Nt, float3 P) { const float3 light_t = mul(TangentFrame, -g_DirLight.dir); float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(Nt, light_t)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return saturate(diffuse); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3x3 TangentFrame, float3 Nt, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float3 Ht = mul(TangentFrame, H); const float h_dot_n = dot(Ht, Nt); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(Ht)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; // calculate spherical reflection coordidates const float3 N = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space const float3 Nv = mul(N, (float3x3)g_mWorldToView); // normal, view-space output.norm_w = N; output.uv0 = input.uv0; output.uv2.x = 0.5 * Nv.x + 0.5; output.uv2.y = -0.5 * Nv.y + 0.5; output.uv3 = input.uv3; output.uv4 = input.uv4; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 Np; if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); Np = g_BumpNormalTexture.Sample(g_BumpWrapSampler, input.uv0).xyz * 2.0 - 1.0; } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); Np = g_BumpNormalTexture.Sample(g_BumpClampSampler, input.uv0).xyz * 2.0 - 1.0; } if (output.a > 0.0) { const float4 reflec = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv2); output.rgb = lerp(output.rgb, reflec.rgb, reflec.a); float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); // do lightsourcing before decals so specular can only affect the base texture if (g_bLightEnabled) { // do per-pixel light sourcing const float3 N0 = normalize(input.norm_w); const float3x3 tangent_frame = compute_tangent_frame(N0, input.pos_w.xyz, input.uv0); float3 Nt = lerp(float3(0.0,0.0,1.0), Np, g_BumpAmount); Nt = normalize(Nt); diffuse = compute_per_pixel_ambient_diffuse(tangent_frame, Nt, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(tangent_frame, Nt, input.pos_w.xyz); output.rgb += specular; // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { specular *= (0.4f / g_SpecularLevel); } } // decals at 3,4 float4 decal = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture4.Sample(g_TextureClampSampler, input.uv4); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHREFLECTIONDECAL2BUMPSPEC.FX // Copyright (c) 2010 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color float g_BumpAmount; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; Texture2D g_MaterialTexture4; Texture2D g_MaterialTexture5; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; SamplerState g_BumpWrapSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_BumpClampSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv3 : TEXCOORD1; float2 uv4 : TEXCOORD2; float2 uv5 : TEXCOORD3; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv3 : TEXCOORD1; float2 uv4 : TEXCOORD2; float2 uv5 : TEXCOORD3; }; //-------------------------------------------------------------------------------------- float3x3 compute_tangent_frame(float3 N, float3 P, float2 uv) { // get edge vectors of the pixel triangle const float3 dp1 = ddx(P); const float3 dp2 = ddy(P); const float2 duv1 = ddx(uv); const float2 duv2 = ddy(uv); // solve the linear system const float2x3 M = float2x3(dp1, dp2); const float3 T = mul(float2(duv1.x, duv2.x), M); const float3 B = mul(float2(duv1.y, duv2.y), M); // construct tangent frame float3 bT = normalize( cross(N, T) ); const float3 nT = cross(bT, N); if (dot(bT, B) < 0) { bT *= -1.0f; } return float3x3( nT, bT, N); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3x3 TangentFrame, float3 Nt, float3 P) { const float3 light_t = mul(TangentFrame, -g_DirLight.dir); float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(Nt, light_t)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return saturate(diffuse); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3x3 TangentFrame, float3 Nt, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float3 Ht = mul(TangentFrame, H); const float h_dot_n = dot(Ht, Nt); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(Ht)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; // calculate spherical reflection coordidates const float3 N = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space const float3 Nv = mul(N, (float3x3)g_mWorldToView); // normal, view-space output.norm_w = N; output.uv0 = input.uv0; output.uv3.x = 0.5 * Nv.x + 0.5; output.uv3.y = -0.5 * Nv.y + 0.5; output.uv4 = input.uv4; output.uv5 = input.uv5; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 Np; float3 sm; if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); Np = g_MaterialTexture1.Sample(g_BumpWrapSampler, input.uv0).xyz * 2.0 - 1.0; sm = g_MaterialTexture2.Sample(g_TextureWrapSampler, input.uv0).rgb; } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); Np = g_MaterialTexture1.Sample(g_BumpClampSampler, input.uv0).xyz * 2.0 - 1.0; sm = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv0).rgb; } if (output.a > 0.0) { // TK TODO add reflection component? use color b for now if (sm.b >= 0.5f) { float sr = clamp(0.0, 1.0, (sm.b - 0.5f) * 2.0f); // 0 at 0-0.5, 0-1 at 0.5 to 1 const float4 reflec = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); output.rgb = lerp(output.rgb, reflec.rgb, (reflec.a * sr)); } float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); // do lightsourcing before decals so specular can only affect the base texture if (g_bLightEnabled) { // do per-pixel light sourcing const float3 N0 = normalize(input.norm_w); const float3x3 tangent_frame = compute_tangent_frame(N0, input.pos_w.xyz, input.uv0); float3 Nt = lerp(float3(0.0,0.0,1.0), Np, g_BumpAmount); Nt = normalize(Nt); diffuse = compute_per_pixel_ambient_diffuse(tangent_frame, Nt, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(tangent_frame, Nt, input.pos_w.xyz); output.rgb += (specular * sm); // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { float3 max_decal_sm = min(g_SpecularLevel * sm, float3(0.4f,0.4f,0.4f)); specular *= (max_decal_sm / g_SpecularLevel); } } // decals at 4,5 float4 decal = g_MaterialTexture4.Sample(g_TextureClampSampler, input.uv4); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture5.Sample(g_TextureClampSampler, input.uv5); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHREFLECTIONDECAL2SPEC.FX // Copyright (c) 2010 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; Texture2D g_MaterialTexture4; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float2 uv4 : TEXCOORD3; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float2 uv4 : TEXCOORD3; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3 N, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float h_dot_n = dot(H, N); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(H)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; // calculate spherical reflection coordidates const float3 N = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space const float3 Nv = mul(N, (float3x3)g_mWorldToView); // normal, view-space output.norm_w = N; output.uv0 = input.uv0; output.uv2.x = 0.5 * Nv.x + 0.5; output.uv2.y = -0.5 * Nv.y + 0.5; output.uv3 = input.uv3; output.uv4 = input.uv4; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 sm; if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); sm = g_MaterialTexture1.Sample(g_TextureWrapSampler, input.uv0).rgb; } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); sm = g_MaterialTexture1.Sample(g_TextureClampSampler, input.uv0).rgb; } if (output.a > 0.0) { // TK TODO add reflection component? use color b for now if (sm.b >= 0.5f) { float sr = clamp(0.0, 1.0, (sm.b - 0.5f) * 2.0f); // 0 at 0-0.5, 0-1 at 0.5 to 1 const float4 reflec = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv2); output.rgb = lerp(output.rgb, reflec.rgb, (reflec.a * sr)); } // do lightsourcing before decals so specular can only affect the base texture float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); if (g_bLightEnabled) { const float3 N = normalize(input.norm_w); // do per-pixel light sourcing diffuse = compute_per_pixel_ambient_diffuse(N, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(N, input.pos_w.xyz); output.rgb += (specular * sm); // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { float3 max_decal_sm = min(g_SpecularLevel * sm, float3(0.4f,0.4f,0.4f)); specular *= (max_decal_sm / g_SpecularLevel); } } // decals at 3,4 at max 40% specular float4 decal = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture4.Sample(g_TextureClampSampler, input.uv4); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHREFLECTIONDECAL3.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; Texture2D g_MaterialTexture4; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3 N, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float h_dot_n = dot(H, N); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(H)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; // calculate spherical reflection coordidates const float3 N = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space const float3 Nv = mul(N, (float3x3)g_mWorldToView); // normal, view-space output.norm_w = N; output.uv0 = input.uv0; output.uv1.x = 0.5 * Nv.x + 0.5; output.uv1.y = -0.5 * Nv.y + 0.5; output.uv2 = input.uv2; output.uv3 = input.uv3; output.uv4 = input.uv4; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); } if (output.a > 0.0) { const float4 reflec = g_MaterialTexture1.Sample(g_TextureClampSampler, input.uv1); output.rgb = lerp(output.rgb, reflec.rgb, reflec.a); // do lightsourcing before decals so specular can only affect the base texture float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); if (g_bLightEnabled) { const float3 N = normalize(input.norm_w); // do per-pixel light sourcing diffuse = compute_per_pixel_ambient_diffuse(N, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(N, input.pos_w.xyz); output.rgb += specular; // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { specular *= (0.4f / g_SpecularLevel); } } // decals at 2,3,4 float4 decal = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv2); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture4.Sample(g_TextureClampSampler, input.uv4); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHREFLECTIONDECAL3BUMP.FX // Copyright (c) 2009 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color float g_BumpAmount; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_BumpNormalTexture; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; Texture2D g_MaterialTexture4; Texture2D g_MaterialTexture5; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; SamplerState g_BumpWrapSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_BumpClampSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float2 uv4 : TEXCOORD3; float2 uv5 : TEXCOORD4; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float2 uv4 : TEXCOORD3; float2 uv5 : TEXCOORD4; }; //-------------------------------------------------------------------------------------- float3x3 compute_tangent_frame(float3 N, float3 P, float2 uv) { // get edge vectors of the pixel triangle const float3 dp1 = ddx(P); const float3 dp2 = ddy(P); const float2 duv1 = ddx(uv); const float2 duv2 = ddy(uv); // solve the linear system const float2x3 M = float2x3(dp1, dp2); const float3 T = mul(float2(duv1.x, duv2.x), M); const float3 B = mul(float2(duv1.y, duv2.y), M); // construct tangent frame float3 bT = normalize( cross(N, T) ); const float3 nT = cross(bT, N); if (dot(bT, B) < 0) { bT *= -1.0f; } return float3x3( nT, bT, N); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3x3 TangentFrame, float3 Nt, float3 P) { const float3 light_t = mul(TangentFrame, -g_DirLight.dir); float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(Nt, light_t)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return saturate(diffuse); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3x3 TangentFrame, float3 Nt, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float3 Ht = mul(TangentFrame, H); const float h_dot_n = dot(Ht, Nt); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(Ht)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; // calculate spherical reflection coordidates const float3 N = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space const float3 Nv = mul(N, (float3x3)g_mWorldToView); // normal, view-space output.norm_w = N; output.uv0 = input.uv0; output.uv2.x = 0.5 * Nv.x + 0.5; output.uv2.y = -0.5 * Nv.y + 0.5; output.uv3 = input.uv3; output.uv4 = input.uv4; output.uv5 = input.uv5; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 Np; if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); Np = g_BumpNormalTexture.Sample(g_BumpWrapSampler, input.uv0).xyz * 2.0 - 1.0; } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); Np = g_BumpNormalTexture.Sample(g_BumpClampSampler, input.uv0).xyz * 2.0 - 1.0; } if (output.a > 0.0) { const float4 reflec = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv2); output.rgb = lerp(output.rgb, reflec.rgb, reflec.a); float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); // do lightsourcing before decals so specular can only affect the base texture if (g_bLightEnabled) { // do per-pixel light sourcing const float3 N0 = normalize(input.norm_w); const float3x3 tangent_frame = compute_tangent_frame(N0, input.pos_w.xyz, input.uv0); float3 Nt = lerp(float3(0.0,0.0,1.0), Np, g_BumpAmount); Nt = normalize(Nt); diffuse = compute_per_pixel_ambient_diffuse(tangent_frame, Nt, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(tangent_frame, Nt, input.pos_w.xyz); output.rgb += specular; // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { specular *= (0.4f / g_SpecularLevel); } } // decals at 3,4,5 float4 decal = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture4.Sample(g_TextureClampSampler, input.uv4); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture5.Sample(g_TextureClampSampler, input.uv5); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHREFLECTIONDECAL3BUMPSPEC.FX // Copyright (c) 2010 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color float g_BumpAmount; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; Texture2D g_MaterialTexture4; Texture2D g_MaterialTexture5; Texture2D g_MaterialTexture6; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; SamplerState g_BumpWrapSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_BumpClampSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv3 : TEXCOORD1; float2 uv4 : TEXCOORD2; float2 uv5 : TEXCOORD3; float2 uv6 : TEXCOORD4; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv3 : TEXCOORD1; float2 uv4 : TEXCOORD2; float2 uv5 : TEXCOORD3; float2 uv6 : TEXCOORD4; }; //-------------------------------------------------------------------------------------- float3x3 compute_tangent_frame(float3 N, float3 P, float2 uv) { // get edge vectors of the pixel triangle const float3 dp1 = ddx(P); const float3 dp2 = ddy(P); const float2 duv1 = ddx(uv); const float2 duv2 = ddy(uv); // solve the linear system const float2x3 M = float2x3(dp1, dp2); const float3 T = mul(float2(duv1.x, duv2.x), M); const float3 B = mul(float2(duv1.y, duv2.y), M); // construct tangent frame float3 bT = normalize( cross(N, T) ); const float3 nT = cross(bT, N); if (dot(bT, B) < 0) { bT *= -1.0f; } return float3x3( nT, bT, N); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3x3 TangentFrame, float3 Nt, float3 P) { const float3 light_t = mul(TangentFrame, -g_DirLight.dir); float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(Nt, light_t)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return saturate(diffuse); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3x3 TangentFrame, float3 Nt, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float3 Ht = mul(TangentFrame, H); const float h_dot_n = dot(Ht, Nt); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(Ht)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; // calculate spherical reflection coordidates const float3 N = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space const float3 Nv = mul(N, (float3x3)g_mWorldToView); // normal, view-space output.norm_w = N; output.uv0 = input.uv0; output.uv3.x = 0.5 * Nv.x + 0.5; output.uv3.y = -0.5 * Nv.y + 0.5; output.uv4 = input.uv4; output.uv5 = input.uv5; output.uv6 = input.uv6; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 Np; float3 sm; if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); Np = g_MaterialTexture1.Sample(g_BumpWrapSampler, input.uv0).xyz * 2.0 - 1.0; sm = g_MaterialTexture2.Sample(g_TextureWrapSampler, input.uv0).rgb; } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); Np = g_MaterialTexture1.Sample(g_BumpClampSampler, input.uv0).xyz * 2.0 - 1.0; sm = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv0).rgb; } if (output.a > 0.0) { // TK TODO add reflection component? use color b for now if (sm.b >= 0.5f) { float sr = clamp(0.0, 1.0, (sm.b - 0.5f) * 2.0f); // 0 at 0-0.5, 0-1 at 0.5 to 1 const float4 reflec = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); output.rgb = lerp(output.rgb, reflec.rgb, (reflec.a * sr)); } float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); // do lightsourcing before decals so specular can only affect the base texture if (g_bLightEnabled) { // do per-pixel light sourcing const float3 N0 = normalize(input.norm_w); const float3x3 tangent_frame = compute_tangent_frame(N0, input.pos_w.xyz, input.uv0); float3 Nt = lerp(float3(0.0,0.0,1.0), Np, g_BumpAmount); Nt = normalize(Nt); diffuse = compute_per_pixel_ambient_diffuse(tangent_frame, Nt, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(tangent_frame, Nt, input.pos_w.xyz); output.rgb += (specular * sm); // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { float3 max_decal_sm = min(g_SpecularLevel * sm, float3(0.4f,0.4f,0.4f)); specular *= (max_decal_sm / g_SpecularLevel); } } // decals at 4,5,6 float4 decal = g_MaterialTexture4.Sample(g_TextureClampSampler, input.uv4); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture5.Sample(g_TextureClampSampler, input.uv5); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture6.Sample(g_TextureClampSampler, input.uv6); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHREFLECTIONDECAL3SPEC.FX // Copyright (c) 2010 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; Texture2D g_MaterialTexture4; Texture2D g_MaterialTexture5; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float2 uv4 : TEXCOORD3; float2 uv5 : TEXCOORD4; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float2 uv4 : TEXCOORD3; float2 uv5 : TEXCOORD4; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3 N, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float h_dot_n = dot(H, N); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(H)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; // calculate spherical reflection coordidates const float3 N = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space const float3 Nv = mul(N, (float3x3)g_mWorldToView); // normal, view-space output.norm_w = N; output.uv0 = input.uv0; output.uv2.x = 0.5 * Nv.x + 0.5; output.uv2.y = -0.5 * Nv.y + 0.5; output.uv3 = input.uv3; output.uv4 = input.uv4; output.uv5 = input.uv5; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 sm; if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); sm = g_MaterialTexture1.Sample(g_TextureWrapSampler, input.uv0).rgb; } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); sm = g_MaterialTexture1.Sample(g_TextureClampSampler, input.uv0).rgb; } if (output.a > 0.0) { // TK TODO add reflection component? use color b for now if (sm.b >= 0.5f) { float sr = clamp(0.0, 1.0, (sm.b - 0.5f) * 2.0f); // 0 at 0-0.5, 0-1 at 0.5 to 1 const float4 reflec = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv2); output.rgb = lerp(output.rgb, reflec.rgb, (reflec.a * sr)); } // do lightsourcing before decals so specular can only affect the base texture float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); if (g_bLightEnabled) { const float3 N = normalize(input.norm_w); // do per-pixel light sourcing diffuse = compute_per_pixel_ambient_diffuse(N, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(N, input.pos_w.xyz); output.rgb += (specular * sm); // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { float3 max_decal_sm = min(g_SpecularLevel * sm, float3(0.4f,0.4f,0.4f)); specular *= (max_decal_sm / g_SpecularLevel); } } // decals at 3,4,5 at max 40% specular float4 decal = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture4.Sample(g_TextureClampSampler, input.uv4); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture5.Sample(g_TextureClampSampler, input.uv5); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHREFLECTIONDECAL4.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; Texture2D g_MaterialTexture4; Texture2D g_MaterialTexture5; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3 N, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float h_dot_n = dot(H, N); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(H)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; // calculate spherical reflection coordidates const float3 N = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space const float3 Nv = mul(N, (float3x3)g_mWorldToView); // normal, view-space output.norm_w = N; output.uv0 = input.uv0; output.uv1.x = 0.5 * Nv.x + 0.5; output.uv1.y = -0.5 * Nv.y + 0.5; output.uv2 = input.uv2; output.uv3 = input.uv3; output.uv4 = input.uv4; output.uv5 = input.uv5; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); } if (output.a > 0.0) { const float4 reflec = g_MaterialTexture1.Sample(g_TextureClampSampler, input.uv1); output.rgb = lerp(output.rgb, reflec.rgb, reflec.a); // do lightsourcing before decals so specular can only affect the base texture float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); if (g_bLightEnabled) { const float3 N = normalize(input.norm_w); // do per-pixel light sourcing diffuse = compute_per_pixel_ambient_diffuse(N, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(N, input.pos_w.xyz); output.rgb += specular; // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { specular *= (0.4f / g_SpecularLevel); } } // decals at 2,3,4,5 float4 decal = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv2); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture4.Sample(g_TextureClampSampler, input.uv4); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture5.Sample(g_TextureClampSampler, input.uv5); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHREFLECTIONDECAL4BUMP.FX // Copyright (c) 2009 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color float g_BumpAmount; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_BumpNormalTexture; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; Texture2D g_MaterialTexture4; Texture2D g_MaterialTexture5; Texture2D g_MaterialTexture6; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; SamplerState g_BumpWrapSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_BumpClampSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float2 uv4 : TEXCOORD3; float2 uv5 : TEXCOORD4; float2 uv6 : TEXCOORD5; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float2 uv4 : TEXCOORD3; float2 uv5 : TEXCOORD4; float2 uv6 : TEXCOORD5; }; //-------------------------------------------------------------------------------------- float3x3 compute_tangent_frame(float3 N, float3 P, float2 uv) { // get edge vectors of the pixel triangle const float3 dp1 = ddx(P); const float3 dp2 = ddy(P); const float2 duv1 = ddx(uv); const float2 duv2 = ddy(uv); // solve the linear system const float2x3 M = float2x3(dp1, dp2); const float3 T = mul(float2(duv1.x, duv2.x), M); const float3 B = mul(float2(duv1.y, duv2.y), M); // construct tangent frame float3 bT = normalize( cross(N, T) ); const float3 nT = cross(bT, N); if (dot(bT, B) < 0) { bT *= -1.0f; } return float3x3( nT, bT, N); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3x3 TangentFrame, float3 Nt, float3 P) { const float3 light_t = mul(TangentFrame, -g_DirLight.dir); float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(Nt, light_t)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return saturate(diffuse); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3x3 TangentFrame, float3 Nt, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float3 Ht = mul(TangentFrame, H); const float h_dot_n = dot(Ht, Nt); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(Ht)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; // calculate spherical reflection coordidates const float3 N = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space const float3 Nv = mul(N, (float3x3)g_mWorldToView); // normal, view-space output.norm_w = N; output.uv0 = input.uv0; output.uv2.x = 0.5 * Nv.x + 0.5; output.uv2.y = -0.5 * Nv.y + 0.5; output.uv3 = input.uv3; output.uv4 = input.uv4; output.uv5 = input.uv5; output.uv6 = input.uv6; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 Np; if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); Np = g_BumpNormalTexture.Sample(g_BumpWrapSampler, input.uv0).xyz * 2.0 - 1.0; } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); Np = g_BumpNormalTexture.Sample(g_BumpClampSampler, input.uv0).xyz * 2.0 - 1.0; } if (output.a > 0.0) { const float4 reflec = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv2); output.rgb = lerp(output.rgb, reflec.rgb, reflec.a); float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); // do lightsourcing before decals so specular can only affect the base texture if (g_bLightEnabled) { // do per-pixel light sourcing const float3 N0 = normalize(input.norm_w); const float3x3 tangent_frame = compute_tangent_frame(N0, input.pos_w.xyz, input.uv0); float3 Nt = lerp(float3(0.0,0.0,1.0), Np, g_BumpAmount); Nt = normalize(Nt); diffuse = compute_per_pixel_ambient_diffuse(tangent_frame, Nt, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(tangent_frame, Nt, input.pos_w.xyz); output.rgb += specular; // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { specular *= (0.4f / g_SpecularLevel); } } // decals at 3,4,5,6 at max 40% specular float4 decal = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture4.Sample(g_TextureClampSampler, input.uv4); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture5.Sample(g_TextureClampSampler, input.uv5); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture6.Sample(g_TextureClampSampler, input.uv6); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHREFLECTIONDECAL4BUMPSPEC.FX // Copyright (c) 2010 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color float g_BumpAmount; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; Texture2D g_MaterialTexture4; Texture2D g_MaterialTexture5; Texture2D g_MaterialTexture6; Texture2D g_MaterialTexture7; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; SamplerState g_BumpWrapSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_BumpClampSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv3 : TEXCOORD1; float2 uv4 : TEXCOORD2; float2 uv5 : TEXCOORD3; float2 uv6 : TEXCOORD4; float2 uv7 : TEXCOORD5; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv3 : TEXCOORD1; float2 uv4 : TEXCOORD2; float2 uv5 : TEXCOORD3; float2 uv6 : TEXCOORD4; float2 uv7 : TEXCOORD5; }; //-------------------------------------------------------------------------------------- float3x3 compute_tangent_frame(float3 N, float3 P, float2 uv) { // get edge vectors of the pixel triangle const float3 dp1 = ddx(P); const float3 dp2 = ddy(P); const float2 duv1 = ddx(uv); const float2 duv2 = ddy(uv); // solve the linear system const float2x3 M = float2x3(dp1, dp2); const float3 T = mul(float2(duv1.x, duv2.x), M); const float3 B = mul(float2(duv1.y, duv2.y), M); // construct tangent frame float3 bT = normalize( cross(N, T) ); const float3 nT = cross(bT, N); if (dot(bT, B) < 0) { bT *= -1.0f; } return float3x3( nT, bT, N); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3x3 TangentFrame, float3 Nt, float3 P) { const float3 light_t = mul(TangentFrame, -g_DirLight.dir); float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(Nt, light_t)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return saturate(diffuse); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3x3 TangentFrame, float3 Nt, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float3 Ht = mul(TangentFrame, H); const float h_dot_n = dot(Ht, Nt); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(Ht)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; // calculate spherical reflection coordidates const float3 N = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space const float3 Nv = mul(N, (float3x3)g_mWorldToView); // normal, view-space output.norm_w = N; output.uv0 = input.uv0; output.uv3.x = 0.5 * Nv.x + 0.5; output.uv3.y = -0.5 * Nv.y + 0.5; output.uv4 = input.uv4; output.uv5 = input.uv5; output.uv6 = input.uv6; output.uv7 = input.uv7; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 Np; float3 sm; if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); Np = g_MaterialTexture1.Sample(g_BumpWrapSampler, input.uv0).xyz * 2.0 - 1.0; sm = g_MaterialTexture2.Sample(g_TextureWrapSampler, input.uv0).rgb; } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); Np = g_MaterialTexture1.Sample(g_BumpClampSampler, input.uv0).xyz * 2.0 - 1.0; sm = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv0).rgb; } if (output.a > 0.0) { // TK TODO add reflection component? use color b for now if (sm.b >= 0.5f) { float sr = clamp(0.0, 1.0, (sm.b - 0.5f) * 2.0f); // 0 at 0-0.5, 0-1 at 0.5 to 1 const float4 reflec = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); output.rgb = lerp(output.rgb, reflec.rgb, (reflec.a * sr)); } float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); // do lightsourcing before decals so specular can only affect the base texture if (g_bLightEnabled) { // do per-pixel light sourcing const float3 N0 = normalize(input.norm_w); const float3x3 tangent_frame = compute_tangent_frame(N0, input.pos_w.xyz, input.uv0); float3 Nt = lerp(float3(0.0,0.0,1.0), Np, g_BumpAmount); Nt = normalize(Nt); diffuse = compute_per_pixel_ambient_diffuse(tangent_frame, Nt, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(tangent_frame, Nt, input.pos_w.xyz); output.rgb += (specular * sm); // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { float3 max_decal_sm = min(g_SpecularLevel * sm, float3(0.4f,0.4f,0.4f)); specular *= (max_decal_sm / g_SpecularLevel); } } // decals at 4,5,6,7 at max 40% specular float4 decal = g_MaterialTexture4.Sample(g_TextureClampSampler, input.uv4); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture5.Sample(g_TextureClampSampler, input.uv5); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture6.Sample(g_TextureClampSampler, input.uv6); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture7.Sample(g_TextureClampSampler, input.uv7); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHREFLECTIONDECAL4SPEC.FX // Copyright (c) 2010 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; Texture2D g_MaterialTexture4; Texture2D g_MaterialTexture5; Texture2D g_MaterialTexture6; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float2 uv4 : TEXCOORD3; float2 uv5 : TEXCOORD4; float2 uv6 : TEXCOORD5; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float2 uv4 : TEXCOORD3; float2 uv5 : TEXCOORD4; float2 uv6 : TEXCOORD5; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3 N, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float h_dot_n = dot(H, N); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(H)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; // calculate spherical reflection coordidates const float3 N = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space const float3 Nv = mul(N, (float3x3)g_mWorldToView); // normal, view-space output.norm_w = N; output.uv0 = input.uv0; output.uv2.x = 0.5 * Nv.x + 0.5; output.uv2.y = -0.5 * Nv.y + 0.5; output.uv3 = input.uv3; output.uv4 = input.uv4; output.uv5 = input.uv5; output.uv6 = input.uv6; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 sm; if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); sm = g_MaterialTexture1.Sample(g_TextureWrapSampler, input.uv0).rgb; } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); sm = g_MaterialTexture1.Sample(g_TextureClampSampler, input.uv0).rgb; } if (output.a > 0.0) { // TK TODO add reflection component? use color b for now if (sm.b >= 0.5f) { float sr = clamp(0.0, 1.0, (sm.b - 0.5f) * 2.0f); // 0 at 0-0.5, 0-1 at 0.5 to 1 const float4 reflec = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv2); output.rgb = lerp(output.rgb, reflec.rgb, (reflec.a * sr)); } // do lightsourcing before decals so specular can only affect the base texture float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); if (g_bLightEnabled) { const float3 N = normalize(input.norm_w); // do per-pixel light sourcing diffuse = compute_per_pixel_ambient_diffuse(N, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(N, input.pos_w.xyz); output.rgb += (specular * sm); // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { float3 max_decal_sm = min(g_SpecularLevel * sm, float3(0.4f,0.4f,0.4f)); specular *= (max_decal_sm / g_SpecularLevel); } } // decals at 3,4,5,6 at max 40% specular float4 decal = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture4.Sample(g_TextureClampSampler, input.uv4); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture5.Sample(g_TextureClampSampler, input.uv5); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture6.Sample(g_TextureClampSampler, input.uv6); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHREFLECTIONDECAL5.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; Texture2D g_MaterialTexture4; Texture2D g_MaterialTexture5; Texture2D g_MaterialTexture6; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3 N, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float h_dot_n = dot(H, N); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(H)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; // calculate spherical reflection coordidates const float3 N = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space const float3 Nv = mul(N, (float3x3)g_mWorldToView); // normal, view-space output.norm_w = N; output.uv0 = input.uv0; output.uv1.x = 0.5 * Nv.x + 0.5; output.uv1.y = -0.5 * Nv.y + 0.5; output.uv2 = input.uv2; output.uv3 = input.uv3; output.uv4 = input.uv4; output.uv5 = input.uv5; output.uv6 = input.uv6; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); } if (output.a > 0.0) { const float4 reflec = g_MaterialTexture1.Sample(g_TextureClampSampler, input.uv1); output.rgb = lerp(output.rgb, reflec.rgb, reflec.a); // do lightsourcing before decals so specular can only affect the base texture float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); if (g_bLightEnabled) { const float3 N = normalize(input.norm_w); // do per-pixel light sourcing diffuse = compute_per_pixel_ambient_diffuse(N, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(N, input.pos_w.xyz); output.rgb += specular; // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { specular *= (0.4f / g_SpecularLevel); } } // decals at 2,3,4,5,6 at max 40% specular float4 decal = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv2); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture4.Sample(g_TextureClampSampler, input.uv4); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture5.Sample(g_TextureClampSampler, input.uv5); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture6.Sample(g_TextureClampSampler, input.uv6); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHREFLECTIONDECAL5BUMP.FX // Copyright (c) 2009 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color float g_BumpAmount; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_BumpNormalTexture; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; Texture2D g_MaterialTexture4; Texture2D g_MaterialTexture5; Texture2D g_MaterialTexture6; Texture2D g_MaterialTexture7; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; SamplerState g_BumpWrapSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_BumpClampSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float2 uv4 : TEXCOORD3; float2 uv5 : TEXCOORD4; float2 uv6 : TEXCOORD5; float2 uv7 : TEXCOORD6; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //xyz = world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float2 uv4 : TEXCOORD3; float2 uv5 : TEXCOORD4; float2 uv6 : TEXCOORD5; float2 uv7 : TEXCOORD6; }; //-------------------------------------------------------------------------------------- float3x3 compute_tangent_frame(float3 N, float3 P, float2 uv) { // get edge vectors of the pixel triangle const float3 dp1 = ddx(P); const float3 dp2 = ddy(P); const float2 duv1 = ddx(uv); const float2 duv2 = ddy(uv); // solve the linear system const float2x3 M = float2x3(dp1, dp2); const float3 T = mul(float2(duv1.x, duv2.x), M); const float3 B = mul(float2(duv1.y, duv2.y), M); // construct tangent frame float3 bT = normalize( cross(N, T) ); const float3 nT = cross(bT, N); if (dot(bT, B) < 0) { bT *= -1.0f; } return float3x3( nT, bT, N); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3x3 TangentFrame, float3 Nt, float3 P) { const float3 light_t = mul(TangentFrame, -g_DirLight.dir); float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(Nt, light_t)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return saturate(diffuse); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3x3 TangentFrame, float3 Nt, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float3 Ht = mul(TangentFrame, H); const float h_dot_n = dot(Ht, Nt); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(Ht)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; // calculate spherical reflection coordidates const float3 N = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space const float3 Nv = mul(N, (float3x3)g_mWorldToView); // normal, view-space output.norm_w = N; output.uv0 = input.uv0; output.uv2.x = 0.5 * Nv.x + 0.5; output.uv2.y = -0.5 * Nv.y + 0.5; output.uv3 = input.uv3; output.uv4 = input.uv4; output.uv5 = input.uv5; output.uv6 = input.uv6; output.uv7 = input.uv7; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 Np; if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); Np = g_BumpNormalTexture.Sample(g_BumpWrapSampler, input.uv0).xyz * 2.0 - 1.0; } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); Np = g_BumpNormalTexture.Sample(g_BumpClampSampler, input.uv0).xyz * 2.0 - 1.0; } if (output.a > 0.0) { const float4 reflec = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv2); output.rgb = lerp(output.rgb, reflec.rgb, reflec.a); float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); // do lightsourcing before decals so specular can only affect the base texture if (g_bLightEnabled) { // do per-pixel light sourcing const float3 N0 = normalize(input.norm_w); const float3x3 tangent_frame = compute_tangent_frame(N0, input.pos_w.xyz, input.uv0); float3 Nt = lerp(float3(0.0,0.0,1.0), Np, g_BumpAmount); Nt = normalize(Nt); diffuse = compute_per_pixel_ambient_diffuse(tangent_frame, Nt, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(tangent_frame, Nt, input.pos_w.xyz); output.rgb += specular; // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { specular *= (0.4f / g_SpecularLevel); } } // decals at 3,4,5,6,7 at max 40% specular float4 decal = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture4.Sample(g_TextureClampSampler, input.uv4); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture5.Sample(g_TextureClampSampler, input.uv5); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture6.Sample(g_TextureClampSampler, input.uv6); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture7.Sample(g_TextureClampSampler, input.uv7); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHREFLECTIONDECAL5SPEC.FX // Copyright (c) 2010 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; Texture2D g_MaterialTexture4; Texture2D g_MaterialTexture5; Texture2D g_MaterialTexture6; Texture2D g_MaterialTexture7; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float2 uv4 : TEXCOORD3; float2 uv5 : TEXCOORD4; float2 uv6 : TEXCOORD5; float2 uv7 : TEXCOORD6; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float2 uv3 : TEXCOORD2; float2 uv4 : TEXCOORD3; float2 uv5 : TEXCOORD4; float2 uv6 : TEXCOORD5; float2 uv7 : TEXCOORD6; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3 N, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float h_dot_n = dot(H, N); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(H)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; // calculate spherical reflection coordidates const float3 N = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space const float3 Nv = mul(N, (float3x3)g_mWorldToView); // normal, view-space output.norm_w = N; output.uv0 = input.uv0; output.uv2.x = 0.5 * Nv.x + 0.5; output.uv2.y = -0.5 * Nv.y + 0.5; output.uv3 = input.uv3; output.uv4 = input.uv4; output.uv5 = input.uv5; output.uv6 = input.uv6; output.uv7 = input.uv7; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 sm; if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); sm = g_MaterialTexture1.Sample(g_TextureWrapSampler, input.uv0).rgb; } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); sm = g_MaterialTexture1.Sample(g_TextureClampSampler, input.uv0).rgb; } if (output.a > 0.0) { // TK TODO add reflection component? use color b for now if (sm.b >= 0.5f) { float sr = clamp(0.0, 1.0, (sm.b - 0.5f) * 2.0f); // 0 at 0-0.5, 0-1 at 0.5 to 1 const float4 reflec = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv2); output.rgb = lerp(output.rgb, reflec.rgb, (reflec.a * sr)); } // do lightsourcing before decals so specular can only affect the base texture float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); if (g_bLightEnabled) { const float3 N = normalize(input.norm_w); // do per-pixel light sourcing diffuse = compute_per_pixel_ambient_diffuse(N, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(N, input.pos_w.xyz); output.rgb += (specular * sm); // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { float3 max_decal_sm = min(g_SpecularLevel * sm, float3(0.4f,0.4f,0.4f)); specular *= (max_decal_sm / g_SpecularLevel); } } // decals at 3,4,5,6,7 at max 40% specular float4 decal = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture4.Sample(g_TextureClampSampler, input.uv4); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture5.Sample(g_TextureClampSampler, input.uv5); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture6.Sample(g_TextureClampSampler, input.uv6); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture7.Sample(g_TextureClampSampler, input.uv7); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHREFLECTIONDECAL6.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularLevel; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; Texture2D g_MaterialTexture4; Texture2D g_MaterialTexture5; Texture2D g_MaterialTexture6; Texture2D g_MaterialTexture7; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3 N, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float h_dot_n = dot(H, N); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(H)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; // calculate spherical reflection coordidates const float3 N = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space const float3 Nv = mul(N, (float3x3)g_mWorldToView); // normal, view-space output.norm_w = N; output.uv0 = input.uv0; output.uv1.x = 0.5 * Nv.x + 0.5; output.uv1.y = -0.5 * Nv.y + 0.5; output.uv2 = input.uv2; output.uv3 = input.uv3; output.uv4 = input.uv4; output.uv5 = input.uv5; output.uv6 = input.uv6; output.uv7 = input.uv7; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); } if (output.a > 0.0) { const float4 reflec = g_MaterialTexture1.Sample(g_TextureClampSampler, input.uv1); output.rgb = lerp(output.rgb, reflec.rgb, reflec.a); // do lightsourcing before decals so specular can only affect the base texture float3 diffuse = float3(1.0f,1.0f,1.0f); float3 specular = float3(0.0f,0.0f,0.0f); if (g_bLightEnabled) { const float3 N = normalize(input.norm_w); // do per-pixel light sourcing diffuse = compute_per_pixel_ambient_diffuse(N, input.pos_w.xyz); output.rgb *= diffuse; specular = compute_per_pixel_specular(N, input.pos_w.xyz); output.rgb += specular; // set specular color for decals so max specular is 0.4 if (g_SpecularLevel > 0.4f) { specular *= (0.4f / g_SpecularLevel); } } // decals at 2,3,4,5,6 float4 decal = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv2); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture3.Sample(g_TextureClampSampler, input.uv3); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture4.Sample(g_TextureClampSampler, input.uv4); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture5.Sample(g_TextureClampSampler, input.uv5); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture6.Sample(g_TextureClampSampler, input.uv6); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } decal = g_MaterialTexture7.Sample(g_TextureClampSampler, input.uv7); if (decal.a > 0.0) { output.rgb = lerp(output.rgb, (diffuse * decal.rgb + specular), decal.a); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MESHREFLECTIONSPEC.FX // Copyright (c) 2010 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; int g_NumSpotLights; PointLight g_aPointLights[8]; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv2 : TEXCOORD1; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3 N, float3 P) { float3 specular = float3(0.0f, 0.0f, 0.0f); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float h_dot_n = dot(H, N); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(H)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; // calculate spherical reflection coordidates const float3 N = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space const float3 Nv = mul(N, (float3x3)g_mWorldToView); // normal, view-space output.norm_w = N; output.uv0 = input.uv0; output.uv2.x = 0.5 * Nv.x + 0.5; output.uv2.y = -0.5 * Nv.y + 0.5; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position, view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 sm; if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); sm = g_MaterialTexture1.Sample(g_TextureWrapSampler, input.uv0).rgb; } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); sm = g_MaterialTexture1.Sample(g_TextureClampSampler, input.uv0).rgb; } if (output.a > 0) { // TK TODO add reflection component? use color b for now if (sm.b >= 0.5f) { float sr = clamp(0.0, 1.0, (sm.b - 0.5f) * 2.0f); // 0 at 0-0.5, 0-1 at 0.5 to 1 const float4 reflec = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv2); output.rgb = lerp(output.rgb, reflec.rgb, (reflec.a * sr)); } if (g_bLightEnabled) { const float3 N = normalize(input.norm_w); // do per-pixel light sourcing output.rgb *= compute_per_pixel_ambient_diffuse(N, input.pos_w.xyz); output.rgb += (compute_per_pixel_specular(N, input.pos_w.xyz) * sm); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: MODELCANOPY.FX // Copyright (c) 2010 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color int g_ReflectionStage; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; int g_NumSpotLights; PointLight g_aPointLights[8]; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- float4 compute_per_pixel_specular_glass(float3 N, float3 P) { float4 specular = float4(0.0f, 0.0f, 0.0f, 0.0f); const float3 Pn = -normalize(P); if (g_SpecularPower > 0.0) { const float3 H = Pn - g_DirLight.dir; const float h_dot_n = dot(H, N); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(H)); const float sp = pow(unit_h_dot_n, g_SpecularPower); specular.rgb = (sp * g_SpecularColor); if (g_ReflectionStage == 1) { // adjust alpha so its more opaque with high specular specular.a = max(0.0, 0.6 * (sp - 0.2) ); } } } if (g_ReflectionStage == 1) { // adjust alpha so its more opaque when viewed perpendicular const float p_dot_n = dot(Pn, N); specular.a += max(0.0, ((1.0 - p_dot_n) - 0.5) ); } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; // calculate spherical reflection coordidates const float3 N = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space const float3 Nv = mul(N, (float3x3)g_mWorldToView); // normal, view-space output.norm_w = N; output.uv0 = input.uv0; output.uv1.x = 0.5 * Nv.x + 0.5; output.uv1.y = -0.5 * Nv.y + 0.5; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv0); if (g_ReflectionStage == 1) { const float4 reflec = g_MaterialTexture1.Sample(g_TextureClampSampler, input.uv1); output.rgb = lerp(output.rgb, reflec.rgb, reflec.a); } const float3 N = normalize(input.norm_w); // do per-pixel light sourcing output.rgb *= compute_per_pixel_ambient_diffuse(N, input.pos_w.xyz); output += compute_per_pixel_specular_glass(N, input.pos_w.xyz); output.a = clamp(0.0, 1.0, output.a); if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: SHADER.FX // Copyright (c) 2010 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- /*------------------------------------------------------------------------------ FXAA SHADER ------------------------------------------------------------------------------*/ uniform extern texture gScreenTexture; uniform extern texture gLumaTexture; //Include SweetFX settings #include "SweetFX_preset.txt" float fxaaQualitySubpix = fxaa_Subpix; float fxaaQualityEdgeThreshold = fxaa_EdgeThreshold; float fxaaQualityEdgeThresholdMin = fxaa_EdgeThresholdMin; // Defines the API to use it with #define FXAA_HLSL_3 1 // Include the FXAA shader #if (USE_FXAA_ANTIALIASING == 1) #include "SweetFX\Shaders\Fxaa3_11.h" #endif // Define samplers #define s0 lumaSampler //NearestScreenSampler #define s1 LinearScreenSampler //LinearScreenSampler //#define width BUFFER_WIDTH //#define height BUFFER_HEIGHT //#define px BUFFER_RCP_WIDTH //#define py BUFFER_RCP_HEIGHT //Definitions: BUFFER_WIDTH, BUFFER_HEIGHT, BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT sampler NearestScreenSampler = sampler_state { Texture = ; MinFilter = NONE; MagFilter = NONE; MipFilter = NONE; AddressU = CLAMP; //MIRROR affects the edges more AddressV = CLAMP; //MIRROR affects the edges more SRGBTexture = FALSE; }; sampler LinearScreenSampler = sampler_state { Texture = ; MinFilter = LINEAR; MagFilter = LINEAR; MipFilter = NONE; AddressU = CLAMP; //MIRROR affects the edges more AddressV = CLAMP; //MIRROR affects the edges more SRGBTexture = FALSE; }; sampler screenSampler = sampler_state { Texture = ; MinFilter = LINEAR; MagFilter = LINEAR; MipFilter = LINEAR; AddressU = BORDER; AddressV = BORDER; SRGBTexture = FALSE; }; sampler lumaSampler = sampler_state { Texture = ; MinFilter = LINEAR; MagFilter = LINEAR; MipFilter = LINEAR; AddressU = BORDER; AddressV = BORDER; SRGBTexture = FALSE; }; //Include the main SweetFX control shader #include "SweetFX/Shaders/Main.h" // FXAA Shader Function float4 LumaShader( float2 Tex : TEXCOORD0 ) : COLOR0 { #if(USE_FXAA_ANTIALIASING == 1) //TODO this should probably be moved up so the entire function won't run if AA is not enabled. Get it working first before trying this though. float4 c0 = FxaaPixelShader( // pos, Output color texture Tex, // tex, Input color texture screenSampler, // fxaaQualityRcpFrame, gets coordinates for screen width and height, xy float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT), //fxaaConsoleRcpFrameOpt2, gets coordinates for screen width and height, xyzw float4(-2.0*BUFFER_RCP_WIDTH,-2.0*BUFFER_RCP_HEIGHT,2.0*BUFFER_RCP_WIDTH,2.0*BUFFER_RCP_HEIGHT), // Choose the amount of sub-pixel aliasing removal fxaaQualitySubpix, // The minimum amount of local contrast required to apply algorithm fxaaQualityEdgeThreshold, // Trims the algorithm from processing darks fxaaQualityEdgeThresholdMin ); #else float4 c0 = tex2D(screenSampler,Tex); #endif return c0; } float4 MyShader( float2 Tex : TEXCOORD0 ) : COLOR0 { float4 c0 = tex2D(lumaSampler,Tex); c0 = main(Tex,c0); // Add the other effects c0.w = 1.0; return saturate(c0); } technique PostProcess1 { pass p1 { PixelShader = compile ps_3_0 LumaShader(); } } technique PostProcess2 { pass p1 { PixelShader = compile ps_3_0 MyShader(); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: SHADOWVOLUMEDX9.FX // Copyright (c) 2007 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- int GlobalParameter : SasGlobal < int3 SasVersion = {1, 0, 0}; string SasEffectDescription = "Shadow Masking"; string SasEffectCompany = "Third Wire Productions, Inc."; >; //-------------------------------------------------------------------------------------- // Variables //-------------------------------------------------------------------------------------- const float4x4 gWorld ; const float4x4 gViewProj ; const int gShadowVert : SHADOW_VERT = { 100 }; const float3 gShadowLength : SHADOW_LENGTH = { 0.447050746,-0.447050746,0.774784655 }; //-------------------------------------------------------------------------------------- // VertexShader I/O //-------------------------------------------------------------------------------------- struct VS_INPUT { float4 Pos : POSITION; }; struct VS_OUTPUT { float4 Pos : POSITION; }; //-------------------------------------------------------------------------------------- // create shadow volume //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; float4 P = mul(float4(input.Pos.xyz, 1.0), gWorld); // position, world-space float f = (float)(input.Pos.w >= (float)gShadowVert); P += float4(f * gShadowLength, 0.0); output.Pos = mul(P, gViewProj); return output; } //-------------------------------------------------------------------------------------- // Techniques //-------------------------------------------------------------------------------------- technique TerrainScatter { pass P0 { VertexShader = compile vs_2_0 VS(); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: TERALPHAOBJECT.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { float3 g_FadeDistance; }; cbuffer cbPerMesh { float3 g_MeshOffsetPos; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture; SamplerState g_LinearSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float4 pos_w : COLOR; //xyz = world space pos, w = fogdist float2 uv : TEXCOORD; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR; //xyz = world space pos, w = fogdist float2 uv : TEXCOORD; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, -g_DirLight.dir.z); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp /= lenL; diffuse += (g_aPointLights[i].color * cp); } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= inv_lenL; diffuse += (g_aSpotLights[j].color * cp); } } } return diffuse; } //-------------------------------------------------------------------------------------- float4 add_fog_fade_alpha(float4 Color, float FogDist, float FogZ) { float4 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, float4(g_FogColor, 0.0f), fog); return (output); } //-------------------------------------------------------------------------------------- float fade_with_distance(float FadeDist) { float fade_alpha = 1.0; const float fd = FadeDist - g_FadeDistance.x; if (fd > 0.0) { fade_alpha = clamp(0.0, 1.0, 1.0 - (fd * g_FadeDistance.z)); } return (fade_alpha); } //-------------------------------------------------------------------------------------- float precision_add_z( const float z1, const float z2, const float z3, const float z4 ) { float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // try to recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from prev add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = z4 - z_err; // include the lost low part from prev add... return (z_sum + z_add); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; pos.z = precision_add_z(P.x * g_mViewProj[0][2], P.y * g_mViewProj[1][2], P.z * g_mViewProj[2][2], g_mViewProj[3][2]); pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = float4((input.pos + g_MeshOffsetPos), 1.0); // position, world-space const float4 Pv = mul(P, g_mWorldToView); // position in view-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; output.pos_w.w = Pv.z; output.uv = input.uv; return output; } //-------------------------------------------------------------------------------------- // PixelShader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output = float4(0.0, 0.0, 0.0, 0.0); if (input.pos_w.w < g_FogDistance.y) { const float fade_alpha = fade_with_distance(input.pos_w.w); if (fade_alpha > 0.0) { output = g_MaterialTexture.Sample(g_LinearSampler, input.uv); if (output.a > 0.0) { output.rgb *= compute_per_pixel_ambient_diffuse(input.pos_w.xyz); output = add_fog_fade_alpha(output, input.pos_w.w, input.pos_w.z); output.a *= fade_alpha; } output = saturate(output); } } return output; } //-------------------------------------------------------------------------------------- // Techniques //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: TERFARTERRAINEFFECT.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMesh { float3 g_MeshOffsetPos; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture; SamplerState g_LinearSampler { Filter = MIN_MAG_MIP_LINEAR; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float3 diffuse : COLOR0; float4 pos_w : COLOR1; //xyz = world space pos, w = fogdist float3 norm_w : COLOR2; //world space normal float2 uv : TEXCOORD; float4 pos : SV_POSITION; }; struct PS_INPUT { float3 diffuse : COLOR0; float4 pos_w : COLOR1; //xyz = world space pos, w = fogdist float3 norm_w : COLOR2; //world space normal float2 uv : TEXCOORD; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_light_source(float3 AmbientDiffuse, float3 N, float3 P) { float3 diffuse = AmbientDiffuse; // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return diffuse; } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float precision_add_z( const float z1, const float z2, const float z3, const float z4 ) { float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // try to recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from prev add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = z4 - z_err; // include the lost low part from prev add... return (z_sum + z_add); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; pos.z = precision_add_z(P.x * g_mViewProj[0][2], P.y * g_mViewProj[1][2], P.z * g_mViewProj[2][2], g_mViewProj[3][2]); pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = float4((input.pos + g_MeshOffsetPos), 1.0); // position, world-space const float4 Pv = mul(P, g_mWorldToView); // position in view-space const float3 L = -g_DirLight.dir; const float3 N = input.norm; // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, L)); output.pos_w.xyz = P.xyz; output.pos_w.w = Pv.z; output.norm_w = N; output.uv = input.uv; return output; } //-------------------------------------------------------------------------------------- // PixelShader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float3 output; if (input.pos_w.w < g_FogDistance.y) { output = g_MaterialTexture.Sample(g_LinearSampler, input.uv).rgb; output *= compute_per_pixel_light_source(input.diffuse.rgb, input.norm_w, input.pos_w.xyz); output = add_fog(output, input.pos_w.w, input.pos_w.z); } else { output = g_FogColor; } return (float4(saturate(output), 1.0)); } //-------------------------------------------------------------------------------------- // Techniques //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: TERFARTERRAINEFFECTDX9.FX // Copyright (c) 2006 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- int GlobalParameter : SasGlobal < int3 SasVersion = {1, 1, 0}; string SasEffectDescription = "Far Terrain Shader"; string SasEffectCompany = "Third Wire Productions, Inc."; >; //-------------------------------------------------------------------------------------- // Variables //-------------------------------------------------------------------------------------- struct SasPointLight { float3 Color; float3 Position; float Range; }; const float4x4 World ; const float4x4 View ; const float4x4 ViewProj ; // light directions in world space const float3 AmbientLight = { 0.0, 0.0, 0.6 }; const float3 LightColor = { 0.8, 0.8, 0.0 }; const float3 LightDir = {0.447050746,-0.447050746,0.774784655}; const int NumPointLights = 0; const SasPointLight PointLight ; const float2 FogDistance : FOG_DISTANCE; texture MaterialTexture; //-------------------------------------------------------------------------------------- // Texture samplers //-------------------------------------------------------------------------------------- sampler TextureSampler = sampler_state { Texture = ; AddressU = CLAMP; AddressV = CLAMP; MipFilter = LINEAR; MinFilter = LINEAR; MagFilter = LINEAR; }; //-------------------------------------------------------------------------------------- // VertexShader I/O //-------------------------------------------------------------------------------------- struct VS_INPUT { float3 Pos : POSITION; float3 Norm : NORMAL; float2 Tex : TEXCOORD0; }; struct VS_OUTPUT { float4 Pos : POSITION; float3 Diffuse : COLOR0; float2 Tex : TEXCOORD0; float3 Norm : TEXCOORD1; float3 PosWorld : TEXCOORD2; float Fog : FOG; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_light_source(float3 AmbientDiffuse, float3 N, float3 P) { float3 diffuse = AmbientDiffuse; const float3 L = PointLight.Position - P; const float L2 = dot(L, L); if (L2 < (PointLight.Range*PointLight.Range)) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float3 Ln = L / (PointLight.Range+0.0001); const float cp = n_dot_l / (sqrt(L2) * (1.0 + 6.0 * dot(Ln, Ln))); diffuse += (PointLight.Color * cp); } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- // This shader computes standard transform and lighting //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.Pos, 1.0), World); // position, world-space const float4 Pv = mul(P, View); // position in view-space, for fog computation const float3 N = mul(input.Norm, (float3x3)World); output.Pos = mul(P, ViewProj); output.Tex = input.Tex; output.Diffuse = AmbientLight + (LightColor * dot(N, -LightDir)); output.Norm = N; output.PosWorld = P.xyz; if (Pv.z < FogDistance.y) { const float fv = 1.0 / (FogDistance.y - FogDistance.x); output.Fog = clamp(0.0, 1.0, (1.0 - (Pv.z - FogDistance.x) * fv)); } else { output.Fog = 0.0; } return output; } //-------------------------------------------------------------------------------------- // PixelShader //-------------------------------------------------------------------------------------- float4 PS( VS_OUTPUT input ) : COLOR { float3 diff = input.Diffuse; float3 sample0 = tex2D(TextureSampler, input.Tex).xyz; if (NumPointLights > 0) { diff = compute_per_pixel_light_source(diff, input.Norm, input.PosWorld); } diff *= sample0.rgb; return (float4(diff, 1.0) ); } //-------------------------------------------------------------------------------------- // Techniques //-------------------------------------------------------------------------------------- technique TerrainBump { pass P0 { SRCBLEND = ONE; DESTBLEND = ZERO; VertexShader = compile vs_2_0 VS(); PixelShader = compile ps_2_0 PS(); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: TERSOLIDOBJECT.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; }; cbuffer cbPerMaterial { float3 g_FadeDistance; }; cbuffer cbPerMesh { float3 g_MeshOffsetPos; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float3 diffuse : COLOR0; float4 pos_w : COLOR1; //xyz = world space pos, w = fogdist float3 norm_w : COLOR2; //world space normal float2 uv : TEXCOORD; float4 pos : SV_POSITION; }; struct PS_INPUT { float3 diffuse : COLOR0; float4 pos_w : COLOR1; //xyz = world space pos, w = fogdist float3 norm_w : COLOR2; //world space normal float2 uv : TEXCOORD; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return diffuse; } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float fade_with_distance(float FadeDist) { float fade_alpha = 1.0; const float fd = FadeDist - g_FadeDistance.x; if (fd > 0.0) { fade_alpha = clamp(0.0, 1.0, 1.0 - (fd * g_FadeDistance.z)); } return (fade_alpha); } //-------------------------------------------------------------------------------------- float precision_add_z( const float z1, const float z2, const float z3, const float z4 ) { float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // try to recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from prev add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = z4 - z_err; // include the lost low part from prev add... return (z_sum + z_add); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; pos.z = precision_add_z(P.x * g_mViewProj[0][2], P.y * g_mViewProj[1][2], P.z * g_mViewProj[2][2], g_mViewProj[3][2]); pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = float4((input.pos + g_MeshOffsetPos), 1.0); // position, world-space const float4 Pv = mul(P, g_mWorldToView); // position in view-space const float3 L = -g_DirLight.dir; const float3 N = input.norm; // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, L)); output.pos_w.xyz = P.xyz; output.pos_w.w = Pv.z; output.norm_w = N; output.uv = input.uv; return output; } //-------------------------------------------------------------------------------------- // PixelShader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output = float4(0.0, 0.0, 0.0, 0.0); if (input.pos_w.w < g_FogDistance.y) { const float fade_alpha = fade_with_distance(input.pos_w.w); if (fade_alpha > 0.0) { output.rgb = g_MaterialTexture.Sample(g_TextureClampSampler, input.uv).rgb; output.rgb *= compute_per_pixel_ambient_diffuse(input.norm_w, input.pos_w.xyz); output.rgb = add_fog(output, input.pos_w.w, input.pos_w.z); output.a = fade_alpha; output = saturate(output); } } return (output); } //-------------------------------------------------------------------------------------- // Techniques //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: TERTERRAINEFFECT.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbConstant { static const float EndFadeDist1 = 2500.0; static const float EndFadeDist2 = 8000.0; static const float NoiseScale = 0.003; static const float StartFadeDist = 800.0; } cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; float3 g_CameraPos; }; cbuffer cbPerMesh { float3 g_MeshOffsetPos; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; cbuffer cbPerMaterial { float g_BumpAmount; }; Texture2D g_MaterialTexture; Texture2D g_BumpTexture ; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; SamplerState g_BumpSampler { Filter = MIN_MAG_MIP_LINEAR; AddressU = Wrap; AddressV = Wrap; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float4 norm_w : COLOR1; //xyz = world space normal, w = bump amount float4 uv : TEXCOORD; //xy = uv0, zw = uv1 float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float4 norm_w : COLOR1; //xyz = world space normal, w = bump amount float4 uv : TEXCOORD; //xy = uv0, zw = uv1 }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3x3 TangentFrame, float3 Nt, float3 P) { const float3 light_t = mul(TangentFrame, -g_DirLight.dir); float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(Nt, light_t)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return diffuse; } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return diffuse; } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float precision_add_z( const float z1, const float z2, const float z3, const float z4 ) { float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from prev add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = z4 - z_err; // include the lost low part from prev add... return (z_sum + z_add); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; pos.z = precision_add_z(P.x * g_mViewProj[0][2], P.y * g_mViewProj[1][2], P.z * g_mViewProj[2][2], g_mViewProj[3][2]); pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = float4((input.pos + g_MeshOffsetPos), 1.0); // position, world-space const float4 Pv = mul(P, g_mWorldToView); // position in view-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; output.pos_w.w = Pv.z; output.norm_w.xyz = input.norm; output.uv.xy = input.uv; if ((g_BumpAmount > 0.0) && (Pv.z < EndFadeDist2)) { output.uv.zw = NoiseScale*P.xy + NoiseScale*g_CameraPos.xy; const float3 I = -normalize(P.xyz); const float fade_end = lerp(EndFadeDist1, EndFadeDist2, max(0.0, I.z)); output.norm_w.w = clamp(0.0, 1.0, g_BumpAmount * (1.0 - ((Pv.z - StartFadeDist) / (fade_end - StartFadeDist)))); } else { output.uv.zw = float2(0.0,0.0); output.norm_w.w = 0; } return output; } //-------------------------------------------------------------------------------------- // PixelShader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float3 output; const float3 N0 = float3(0,0,1); if (input.pos_w.w < g_FogDistance.y) { output = g_MaterialTexture.Sample(g_TextureClampSampler, input.uv.xy).rgb; const float3 N = normalize(input.norm_w.xyz); if (input.norm_w.w > 0.0) { float3 Nt = g_BumpTexture.Sample(g_BumpSampler, frac(input.uv.zw)).xyz * 2.0 - 1.0; Nt = lerp(N0, Nt, input.norm_w.w); Nt = normalize(Nt); // do per-pixel light sourcing const float3 nT = normalize(float3(N.z, 0.0, -N.x)); const float3x3 tangent_frame = float3x3(nT, cross(N, nT), N); output *= compute_per_pixel_ambient_diffuse(tangent_frame, Nt, input.pos_w.xyz); } else { output *= compute_per_pixel_ambient_diffuse(N, input.pos_w.xyz); } // do per-pixel linear fog output = add_fog(output, input.pos_w.w, input.pos_w.z); } else { output = g_FogColor; } return (float4(saturate(output), 1.0)); } //-------------------------------------------------------------------------------------- // Techniques //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: TERTERRAINEFFECTDX9.FX // Copyright (c) 2006 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- int GlobalParameter : SasGlobal < int3 SasVersion = {1, 1, 0}; string SasEffectDescription = "Terrain Shader"; string SasEffectCompany = "Third Wire Productions, Inc."; >; //-------------------------------------------------------------------------------------- // Variables //-------------------------------------------------------------------------------------- struct SasPointLight { float3 Color; float3 Position; float Range; }; const float4x4 World ; const float4x4 View ; const float4x4 ViewProj ; // light directions in world space const float3 AmbientLight = { 0.0, 0.0, 0.6 }; const float3 LightColor = { 0.8, 0.8, 0.0 }; const float3 LightDir = {0.447050746,-0.447050746,0.774784655}; const int NumPointLights = 0; const SasPointLight PointLight ; const float3 CameraPos : CAMERA_GLOBAL_POSITION; const float2 FogDistance : FOG_DISTANCE; const float BumpAmount : BUMP_AMOUNT; const float StartFadeDist = 800.0; const float EndFadeDist1 = 2500.0; const float EndFadeDist2 = 8000.0; const float NoiseScale = 0.003; texture MaterialTexture; texture BumpTexture ; //-------------------------------------------------------------------------------------- // Texture samplers //-------------------------------------------------------------------------------------- sampler TextureSampler = sampler_state { Texture = ; AddressU = CLAMP; AddressV = CLAMP; MipFilter = LINEAR; MinFilter = LINEAR; MagFilter = LINEAR; }; sampler BumpSampler = sampler_state { Texture = ; AddressU = WRAP; AddressV = WRAP; MipFilter = LINEAR; MinFilter = LINEAR; MagFilter = LINEAR; }; //-------------------------------------------------------------------------------------- // VertexShader I/O //-------------------------------------------------------------------------------------- struct VS_INPUT { float3 Pos : POSITION; float3 Norm : NORMAL; float2 Tex : TEXCOORD0; }; struct VS_OUTPUT { float4 Pos : POSITION; float4 Tex0 : TEXCOORD0; //xy = uv0, wz = uv1 float3 LightDir : TEXCOORD1; float3 LightPt : TEXCOORD2; float4 PosWorld : TEXCOORD3; // xyz = pos, w = bump amount float Fog : FOG; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_light_source(float3 AmbientDiffuse, float3 Nt, float3 Lt, float3 P) { // Lt in tangent space,already noramlized float3 diffuse = AmbientDiffuse; const float3 L = PointLight.Position - P; const float L2 = dot(L, L); if (L2 < (PointLight.Range*PointLight.Range)) { const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0) { const float3 Ln = L / (PointLight.Range+0.0001); const float cp = n_dot_l / (1.0 + 6.0 * dot(Ln, Ln)); diffuse += (PointLight.Color * cp); } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- // This shader computes standard transform and lighting //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.Pos, 1.0), World); // position, world-space const float4 Pv = mul(P, View); // position in view-space, for fade computation const float3 N = mul(input.Norm, (float3x3)World); output.Pos = mul(P, ViewProj); output.Tex0.xy = input.Tex; // save out LightDir in terrain tangent-space float3x3 TangentFrame; TangentFrame[0] = normalize(float3(N.z, 0.0, -N.y)); TangentFrame[1] = cross(N, TangentFrame[0]); TangentFrame[2] = N; output.LightDir = mul(TangentFrame, -LightDir); if (NumPointLights > 0) { output.LightPt = mul(TangentFrame, normalize(PointLight.Position - P.xyz)); } else { output.LightPt = float3(0,0,0); } output.PosWorld.xyz = P.xyz; if ((BumpAmount > 0) && (Pv.z < EndFadeDist2)) { output.Tex0.z = NoiseScale*P.x + NoiseScale*CameraPos.x; output.Tex0.w = NoiseScale*P.y + NoiseScale*CameraPos.y; const float3 I = -normalize(P.xyz); const float FadeEnd = lerp(EndFadeDist1, EndFadeDist2, max(0.0, I.z)); const float bv = 1.0 / (FadeEnd - StartFadeDist); output.PosWorld.w = clamp(0.0, 1.0, BumpAmount * (1.0 - (Pv.z - StartFadeDist) * bv)); } else { output.Tex0.zw = float2(0,0); output.PosWorld.w = 0.0; } if (Pv.z < FogDistance.y) { const float fv = 1.0 / (FogDistance.y - FogDistance.x); output.Fog = clamp(0.0, 1.0, (1.0 - (Pv.z - FogDistance.x) * fv)); } else { output.Fog = 0.0; } return output; } //-------------------------------------------------------------------------------------- // PixelShader //-------------------------------------------------------------------------------------- float4 PS( VS_OUTPUT input ) : COLOR { float3 diff = AmbientLight; float3 sample0 = tex2D(TextureSampler, input.Tex0.xy).xyz; float3 Nt = float3(0,0,1); if (input.PosWorld.w > 0) { const float3 N1 = tex2D(BumpSampler, frac(input.Tex0.zw)) * 2.0 - 1.0; Nt = lerp(Nt, N1, input.PosWorld.w); //Nt = normalize(Nt); diff += (LightColor * dot(Nt, input.LightDir)); } else { diff += (LightColor * input.LightDir.z); } if (NumPointLights > 0) { diff = compute_per_pixel_light_source(diff, Nt, input.LightPt, input.PosWorld.xyz); } sample0 *= diff; return (float4(saturate(sample0), 1.0)); } //-------------------------------------------------------------------------------------- // Techniques //-------------------------------------------------------------------------------------- technique TerrainBump { pass P0 { SRCBLEND = ONE; DESTBLEND = ZERO; VertexShader = compile vs_2_0 VS(); PixelShader = compile ps_2_0 PS(); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: TERWATEREFFECT0.FX // Copyright (c) 2009 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbConstant { static const float EndFadeDist1 = 2500.0; static const float EndFadeDist2 = 8000.0; static const float NoiseScale = 0.003; static const float StartFadeDist = 800.0; }; cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; float3 g_CameraPos; }; cbuffer cbPerMaterial { float g_BumpAmount; }; cbuffer cbPerMesh { float3 g_MeshOffsetPos; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture; Texture2D g_BumpTexture ; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; SamplerState g_BumpSampler { Filter = MIN_MAG_MIP_LINEAR; AddressU = Wrap; AddressV = Wrap; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float4 norm_w : COLOR1; //xyz = world space normal, w = bump amount float4 uv : TEXCOORD0; //xy = uv0, zw = uv1 float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float4 norm_w : COLOR1; //xyz = world space normal, w = bump amount float4 uv : TEXCOORD0; //xy = uv0, zw = uv1 }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3x3 TangentFrame, float3 Nt, float3 P) { const float3 light_t = mul(TangentFrame, -g_DirLight.dir); float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(Nt, light_t)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return diffuse; } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return diffuse; } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 P) { // N = 0,0,1 float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, -g_DirLight.dir.z); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; //const float n_dot_l = L.z; if (L.z > 0) { const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (L.z / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; //const float n_dot_l = L.z; if (L.z > 0) { const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (L.z * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return diffuse; } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float precision_add_z( const float z1, const float z2, const float z3, const float z4 ) { float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // try to recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from prev add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = z4 - z_err; // include the lost low part from prev add... return (z_sum + z_add); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; pos.z = precision_add_z(P.x * g_mViewProj[0][2], P.y * g_mViewProj[1][2], P.z * g_mViewProj[2][2], g_mViewProj[3][2]); pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = float4((input.pos + g_MeshOffsetPos), 1.0); // position, world-space const float4 Pv = mul(P, g_mWorldToView); // position in view-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; output.pos_w.w = Pv.z; output.norm_w.xyz = input.norm; output.uv.xy = input.uv; if ((g_BumpAmount > 0.0) && (Pv.z < EndFadeDist2)) { output.uv.zw = NoiseScale*P.xy + NoiseScale*g_CameraPos.xy; const float3 I = -normalize(P.xyz); const float fade_end = lerp(EndFadeDist1, EndFadeDist2, max(0.0, I.z)); output.norm_w.w = clamp(0.0, 1.0, g_BumpAmount * (1.0 - ((Pv.z - StartFadeDist) / (fade_end - StartFadeDist)))); } else { output.uv.zw = float2(0.0,0.0); output.norm_w.w = 0; } return output; } //-------------------------------------------------------------------------------------- // PixelShader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; const float3 N0 = float3(0,0,1); if (input.pos_w.w < g_FogDistance.y) { output = g_MaterialTexture.Sample(g_TextureClampSampler, input.uv.xy); float3 water_diff = output.rgb; float3 land_diff = output.rgb; if (output.a > 0.0) { // water if (input.norm_w.w > 0.0) { const float2 uv0 = frac(0.7f * input.uv.zw); float3 N1 = g_BumpTexture.Sample(g_BumpSampler, float2(uv0.y, uv0.x)).xyz * 2.0 - 1.0; const float noise_amount = input.norm_w.w * 0.4f; // add some noise so it doesn't look completely flat N1 = lerp(N0, N1, noise_amount); N1 = normalize(N1); water_diff *= compute_per_pixel_ambient_diffuse(N1, input.pos_w.xyz); } else { water_diff *= compute_per_pixel_ambient_diffuse(input.pos_w.xyz); } } if (output.a < 1.0) { // non-water const float3 N = normalize(input.norm_w.xyz); if (input.norm_w.w > 0.0) { float3 Nt = g_BumpTexture.Sample(g_BumpSampler, frac(input.uv.zw)).xyz * 2.0 - 1.0; Nt = lerp(N0, Nt, input.norm_w.w); Nt = normalize(Nt); // do per-pixel light sourcing const float3 nT = normalize(float3(N.z, 0.0, -N.y)); const float3x3 tangent_frame = float3x3(nT, cross(N, nT), N); land_diff *= compute_per_pixel_ambient_diffuse(tangent_frame, Nt, input.pos_w.xyz); } else { land_diff *= compute_per_pixel_ambient_diffuse(N, input.pos_w.xyz); } } land_diff = lerp(land_diff, water_diff, output.a); output.rgb = add_fog(land_diff, input.pos_w.w, input.pos_w.z); } else { output.rgb = g_FogColor; } return (float4(saturate(output.rgb), 1.0)); } //-------------------------------------------------------------------------------------- // Techniques //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: TERWATEREFFECT0DX9.FX // Copyright (c) 2009 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- int GlobalParameter : SasGlobal < int3 SasVersion = {1, 1, 0}; string SasEffectDescription = "Water Shader 0"; string SasEffectCompany = "Third Wire Productions, Inc."; >; //-------------------------------------------------------------------------------------- // Variables //-------------------------------------------------------------------------------------- struct SasPointLight { float3 Color; float3 Position; float Range; }; const float4x4 World ; const float4x4 View ; const float4x4 ViewProj ; // light directions in world space const float3 AmbientLight = { 0.0, 0.0, 0.6 }; const float3 LightColor = { 0.8, 0.8, 0.0 }; const float3 LightDir = {0.447050746,-0.447050746,0.774784655}; const int NumPointLights = 0; const SasPointLight PointLight ; const float3 CameraPos : CAMERA_GLOBAL_POSITION; const float2 FogDistance : FOG_DISTANCE; const float BumpAmount : BUMP_AMOUNT; const float StartFadeDist = 800.0; const float EndFadeDist1 = 2500.0; const float EndFadeDist2 = 8000.0; const float NoiseScale = 0.003; texture MaterialTexture; texture BumpTexture ; //-------------------------------------------------------------------------------------- // Texture samplers //-------------------------------------------------------------------------------------- sampler TextureSampler = sampler_state { Texture = ; AddressU = CLAMP; AddressV = CLAMP; MipFilter = LINEAR; MinFilter = LINEAR; MagFilter = LINEAR; }; sampler BumpSampler = sampler_state { Texture = ; AddressU = WRAP; AddressV = WRAP; MipFilter = LINEAR; MinFilter = LINEAR; MagFilter = LINEAR; }; //-------------------------------------------------------------------------------------- // VertexShader I/O //-------------------------------------------------------------------------------------- struct VS_INPUT { float3 Pos : POSITION; float3 Norm : NORMAL; float2 Tex : TEXCOORD0; }; struct VS_OUTPUT { float4 Pos : POSITION; float4 Tex0 : TEXCOORD0; //xy = uv0, wz = uv1 float3 LightDir : TEXCOORD1; float3 LightPt : TEXCOORD2; float4 PosWorld : TEXCOORD3; // xyz = pos, w = bump amount float Fog : FOG; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_light_source(float3 AmbientDiffuse, float3 N, float3 P) { float3 diffuse = AmbientDiffuse; const float3 L = PointLight.Position - P; const float L2 = dot(L, L); if (L2 < (PointLight.Range*PointLight.Range)) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float3 Ln = L / (PointLight.Range+0.0001); const float cp = n_dot_l / (sqrt(L2) * (1.0 + 6.0 * dot(Ln, Ln))); diffuse += (PointLight.Color * cp); } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_light_source(float3 AmbientDiffuse, float3 Nt, float3 Lt, float3 P) { // Lt in tangent space,already noramlized float3 diffuse = AmbientDiffuse; const float3 L = PointLight.Position - P; const float L2 = dot(L, L); if (L2 < (PointLight.Range*PointLight.Range)) { const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0) { const float3 Ln = L / (PointLight.Range+0.0001); const float cp = n_dot_l / (1.0 + 6.0 * dot(Ln, Ln)); diffuse += (PointLight.Color * cp); } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- // This shader computes standard transform and lighting //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.Pos, 1.0), World); // position, world-space const float4 Pv = mul(P, View); // position in view-space, for fade computation const float3 N = mul(input.Norm, (float3x3)World); output.Pos = mul(P, ViewProj); output.Tex0.xy = input.Tex; // save out LightDir in terrain tangent-space float3x3 TangentFrame; TangentFrame[0] = normalize(float3(N.z, 0.0, -N.y)); TangentFrame[1] = cross(N, TangentFrame[0]); TangentFrame[2] = N; output.LightDir = mul(TangentFrame, -LightDir); if (NumPointLights > 0) { output.LightPt = mul(TangentFrame, normalize(PointLight.Position - P.xyz)); } else { output.LightPt = float3(0,0,0); } output.PosWorld.xyz = P.xyz; if ((BumpAmount > 0) && (Pv.z < EndFadeDist2)) { output.Tex0.z = NoiseScale*P.x + NoiseScale*CameraPos.x; output.Tex0.w = NoiseScale*P.y + NoiseScale*CameraPos.y; const float3 I = -normalize(P.xyz); const float FadeEnd = lerp(EndFadeDist1, EndFadeDist2, max(0.0, I.z)); const float bv = 1.0 / (FadeEnd - StartFadeDist); output.PosWorld.w = clamp(0.0, 1.0, BumpAmount * (1.0 - (Pv.z - StartFadeDist) * bv)); } else { output.Tex0.zw = float2(0,0); output.PosWorld.w = 0.0; } if (Pv.z < FogDistance.y) { output.Fog = clamp(0.0, 1.0, (1.0 - (Pv.z - FogDistance.x) / (FogDistance.y - FogDistance.x))); } else { output.Fog = 0.0; } return output; } //-------------------------------------------------------------------------------------- // PixelShader //-------------------------------------------------------------------------------------- float4 PS( VS_OUTPUT input ) : COLOR { float3 water_diff = AmbientLight; float3 land_diff = AmbientLight; float4 sample0 = tex2D(TextureSampler, input.Tex0.xy); if (sample0.a > 0) { float3 Nw = float3(0,0,1); if (input.PosWorld.w > 0) { const float2 uv0 = frac(0.7f * input.Tex0.zw); const float3 N1 = tex2D(BumpSampler, float2(uv0.y, uv0.x)) * 2.0 - 1.0; const float noise_amount = input.PosWorld.w * 0.4f; // add some noise so it doesn't look completely flat Nw = lerp(Nw, N1, noise_amount); //Nw = normalize(Nw); water_diff += (LightColor * dot(Nw, -LightDir)); } else { water_diff += (LightColor * -LightDir.z); } if (NumPointLights > 0) { water_diff = compute_per_pixel_light_source(water_diff, Nw, input.PosWorld.xyz); } } if (sample0.a < 1.0) { float3 Nt = float3(0,0,1); if (input.PosWorld.w > 0) { const float3 N1 = tex2D(BumpSampler, frac(input.Tex0.zw)) * 2.0 - 1.0; Nt = lerp(Nt, N1, input.PosWorld.w); //Nt = normalize(Nt); land_diff += (LightColor * dot(Nt, input.LightDir)); } else { land_diff += (LightColor * input.LightDir.z); } if (NumPointLights > 0) { land_diff = compute_per_pixel_light_source(land_diff, Nt, input.LightPt, input.PosWorld.xyz); } } land_diff = lerp(land_diff, water_diff, sample0.a); land_diff *= sample0.rgb; return (float4(land_diff, 1.0) ); } //-------------------------------------------------------------------------------------- // Techniques //-------------------------------------------------------------------------------------- technique WaterBump { pass P0 { SRCBLEND = ONE; DESTBLEND = ZERO; VertexShader = compile vs_2_0 VS(); PixelShader = compile ps_2_0 PS(); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: TERWATEREFFECT1.FX // Copyright (c) 2009 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbConstant { static const float EndFadeDist1 = 2500.0; static const float EndFadeDist2 = 8000.0; static const float NoiseScale = 0.003; static const float StartFadeDist = 800.0; }; cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; float3 g_CameraPos; }; cbuffer cbPerMaterial { float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color float g_BumpAmount; }; cbuffer cbPerMesh { float3 g_MeshOffsetPos; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture; Texture2D g_BumpTexture ; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; SamplerState g_BumpSampler { Filter = MIN_MAG_MIP_LINEAR; AddressU = Wrap; AddressV = Wrap; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float4 norm_w : COLOR1; //xyz = world space normal, w = bump amount float4 uv : TEXCOORD0; //xy = uv0, zw = uv1 float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float4 norm_w : COLOR1; //xyz = world space normal, w = bump amount float4 uv : TEXCOORD0; //xy = uv0, zw = uv1 }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3x3 TangentFrame, float3 Nt, float3 P) { const float3 light_t = mul(TangentFrame, -g_DirLight.dir); float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(Nt, light_t)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return diffuse; } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return diffuse; } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 P) { // N = 0,0,1 float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, -g_DirLight.dir.z); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; //const float n_dot_l = L.z; if (L.z > 0) { const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (L.z / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; //const float n_dot_l = L.z; if (L.z > 0) { const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (L.z * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return diffuse; } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3 N, float3 P) { float3 specular = float3(0.0,0.0,0.0); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float h_dot_n = dot(H, N); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(H)); specular = pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor; } } return (specular); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3 P) { // N = 0,0,1 float3 specular = float3(0.0,0.0,0.0); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; //const float h_dot_n = H.z; if (H.z > 0.0) { const float unit_h_dot_n = H.z / length(H); specular = pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor; } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float precision_add_z( const float z1, const float z2, const float z3, const float z4 ) { float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // try to recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from prev add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = z4 - z_err; // include the lost low part from prev add... return (z_sum + z_add); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; pos.z = precision_add_z(P.x * g_mViewProj[0][2], P.y * g_mViewProj[1][2], P.z * g_mViewProj[2][2], g_mViewProj[3][2]); pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = float4((input.pos + g_MeshOffsetPos), 1.0); // position, world-space const float4 Pv = mul(P, g_mWorldToView); // position in view-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; output.pos_w.w = Pv.z; output.norm_w.xyz = input.norm; output.uv.xy = input.uv; if ((g_BumpAmount > 0.0) && (Pv.z < EndFadeDist2)) { output.uv.zw = NoiseScale*P.xy + NoiseScale*g_CameraPos.xy; const float3 I = -normalize(P.xyz); const float fade_end = lerp(EndFadeDist1, EndFadeDist2, max(0.0, I.z)); output.norm_w.w = clamp(0.0, 1.0, g_BumpAmount * (1.0 - ((Pv.z - StartFadeDist) / (fade_end - StartFadeDist)))); } else { output.uv.zw = float2(0.0,0.0); output.norm_w.w = 0; } return output; } //-------------------------------------------------------------------------------------- // PixelShader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; const float3 N0 = float3(0,0,1); if (input.pos_w.w < g_FogDistance.y) { output = g_MaterialTexture.Sample(g_TextureClampSampler, input.uv.xy); float3 water_diff = output.rgb; float3 land_diff = output.rgb; if (output.a > 0.0) { // water if (input.norm_w.w > 0.0) { const float2 uv0 = frac(0.7f * input.uv.zw); float3 N1 = g_BumpTexture.Sample(g_BumpSampler, float2(uv0.y, uv0.x)).xyz * 2.0 - 1.0; const float noise_amount = input.norm_w.w * 0.4f; // add some noise so it doesn't look completely flat N1 = lerp(N0, N1, noise_amount); N1 = normalize(N1); water_diff *= compute_per_pixel_ambient_diffuse(N1, input.pos_w.xyz); water_diff += compute_per_pixel_specular(N1, input.pos_w.xyz); } else { water_diff *= compute_per_pixel_ambient_diffuse(input.pos_w.xyz); water_diff += compute_per_pixel_specular(input.pos_w.xyz); } } if (output.a < 1.0) { // non-water const float3 N = normalize(input.norm_w.xyz); if (input.norm_w.w > 0.0) { float3 Nt = g_BumpTexture.Sample(g_BumpSampler, frac(input.uv.zw)).xyz * 2.0 - 1.0; Nt = lerp(N0, Nt, input.norm_w.w); Nt = normalize(Nt); // do per-pixel light sourcing const float3 nT = normalize(float3(N.z, 0.0, -N.y)); const float3x3 tangent_frame = float3x3(nT, cross(N, nT), N); land_diff *= compute_per_pixel_ambient_diffuse(tangent_frame, Nt, input.pos_w.xyz); } else { land_diff *= compute_per_pixel_ambient_diffuse(N, input.pos_w.xyz); } } land_diff = lerp(land_diff, water_diff, output.a); output.rgb = add_fog(land_diff, input.pos_w.w, input.pos_w.z); } else { output.rgb = g_FogColor; } return (float4(saturate(output.rgb), 1.0)); } //-------------------------------------------------------------------------------------- // Techniques //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: TERWATEREFFECT1DX9.FX // Copyright (c) 2009 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- int GlobalParameter : SasGlobal < int3 SasVersion = {1, 1, 0}; string SasEffectDescription = "Water Shader 1"; string SasEffectCompany = "Third Wire Productions, Inc."; >; //-------------------------------------------------------------------------------------- // Variables //-------------------------------------------------------------------------------------- struct SasPointLight { float3 Color; float3 Position; float Range; }; const float4x4 World ; const float4x4 View ; const float4x4 ViewProj ; // light directions in world space const float3 AmbientLight = { 0.0, 0.0, 0.6 }; const float3 LightColor = { 0.8, 0.8, 0.0 }; const float3 LightDir = {0.447050746,-0.447050746,0.774784655}; const int NumPointLights = 0; const SasPointLight PointLight ; const float3 CameraPos : CAMERA_GLOBAL_POSITION; const float3 SpecularColor : SPECULAR_LIGHT_COLOR = { 0.8, 0.8, 0.8 }; const float2 FogDistance : FOG_DISTANCE; const float BumpAmount : BUMP_AMOUNT; const float SpecularPower : SPECULAR_POWER; const float StartFadeDist = 800.0; const float EndFadeDist1 = 2500.0; const float EndFadeDist2 = 8000.0; const float NoiseScale = 0.003; texture MaterialTexture; texture BumpTexture ; //-------------------------------------------------------------------------------------- // Texture samplers //-------------------------------------------------------------------------------------- sampler TextureSampler = sampler_state { Texture = ; AddressU = CLAMP; AddressV = CLAMP; MipFilter = LINEAR; MinFilter = LINEAR; MagFilter = LINEAR; }; sampler BumpSampler = sampler_state { Texture = ; AddressU = WRAP; AddressV = WRAP; MipFilter = LINEAR; MinFilter = LINEAR; MagFilter = LINEAR; }; //-------------------------------------------------------------------------------------- // VertexShader I/O //-------------------------------------------------------------------------------------- struct VS_INPUT { float3 Pos : POSITION; float3 Norm : NORMAL; float2 Tex : TEXCOORD0; }; struct VS_OUTPUT { float4 Pos : POSITION; float4 Tex0 : TEXCOORD0; //xy = uv0, wz = uv1 float3 LightDir : TEXCOORD1; float3 LightPt : TEXCOORD2; float4 PosWorld : TEXCOORD3; // xyz = pos, w = bump amount float3 Half : TEXCOORD4; // H float Fog : FOG; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_light_source(float3 AmbientDiffuse, float3 N, float3 P) { float3 diffuse = AmbientDiffuse; const float3 L = PointLight.Position - P; const float L2 = dot(L, L); if (L2 < (PointLight.Range*PointLight.Range)) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float3 Ln = L / (PointLight.Range+0.0001); const float cp = n_dot_l / (sqrt(L2) * (1.0 + 6.0 * dot(Ln, Ln))); diffuse += (PointLight.Color * cp); } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_light_source(float3 AmbientDiffuse, float3 Nt, float3 Lt, float3 P) { // Lt in tangent space,already noramlized float3 diffuse = AmbientDiffuse; const float3 L = PointLight.Position - P; const float L2 = dot(L, L); if (L2 < (PointLight.Range*PointLight.Range)) { const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0) { const float3 Ln = L / (PointLight.Range+0.0001); const float cp = n_dot_l / (1.0 + 6.0 * dot(Ln, Ln)); diffuse += (PointLight.Color * cp); } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- // This shader computes standard transform and lighting //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.Pos, 1.0), World); // position, world-space const float4 Pv = mul(P, View); // position in view-space, for fade computation const float3 N = mul(input.Norm, (float3x3)World); const float3 L = -LightDir; const float3 I = -normalize(P.xyz); output.Pos = mul(P, ViewProj); output.Tex0.xy = input.Tex; // save out LightDir in terrain tangent-space float3x3 TangentFrame; TangentFrame[0] = normalize(float3(N.z, 0.0, -N.y)); TangentFrame[1] = cross(N, TangentFrame[0]); TangentFrame[2] = N; output.LightDir = mul(TangentFrame, -LightDir); if (NumPointLights > 0) { output.LightPt = mul(TangentFrame, normalize(PointLight.Position - P.xyz)); } else { output.LightPt = float3(0,0,0); } output.PosWorld.xyz = P.xyz; if ((BumpAmount > 0) && (Pv.z < EndFadeDist2)) { output.Tex0.z = NoiseScale*P.x + NoiseScale*CameraPos.x; output.Tex0.w = NoiseScale*P.y + NoiseScale*CameraPos.y; const float FadeEnd = lerp(EndFadeDist1, EndFadeDist2, max(0.0, I.z)); const float bv = 1.0 / (FadeEnd - StartFadeDist); output.PosWorld.w = clamp(0.0, 1.0, BumpAmount * (1.0 - (Pv.z - StartFadeDist) * bv)); } else { output.Tex0.zw = float2(0,0); output.PosWorld.w = 0.0; } output.Half = normalize(I + L); if (Pv.z < FogDistance.y) { const float fv = 1.0 / (FogDistance.y - FogDistance.x); output.Fog = clamp(0.0, 1.0, (1.0 - (Pv.z - FogDistance.x) * fv)); } else { output.Fog = 0.0; } return output; } //-------------------------------------------------------------------------------------- // PixelShader //-------------------------------------------------------------------------------------- float4 PS( VS_OUTPUT input ) : COLOR { float3 water_diff = AmbientLight; float3 land_diff = AmbientLight; float4 sample0 = tex2D(TextureSampler, input.Tex0.xy); if (sample0.a > 0) { float3 Nw = float3(0,0,1); if (input.PosWorld.w > 0) { const float2 uv0 = frac(0.7f * input.Tex0.zw); const float3 N1 = tex2D(BumpSampler, float2(uv0.y, uv0.x)) * 2.0 - 1.0; const float noise_amount = input.PosWorld.w * 0.4f; // add some noise so it doesn't look completely flat Nw = lerp(Nw, N1, noise_amount); //Nw = normalize(Nw); water_diff += (LightColor * dot(Nw, -LightDir)); } else { water_diff += (LightColor * -LightDir.z); } if (NumPointLights > 0) { water_diff = compute_per_pixel_light_source(water_diff, Nw, input.PosWorld.xyz); } water_diff *= sample0.rgb; const float spec = dot(Nw, input.Half); water_diff += (pow(spec, SpecularPower) * SpecularColor); } if (sample0.a < 1.0) { float3 Nt = float3(0,0,1); if (input.PosWorld.w > 0) { const float3 N1 = tex2D(BumpSampler, frac(input.Tex0.zw)) * 2.0 - 1.0; Nt = lerp(Nt, N1, input.PosWorld.w); //Nt = normalize(Nt); land_diff += (LightColor * dot(Nt, input.LightDir)); } else { land_diff += (LightColor * input.LightDir.z); } if (NumPointLights > 0) { land_diff = compute_per_pixel_light_source(land_diff, Nt, input.LightPt, input.PosWorld.xyz); } land_diff *= sample0.rgb; } land_diff = lerp(land_diff, water_diff, sample0.a); return (float4(land_diff, 1.0) ); } //-------------------------------------------------------------------------------------- // Techniques //-------------------------------------------------------------------------------------- technique WaterBump { pass P0 { SRCBLEND = ONE; DESTBLEND = ZERO; VertexShader = compile vs_2_0 VS(); PixelShader = compile ps_2_0 PS(); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: TERWATEREFFECT2.FX // Copyright (c) 2009 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbConstant { static const float EndFadeDist1 = 2500.0; static const float EndFadeDist2 = 8000.0; static const float NoiseScale = 0.003; static const float StartFadeDist = 800.0; static const float WaveCycleRate = 1.3; static const float WaveNoiseScale = 0.0005; static const float WaveBumpAmount = 2.00; static const float WaveStartFadeDist = 1000.0; // static const float WaveEndFadeDist = 12000.0; static const float WaveFadeFactor = 0.0000909; // 1 / (WaveEndFadeDist - WaveStartFadeDist) static const float WaveMovementRate = 0.0003; static const float3 WindVelocity = { 3.0, -6.0, 0.0 }; }; cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; float g_TimeNow; float3 g_CameraPos; // float3 g_WindVelocity; }; cbuffer cbPerMaterial { float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color float g_BumpAmount; }; cbuffer cbPerMesh { float3 g_MeshOffsetPos; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture; Texture2D g_BumpTexture ; Texture2D g_WaveTexture ; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; SamplerState g_BumpSampler { Filter = MIN_MAG_MIP_LINEAR; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_WaveSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Wrap; AddressV = Wrap; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float4 norm_w : COLOR1; //xyz = world space normal, w = bump amount float4 uv : TEXCOORD0; //xy = uv0, zw = uv1 float4 wave : TEXCOORD1; //xy = wave, zw = uv2 float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float4 norm_w : COLOR1; //xyz = world space normal, w = bump amount float4 uv : TEXCOORD; //xy = uv0, zw = uv1 float4 wave : TEXCOORD1; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3x3 TangentFrame, float3 Nt, float3 P) { const float3 light_t = mul(TangentFrame, -g_DirLight.dir); float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(Nt, light_t)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return diffuse; } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return diffuse; } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 P) { // N = 0,0,1 float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, -g_DirLight.dir.z); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; //const float n_dot_l = L.z; if (L.z > 0) { const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (L.z / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; //const float n_dot_l = L.z; if (L.z > 0) { const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (L.z * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return diffuse; } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3 N, float3 P) { float3 specular = float3(0.0,0.0,0.0); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float h_dot_n = dot(H, N); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(H)); specular = pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor; } } return (specular); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3 P) { // N = 0,0,1 float3 specular = float3(0.0,0.0,0.0); if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; //const float h_dot_n = H.z; if (H.z > 0.0) { const float unit_h_dot_n = H.z / length(H); specular = pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor; } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float precision_add_z( const float z1, const float z2, const float z3, const float z4 ) { float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // try to recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from prev add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = z4 - z_err; // include the lost low part from prev add... return (z_sum + z_add); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; pos.z = precision_add_z(P.x * g_mViewProj[0][2], P.y * g_mViewProj[1][2], P.z * g_mViewProj[2][2], g_mViewProj[3][2]); pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = float4((input.pos + g_MeshOffsetPos), 1.0); // position, world-space const float4 Pv = mul(P, g_mWorldToView); // position in view-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.pos_w.xyz = P.xyz; output.pos_w.w = Pv.z; output.norm_w.xyz = input.norm; output.uv.xy = input.uv; // terrain if ((g_BumpAmount > 0.0) && (Pv.z < EndFadeDist2)) { output.uv.zw = NoiseScale*P.xy + NoiseScale*g_CameraPos.xy; const float3 I = -normalize(P.xyz); const float fade_end = lerp(EndFadeDist1, EndFadeDist2, max(0.0, I.z)); output.norm_w.w = clamp(0.0, 1.0, g_BumpAmount * (1.0 - ((Pv.z - StartFadeDist) / (fade_end - StartFadeDist)))); } else { output.uv.zw = float2(0.0,0.0); output.norm_w.w = 0; } // water output.wave.y = clamp(0.0, 1.0, WaveBumpAmount * (1.0 - (Pv.z - WaveStartFadeDist) * WaveFadeFactor)); if (output.wave.y > 0.0) { const float sin_wave = sin(float(WaveCycleRate*g_TimeNow + WaveNoiseScale*((P.x - P.y) + (g_CameraPos.x - g_CameraPos.y)))); output.wave.x = 0.5 * (sin_wave + 1.0); output.wave.zw = WaveNoiseScale*P.xy + WaveNoiseScale*g_CameraPos.xy + g_TimeNow*WaveMovementRate*WindVelocity.xy; } else { output.wave.x = 0.0; output.wave.zw = float2(0.0,0.0); } return output; } //-------------------------------------------------------------------------------------- // PixelShader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output; const float3 N0 = float3(0,0,1); if (input.pos_w.w < g_FogDistance.y) { output = g_MaterialTexture.Sample(g_TextureClampSampler, input.uv.xy); float3 water_diff = output.rgb; float3 land_diff = output.rgb; if (output.a > 0.0) { // water area if (input.wave.y > 0.0) { const float2 nt = frac(input.wave.zw); const float3 N1 = g_WaveTexture.Sample(g_WaveSampler, float2(nt.x + 0.5, nt.y + 0.5)).xyz; float3 N2 = g_WaveTexture.Sample(g_WaveSampler, nt).xyz; N2 = lerp(N1, N2, input.wave.x) * 2.0 - 1.0; N2 = lerp(N0, N2, input.wave.y); N2 = normalize(N2); water_diff *= compute_per_pixel_ambient_diffuse(N2, input.pos_w.xyz); water_diff += compute_per_pixel_specular(N2, input.pos_w.xyz); } else { water_diff *= compute_per_pixel_ambient_diffuse(input.pos_w.xyz); water_diff += compute_per_pixel_specular(input.pos_w.xyz); } } if (output.a < 1.0) { // non-water const float3 N = normalize(input.norm_w.xyz); if (input.norm_w.w > 0.0) { float3 Nt = g_BumpTexture.Sample(g_BumpSampler, frac(input.uv.zw)).xyz * 2.0 - 1.0; Nt = lerp(N0, Nt, input.norm_w.w); Nt = normalize(Nt); // do per-pixel light sourcing const float3 nT = normalize(float3(N.z, 0.0, -N.x)); const float3x3 tangent_frame = float3x3(nT, cross(N, nT), N); land_diff *= compute_per_pixel_ambient_diffuse(tangent_frame, Nt, input.pos_w.xyz); } else { land_diff *= compute_per_pixel_ambient_diffuse(N, input.pos_w.xyz); } } land_diff = lerp(land_diff, water_diff, output.a); output.rgb = add_fog(land_diff, input.pos_w.w, input.pos_w.z); } else { output.rgb = g_FogColor; } return (float4(saturate(output.rgb), 1.0)); } //-------------------------------------------------------------------------------------- // Techniques //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: TERWATEREFFECT2DX9.FX // Copyright (c) 2006 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- int GlobalParameter : SasGlobal < int3 SasVersion = {1, 1, 0}; string SasEffectDescription = "Water Shader 2"; string SasEffectCompany = "Third Wire Productions, Inc."; >; //-------------------------------------------------------------------------------------- // Variables //-------------------------------------------------------------------------------------- struct SasPointLight { float3 Color; float3 Position; float Range; }; const float4x4 World ; const float4x4 View ; const float4x4 ViewProj ; // light directions in world space const float3 AmbientLight = { 0.0, 0.0, 0.6 }; const float3 LightColor = { 0.8, 0.8, 0.0 }; const float3 LightDir = {0.447050746,-0.447050746,0.774784655}; const int NumPointLights = 0; const SasPointLight PointLight ; const float Time ; const float3 CameraPos : CAMERA_GLOBAL_POSITION; const float3 SpecularColor : SPECULAR_LIGHT_COLOR = { 0.8, 0.8, 0.8 }; const float3 WindVelocity /*: WIND_VELOCITY */ = { 3.0, -6.0, 0.0 }; const float2 FogDistance : FOG_DISTANCE; const float BumpAmount : BUMP_AMOUNT; const float SpecularPower : SPECULAR_POWER; const float StartFadeDist = 800.0; const float EndFadeDist1 = 2500.0; const float EndFadeDist2 = 8000.0; const float NoiseScale = 0.003; const float WaveStartFadeDist = 1000.0; const float WaveEndFadeDist = 12000.0; const float WaveFadeFactor = 0.0000909090; // 1 / (WaveEndFadeDist - WaveStartFadeDist); const float WaveBumpAmount = 2.00; const float WaveNoiseScale = 0.0005; const float WaveCycleRate = 1.3; const float WaveMovementRate = 0.0003; texture MaterialTexture; texture BumpTexture ; texture WaveTexture ; //-------------------------------------------------------------------------------------- // Texture samplers //-------------------------------------------------------------------------------------- sampler TextureSampler = sampler_state { Texture = ; AddressU = CLAMP; AddressV = CLAMP; MipFilter = LINEAR; MinFilter = LINEAR; MagFilter = LINEAR; }; sampler BumpSampler = sampler_state { Texture = ; AddressU = WRAP; AddressV = WRAP; MipFilter = LINEAR; MinFilter = LINEAR; MagFilter = LINEAR; }; sampler WaveSampler = sampler_state { Texture = ; AddressU = WRAP; AddressV = WRAP; MipFilter = NONE; MinFilter = LINEAR; MagFilter = LINEAR; }; //-------------------------------------------------------------------------------------- // VertexShader I/O //-------------------------------------------------------------------------------------- struct VS_INPUT { float3 Pos : POSITION; float3 Norm : NORMAL; float2 Tex : TEXCOORD0; }; struct VS_OUTPUT { float4 Pos : POSITION; float4 Tex0 : TEXCOORD0; //xy = uv0, zw = uv1 float3 LightDir : TEXCOORD1; float3 LightPt : TEXCOORD2; float4 PosWorld : TEXCOORD3; // xyz = pos, w = bump amount float4 Wave : TEXCOORD4; // xy = uv2, zw = spec float3 Half : TEXCOORD5; // H float Fog : FOG; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_light_source(float3 AmbientDiffuse, float3 N, float3 P) { float3 diffuse = AmbientDiffuse; const float3 L = PointLight.Position - P; const float L2 = dot(L, L); if (L2 < (PointLight.Range*PointLight.Range)) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float3 Ln = L / (PointLight.Range+0.0001); const float cp = n_dot_l / (sqrt(L2) * (1.0 + 6.0 * dot(Ln, Ln))); diffuse += (PointLight.Color * cp); } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_light_source(float3 AmbientDiffuse, float3 Nt, float3 Lt, float3 P) { // Lt in tangent space,already noramlized float3 diffuse = AmbientDiffuse; const float3 L = PointLight.Position - P; const float L2 = dot(L, L); if (L2 < (PointLight.Range*PointLight.Range)) { const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0) { const float3 Ln = L / (PointLight.Range+0.0001); const float cp = n_dot_l / (1.0 + 6.0 * dot(Ln, Ln)); diffuse += (PointLight.Color * cp); } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- // This shader computes standard transform and lighting //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.Pos, 1.0), World); // position, world-space const float4 Pv = mul(P, View); // position in view-space, for fade computation const float3 N = mul(input.Norm, (float3x3)World); const float3 L = -LightDir; const float3 I = -normalize(P.xyz); output.Pos = mul(P, ViewProj); output.Tex0.xy = input.Tex; // save out LightDir in terrain tangent-space float3x3 TangentFrame; TangentFrame[0] = normalize(float3(N.z, 0.0, -N.y)); TangentFrame[1] = cross(N, TangentFrame[0]); TangentFrame[2] = N; output.LightDir = mul(TangentFrame, L); if (NumPointLights > 0) { output.LightPt = mul(TangentFrame, normalize(PointLight.Position - P.xyz)); } else { output.LightPt = float3(0,0,0); } output.PosWorld.xyz = P.xyz; if ((BumpAmount > 0) && (Pv.z < EndFadeDist2)) { output.Tex0.z = NoiseScale*P.x + NoiseScale*CameraPos.x; output.Tex0.w = NoiseScale*P.y + NoiseScale*CameraPos.y; const float FadeEnd = lerp(EndFadeDist1, EndFadeDist2, max(0.0, I.z)); const float bv = 1.0 / (FadeEnd - StartFadeDist); output.PosWorld.w = clamp(0.0, 1.0, BumpAmount * (1.0 - (Pv.z - StartFadeDist) * bv)); } else { output.Tex0.zw = float2(0,0); output.PosWorld.w = 0.0; } if (Pv.z < WaveEndFadeDist) { output.Wave.x = WaveNoiseScale*P.x + WaveNoiseScale*CameraPos.x + Time*WaveMovementRate*WindVelocity.x; output.Wave.y = WaveNoiseScale*P.y + WaveNoiseScale*CameraPos.y + Time*WaveMovementRate*WindVelocity.y; float SinWave = sin(WaveCycleRate*Time + WaveNoiseScale*((P.x - P.y) + (CameraPos.x - CameraPos.y))); output.Wave.z = clamp(0.0, 1.0, WaveBumpAmount * (1.0 - (Pv.z - WaveStartFadeDist) * WaveFadeFactor)); output.Wave.w = 0.5 * (SinWave + 1.0); } else { output.Wave = float4(0,0,0,0); } output.Half.xyz = normalize(I + L); if (Pv.z < FogDistance.y) { const float fv = 1.0 / (FogDistance.y - FogDistance.x); output.Fog = clamp(0.0, 1.0, (1.0 - (Pv.z - FogDistance.x) * fv)); } else { output.Fog = 0.0; } return output; } //-------------------------------------------------------------------------------------- // PixelShader //-------------------------------------------------------------------------------------- float4 PS( VS_OUTPUT input ) : COLOR { float3 water_diff = AmbientLight; float3 land_diff = AmbientLight; float4 sample0 = tex2D(TextureSampler, input.Tex0.xy); if (sample0.a > 0.0) { float3 Nw = float3(0,0,1); if (input.Wave.z > 0) { const float2 nt = frac(input.Wave.xy); const float3 N1 = tex2D(WaveSampler, nt); float3 N2 = tex2D(WaveSampler, float2(nt.x + 0.5, nt.y + 0.5)); N2 = lerp(N1, N2, input.Wave.w) * 2.0 - 1.0; Nw = lerp(Nw, N2, input.Wave.z); //Nw = normalize(Nw); water_diff += (LightColor * dot(Nw, -LightDir)); } else { water_diff += (LightColor * -LightDir.z); } if (NumPointLights > 0) { water_diff = compute_per_pixel_light_source(water_diff, Nw, input.PosWorld.xyz); } water_diff *= sample0.rgb; const float spec = dot(Nw, input.Half); water_diff += (pow(spec, SpecularPower) * SpecularColor); } //if (sample0.a < 1.0) { float3 Nt = float3(0,0,1); if (input.PosWorld.w > 0) { const float3 N1 = tex2D(BumpSampler, frac(input.Tex0.zw)) * 2.0 - 1.0; Nt = lerp(Nt, N1, input.PosWorld.w); //Nt = normalize(Nt); land_diff += (LightColor * dot(Nt, input.LightDir)); } else { land_diff += (LightColor * input.LightDir.z); } if (NumPointLights > 0) { land_diff = compute_per_pixel_light_source(land_diff, Nt, input.LightPt, input.PosWorld.xyz); } land_diff *= sample0.rgb; } land_diff = lerp(land_diff, water_diff, sample0.a); return (float4(land_diff, 1.0) ); } //-------------------------------------------------------------------------------------- // Techniques //-------------------------------------------------------------------------------------- technique WaterBump { pass P0 { SRCBLEND = ONE; DESTBLEND = ZERO; VertexShader = compile vs_2_0 VS(); PixelShader = compile ps_2_0 PS(); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: TWCOLOR0.FX // Copyright (c) 2009 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mViewProj; float g_InvFarClip; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; }; struct VS_INPUT { float3 pos : POSITION; float4 diffuse : COLOR; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float4 diffuse : COLOR; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 diffuse : COLOR; }; //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space output.pos = mul(P, g_mViewProj); output.diffuse = input.diffuse; return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { return (input.diffuse); } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: TWCOLOR1.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mViewProj; float g_InvFarClip; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; }; Texture2D g_MaterialTexture; SamplerState g_LinearSampler { Filter = MIN_MAG_MIP_LINEAR; AddressU = Wrap; AddressV = Wrap; }; struct VS_INPUT { float3 pos : POSITION; float4 diffuse : COLOR; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float4 diffuse : COLOR; float2 uv : TEXCOORD; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 diffuse : COLOR; float2 uv : TEXCOORD; }; //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space output.pos = mul(P, g_mViewProj); output.uv = input.uv; output.diffuse = input.diffuse; return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output = g_MaterialTexture.Sample(g_LinearSampler, input.uv); return (input.diffuse * output); } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- TWCOLOR1.FX PURPOSE - This shader is designed for rendering textured objects with per-vertex color blending. It supports linear filtering for smooth texture sampling and simple transformations for efficient performance in lightweight applications. KEY FEATURES - Per-Vertex Color Blending: > Blends per-vertex diffuse colors with texture sampling for flexible color effects. > Supports dynamic color variations across vertices. - Texture Sampling: > Uses g_MaterialTexture for applying a texture map to the mesh. > Linear filtering via g_LinearSampler ensures smooth transitions between texels. - Lightweight Transformations: > Transforms vertices from model space to view-projection space using g_mMeshToWorld and g_mViewProj matrices. > Optimized for scenarios where complex lighting and shading are unnecessary. - Efficiency: > Minimal computational overhead due to simple vertex and pixel shader operations. > No lighting or fog integration, keeping the shader focused on texture and color blending. //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: TWCOLOR2.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mViewProj; float g_InvFarClip; }; cbuffer cbPerMaterial { int g_NumTextures; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; SamplerState g_LinearSampler { Filter = MIN_MAG_MIP_LINEAR; AddressU = Wrap; AddressV = Wrap; }; struct VS_INPUT { float3 pos : POSITION; float4 diffuse : COLOR; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; }; struct VS_OUTPUT { float4 diffuse : COLOR; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 diffuse : COLOR; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; }; //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space output.pos = mul(P, g_mViewProj); output.uv0 = input.uv0; output.uv1 = input.uv1; output.diffuse = input.diffuse; return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output = g_MaterialTexture0.Sample(g_LinearSampler, input.uv0); if (g_NumTextures > 1) { float4 stage = g_MaterialTexture1.Sample(g_LinearSampler, input.uv1); output.rgb = output.rgb * (1.0 - stage.a) + stage.rgb * stage.a; } return (input.diffuse * output); } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: TWCOLOR8.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mViewProj; float g_InvFarClip; }; cbuffer cbPerMaterial { int g_NumTextures; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; Texture2D g_MaterialTexture4; Texture2D g_MaterialTexture5; Texture2D g_MaterialTexture6; Texture2D g_MaterialTexture7; SamplerState g_LinearSampler { Filter = MIN_MAG_MIP_LINEAR; AddressU = Wrap; AddressV = Wrap; }; struct VS_INPUT { float3 pos : POSITION; float4 diffuse : COLOR; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; struct VS_OUTPUT { float4 diffuse : COLOR; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 diffuse : COLOR; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space output.pos = mul(P, g_mViewProj); output.uv0 = input.uv0; output.uv1 = input.uv1; output.uv2 = input.uv2; output.uv3 = input.uv3; output.uv4 = input.uv4; output.uv5 = input.uv5; output.uv6 = input.uv6; output.uv7 = input.uv7; output.diffuse = input.diffuse; return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output = g_MaterialTexture0.Sample(g_LinearSampler, input.uv0); float4 stage; if (g_NumTextures > 1) { stage = g_MaterialTexture1.Sample(g_LinearSampler, input.uv1); output.rgb = output.rgb * (1.0 - stage.a) + stage.rgb * stage.a; if (g_NumTextures > 2) { stage = g_MaterialTexture2.Sample(g_LinearSampler, input.uv2); output.rgb = output.rgb * (1.0 - stage.a) + stage.rgb * stage.a; if (g_NumTextures > 3) { stage = g_MaterialTexture3.Sample(g_LinearSampler, input.uv3); output.rgb = output.rgb * (1.0 - stage.a) + stage.rgb * stage.a; if (g_NumTextures > 4) { stage = g_MaterialTexture4.Sample(g_LinearSampler, input.uv4); output.rgb = output.rgb * (1.0 - stage.a) + stage.rgb * stage.a; if (g_NumTextures > 5) { stage = g_MaterialTexture5.Sample(g_LinearSampler, input.uv5); output.rgb = output.rgb * (1.0 - stage.a) + stage.rgb * stage.a; if (g_NumTextures > 6) { stage = g_MaterialTexture6.Sample(g_LinearSampler, input.uv6); output.rgb = output.rgb * (1.0 - stage.a) + stage.rgb * stage.a; if (g_NumTextures > 7) { stage = g_MaterialTexture7.Sample(g_LinearSampler, input.uv7); output.rgb = output.rgb * (1.0 - stage.a) + stage.rgb * stage.a; } } } } } } } return (input.diffuse * output); } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: TWCOLORBIAS.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- struct VS_INPUT { float4 pos : POSITION; float4 diffuse : COLOR; }; struct VS_OUTPUT { float4 diffuse : COLOR; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 diffuse : COLOR; }; //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; output.diffuse = input.diffuse; output.pos = input.pos; return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { return (input.diffuse); } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: TWFONT.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float g_InvScreenWidth; float g_InvScreenHeight; float2 g_ViewportTopLeft; }; Texture2D g_MaterialTexture; SamplerState g_LinearSampler { Filter = MIN_MAG_MIP_LINEAR; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float4 pos : POSITION; float4 diffuse : COLOR; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float4 diffuse : COLOR; float2 uv : TEXCOORD; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 diffuse : COLOR; float2 uv : TEXCOORD; }; //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; //convert from screen coordinates to clip space coordinates output.pos.x = (input.pos.x - g_ViewportTopLeft.x) * 2.0f * g_InvScreenWidth - 1.0f; output.pos.y = 1.0f - (input.pos.y - g_ViewportTopLeft.y) * 2.0f * g_InvScreenHeight; output.pos.z = input.pos.z; output.pos.w = input.pos.w; output.diffuse = input.diffuse; output.uv = input.uv; return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output = g_MaterialTexture.Sample(g_LinearSampler, input.uv); return (input.diffuse * output); } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: TWLINE.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; }; struct VS_INPUT { float3 pos : POSITION; float4 diffuse : COLOR0; }; struct VS_OUTPUT { float4 diffuse : COLOR; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 diffuse : COLOR; }; //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space output.pos = mul(P, g_mViewProj); output.diffuse = input.diffuse; return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { return (input.diffuse); } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: TWNORMAL1.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; float3 g_CameraPos; int g_bInReflection; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; int g_NumSpotLights; PointLight g_aPointLights[8]; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv : TEXCOORD; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv : TEXCOORD; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3 N, float3 P) { float3 specular = 0.0; if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float h_dot_n = dot(H, N); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(H)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); const float3 N = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space output.pos_w.xyz = P.xyz; output.norm_w = N; output.uv = input.uv; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { if (g_bInReflection) { clip(input.pos_w.z + g_CameraPos.z); } float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { if (!g_bClampTexture) { output = g_MaterialTexture.Sample(g_TextureWrapSampler, input.uv); } else { output = g_MaterialTexture.Sample(g_TextureClampSampler, input.uv) ; } if (g_bLightEnabled) { const float3 N = normalize(input.norm_w); // do per-pixel light sourcing output.rgb *= compute_per_pixel_ambient_diffuse(N, input.pos_w.xyz); output.rgb += compute_per_pixel_specular(N, input.pos_w.xyz); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z+g_CameraPos.z); } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: TWNORMAL1BUMP.FX // Copyright (c) 2009 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; float3 g_CameraPos; int g_bBumpEnabled; int g_bInReflection; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color float g_BumpAmount; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; int g_NumSpotLights; PointLight g_aPointLights[8]; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture; Texture2D g_BumpNormalTexture; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; SamplerState g_BumpWrapSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_BumpClampSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv : TEXCOORD; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv : TEXCOORD; }; //-------------------------------------------------------------------------------------- float3x3 compute_tangent_frame(float3 N, float3 P, float2 uv) { // get edge vectors of the pixel triangle const float3 dp1 = ddx(P); const float3 dp2 = ddy(P); const float2 duv1 = ddx(uv); const float2 duv2 = ddy(uv); // solve the linear system const float2x3 M = float2x3(dp1, dp2); const float3 T = mul(float2(duv1.x, duv2.x), M); const float3 B = mul(float2(duv1.y, duv2.y), M); // construct tangent frame float3 bT = normalize( cross(N, T) ); const float3 nT = cross(bT, N); if (dot(bT, B) < 0) { bT *= -1.0f; } return float3x3( nT, bT, N); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3x3 TangentFrame, float3 Nt, float3 P) { const float3 light_t = mul(TangentFrame, -g_DirLight.dir); float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(Nt, light_t)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return saturate(diffuse); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3x3 TangentFrame, float3 Nt, float3 P) { float3 specular = 0.0; if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float3 Ht = mul(TangentFrame, H); const float h_dot_n = dot(Ht, Nt); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(Ht)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); const float3 N = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space output.pos_w.xyz = P.xyz; output.norm_w = N; output.uv = input.uv; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { if (g_bInReflection) { clip(input.pos_w.z + g_CameraPos.z); } float4 output; if (g_bInReflection) { clip(input.pos_w.z + g_CameraPos.z); } if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 Np; if (!g_bClampTexture) { output = g_MaterialTexture.Sample(g_TextureWrapSampler, input.uv); Np = g_BumpNormalTexture.Sample(g_BumpWrapSampler, input.uv).xyz * 2.0 - 1.0; } else { output = g_MaterialTexture.Sample(g_TextureClampSampler, input.uv) ; Np = g_BumpNormalTexture.Sample(g_BumpClampSampler, input.uv).xyz * 2.0 - 1.0; } if (output.a > 0.0) { if (g_bLightEnabled) { // do per-pixel light sourcing const float3 N0 = normalize(input.norm_w); const float3x3 tangent_frame = compute_tangent_frame(N0, input.pos_w.xyz, input.uv); float3 Nt = lerp(float3(0.0,0.0,1.0), Np, g_BumpAmount); Nt = normalize(Nt); output.rgb *= compute_per_pixel_ambient_diffuse(tangent_frame, Nt, input.pos_w.xyz); output.rgb += compute_per_pixel_specular(tangent_frame, Nt, input.pos_w.xyz); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: TWNORMAL1BUMPSPEC.FX // Copyright (c) 2010 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; float3 g_CameraPos; int g_bBumpEnabled; int g_bInReflection; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color float g_BumpAmount; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; int g_NumSpotLights; PointLight g_aPointLights[8]; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; SamplerState g_BumpWrapSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_BumpClampSampler { Filter = MIN_MAG_LINEAR_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv : TEXCOORD; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv : TEXCOORD; }; //-------------------------------------------------------------------------------------- float3x3 compute_tangent_frame(float3 N, float3 P, float2 uv) { // get edge vectors of the pixel triangle const float3 dp1 = ddx(P); const float3 dp2 = ddy(P); const float2 duv1 = ddx(uv); const float2 duv2 = ddy(uv); // solve the linear system const float2x3 M = float2x3(dp1, dp2); const float3 T = mul(float2(duv1.x, duv2.x), M); const float3 B = mul(float2(duv1.y, duv2.y), M); // construct tangent frame float3 bT = normalize( cross(N, T) ); const float3 nT = cross(bT, N); if (dot(bT, B) < 0) { bT *= -1.0f; } return float3x3( nT, bT, N); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3x3 TangentFrame, float3 Nt, float3 P) { const float3 light_t = mul(TangentFrame, -g_DirLight.dir); float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(Nt, light_t)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float3 Lt = mul(TangentFrame, L); const float n_dot_l = dot(Nt, Lt); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return saturate(diffuse); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3x3 TangentFrame, float3 Nt, float3 P) { float3 specular = 0.0; if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float3 Ht = mul(TangentFrame, H); const float h_dot_n = dot(Ht, Nt); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(Ht)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); const float3 N = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space output.pos_w.xyz = P.xyz; output.norm_w = N; output.uv = input.uv; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { if (g_bInReflection) { clip(input.pos_w.z + g_CameraPos.z); } float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 Np; float3 sm; if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv); Np = g_MaterialTexture1.Sample(g_BumpWrapSampler, input.uv).xyz * 2.0 - 1.0; sm = g_MaterialTexture2.Sample(g_TextureWrapSampler, input.uv); } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv) ; Np = g_MaterialTexture1.Sample(g_BumpClampSampler, input.uv).xyz * 2.0 - 1.0; sm = g_MaterialTexture2.Sample(g_TextureClampSampler, input.uv); } if (output.a > 0.0) { if (g_bLightEnabled) { // do per-pixel light sourcing const float3 N0 = normalize(input.norm_w); const float3x3 tangent_frame = compute_tangent_frame(N0, input.pos_w.xyz, input.uv); float3 Nt = lerp(float3(0.0,0.0,1.0), Np, g_BumpAmount); Nt = normalize(Nt); output.rgb *= compute_per_pixel_ambient_diffuse(tangent_frame, Nt, input.pos_w.xyz); output.rgb += (compute_per_pixel_specular(tangent_frame, Nt, input.pos_w.xyz) * sm); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: TWNORMAL1SPEC.FX // Copyright (c) 2010 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; float3 g_CameraPos; int g_bInReflection; }; cbuffer cbPerMaterial { int g_bClampTexture; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; int g_NumSpotLights; PointLight g_aPointLights[8]; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; SamplerState g_TextureClampSampler { Filter = ANISOTROPIC; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv : TEXCOORD; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 pos_w : COLOR0; //xyz = world space pos, w = fogdist float3 norm_w : COLOR1; //world space normal float2 uv : TEXCOORD; }; //-------------------------------------------------------------------------------------- float3 compute_per_pixel_ambient_diffuse(float3 N, float3 P) { float3 diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, -g_DirLight.dir)); // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - P; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - P; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(N, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } return (saturate(diffuse)); } //-------------------------------------------------------------------------------------- float3 compute_per_pixel_specular(float3 N, float3 P) { float3 specular = 0.0; if (g_SpecularPower > 0.0) { const float3 H = -normalize(P) - g_DirLight.dir; const float h_dot_n = dot(H, N); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(H)); specular = (pow(unit_h_dot_n, g_SpecularPower) * g_SpecularColor); } } return (specular); } //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); const float3 N = mul(input.norm, (float3x3)g_mMeshToWorld); // normal, world-space output.pos_w.xyz = P.xyz; output.norm_w = N; output.uv = input.uv; if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { if (g_bInReflection) { clip(input.pos_w.z + g_CameraPos.z); } float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { float3 sm; if (!g_bClampTexture) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv); sm = g_MaterialTexture1.Sample(g_TextureWrapSampler, input.uv); } else { output = g_MaterialTexture0.Sample(g_TextureClampSampler, input.uv) ; sm = g_MaterialTexture1.Sample(g_TextureClampSampler, input.uv); } if (g_bLightEnabled) { const float3 N = normalize(input.norm_w); // do per-pixel light sourcing output.rgb *= compute_per_pixel_ambient_diffuse(N, input.pos_w.xyz); output.rgb += (compute_per_pixel_specular(N, input.pos_w.xyz) * sm); } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: TWNORMAL2.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; float3 g_CameraPos; int g_bInReflection; }; cbuffer cbPerMaterial { int g_NumTextures; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; }; struct VS_OUTPUT { float3 diffuse : COLOR0; float3 specular : COLOR1; float4 pos_w : COLOR2; //xyz = world space pos, w = fogdist float3 norm_w : COLOR3; //world space normal float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float4 pos : SV_POSITION; }; struct PS_INPUT { float3 diffuse : COLOR0; float3 specular : COLOR1; float4 pos_w : COLOR2; //xyz = world space pos, w = fogdist float3 norm_w : COLOR3; //world space normal float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; }; //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.uv0 = input.uv0; output.uv1 = input.uv1; output.pos_w.xyz = P.xyz; if (g_bLightEnabled) { const float3 L = -g_DirLight.dir; const float3 N = mul(input.norm, (float3x3)g_mMeshToWorld); output.norm_w = N; output.diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, L)); // do per-vertex specular lighting output.specular = float3(0.0, 0.0, 0.0); if (g_bSpecularEnabled && (g_SpecularPower > 0.0)) { const float3 H = -normalize(P.xyz) + L; const float h_dot_n = dot(H, N); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(H)); output.specular = pow(abs(unit_h_dot_n), g_SpecularPower) * g_SpecularColor; } } } else { output.norm_w = float3(0.0, 0.0, 0.0); output.diffuse = float3(1.0, 1.0, 1.0); output.specular = float3(0.0, 0.0, 0.0); } if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { if (g_bInReflection) { clip(input.pos_w.z + g_CameraPos.z); } float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); if (g_NumTextures > 1) { const float4 stage = g_MaterialTexture1.Sample(g_TextureWrapSampler, input.uv1); output.rgb = output.rgb * (1.0 - stage.a) + stage.rgb * stage.a; } if (g_bLightEnabled) { float3 diffuse = input.diffuse.rgb; // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - input.pos_w.xyz; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(input.norm_w, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - input.pos_w.xyz; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(input.norm_w, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[j].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[j].color * cp); } } } } output.rgb *= saturate(diffuse); output.rgb += input.specular; } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: TWNORMAL8.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- struct DirLight { float3 dir; float ___d4; //float3 aligned to 4 float3 color; float ___c4; //float3 aligned to 4 }; struct PointLight { float3 color; float Range2; //float3 aligned to 4 float3 pos; float invRange; }; struct SpotLight { float3 color; float ___c4; //float3 aligned to 4 float3 pos; float ___p4; //float3 aligned to 4 float3 dir; float Range2; //float3 aligned to 4 float invRange; float3 angles; // x = cos(Theta/2) (inner angle), y = cos(Phi/2) (outer angle), z = 1/(x - y) }; //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mWorldToView; float4x4 g_mViewProj; float g_InvFarClip; float3 g_FogDistance; // x = Start, y = End, z = 1 / (y - x) float3 g_FogColor; float3 g_FogLayer; // x = amount, y = altitude (camera-relative), z = thickness float3 g_AmbientLight; DirLight g_DirLight; float3 g_CameraPos; int g_bInReflection; }; cbuffer cbPerMaterial { int g_NumTextures; int g_bFogEnabled; int g_bLightEnabled; int g_bSpecularEnabled; float g_SpecularPower; float3 g_SpecularColor; // specular level * dir light specular color * mat specular color }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; int g_NumPointLights; PointLight g_aPointLights[8]; int g_NumSpotLights; SpotLight g_aSpotLights[2]; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; Texture2D g_MaterialTexture4; Texture2D g_MaterialTexture5; Texture2D g_MaterialTexture6; Texture2D g_MaterialTexture7; SamplerState g_TextureWrapSampler { Filter = ANISOTROPIC; AddressU = Wrap; AddressV = Wrap; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; struct VS_OUTPUT { float3 diffuse : COLOR0; float3 specular : COLOR1; float4 pos_w : COLOR2; //xyz = world space pos, w = fogdist float3 norm_w : COLOR3; //world space normal float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; float4 pos : SV_POSITION; }; struct PS_INPUT { float3 diffuse : COLOR0; float3 specular : COLOR1; float4 pos_w : COLOR2; //xyz = world space pos, w = fogdist float3 norm_w : COLOR3; //world space normal float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; //-------------------------------------------------------------------------------------- float3 add_fog(float3 Color, float FogDist, float FogZ) { float3 output = Color; float fog = 0.0f; const float fd = FogDist - g_FogDistance.x; if (fd > 0.0) { fog = (fd * g_FogDistance.z); } if (g_FogLayer.x > 0.0) { const float fz = abs(FogZ - g_FogLayer.y); float depth = g_FogLayer.z - fz; if (depth > 0.0) { depth = min(FogDist, depth); fog += (g_FogLayer.x * (smoothstep(0.0, g_FogLayer.z, depth))); } } fog = clamp(0.0, 1.0, fog); output = lerp(output, g_FogColor, fog); return (output); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // output.pos = mul(P, g_mViewProj); // instead of this... // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; const float z1 = P.x * g_mViewProj[0][2]; const float z2 = P.y * g_mViewProj[1][2]; const float z3 = P.z * g_mViewProj[2][2]; float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from last add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = g_mViewProj[3][2] - z_err; // include the lost low part from last add... pos.z = z_sum + z_add; pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); output.uv0 = input.uv0; output.uv1 = input.uv1; output.uv2 = input.uv2; output.uv3 = input.uv3; output.uv4 = input.uv4; output.uv5 = input.uv5; output.uv6 = input.uv6; output.uv7 = input.uv7; output.pos_w.xyz = P.xyz; if (g_bLightEnabled) { const float3 L = -g_DirLight.dir; const float3 N = mul(input.norm, (float3x3)g_mMeshToWorld); output.norm_w = N; output.diffuse = g_AmbientLight + g_DirLight.color * max(0, dot(N, L)); // do per-vertex specular lighting output.specular = float3(0.0, 0.0, 0.0); if (g_bSpecularEnabled && (g_SpecularPower > 0.0)) { const float3 H = -normalize(P.xyz) + L; const float h_dot_n = dot(H, N); if (h_dot_n > 0.0) { const float unit_h_dot_n = min(1.0, h_dot_n / length(H)); output.specular = pow(abs(unit_h_dot_n), g_SpecularPower) * g_SpecularColor; } } } else { output.norm_w = float3(0.0, 0.0, 0.0); output.diffuse = float3(1.0, 1.0, 1.0); output.specular = float3(0.0, 0.0, 0.0); } if (g_bFogEnabled) { const float4 Pv = mul(P, g_mWorldToView); // position in view-space output.pos_w.w = Pv.z; } else { output.pos_w.w = 0.0f; } return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { if (g_bInReflection) { clip(input.pos_w.z + g_CameraPos.z); } float4 output; if (!g_bFogEnabled || (input.pos_w.w < g_FogDistance.y)) { output = g_MaterialTexture0.Sample(g_TextureWrapSampler, input.uv0); if (g_NumTextures > 1) { float4 stage = g_MaterialTexture1.Sample(g_TextureWrapSampler, input.uv1); output.rgb = output.rgb * (1.0 - stage.a) + stage.rgb * stage.a; if (g_NumTextures > 2) { stage = g_MaterialTexture2.Sample(g_TextureWrapSampler, input.uv2); output.rgb = output.rgb * (1.0 - stage.a) + stage.rgb * stage.a; if (g_NumTextures > 3) { stage = g_MaterialTexture3.Sample(g_TextureWrapSampler, input.uv3); output.rgb = output.rgb * (1.0 - stage.a) + stage.rgb * stage.a; if (g_NumTextures > 4) { stage = g_MaterialTexture4.Sample(g_TextureWrapSampler, input.uv4); output.rgb = output.rgb * (1.0 - stage.a) + stage.rgb * stage.a; if (g_NumTextures > 5) { stage = g_MaterialTexture5.Sample(g_TextureWrapSampler, input.uv5); output.rgb = output.rgb * (1.0 - stage.a) + stage.rgb * stage.a; if (g_NumTextures > 6) { stage = g_MaterialTexture6.Sample(g_TextureWrapSampler, input.uv6); output.rgb = output.rgb * (1.0 - stage.a) + stage.rgb * stage.a; if (g_NumTextures > 7) { stage = g_MaterialTexture7.Sample(g_TextureWrapSampler, input.uv7); output.rgb = output.rgb * (1.0 - stage.a) + stage.rgb * stage.a; } } } } } } } if (g_bLightEnabled) { float3 diffuse = input.diffuse.rgb; // do per-pixel light sourcing for point/spot lights for (int i = 0; i < g_NumPointLights; i++) { const float3 L = g_aPointLights[i].pos - input.pos_w.xyz; const float L2 = dot(L, L); if (L2 < g_aPointLights[i].Range2) { const float n_dot_l = dot(input.norm_w, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float Ln = lenL * g_aPointLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } cp *= (n_dot_l / lenL); diffuse += (g_aPointLights[i].color * cp); } } } for (int j = 0; j < g_NumSpotLights; j++) { const float3 L = g_aSpotLights[j].pos - input.pos_w.xyz; const float L2 = dot(L, L); if (L2 < g_aSpotLights[j].Range2) { const float n_dot_l = dot(input.norm_w, L); if (n_dot_l > 0.0) { const float lenL = sqrt(L2); const float inv_lenL = 1.0 / lenL; const float3 Lu = -L * inv_lenL; const float ca = dot(Lu, g_aSpotLights[j].dir); if (ca > g_aSpotLights[j].angles.y) { const float Ln = lenL * g_aSpotLights[i].invRange; float cp = 0; if (Ln < 0.5) { cp = 1.0-2.0*Ln*Ln; } else { cp = 2*(1.0-Ln)*(1.0-Ln); } if (ca < g_aSpotLights[j].angles.x) { cp *= (ca - g_aSpotLights[j].angles.y) * g_aSpotLights[j].angles.z; } cp *= (n_dot_l * inv_lenL); diffuse += (g_aSpotLights[i].color * cp); } } } } output.rgb *= saturate(diffuse); output.rgb += input.specular; } if (g_bFogEnabled) { output.rgb = add_fog(output.rgb, input.pos_w.w, input.pos_w.z); } } else { output = float4(g_FogColor, 1.0); } return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: TWPOSTPROCESS.FX // Copyright (c) 2009 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- // Based on Sample HDRFormats.FX file included with Microsoft DirectX SDK and // http://wiki.gamedev.net/index.php/D3DBook:High-Dynamic_Range_Rendering cbuffer cbGlobal { float g_LightLevel; float g_SunBrightness; // daylight sun brightness }; float2 g_avSampleOffsets[15]; float4 g_avSampleWeights[15]; Texture2D g_SceneTex0; Texture2D g_SceneTex1; Texture2D g_SceneTex2; SamplerState PointSampler { Filter = MIN_MAG_MIP_POINT; AddressU = Clamp; AddressV = Clamp; }; SamplerState LinearSampler { Filter = MIN_MAG_MIP_LINEAR; AddressU = Clamp; AddressV = Clamp; }; //-------------------------------------------------------------------------------------- // color space conversion functions //-------------------------------------------------------------------------------------- float3 GetYxyFromRGB(uniform float3 vRGB) { // RGB -> XYZ conversion ( http://www.w3.org/Graphics/Color/sRGB ) const float3x3 RGB2XYZ = { 0.5141f, 0.3239f, 0.1604f, 0.2651f, 0.6702f, 0.0641f, 0.0241f, 0.1228f, 0.8444f }; const float3 vXYZ = mul(RGB2XYZ, vRGB); // XYZ -> Yxy conversion: X = Y, x = X / (X + Y + Z), y = Y / (X + Y + Z) const float inv_XYZ = 1.0f / (vXYZ.r + vXYZ.g + vXYZ.b + 0.0001f); return ( float3(vXYZ.g, vXYZ.r * inv_XYZ, vXYZ.g * inv_XYZ) ); }; float3 GetRGBFromYxy(uniform float3 vYxy) { float3 vRGB = float3(0.0f, 0.0f, 0.0f); // make sure intesity is positive if (vYxy.r > 0.0f) { // Yxy -> XYZ conversion const float inv_Yxy = 1.0f / (vYxy.b + 0.0001f); const float3 vXYZ = float3( vYxy.r * vYxy.g * inv_Yxy, vYxy.r, vYxy.r * (1.0f - vYxy.g - vYxy.b) * inv_Yxy ); // XYZ -> RGB conversion const float3x3 XYZ2RGB = { 2.5651f,-1.1665f,-0.3986f, -1.0217f, 1.9777f, 0.0439f, 0.0753f,-0.2543f, 1.1892f }; vRGB = max(0, mul(XYZ2RGB, vXYZ)); // make sure rbg values are positive! } return (vRGB); }; //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- struct VS_INPUT { float4 pos : POSITION; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float2 uv : TEXCOORD; float4 pos : SV_POSITION; }; struct PS_INPUT { float2 uv : TEXCOORD; }; VS_OUTPUT VS_Quad( VS_INPUT input ) { VS_OUTPUT output; output.uv = input.uv; output.pos = input.pos; return output; } //-------------------------------------------------------------------------------------- // Pixel Shaders //-------------------------------------------------------------------------------------- //g_SceneTex0: DXGI_FORMAT_R16G16B16A16_FLOAT rendered scene texture //g_SceneTex1: DXGI_FORMAT_R16G16B16A16_FLOAT brightness scene texture //RenderTarget: DXGI_FORMAT_R16_FLOAT first level luminance map float PS_DownScale_Lum ( PS_INPUT input ) : SV_TARGET { const float3 RGB2Lum = { 0.2125f, 0.7154f, 0.0721f }; float4 vColor; float4 fBrightness; float fLum = 0.0f; float fLumSum = 0.0f; float fMaxBrightness = 0.0f; for( int y = -1; y <= 1; y++ ) { for( int x = -1; x <= 1; x++ ) { // Compute the sum of color values vColor = g_SceneTex0.Sample( PointSampler, input.uv, int2(x,y) ); fLumSum += dot( vColor.rgb, RGB2Lum ); fBrightness = g_SceneTex1.Sample( PointSampler, input.uv, int2(x,y) ); fMaxBrightness = max(fMaxBrightness, fBrightness.r); } } // take the average... fLumSum *= 0.1111f; // make it so brigtness drops off as we get away from the screen center float2 p = 2.0f * (input.uv - (float2)(0.5f, 0.5f)); float r = length(p.xy); if (r > 0.5f) { fMaxBrightness *= (1.0f - (r - 0.5f)); } fLumSum += fMaxBrightness; return (fLumSum); } //----------------------------------------------------------------------------- //g_SceneTex0: DXGI_FORMAT_R16_FLOAT previous level luminance map //RenderTarget: DXGI_FORMAT_R16_FLOAT next level luminance map float PS_DownScale( PS_INPUT input ) : SV_TARGET { float fLumSum = 0.0f; for( int y = -1; y <= 1; y++ ) { for( int x = -1; x <= 1; x++ ) { fLumSum += g_SceneTex0.Sample( PointSampler, input.uv, int2(x,y) ); } } return (fLumSum * 0.1111f); } //----------------------------------------------------------------------------- //g_SceneTex0: DXGI_FORMAT_R16G16B16A16_FLOAT rendered scene texture //g_SceneTex1: DXGI_FORMAT_R16G16B16A16_FLOAT brightness scene texture //RenderTarget: DXGI_FORMAT_R16G16B16A16_FLOAT bright-pass texture float4 PS_DownScale_BrightPass( PS_INPUT input ) : SV_TARGET { float4 vSample; float4 fBrightness; float3 vColor = 0.0f; float3 vMax = 0.0f; float fMaxBrightness = 0.0f; // take the average for( int y = -2; y <= 2; y++ ) { for( int x = -2; x <= 2; x++ ) { // Compute the sum of color values vSample = g_SceneTex0.Sample( PointSampler, input.uv, int2(x,y) ); vColor += vSample.rgb; vMax = max(vMax, vSample.rgb); fBrightness = g_SceneTex1.Sample( PointSampler, input.uv, int2(x,y) ); fMaxBrightness = max(fMaxBrightness, fBrightness.r); } } if (fMaxBrightness <= 0.0f) { // take the average vColor *= 0.04f; } else { // to make sure pixel sized bright spots (like tracers at distance) // are propagated, use the max value instead of average vColor = vMax; if (fMaxBrightness > 1.0f) { if (fMaxBrightness < 21.0f) { vColor *= (1.0f + 0.01f * (fMaxBrightness-1.0f) ); } else { vColor *= 1.2f; } } } // filter based on intesity float3 vYxy = GetYxyFromRGB(vColor); vYxy.r -= (0.1f + g_SunBrightness * 0.9f); vColor.rgb = GetRGBFromYxy(vYxy); return float4(vColor, 1.0f); } //----------------------------------------------------------------------------- //g_SceneTex0: DXGI_FORMAT_R16G16B16A16_FLOAT bright-pass texture or previous bloom texture //RenderTarget: DXGI_FORMAT_R16G16B16A16_FLOAT bloom texture float4 PS_Bloom( PS_INPUT input ) : SV_TARGET { float4 vSample = 0.0f; float4 vColor = 0.0f; float2 vSamplePosition; for( int iSample = 0; iSample < 15; iSample++ ) { // Sample from adjacent points vSamplePosition = input.uv + g_avSampleOffsets[iSample]; vColor = g_SceneTex0.Sample( PointSampler, vSamplePosition); vSample += g_avSampleWeights[iSample] * vColor; } return vSample; } //----------------------------------------------------------------------------- //g_SceneTex0: DXGI_FORMAT_R16G16B16A16_FLOAT rendered scene texture //g_SceneTex1: DXGI_FORMAT_R16_FLOAT luminance map (single pixel) //g_SceneTex1: DXGI_FORMAT_R16G16B16A16_FLOAT final bloom texture //RenderTarget: DXGI_FORMAT_R16G16B16A16_FLOAT output buffer float4 PS_FinalPass( PS_INPUT input ) : SV_TARGET { float4 vColor = g_SceneTex0.Sample( PointSampler, input.uv ); float3 vYxy = GetYxyFromRGB(vColor.rgb); // scale luminance const float fLumAve = g_SceneTex1.Sample( PointSampler, float2(0,0) ); const float fMiddleGray = g_LightLevel * 0.50f + 0.08f; const float fToneMapScale = clamp(0.0f, 2.0f, fMiddleGray / (fLumAve + 0.0001f)); float fLumScaled = vYxy.r; if (fToneMapScale <= 1.0f) { fLumScaled *= (0.5f + 0.5f * fToneMapScale); } else { fLumScaled *= (1.0f + (fToneMapScale-1.0f) * 0.1f); } float fWhiteMin = 0.6f + g_LightLevel * 0.4f; float fWhiteMin2 = fWhiteMin * fWhiteMin; vYxy.r = fLumScaled * (1.0f + fLumScaled / fWhiteMin2) / (1.0f + fLumScaled); vColor.rgb = GetRGBFromYxy(vYxy); // add bloom vColor.rgb += g_SceneTex2.Sample( LinearSampler, input.uv ); // add very slight vignette effect float2 p = 2.0f * (input.uv - (float2)(0.5f, 0.5f)); float r = length(p.xy); if (r > 0.8f) { vColor.rgb *= (1.0f - 0.1f * (r - 0.8f)); } vColor.a = 1.0f; return vColor; } //----------------------------------------------------------------------------- // Techniques //----------------------------------------------------------------------------- technique10 DownScale_Lum { pass p0 { SetVertexShader( CompileShader( vs_4_0, VS_Quad() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS_DownScale_Lum() ) ); } } //----------------------------------------------------------------------------- technique10 DownScale { pass p0 { SetVertexShader( CompileShader( vs_4_0, VS_Quad() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS_DownScale() ) ); } } //----------------------------------------------------------------------------- technique10 DownScale_BrightPass { pass p0 { SetVertexShader( CompileShader( vs_4_0, VS_Quad() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS_DownScale_BrightPass() ) ); } } //----------------------------------------------------------------------------- technique10 Bloom { pass p0 { SetVertexShader( CompileShader( vs_4_0, VS_Quad() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS_Bloom() ) ); } } //----------------------------------------------------------------------------- technique10 FinalPass { pass p0 { SetVertexShader( CompileShader( vs_4_0, VS_Quad() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS_FinalPass() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: TWSHADOWDYNAMIC.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mViewProj; float g_InvFarClip; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; float g_ShadowVert; float3 g_ShadowLength; }; struct VS_INPUT { float3 pos : POSITION; float vertex : COLOR; }; struct VS_OUTPUT { float4 pos : SV_POSITION; }; //-------------------------------------------------------------------------------------- float precision_add_z( const float z1, const float z2, const float z3, const float z4 ) { float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // try to recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from prev add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = z4 - z_err; // include the lost low part from prev add... return (z_sum + z_add); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; pos.z = precision_add_z(P.x * g_mViewProj[0][2], P.y * g_mViewProj[1][2], P.z * g_mViewProj[2][2], g_mViewProj[3][2]); pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space if (input.vertex >= g_ShadowVert) { P.xyz += g_ShadowLength; } // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( NULL ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: TWSHADOWSTATIC.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float4x4 g_mViewProj; float g_InvFarClip; }; cbuffer cbPerMesh { float4x4 g_mMeshToWorld; }; struct VS_INPUT { float3 pos : POSITION; }; struct VS_OUTPUT { float4 pos : SV_POSITION; }; //-------------------------------------------------------------------------------------- float precision_add_z( const float z1, const float z2, const float z3, const float z4 ) { float z_sum = 0.0; float z_add = 0.0; float z_largest = 0.0; float z_temp = 0.0; float z_err = 0.0; if (z1 > z2) { z_sum = z2; if (z1 > z3) { z_largest = z1; z_add = z3; } else { z_largest = z3; z_add = z1; } } else { z_sum = z1; if (z2 > z3) { z_largest = z2; z_add = z3; } else { z_largest = z3; z_add = z2; } } // use Kahan summation z_temp = z_sum + z_add; // if z_sum is big and z_add small, low-order digits can get lost... z_err = (z_temp - z_sum) - z_add; // try to recover the lost digits... z_sum = z_temp; z_add = z_largest - z_err; // include the lost low part from prev add...... z_temp = z_sum + z_add; z_err = (z_temp - z_sum) - z_add; z_sum = z_temp; z_add = z4 - z_err; // include the lost low part from prev add... return (z_sum + z_add); } //-------------------------------------------------------------------------------------- float4 compute_pos( const float4 P ) { float4 pos; // try to compute z with minimal loss of precision ... // TK TODO DX11/SM5.0 has double! pos.x = P.x * g_mViewProj[0][0] + P.y * g_mViewProj[1][0] + P.z * g_mViewProj[2][0]; pos.y = P.x * g_mViewProj[0][1] + P.y * g_mViewProj[1][1] + P.z * g_mViewProj[2][1]; pos.z = precision_add_z(P.x * g_mViewProj[0][2], P.y * g_mViewProj[1][2], P.z * g_mViewProj[2][2], g_mViewProj[3][2]); pos.w = P.x * g_mViewProj[0][3] + P.y * g_mViewProj[1][3] + P.z * g_mViewProj[2][3] + g_mViewProj[3][3]; return (pos); } //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; const float4 P = mul(float4(input.pos, 1.0), g_mMeshToWorld); // position, world-space // output.pos = mul(P, g_mViewProj); output.pos = compute_pos(P); return output; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( NULL ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: TWSTENCIL.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- float4 VS( float4 Pos : POSITION ) : SV_POSITION { return Pos; } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( NULL ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: TWTRANSFORMED0.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float g_InvScreenWidth; float g_InvScreenHeight; float2 g_ViewportTopLeft; }; struct VS_INPUT { float4 pos : POSITION; float4 diffuse : COLOR; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float4 diffuse : COLOR; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 diffuse : COLOR; }; //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; //convert from screen coordinates to clip space coordinates output.pos.x = (input.pos.x - g_ViewportTopLeft.x) * 2.0f * g_InvScreenWidth - 1.0f; output.pos.y = 1.0f - (input.pos.y - g_ViewportTopLeft.y) * 2.0f * g_InvScreenHeight; output.pos.z = input.pos.z; output.pos.w = input.pos.w; output.diffuse = input.diffuse; return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { return (input.diffuse); } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: TWTRANSFORMED1.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float g_InvScreenWidth; float g_InvScreenHeight; float2 g_ViewportTopLeft; }; Texture2D g_MaterialTexture; SamplerState g_LinearSampler { Filter = MIN_MAG_MIP_LINEAR; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float4 pos : POSITION; float4 diffuse : COLOR; float2 uv : TEXCOORD; }; struct VS_OUTPUT { float4 diffuse : COLOR; float2 uv : TEXCOORD; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 diffuse : COLOR; float2 uv : TEXCOORD; }; //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; //convert from screen coordinates to clip space coordinates output.pos.x = (input.pos.x - g_ViewportTopLeft.x) * 2.0f * g_InvScreenWidth - 1.0f; output.pos.y = 1.0f - (input.pos.y - g_ViewportTopLeft.y) * 2.0f * g_InvScreenHeight; output.pos.z = input.pos.z; output.pos.w = input.pos.w; output.diffuse = input.diffuse; output.uv = input.uv; return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output = g_MaterialTexture.Sample(g_LinearSampler, input.uv); return (input.diffuse * output); } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: TWTRANSFORMED2.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float g_InvScreenWidth; float g_InvScreenHeight; float2 g_ViewportTopLeft; }; cbuffer cbPerMaterial { int g_NumTextures; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; SamplerState g_LinearSampler { Filter = MIN_MAG_MIP_LINEAR; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float4 pos : POSITION; float4 diffuse : COLOR; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; }; struct VS_OUTPUT { float4 diffuse : COLOR; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 diffuse : COLOR; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; }; //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; //convert from screen coordinates to clip space coordinates output.pos.x = (input.pos.x - g_ViewportTopLeft.x) * 2.0f * g_InvScreenWidth - 1.0f; output.pos.y = 1.0f - (input.pos.y - g_ViewportTopLeft.y) * 2.0f * g_InvScreenHeight; output.pos.z = input.pos.z; output.pos.w = input.pos.w; output.diffuse = input.diffuse; output.uv0 = input.uv0; output.uv1 = input.uv1; return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output = g_MaterialTexture0.Sample(g_LinearSampler, input.uv0); if (g_NumTextures > 1) { float4 stage = g_MaterialTexture1.Sample(g_LinearSampler, input.uv1); output.rgb = output.rgb * (1.0 - stage.a) + stage.rgb * stage.a; } return (input.diffuse * output); } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // File: TWTRANSFORMED8.FX // Copyright (c) 2008 Third Wire Productions, Inc. //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- // Constant Buffers //-------------------------------------------------------------------------------------- cbuffer cbGlobal { float g_InvScreenWidth; float g_InvScreenHeight; float2 g_ViewportTopLeft; }; cbuffer cbPerMaterial { int g_NumTextures; }; Texture2D g_MaterialTexture0; Texture2D g_MaterialTexture1; Texture2D g_MaterialTexture2; Texture2D g_MaterialTexture3; Texture2D g_MaterialTexture4; Texture2D g_MaterialTexture5; Texture2D g_MaterialTexture6; Texture2D g_MaterialTexture7; SamplerState g_LinearSampler { Filter = MIN_MAG_MIP_LINEAR; AddressU = Clamp; AddressV = Clamp; }; struct VS_INPUT { float4 pos : POSITION; float4 diffuse : COLOR; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; struct VS_OUTPUT { float4 diffuse : COLOR; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; float4 pos : SV_POSITION; }; struct PS_INPUT { float4 diffuse : COLOR; float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; float2 uv2 : TEXCOORD2; float2 uv3 : TEXCOORD3; float2 uv4 : TEXCOORD4; float2 uv5 : TEXCOORD5; float2 uv6 : TEXCOORD6; float2 uv7 : TEXCOORD7; }; //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS( VS_INPUT input ) { VS_OUTPUT output; //convert from screen coordinates to clip space coordinates output.pos.x = (input.pos.x - g_ViewportTopLeft.x) * 2.0f * g_InvScreenWidth - 1.0f; output.pos.y = 1.0f - (input.pos.y - g_ViewportTopLeft.y) * 2.0f * g_InvScreenHeight; output.pos.z = input.pos.z; output.pos.w = input.pos.w; output.diffuse = input.diffuse; output.uv0 = input.uv0; output.uv1 = input.uv1; output.uv2 = input.uv2; output.uv3 = input.uv3; output.uv4 = input.uv4; output.uv5 = input.uv5; output.uv6 = input.uv6; output.uv7 = input.uv7; return output; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( PS_INPUT input ) : SV_TARGET { float4 output = g_MaterialTexture0.Sample(g_LinearSampler, input.uv0); float4 stage; if (g_NumTextures > 1) { stage = g_MaterialTexture1.Sample(g_LinearSampler, input.uv1); output.rgb = output.rgb * (1.0 - stage.a) + stage.rgb * stage.a; if (g_NumTextures > 2) { stage = g_MaterialTexture2.Sample(g_LinearSampler, input.uv2); output.rgb = output.rgb * (1.0 - stage.a) + stage.rgb * stage.a; if (g_NumTextures > 3) { stage = g_MaterialTexture3.Sample(g_LinearSampler, input.uv3); output.rgb = output.rgb * (1.0 - stage.a) + stage.rgb * stage.a; if (g_NumTextures > 4) { stage = g_MaterialTexture4.Sample(g_LinearSampler, input.uv4); output.rgb = output.rgb * (1.0 - stage.a) + stage.rgb * stage.a; if (g_NumTextures > 5) { stage = g_MaterialTexture5.Sample(g_LinearSampler, input.uv5); output.rgb = output.rgb * (1.0 - stage.a) + stage.rgb * stage.a; if (g_NumTextures > 6) { stage = g_MaterialTexture6.Sample(g_LinearSampler, input.uv6); output.rgb = output.rgb * (1.0 - stage.a) + stage.rgb * stage.a; if (g_NumTextures > 7) { stage = g_MaterialTexture7.Sample(g_LinearSampler, input.uv7); output.rgb = output.rgb * (1.0 - stage.a) + stage.rgb * stage.a; } } } } } } } return (input.diffuse * output); } //-------------------------------------------------------------------------------------- technique10 Render { pass P0 { SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } } //-------------------------------------------------------------------------------------- //====================================================================================== //--------------------------------------------------------------------------------------