Thursday 28 June 2012

SM3 Fog



So here is the SM3 (Shader Model 3) HLSL fog. Now this is taken pretty much 99% from Leaf's example, but thought I would comment on how easy this technique is to put into your existing shaders.



I also found that adding this to a shader pushes the operation count up a fair bit, the limit in SM2 is 64 operations per shader, so 128 in all, 64 in the Vertex Shader and another 64 in the Pixel Shader. So What I did was put the fog code into a second pass so giving me another 64x64 operation slots to play with.

So here are the shaders:

This first shader is the one used for the buildings you see in the shots, it is a single pass and a simple texture shader.

ShaderFog.fx
float4x4 World : World;
float4x4 WorldViewProject : WorldViewProjection;
float3 EyePosition : CameraPosition;
texture thisTexture;
float3 LightPos = (0,-1,0);
float4 ambient = {0.25, 0.25, 0.25, 1.0};
float4 diffuse = {1.0, 1.0, 1.0, 1.0};
float4 specularColor = {0.2, 0.2, 0.2, 1.0};
float shininess = 40;
float fogNear = 10;
float fogFar = 100;
float fogAltitudeScale = 10;
float fogThinning = 100;
float4 fogColor = {0.5, 0.5, 0.5, 1.0};
sampler TextureSampler = sampler_state
{
Texture = <thisTexture>;
};
struct VS_INPUT
{
float4 Position : POSITION0;
float2 Texcoord : TEXCOORD0;
float3 Normal : NORMAL0;
};
struct VS_OUTPUT
{
float4 Position : POSITION;
float2 Texcoord : TEXCOORD0;
float3 Normal : TEXCOORD1;
float3 WorldPos : TEXCOORD2;
};
struct PS_INPUT
{
float4 Position : TEXCOORD4;
float2 Texcoord : TEXCOORD0;
float3 Normal : TEXCOORD1;
float3 WorldPos : TEXCOORD2;
};
float4 blinn2(
float3 N,
float3 L,
float3 V,
uniform float4 diffuseColor,
uniform float4 specularColor,
uniform float shininess)
{
float3 H = normalize(V+L);
float4 lighting = lit(dot(L,N), dot(H,N), shininess);
return diffuseColor*lighting.y + specularColor*lighting.z;
}
VS_OUTPUT Transform(VS_INPUT Input)
{
VS_OUTPUT Output;
Output.WorldPos = mul(Input.Position,World);
Output.Position = mul(Input.Position, WorldViewProject);
Output.Texcoord = Input.Texcoord;
Output.Normal = mul(Input.Normal,World);
return Output;
}
float4 Texture(PS_INPUT Input) : COLOR0
{
float4 colorMap = tex2D(TextureSampler, Input.Texcoord.xy) * 1.5;
float3 N = normalize(Input.Normal);
float3 V = normalize(EyePosition - Input.WorldPos);
float3 L = normalize(LightPos - Input.WorldPos);
float4 C = ambient*colorMap;
C += blinn2(N, L, V, colorMap * diffuse, specularColor * colorMap.a, shininess);
float d = length(Input.WorldPos - EyePosition);
float l = saturate((d - fogNear) / (fogFar - fogNear) / clamp(Input.Position.y / fogAltitudeScale + 1, 1, fogThinning));
return lerp(C, fogColor, l);
};
technique TransformTexture
{
pass P0
{
VertexShader = compile vs_1_1 Transform();
PixelShader = compile ps_2_0 Texture();
}
}

This is the shader I use for the floor tile, again this is a single pass. Just a variation on the theam really.


Floor.fx
float4x4 World : World;
float4x4 WorldViewProject : WorldViewProjection;
float3 EyePosition : CameraPosition;
texture thisTexture;
float3 LightPos = (0,-1,0);
float4 ambient = {0.25, 0.25, 0.25, 1.0};
float4 diffuse = {1.0, 1.0, 1.0, 1.0};
float4 specularColor = {0.2, 0.2, 0.2, 1.0};
float shininess = 0;
float fogNear = 10;
float fogFar = 100;
float fogAltitudeScale = 10;
float fogThinning = 100;
float4 fogColor = {0.5, 0.5, 0.5, 1.0};
sampler TextureSampler = sampler_state
{
Texture = <thisTexture>;
};
struct VS_INPUT
{
float4 Position : POSITION0;
float2 Texcoord : TEXCOORD0;
float3 Normal : NORMAL0;
};
struct VS_OUTPUT
{
float4 Position : POSITION;
float2 Texcoord : TEXCOORD0;
float3 Normal : TEXCOORD1;
float3 WorldPos : TEXCOORD2;
};
struct PS_INPUT
{
float4 Position : TEXCOORD4;
float2 Texcoord : TEXCOORD0;
float3 Normal : TEXCOORD1;
float3 WorldPos : TEXCOORD2;
};
float4 blinn2(
float3 N,
float3 L,
float3 V,
uniform float4 diffuseColor,
uniform float4 specularColor,
uniform float shininess)
{
float3 H = normalize(V+L);
float4 lighting = lit(dot(L,N), dot(H,N), shininess);
return diffuseColor*lighting.y + specularColor*lighting.z;
}
VS_OUTPUT Transform(VS_INPUT Input)
{
VS_OUTPUT Output;
Output.WorldPos = mul(Input.Position,World);
Output.Position = mul(Input.Position, WorldViewProject);
Output.Texcoord = Input.Texcoord * 500;
Output.Normal = mul(Input.Normal,World);
return Output;
}
float4 Texture(PS_INPUT Input) : COLOR0
{
float4 colorMap = tex2D(TextureSampler, Input.Texcoord.xy);
float3 N = normalize(Input.Normal);
float3 V = normalize(EyePosition - Input.WorldPos);
float3 L = normalize(LightPos - Input.WorldPos);
float4 C = ambient*colorMap;
C += blinn2(N, L, V, colorMap * diffuse, specularColor * colorMap.a, shininess);
float d = length(Input.WorldPos - EyePosition);
float l = saturate((d - fogNear) / (fogFar - fogNear) / clamp(Input.Position.y / fogAltitudeScale + 1, 1, fogThinning));
return lerp(C, fogColor, l);
};
technique TransformTexture
{
pass P0
{
VertexShader = compile vs_1_1 Transform();
PixelShader = compile ps_2_0 Texture();
}
}

