History: Terrain Alphasplat Shader
Source of version: 4 (current)
Copy to clipboard
This shader is written in hlsl, but is used as CG here. 11 textures are passed to the vertex shader: two alphamaps, eight splat textures and a detail map. Works in OpenGL as well as in D3D.
{CODE(wrap="1", colors="c++")}struct TerrainVSOutput
{
// transformed vertex coordinate
float4 position : POSITION;
// lighting intensity color multiplier
float4 color : COLOR0;
// texture coordinate from vertex
float2 texCoord : TEXCOORD0;
// texture coordinate from vertex that has been scaled
float2 scaledTexCoord : TEXCOORD2;
// world coordinates of the vertex (one unit per meter)
float2 worldTexCoord : TEXCOORD3;
// world coordinates of the vertex (one unit per page)
float2 worldPageTexCoord : TEXCOORD4;
// offset of the vertex within the current terrain page (one unit per page, so its limited to 0..1)
float2 pageTexCoord : TEXCOORD5;
// texture coordinates for alpha0 splatting map
float2 alpha0TexCoord : TEXCOORD6;
// texture coordinates for alpha1 splatting map
float2 alpha1TexCoord : TEXCOORD7;
// fog factor
float fog : FOG;
};
// Vertex program for automatic terrain texture generation
TerrainVSOutput TerrainVP
(
float4 iPosition : POSITION,
float3 iNormal : NORMAL,
float2 iTexcoord : TEXCOORD0,
// the full World/View/Proj combined matrix
uniform float4x4 worldViewProj,
// Just the world matrix. Used to find the world coordinates of the vertices for generating
// some texture coordinates
uniform float4x4 worldMat,
// Fog settings
// fogSettings[0] - fog near distance
// fogSettings[1] - fog far distance
// fogSettings[2] - fog scale
uniform float4 fogSettings,
uniform float4 LightPosition[2],
uniform float4 LightAttenuation[2],
// Diffuse color of the light
uniform float4 LightDiffuse[2],
// Color of the ambient light
uniform float4 lightAmbient,
// Diffuse color of the terrain
uniform float4 materialDiffuse,
// Ambient color of the terrain
uniform float4 materialAmbient,
// Size of a terrain page
uniform float pageSize,
// How many meters is one tiling of the terrain textures
uniform float textureTileSize,
// used to convert page texture coord to alpha map texture coords
uniform float4 alpha0TextureCoordAdjust,
uniform float4 alpha1TextureCoordAdjust
)
{
TerrainVSOutput output;
// Calculate the output position and texture coordinates
output.position = mul(worldViewProj,iPosition);
output.texCoord = float2(iPosition.x, iPosition.z)/pageSize;
output.scaledTexCoord = output.texCoord * 256.0f / textureTileSize;
float3 lightDirection[2];
float lightAttenuation[2];
// transform position to world space
float4 position = mul(worldMat, iPosition);
// get the light and eye direction in world space (not normalized)
for (int lightIndex = 0; lightIndex < 2; ++lightIndex) {
float4 lightPosition = mul(worldMat, LightPosition[lightIndex]);
// Account for whether the light is a point source.
lightDirection[lightIndex] = lightPosition.xyz - (position * lightPosition.w).xyz;
// set up attenuation params
float lightDistance = length(lightDirection[lightIndex]);
float lightDistanceSquared = lightDistance * lightDistance;
//lightDistance = 1;
//LightAttenuation[1].x = 0;
lightAttenuation[lightIndex] = (lightDistance >
LightAttenuation[lightIndex].x) ?
0 : (1 / (LightAttenuation[lightIndex].y +
LightAttenuation[lightIndex].z * lightDistance +
LightAttenuation[lightIndex].w * lightDistanceSquared));
}
// Do lighting calculations
output.color = saturate(
max(dot(iNormal, normalize(lightDirection[0])), 0) * // diffuse lighting
LightDiffuse[0] * materialDiffuse * lightAttenuation[0] + // diffuse color
max(dot(iNormal, normalize(lightDirection[1])), 0) * // diffuse lighting
LightDiffuse[1] * materialDiffuse * lightAttenuation[1] + // diffuse color
lightAmbient * materialAmbient); // ambient color
// compute page relative offset of vertex, for use as a texture coord
output.pageTexCoord = fmod( float2(worldMat._m03, worldMat._m23), float2(pageSize, pageSize) );
if ( output.pageTexCoord.x < 0 ) {
output.pageTexCoord.x += pageSize;
}
if ( output.pageTexCoord.y < 0 ) {
output.pageTexCoord.y += pageSize;
}
output.pageTexCoord = float2(iPosition.x, iPosition.z) / pageSize;
// compute world world coordinates (just 2d) of vertex, for use as texture coord
output.worldTexCoord = ( float2(worldMat._m03, worldMat._m23) + float2(iPosition.x, iPosition.z) );
// scale world coords to page size (one unit is one page)
output.worldPageTexCoord = output.worldTexCoord / pageSize;
// scale world coords to be one unit per meter
output.worldTexCoord /= 1000;
// compute alpha map texture coords
output.alpha0TexCoord = output.pageTexCoord * alpha0TextureCoordAdjust.yw + alpha0TextureCoordAdjust.xz;
output.alpha1TexCoord = output.pageTexCoord * alpha1TextureCoordAdjust.yw + alpha1TextureCoordAdjust.xz;
// compute fog
float fog = clamp(( output.position.z - fogSettings[0] ) / (fogSettings[1] - fogSettings[0]),0.0,1.0) * fogSettings[2];
output.fog = 1.0 - fog;
return output;
}
//
// Fragment program for automatic terrain texture generation
// This fragment program splats 4 different terrain textures, and then applies a shade
// mask to vary the intensity of the terrain
//
float4 TerrainFP(
// output of vertex shader
TerrainVSOutput In,
uniform float4 alpha0Mask,
uniform float4 alpha1Mask,
// alpha map 0
uniform sampler2D alphaMap0Sampler : register(s0),
// alpha map 1
uniform sampler2D alphaMap1Sampler : register(s1),
// layer 0 texture
uniform sampler2D layer0Sampler : register(s2),
// layer 1 texture
uniform sampler2D layer1Sampler : register(s3),
// layer 2 texture
uniform sampler2D layer2Sampler : register(s4),
// layer 3 texture
uniform sampler2D layer3Sampler : register(s5),
// layer 4 texture
uniform sampler2D layer4Sampler : register(s6),
// layer 5 texture
uniform sampler2D layer5Sampler : register(s7),
// layer 6 texture
uniform sampler2D layer6Sampler : register(s8),
// layer 7 texture
uniform sampler2D layer7Sampler : register(s9),
// detail texture
uniform sampler2D detailSampler : register(s10)
) : COLOR
{
float4 outputColor;
//return In.color;
// XXX - use worldPageTexCoord for now
float4 alpha0 = tex2D(alphaMap0Sampler, In.alpha0TexCoord);
float4 alpha1 = tex2D(alphaMap1Sampler, In.alpha1TexCoord);
alpha0 = alpha0 * alpha0Mask;
alpha1 = alpha1 * alpha1Mask;
float4 l0 = tex2D(layer0Sampler, In.scaledTexCoord.xy);
float4 l1 = tex2D(layer1Sampler, In.scaledTexCoord.xy);
float4 l2 = tex2D(layer2Sampler, In.scaledTexCoord.xy);
float4 l3 = tex2D(layer3Sampler, In.scaledTexCoord.xy);
float4 l4 = tex2D(layer4Sampler, In.scaledTexCoord.xy);
float4 l5 = tex2D(layer5Sampler, In.scaledTexCoord.xy);
float4 l6 = tex2D(layer6Sampler, In.scaledTexCoord.xy);
float4 l7 = tex2D(layer7Sampler, In.scaledTexCoord.xy);
outputColor = alpha0.r * l0 + alpha0.g * l1 + alpha0.b * l2 + alpha0.a * l3
+ alpha1.r * l4 + alpha1.g * l5 + alpha1.b * l6 + alpha1.a * l7;
// scale output color by the color from the vertex shader, which is the
// output of the lighting calculations
outputColor *= In.color;
// add detail map
outputColor *= tex2D(detailSampler, In.pageTexCoord.xy);
return outputColor;
}{CODE}
---
Alias: (alias(Terrain_Alphasplat_Shader))