// Compulsory lines for entry points // #o3d VertexShaderEntryPoint VS // #o3d PixelShaderEntryPoint PS // #o3d MatrixLoadOrder RowMajor float4x4 worldViewProjection : WorldViewProjection; // The 4x4 world view projection matrix. float4x4 worldInverseTranspose : WorldInverseTranspose; float4x4 world : World; float4x4 viewInverse : ViewInverse; float4x4 view : VIEW; float GlobalTime; float3 LightWorldPosition; float3 LightWorldDirection; float4 LightColor; float RangeMin; // The range at which the light's power starts to decrease float RangeMax; // The range at which the light's power is 0 float RangeAttenuationPower; // The power at which range is decreasing (<1 is rapidly, >1 is slowly) float CosAngleMin; // The cos(angle/2) at which the light's power starts to decrease float CosAngleMax; // The cos(angle/2) at which the light's power is 0 float AngleAttenuationPower; // The power at which angle is decreasing (<1 is rapidly, >1 is slowly) sampler2D SamplerDiffuse; sampler2D SamplerNormal; //////////////////////////////////////////////////////////////// // struct VertexShaderInput { float4 Position : POSITION; float4 Normal : NORMAL; float4 Tangent : TANGENT; float4 Binormal : BINORMAL; float2 UV : TEXCOORD0; }; struct PixelShaderInput { float4 Position : POSITION; float2 UV : TEXCOORD0; float3 Normal : TEXCOORD1; float3 Tangent : TEXCOORD2; float3 Binormal : TEXCOORD3; float3 WorldPosition : TEXCOORD4; }; //////////////////////////////////////////////////////////////// // Function declaration for Spotlight attenuation // // _Position, the world position to light with the spot // Returns the spot attenuation to multiply the light color with and use in the lighting equation // NOTE: This is ONE possible implementation of a spotlight, it's not "THE SPOTLIGHT CODE" ! :) // float ComputeSpotAttenuation( float3 _Position ) { float3 ToPixel = _Position - LightWorldPosition; float fDistance = length( ToPixel ); // This also gives us the distance of the pixel from the spotlight ToPixel /= fDistance; // Normalize float fRangeAttenuation = saturate( (RangeMax - fDistance) / (RangeMax - RangeMin) ); float fAngularAttenuation = saturate( (dot( ToPixel, LightWorldDirection ) - CosAngleMax) / (CosAngleMin - CosAngleMax) ); return pow( fRangeAttenuation, RangeAttenuationPower ) * pow( fAngularAttenuation, AngleAttenuationPower ); } //////////////////////////////////////////////////////////////// // PixelShaderInput VS( VertexShaderInput _Input ) { PixelShaderInput output; // Transform Position into clip space. output.Position = mul( _Input.Position, worldViewProjection ); // Transform the Tangent frame into world space. output.Tangent = mul( float4( _Input.Tangent.xyz, 0 ), world ).xyz; output.Binormal = mul( float4( _Input.Binormal.xyz, 0 ), world ).xyz; output.Normal = mul( float4( _Input.Normal.xyz, 0 ), world ).xyz; // Pass through the texture coordinates. output.UV = float2( 2 * _Input.UV.y, 1 - _Input.UV.x ); // Calculate surface Position in world space. Used for lighting. output.WorldPosition = mul( _Input.Position, world ).xyz; return output; } float4 PS( PixelShaderInput _Input ) : COLOR { _Input.Tangent = normalize( _Input.Tangent ); _Input.Binormal = normalize( _Input.Binormal ); _Input.Normal = normalize( _Input.Normal ); LightWorldDirection = normalize( LightWorldDirection ); // Compute view vector float3 ToCamera = viewInverse[3].xyz - _Input.WorldPosition.xyz; float fCameraDistance = length( ToCamera ); ToCamera /= fCameraDistance; // Compute light vector float3 ToLight = LightWorldPosition - _Input.WorldPosition.xyz; float fLightDistance = length( ToLight ); ToLight /= fLightDistance; ///////////////////////////////////////////////////////// // Compute attenuation due to spotlight // LightColor *= ComputeSpotAttenuation( _Input.WorldPosition.xyz ); // Simply multiply the light color with the attenuation, no need to change the lighting equation below // ///////////////////////////////////////////////////////// // Construct a transform from Tangent space into world space. float3x3 Tangent2World = float3x3( _Input.Binormal, _Input.Tangent, _Input.Normal ); // Read the diffuse & normal float4 DiffuseColor = tex2D( SamplerDiffuse, _Input.UV ); float3 Normal = 2 * tex2D( SamplerNormal, _Input.UV ).xyz - 1; Normal = normalize( mul( Normal, Tangent2World ) ); float4 AmbientColor = 0.5 * float4( 0, 0.1, 0.2, 1 ); float4 SpecularColor = float4( 1, 1, 1, 1 ); // Apply lighting in world space float3 HalfVector = normalize( ToLight + ToCamera ); float4 Lighting = lit( dot( Normal, ToLight ), dot( Normal, HalfVector ), 20.0 ); float4 Result = AmbientColor * DiffuseColor + LightColor * (DiffuseColor * Lighting.y + SpecularColor * Lighting.z); return float4( Result.rgb, 1 ); }