And finaly this is the shader used for the sky box, now, you may think, why is he using a sky box when he has such dense fog? Well it is here as an example and this is where I have put the fog calcs into the second pass so you can see how to do it (or rather how I did it)

/////////////////////////////////////////////////////////////
// //
// Writen by C.Humphrey //
// 26/07/2007 //
// //
// //
// Shader used to render a cube map to an inverted box //
// mesh. //
// //
// 17/08/2006 Multi pass fog aded. //
// //
//////////////////////////////////////////////////////////////
Texture surfaceTexture;
samplerCUBE TextureSampler = sampler_state
{
texture = <surfaceTexture> ;
magfilter = LINEAR;
minfilter = LINEAR;
mipfilter = LINEAR;
AddressU = Mirror;
AddressV = Mirror;
};
float4x4 World : World;
float4x4 View : View;
float4x4 Projection : Projection;
float3 EyePosition : CameraPosition;
float4 ambient = {0.25, 0.25, 0.25, 1.0};
float4 diffuse = {1.0, 1.0, 1.0, 1.0};
float4 specularColor = {0.2, 0.2, 0.2, 1.0};
float shininess = 10;
float fogNear = 500;
float fogFar = 1000;
float fogAltitudeScale = 0;
float fogThinning = 1;
float4 fogColor = {0.5, 0.5, 0.5, 1.0};
float4 c;
struct VS_INPUT
{
float4 Position : POSITION0;
float3 Normal : NORMAL0;
};
struct VS_OUTPUT
{
float4 Position : POSITION0;
float3 ViewDirection : TEXCOORD2;
float3 Normal : TEXCOORD0;
float4 WorldPos : TEXCOORD1;
};
float4 CubeMapLookup(float3 CubeTexcoord)
{
return texCUBE(TextureSampler, CubeTexcoord);
}
VS_OUTPUT Transform(VS_INPUT Input)
{
float4x4 WorldViewProjection = mul(mul(World, View), Projection);
float3 ObjectPosition = mul(Input.Position, World);
VS_OUTPUT Output;
Output.Position = mul(Input.Position, WorldViewProjection);
Output.ViewDirection = EyePosition - ObjectPosition;
Output.WorldPos = mul(Input.Position,World);
Output.Normal = mul(Input.Normal,World);
return Output;
}
float4 blinn2(
float3 N,
float3 L,
float3 V,
uniform float4 diffuseColor,
uniform float4 specularColor,
uniform float shininess)
{
float3 H = normalize(V+L);
float4 lighting = lit(dot(L,N), dot(H,N), shininess);
return diffuseColor*lighting.y + specularColor*lighting.z;
}
struct PS_INPUT
{
float3 ViewDirection : TEXCOORD2;
float3 Normal : TEXCOORD0;
float3 WorldPos : TEXCOORD1;
float4 Position : TEXCOORD3;
};
float4 BasicShader(PS_INPUT Input) : COLOR0
{
float3 ViewDirection = normalize(Input.ViewDirection);
float4 C = CubeMapLookup(-ViewDirection);
c = C;
return C;
}
float4 Fog(PS_INPUT Input) : COLOR0
{
float3 ViewDirection = normalize(Input.ViewDirection);
float3 N = normalize(Input.Normal);
float3 V = normalize(EyePosition - Input.WorldPos);
float3 L = normalize(Input.WorldPos);
L = normalize(Input.WorldPos);
float4 C = c;
C += blinn2(N, L, V, C * diffuse, specularColor * C.a, shininess);
float d = fogFar-(fogFar/35);
float l = saturate((d - fogNear) / (fogFar - fogNear) / clamp(Input.Position.y / fogAltitudeScale + 1, 1, fogThinning));
return lerp(C, fogColor, l);
}
technique BasicShader
{
pass P0
{
VertexShader = compile vs_2_0 Transform();
PixelShader = compile ps_2_0 BasicShader();
}
pass P1
{
AlphaBlendEnable = true;
SrcBlend = SrcAlpha;
DestBlend = InvSrcAlpha;
PixelShader = compile ps_2_0 Fog();
}
}



Controls
Mouse rotates camera
Arrow Keys translate camera
Esc to exit.

GenericExampleShaderFog.zip

No comments:

Post a Comment