Files
FlaxEngine/Content/Editor/MaterialTemplates/Terrain.shader

798 lines
24 KiB
GLSL

// File generated by Flax Materials Editor
// Version: @0
#define MATERIAL 1
@3
// Enables/disables smooth terrain chunks LOD transitions (with morphing higher LOD near edges to the lower LOD in the neighbour)
#define USE_SMOOTH_LOD_TRANSITION 1
// Switches between using 0, 4 or 8 heightmap layers (values: 0, 1, 2)
#define TERRAIN_LAYERS_DATA_SIZE 2
#define USE_TERRAIN_LAYERS (TERRAIN_LAYERS_DATA_SIZE > 0)
#include "./Flax/Common.hlsl"
#include "./Flax/MaterialCommon.hlsl"
#include "./Flax/GBufferCommon.hlsl"
@7
// Primary constant buffer (with additional material parameters)
META_CB_BEGIN(0, Data)
float4x4 ViewProjectionMatrix;
float4x4 WorldMatrix;
float4x4 ViewMatrix;
float3 ViewPos;
float ViewFar;
float3 ViewDir;
float TimeParam;
float4 ViewInfo;
float4 ScreenSize;
float4 LightmapArea;
float3 WorldInvScale;
float WorldDeterminantSign;
float PerInstanceRandom;
float CurrentLOD;
float ChunkSizeNextLOD;
float TerrainChunkSizeLOD0;
float4 HeightmapUVScaleBias;
float4 NeighborLOD;
float2 OffsetUV;
float2 Dummy0;
@1META_CB_END
// Irradiance and directionality prebaked lightmaps
Texture2D Lightmap0 : register(t0);
Texture2D Lightmap1 : register(t1);
Texture2D Lightmap2 : register(t2);
// Terrain data
Texture2D Heightmap : register(t3);
Texture2D Splatmap0 : register(t4);
Texture2D Splatmap1 : register(t5);
// Material shader resources
@2
// Interpolants passed from the vertex shader
struct VertexOutput
{
float4 Position : SV_Position;
float3 WorldPosition : TEXCOORD0;
float2 TexCoord : TEXCOORD1;
float2 LightmapUV : TEXCOORD2;
float3 WorldNormal : TEXCOORD3;
float HolesMask : TEXCOORD4;
#if USE_TERRAIN_LAYERS
float4 Layers[TERRAIN_LAYERS_DATA_SIZE] : TEXCOORD5;
#endif
#if USE_CUSTOM_VERTEX_INTERPOLATORS
float4 CustomVSToPS[CUSTOM_VERTEX_INTERPOLATORS_COUNT] : TEXCOORD9;
#endif
#if USE_TESSELLATION
float TessellationMultiplier : TESS;
#endif
};
// Interpolants passed to the pixel shader
struct PixelInput
{
float4 Position : SV_Position;
float3 WorldPosition : TEXCOORD0;
float2 TexCoord : TEXCOORD1;
float2 LightmapUV : TEXCOORD2;
float3 WorldNormal : TEXCOORD3;
float HolesMask : TEXCOORD4;
#if USE_TERRAIN_LAYERS
float4 Layers[TERRAIN_LAYERS_DATA_SIZE] : TEXCOORD5;
#endif
#if USE_CUSTOM_VERTEX_INTERPOLATORS
float4 CustomVSToPS[CUSTOM_VERTEX_INTERPOLATORS_COUNT] : TEXCOORD9;
#endif
bool IsFrontFace : SV_IsFrontFace;
};
// Material properties generation input
struct MaterialInput
{
float3 WorldPosition;
float TwoSidedSign;
float2 TexCoord;
#if USE_LIGHTMAP
float2 LightmapUV;
#endif
float3x3 TBN;
float4 SvPosition;
float3 PreSkinnedPosition;
float3 PreSkinnedNormal;
float HolesMask;
#if USE_TERRAIN_LAYERS
float4 Layers[TERRAIN_LAYERS_DATA_SIZE];
#endif
#if USE_CUSTOM_VERTEX_INTERPOLATORS
float4 CustomVSToPS[CUSTOM_VERTEX_INTERPOLATORS_COUNT];
#endif
};
MaterialInput GetMaterialInput(PixelInput input)
{
MaterialInput result = (MaterialInput)0;
result.WorldPosition = input.WorldPosition;
result.TexCoord = input.TexCoord;
#if USE_LIGHTMAP
result.LightmapUV = input.LightmapUV;
#endif
result.TBN = CalcTangentBasisFromWorldNormal(input.WorldNormal);
result.TwoSidedSign = WorldDeterminantSign * (input.IsFrontFace ? 1.0 : -1.0);
result.SvPosition = input.Position;
result.HolesMask = input.HolesMask;
#if USE_TERRAIN_LAYERS
result.Layers = input.Layers;
#endif
#if USE_CUSTOM_VERTEX_INTERPOLATORS
result.CustomVSToPS = input.CustomVSToPS;
#endif
return result;
}
// Removes the scale vector from the local to world transformation matrix
float3x3 RemoveScaleFromLocalToWorld(float3x3 localToWorld)
{
localToWorld[0] *= WorldInvScale.x;
localToWorld[1] *= WorldInvScale.y;
localToWorld[2] *= WorldInvScale.z;
return localToWorld;
}
// Transforms a vector from tangent space to world space
float3 TransformTangentVectorToWorld(MaterialInput input, float3 tangentVector)
{
return mul(tangentVector, input.TBN);
}
// Transforms a vector from world space to tangent space
float3 TransformWorldVectorToTangent(MaterialInput input, float3 worldVector)
{
return mul(input.TBN, worldVector);
}
// Transforms a vector from world space to view space
float3 TransformWorldVectorToView(MaterialInput input, float3 worldVector)
{
return mul(worldVector, (float3x3)ViewMatrix);
}
// Transforms a vector from view space to world space
float3 TransformViewVectorToWorld(MaterialInput input, float3 viewVector)
{
return mul((float3x3)ViewMatrix, viewVector);
}
// Transforms a vector from local space to world space
float3 TransformLocalVectorToWorld(MaterialInput input, float3 localVector)
{
float3x3 localToWorld = (float3x3)WorldMatrix;
//localToWorld = RemoveScaleFromLocalToWorld(localToWorld);
return mul(localVector, localToWorld);
}
// Transforms a vector from local space to world space
float3 TransformWorldVectorToLocal(MaterialInput input, float3 worldVector)
{
float3x3 localToWorld = (float3x3)WorldMatrix;
//localToWorld = RemoveScaleFromLocalToWorld(localToWorld);
return mul(localToWorld, worldVector);
}
// Gets the current object position
float3 GetObjectPosition(MaterialInput input)
{
return WorldMatrix[3].xyz;
}
// Gets the current object size
float3 GetObjectSize(MaterialInput input)
{
return float3(1, 1, 1);
}
// Get the current object random value
float GetPerInstanceRandom(MaterialInput input)
{
return PerInstanceRandom;
}
// Get the current object LOD transition dither factor
float GetLODDitherFactor(MaterialInput input)
{
return 0;
}
// Gets the interpolated vertex color (in linear space)
float4 GetVertexColor(MaterialInput input)
{
return 1;
}
// Evaluates the H-Basis coefficients in the tangent space normal direction
float3 GetHBasisIrradiance(float3 n, float3 h0, float3 h1, float3 h2, float3 h3)
{
// Band 0
float3 color = h0 * (1.0f / sqrt(2.0f * PI));
// Band 1
color += h1 * -sqrt(1.5f / PI) * n.y;
color += h2 * sqrt(1.5f / PI) * (2 * n.z - 1.0f);
color += h3 * -sqrt(1.5f / PI) * n.x;
return color;
}
@8
// Get material properties function (for vertex shader)
Material GetMaterialVS(MaterialInput input)
{
@5
}
// Get material properties function (for domain shader)
Material GetMaterialDS(MaterialInput input)
{
@6
}
// Get material properties function (for pixel shader)
Material GetMaterialPS(MaterialInput input)
{
@4
}
// Fix line for errors/warnings for shader code from template
#line 1000
// Calculates LOD value (with fractional part for blending)
float CalcLOD(float2 xy, float4 morph)
{
#if USE_SMOOTH_LOD_TRANSITION
// Use LOD value based on Barycentric coordinates to morph to the lower LOD near chunk edges
float4 lodCalculated = morph * CurrentLOD + NeighborLOD * (float4(1, 1, 1, 1) - morph);
// Pick a quadrant (top, left, right or bottom)
float lod;
if ((xy.x + xy.y) > 1)
{
if (xy.x < xy.y)
{
lod = lodCalculated.w;
}
else
{
lod = lodCalculated.z;
}
}
else
{
if (xy.x < xy.y)
{
lod = lodCalculated.y;
}
else
{
lod = lodCalculated.x;
}
}
return lod;
#else
return CurrentLOD;
#endif
}
float3x3 CalcTangentToWorld(float4x4 world, float3x3 tangentToLocal)
{
float3x3 localToWorld = RemoveScaleFromLocalToWorld((float3x3)world);
return mul(tangentToLocal, localToWorld);
}
// Must match structure defined in TerrainManager.cpp
struct TerrainVertexInput
{
float2 TexCoord : TEXCOORD0;
float4 Morph : TEXCOORD1;
};
// Vertex Shader function for terrain rendering
META_VS(true, FEATURE_LEVEL_ES2)
META_VS_IN_ELEMENT(TEXCOORD, 0, R32G32_FLOAT, 0, ALIGN, PER_VERTEX, 0, true)
META_VS_IN_ELEMENT(TEXCOORD, 1, R8G8B8A8_UNORM, 0, ALIGN, PER_VERTEX, 0, true)
VertexOutput VS(TerrainVertexInput input)
{
VertexOutput output;
// Calculate terrain LOD for this chunk
float lodCalculated = CalcLOD(input.TexCoord, input.Morph);
float lodValue = CurrentLOD;
float morphAlpha = lodCalculated - CurrentLOD;
// Sample heightmap
float2 heightmapUVs = input.TexCoord * HeightmapUVScaleBias.xy + HeightmapUVScaleBias.zw;
#if USE_SMOOTH_LOD_TRANSITION
float4 heightmapValueThisLOD = Heightmap.SampleLevel(SamplerPointClamp, heightmapUVs, lodValue);
float2 nextLODPos = round(input.TexCoord * ChunkSizeNextLOD) / ChunkSizeNextLOD;
float2 heightmapUVsNextLOD = nextLODPos * HeightmapUVScaleBias.xy + HeightmapUVScaleBias.zw;
float4 heightmapValueNextLOD = Heightmap.SampleLevel(SamplerPointClamp, heightmapUVsNextLOD, lodValue + 1);
float4 heightmapValue = lerp(heightmapValueThisLOD, heightmapValueNextLOD, morphAlpha);
bool isHole = max(heightmapValueThisLOD.b + heightmapValueThisLOD.a, heightmapValueNextLOD.b + heightmapValueNextLOD.a) >= 1.9f;
#if USE_TERRAIN_LAYERS
float4 splatmapValueThisLOD = Splatmap0.SampleLevel(SamplerPointClamp, heightmapUVs, lodValue);
float4 splatmapValueNextLOD = Splatmap0.SampleLevel(SamplerPointClamp, heightmapUVsNextLOD, lodValue + 1);
float4 splatmap0Value = lerp(splatmapValueThisLOD, splatmapValueNextLOD, morphAlpha);
#if TERRAIN_LAYERS_DATA_SIZE > 1
splatmapValueThisLOD = Splatmap1.SampleLevel(SamplerPointClamp, heightmapUVs, lodValue);
splatmapValueNextLOD = Splatmap1.SampleLevel(SamplerPointClamp, heightmapUVsNextLOD, lodValue + 1);
float4 splatmap1Value = lerp(splatmapValueThisLOD, splatmapValueNextLOD, morphAlpha);
#endif
#endif
#else
float4 heightmapValue = Heightmap.SampleLevel(SamplerPointClamp, heightmapUVs, lodValue);
bool isHole = (heightmapValue.b + heightmapValue.a) >= 1.9f;
#if USE_TERRAIN_LAYERS
float4 splatmap0Value = Splatmap0.SampleLevel(SamplerPointClamp, heightmapUVs, lodValue);
#if TERRAIN_LAYERS_DATA_SIZE > 1
float4 splatmap1Value = Splatmap1.SampleLevel(SamplerPointClamp, heightmapUVs, lodValue);
#endif
#endif
#endif
float height = (float)((int)(heightmapValue.x * 255.0) + ((int)(heightmapValue.y * 255) << 8)) / 65535.0;
// Extract normal and the holes mask
float2 normalTemp = float2(heightmapValue.b, heightmapValue.a) * 2.0f - 1.0f;
float3 normal = float3(normalTemp.x, sqrt(1.0 - saturate(dot(normalTemp, normalTemp))), normalTemp.y);
normal = normalize(normal);
output.HolesMask = isHole ? 0 : 1;
if (isHole)
{
normal = float3(0, 1, 0);
}
// Construct vertex position
#if USE_SMOOTH_LOD_TRANSITION
float2 positionXZThisLOD = input.TexCoord * TerrainChunkSizeLOD0;
float2 positionXZNextLOD = nextLODPos * TerrainChunkSizeLOD0;
float2 positionXZ = lerp(positionXZThisLOD, positionXZNextLOD, morphAlpha);
#else
float2 positionXZ = input.TexCoord * TerrainChunkSizeLOD0;
#endif
float3 position = float3(positionXZ.x, height, positionXZ.y);
// Compute world space vertex position
output.WorldPosition = mul(float4(position, 1), WorldMatrix).xyz;
// Compute clip space position
output.Position = mul(float4(output.WorldPosition.xyz, 1), ViewProjectionMatrix);
// Pass vertex attributes
#if USE_SMOOTH_LOD_TRANSITION
float2 texCoord = lerp(input.TexCoord, nextLODPos, morphAlpha);
#else
float2 texCoord = input.TexCoord;
#endif
output.TexCoord = positionXZ * (1.0f / TerrainChunkSizeLOD0) + OffsetUV;
output.LightmapUV = texCoord * LightmapArea.zw + LightmapArea.xy;
// Extract terrain layers weights from the splatmap
#if USE_TERRAIN_LAYERS
output.Layers[0] = splatmap0Value;
#if TERRAIN_LAYERS_DATA_SIZE > 1
output.Layers[1] = splatmap1Value;
#endif
#endif
// Compute world space normal vector
float3x3 tangentToLocal = CalcTangentBasisFromWorldNormal(normal);
float3x3 tangentToWorld = CalcTangentToWorld(WorldMatrix, tangentToLocal);
output.WorldNormal = tangentToWorld[2];
// Get material input params if need to evaluate any material property
#if USE_POSITION_OFFSET || USE_TESSELLATION || USE_CUSTOM_VERTEX_INTERPOLATORS
MaterialInput materialInput = (MaterialInput)0;
materialInput.WorldPosition = output.WorldPosition;
materialInput.TexCoord = output.TexCoord;
#if USE_LIGHTMAP
materialInput.LightmapUV = output.LightmapUV;
#endif
materialInput.TBN = CalcTangentBasisFromWorldNormal(output.WorldNormal);
materialInput.TwoSidedSign = WorldDeterminantSign;
materialInput.SvPosition = output.Position;
materialInput.PreSkinnedPosition = position;
materialInput.PreSkinnedNormal = normal;
materialInput.HolesMask = output.HolesMask;
#if USE_TERRAIN_LAYERS
materialInput.Layers = output.Layers;
#endif
Material material = GetMaterialVS(materialInput);
#endif
// Apply world position offset per-vertex
#if USE_POSITION_OFFSET
output.WorldPosition += material.PositionOffset;
output.Position = mul(float4(output.WorldPosition.xyz, 1), ViewProjectionMatrix);
#endif
// Get tessalation multiplier (per vertex)
#if USE_TESSELLATION
output.TessellationMultiplier = material.TessellationMultiplier;
#endif
// Copy interpolants for other shader stages
#if USE_CUSTOM_VERTEX_INTERPOLATORS
output.CustomVSToPS = material.CustomVSToPS;
#endif
return output;
}
#if USE_TESSELLATION
// Interpolants passed from the hull shader to the domain shader
struct TessalationHSToDS
{
float4 Position : SV_Position;
float3 WorldPosition : TEXCOORD0;
float2 TexCoord : TEXCOORD1;
float2 LightmapUV : TEXCOORD2;
float3 WorldNormal : TEXCOORD3;
float HolesMask : TEXCOORD4;
#if USE_TERRAIN_LAYERS
float4 Layers[TERRAIN_LAYERS_DATA_SIZE] : TEXCOORD5;
#endif
#if USE_CUSTOM_VERTEX_INTERPOLATORS
float4 CustomVSToPS[CUSTOM_VERTEX_INTERPOLATORS_COUNT] : TEXCOORD9;
#endif
float TessellationMultiplier : TESS;
};
// Interpolants passed from the domain shader and to the pixel shader
struct TessalationDSToPS
{
float4 Position : SV_Position;
float3 WorldPosition : TEXCOORD0;
float2 TexCoord : TEXCOORD1;
float2 LightmapUV : TEXCOORD2;
float3 WorldNormal : TEXCOORD3;
float HolesMask : TEXCOORD4;
#if USE_TERRAIN_LAYERS
float4 Layers[TERRAIN_LAYERS_DATA_SIZE] : TEXCOORD5;
#endif
#if USE_CUSTOM_VERTEX_INTERPOLATORS
float4 CustomVSToPS[CUSTOM_VERTEX_INTERPOLATORS_COUNT] : TEXCOORD9;
#endif
};
MaterialInput GetMaterialInput(TessalationDSToPS input)
{
MaterialInput result = (MaterialInput)0;
result.WorldPosition = input.WorldPosition;
result.TexCoord = input.TexCoord;
#if USE_LIGHTMAP
result.LightmapUV = input.LightmapUV;
#endif
result.TBN = CalcTangentBasisFromWorldNormal(input.WorldNormal);
result.TwoSidedSign = WorldDeterminantSign;
result.SvPosition = input.Position;
result.HolesMask = input.HolesMask;
#if USE_TERRAIN_LAYERS
result.Layers = input.Layers;
#endif
#if USE_CUSTOM_VERTEX_INTERPOLATORS
result.CustomVSToPS = input.CustomVSToPS;
#endif
return result;
}
struct TessalationPatch
{
float EdgeTessFactor[3] : SV_TessFactor;
float InsideTessFactor : SV_InsideTessFactor;
#if MATERIAL_TESSELLATION == MATERIAL_TESSELLATION_PN
float3 B210 : POSITION4;
float3 B120 : POSITION5;
float3 B021 : POSITION6;
float3 B012 : POSITION7;
float3 B102 : POSITION8;
float3 B201 : POSITION9;
float3 B111 : CENTER;
#endif
};
TessalationPatch HS_PatchConstant(InputPatch<VertexOutput, 3> input)
{
TessalationPatch output;
// Average tess factors along edges, and pick an edge tess factor for the interior tessellation
float4 TessellationMultipliers;
TessellationMultipliers.x = 0.5f * (input[1].TessellationMultiplier + input[2].TessellationMultiplier);
TessellationMultipliers.y = 0.5f * (input[2].TessellationMultiplier + input[0].TessellationMultiplier);
TessellationMultipliers.z = 0.5f * (input[0].TessellationMultiplier + input[1].TessellationMultiplier);
TessellationMultipliers.w = 0.333f * (input[0].TessellationMultiplier + input[1].TessellationMultiplier + input[2].TessellationMultiplier);
TessellationMultipliers = clamp(TessellationMultipliers, 1, MAX_TESSELLATION_FACTOR);
output.EdgeTessFactor[0] = TessellationMultipliers.x; // 1->2 edge
output.EdgeTessFactor[1] = TessellationMultipliers.y; // 2->0 edge
output.EdgeTessFactor[2] = TessellationMultipliers.z; // 0->1 edge
output.InsideTessFactor = TessellationMultipliers.w;
#if MATERIAL_TESSELLATION == MATERIAL_TESSELLATION_PN
// Calculate PN-Triangle coefficients
// Refer to Vlachos 2001 for the original formula
float3 p1 = input[0].WorldPosition;
float3 p2 = input[1].WorldPosition;
float3 p3 = input[2].WorldPosition;
float3 n1 = input[0].WorldNormal;
float3 n2 = input[1].WorldNormal;
float3 n3 = input[2].WorldNormal;
// Calculate control points
output.B210 = (2.0f * p1 + p2 - dot((p2 - p1), n1) * n1) / 3.0f;
output.B120 = (2.0f * p2 + p1 - dot((p1 - p2), n2) * n2) / 3.0f;
output.B021 = (2.0f * p2 + p3 - dot((p3 - p2), n2) * n2) / 3.0f;
output.B012 = (2.0f * p3 + p2 - dot((p2 - p3), n3) * n3) / 3.0f;
output.B102 = (2.0f * p3 + p1 - dot((p1 - p3), n3) * n3) / 3.0f;
output.B201 = (2.0f * p1 + p3 - dot((p3 - p1), n1) * n1) / 3.0f;
float3 e = (output.B210 + output.B120 + output.B021 +
output.B012 + output.B102 + output.B201) / 6.0f;
float3 v = (p1 + p2 + p3) / 3.0f;
output.B111 = e + ((e - v) / 2.0f);
#endif
return output;
}
META_HS(USE_TESSELLATION, FEATURE_LEVEL_SM5)
META_HS_PATCH(TESSELLATION_IN_CONTROL_POINTS)
[domain("tri")]
[partitioning("fractional_odd")]
[outputtopology("triangle_cw")]
[maxtessfactor(MAX_TESSELLATION_FACTOR)]
[outputcontrolpoints(3)]
[patchconstantfunc("HS_PatchConstant")]
TessalationHSToDS HS(InputPatch<VertexOutput, TESSELLATION_IN_CONTROL_POINTS> input, uint ControlPointID : SV_OutputControlPointID)
{
TessalationHSToDS output;
// Pass through shader
#define COPY(thing) output.thing = input[ControlPointID].thing;
COPY(Position);
COPY(WorldPosition);
COPY(TexCoord);
COPY(LightmapUV);
COPY(WorldNormal);
COPY(HolesMask);
COPY(TessellationMultiplier);
#if USE_TERRAIN_LAYERS
COPY(Layers);
#endif
#if USE_CUSTOM_VERTEX_INTERPOLATORS
COPY(CustomVSToPS);
#endif
#undef COPY
return output;
}
#if MATERIAL_TESSELLATION == MATERIAL_TESSELLATION_PHONG
// Orthogonal projection on to plane
float3 ProjectOntoPlane(float3 planeNormal, float3 planePoint, float3 pointToProject)
{
return pointToProject - dot(pointToProject-planePoint, planeNormal) * planeNormal;
}
#endif
META_DS(USE_TESSELLATION, FEATURE_LEVEL_SM5)
[domain("tri")]
TessalationDSToPS DS(TessalationPatch constantData, float3 barycentricCoords : SV_DomainLocation, const OutputPatch<TessalationHSToDS, 3> input)
{
TessalationDSToPS output;
// Get the barycentric coords
float U = barycentricCoords.x;
float V = barycentricCoords.y;
float W = barycentricCoords.z;
// Interpolate patch attributes to generated vertices
#define INTERPOLATE(thing) output.thing = U * input[0].thing + V * input[1].thing + W * input[2].thing
#define COPY(thing) output.thing = input[0].thing
INTERPOLATE(Position);
#if MATERIAL_TESSELLATION == MATERIAL_TESSELLATION_PN
float UU = U * U;
float VV = V * V;
float WW = W * W;
float UU3 = UU * 3.0f;
float VV3 = VV * 3.0f;
float WW3 = WW * 3.0f;
// Interpolate using barycentric coordinates and PN Triangle control points
output.WorldPosition =
input[0].WorldPosition * UU * U +
input[1].WorldPosition * VV * V +
input[2].WorldPosition * WW * W +
constantData.B210 * UU3 * V +
constantData.B120 * VV3 * U +
constantData.B021 * VV3 * W +
constantData.B012 * WW3 * V +
constantData.B102 * WW3 * U +
constantData.B201 * UU3 * W +
constantData.B111 * 6.0f * W * U * V;
#else
INTERPOLATE(WorldPosition);
#endif
INTERPOLATE(TexCoord);
INTERPOLATE(LightmapUV);
INTERPOLATE(WorldNormal);
INTERPOLATE(HolesMask);
#if USE_TERRAIN_LAYERS
UNROLL
for (int i = 0; i < TERRAIN_LAYERS_DATA_SIZE; i++)
{
INTERPOLATE(Layers[i]);
}
#endif
#if USE_CUSTOM_VERTEX_INTERPOLATORS
UNROLL
for (int i = 0; i < CUSTOM_VERTEX_INTERPOLATORS_COUNT; i++)
{
INTERPOLATE(CustomVSToPS[i]);
}
#endif
#undef INTERPOLATE
#undef COPY
// Interpolating normal can unnormalize it, so normalize it
output.WorldNormal = normalize(output.WorldNormal);
#if MATERIAL_TESSELLATION == MATERIAL_TESSELLATION_PHONG
// Orthogonal projection in the tangent planes
float3 posProjectedU = ProjectOntoPlane(input[0].WorldNormal, input[0].WorldPosition, output.WorldPosition);
float3 posProjectedV = ProjectOntoPlane(input[1].WorldNormal, input[1].WorldPosition, output.WorldPosition);
float3 posProjectedW = ProjectOntoPlane(input[2].WorldNormal, input[2].WorldPosition, output.WorldPosition);
// Interpolate the projected points
output.WorldPosition = U * posProjectedU + V * posProjectedV + W * posProjectedW;
#endif
// Perform displacement mapping
#if USE_DISPLACEMENT
MaterialInput materialInput = GetMaterialInput(output);
Material material = GetMaterialDS(materialInput);
output.WorldPosition += material.WorldDisplacement;
#endif
// Recalculate the clip space position
output.Position = mul(float4(output.WorldPosition, 1), ViewProjectionMatrix);
return output;
}
#endif
#if USE_LIGHTMAP
float3 SampleLightmap(Material material, MaterialInput materialInput)
{
// Sample lightmaps
float4 lightmap0 = Lightmap0.Sample(SamplerLinearClamp, materialInput.LightmapUV);
float4 lightmap1 = Lightmap1.Sample(SamplerLinearClamp, materialInput.LightmapUV);
float4 lightmap2 = Lightmap2.Sample(SamplerLinearClamp, materialInput.LightmapUV);
// Unpack H-basis
float3 h0 = float3(lightmap0.x, lightmap1.x, lightmap2.x);
float3 h1 = float3(lightmap0.y, lightmap1.y, lightmap2.y);
float3 h2 = float3(lightmap0.z, lightmap1.z, lightmap2.z);
float3 h3 = float3(lightmap0.w, lightmap1.w, lightmap2.w);
// Sample baked diffuse irradiance from the H-basis coefficients
float3 normal = material.TangentNormal;
#if MATERIAL_SHADING_MODEL == SHADING_MODEL_FOLIAGE
normal *= material.TangentNormal;
#endif
return GetHBasisIrradiance(normal, h0, h1, h2, h3) / PI;
}
#endif
// Pixel Shader function for GBuffer Pass
META_PS(true, FEATURE_LEVEL_ES2)
META_PERMUTATION_1(USE_LIGHTMAP=0)
META_PERMUTATION_1(USE_LIGHTMAP=1)
void PS_GBuffer(
in PixelInput input
,out float4 Light : SV_Target0
#if MATERIAL_BLEND == MATERIAL_BLEND_OPAQUE
,out float4 RT0 : SV_Target1
,out float4 RT1 : SV_Target2
,out float4 RT2 : SV_Target3
#if USE_GBUFFER_CUSTOM_DATA
,out float4 RT3 : SV_Target4
#endif
#endif
)
{
Light = 0;
// Get material parameters
MaterialInput materialInput = GetMaterialInput(input);
Material material = GetMaterialPS(materialInput);
// Masking
#if MATERIAL_MASKED
clip(material.Mask - MATERIAL_MASK_THRESHOLD);
#endif
#if USE_LIGHTMAP
float3 diffuseColor = GetDiffuseColor(material.Color, material.Metalness);
float3 specularColor = GetSpecularColor(material.Color, material.Specular, material.Metalness);
// Sample lightmap
float3 diffuseIndirectLighting = SampleLightmap(material, materialInput);
// Apply static indirect light
Light.rgb = diffuseColor * diffuseIndirectLighting * AOMultiBounce(material.AO, diffuseColor);
#endif
#if MATERIAL_BLEND == MATERIAL_BLEND_OPAQUE
// Pack material properties to GBuffer
RT0 = float4(material.Color, material.AO);
RT1 = float4(material.WorldNormal * 0.5 + 0.5, MATERIAL_SHADING_MODEL * (1.0 / 3.0));
RT2 = float4(material.Roughness, material.Metalness, material.Specular, 0);
// Custom data
#if USE_GBUFFER_CUSTOM_DATA
#if MATERIAL_SHADING_MODEL == SHADING_MODEL_SUBSURFACE
RT3 = float4(material.SubsurfaceColor, material.Opacity);
#elif MATERIAL_SHADING_MODEL == SHADING_MODEL_FOLIAGE
RT3 = float4(material.SubsurfaceColor, material.Opacity);
#else
RT3 = float4(0, 0, 0, 0);
#endif
#endif
// Add light emission
#if USE_EMISSIVE
Light.rgb += material.Emissive;
#endif
#else
// Handle blending as faked forward pass (use Light buffer and skip GBuffer modification)
Light = float4(material.Emissive, material.Opacity);
#endif
}
// Pixel Shader function for Depth Pass
META_PS(true, FEATURE_LEVEL_ES2)
void PS_Depth(PixelInput input
#if GLSL
, out float4 OutColor : SV_Target0
#endif
)
{
#if MATERIAL_MASKED
// Perform per pixel clipping if material requries it
MaterialInput materialInput = GetMaterialInput(input);
Material material = GetMaterialPS(materialInput);
clip(material.Mask - MATERIAL_MASK_THRESHOLD);
#endif
#if GLSL
OutColor = 0;
#endif
}
@9