#include "../Common.hlsli"
#include "../Normals.hlsli"
/// Constants at Constant Buffer View (CBV) register 0
cbuffer RootConstants : register(b0)
{
/// Render node ID
uint ID;
}
/// Constant buffer at Constant Buffer View (CBV) register 1
cbuffer CameraBuffer : register(b1)
{
/// Camera view matrix (world space->view space)
float4x4 ViewMatrix;
/// Camera projection matrix (view space->clip space)
float4x4 ProjectionMatrix;
/// Padding
float4 pad[8];
};
/// Render nodes buffer
StructuredBuffer RenderNodes : register(t0);
/// Materials buffer (bindless)
StructuredBuffer Materials: register(t1);
/// Textures buffer (bindless)
Texture2D Textures[]: register(t2);
/// Anisotropic texture sampler
SamplerState AnisoSampler : register(s0);
/// Structure holding data passed from vertex shader
struct VSOut
{
/// Clip space position
float4 position : SV_POSITION;
/// Texture coordinates for maps
float2 texCoord : TEXCOORD0;
/// View space vertex normals
float3 normal : TEXCOORD1;
/// View space S-tangent vector
float3 tangent : TEXCOORD2;
/// View space T-tangent vector
float3 bitangent : TEXCOORD3;
/// Clip space position passed to fragment shader
float4 clipPos : TEXCOORD4;
};
/// Vertex shader entry point
/// Vertex position (object space)
/// Vertex normal
/// Vertex texture coordinates
/// Vertex S-tangent vector
/// Vertex T-tangent vector
/// Filled structure VSOut
VSOut VS(float3 position : POSITION,
float3 normal : NORMAL,
float2 texCoord : TEXCOORD0,
float3 tangent : TEXCOORD2,
float3 bitangent : TEXCOORD3)
{
VSOut result;
// Transform vertex positions into world space
float4 positionWS = mul(float4(position, 1.0f), RenderNodes[ID].WorldMatrix);
// Transform vertex positions into clip space and set into output
result.position = mul(ProjectionMatrix, mul(ViewMatrix, positionWS));
// Set vertex texture coordinates into output
result.texCoord = texCoord;
// Transform vertex normal into view space normals
result.normal = mul(ViewMatrix, float4(mul(float4(normal.xyz, 1.0f), RenderNodes[ID].WorldMatrixInverseTranspose).xyz, 0.0f)).xyz;
// Transform S-tangent vector into view space normals
result.tangent = mul(ViewMatrix, float4(mul(float4(tangent.xyz, 1.0f), RenderNodes[ID].WorldMatrixInverseTranspose).xyz, 0.0f)).xyz;
// Transform T-tangent vector into view space normals
result.bitangent = mul(ViewMatrix, float4(mul(float4(bitangent.xyz, 1.0f), RenderNodes[ID].WorldMatrixInverseTranspose).xyz, 0.0f)).xyz;
// Calculate depth
result.clipPos = result.position;
return result;
}
/// Structure holding data output from pixel shader (i.e. Multiple Render Targets data)
struct PSOut
{
/// Color stored in first render target
float4 color : SV_TARGET0;
/// Normal - encoded to 2 channels (along with metallic and roughness) stored in second render target
float4 normal : SV_TARGET1;
/// Depth stored in third render target
float depth : SV_TARGET2;
};
/// Pixel shader entry point
/// VSOut structure holding data passed from vertex shader
/// Filled structure PSOut (Multiple Render Targets)
PSOut PS(VSOut input)
{
PSOut result;
// Read diffuse texture (based on MaterialID for current render node), and set into color output
result.color = pow(Textures[Materials[RenderNodes[ID].MaterialID].DiffuseMap].Sample(AnisoSampler, input.texCoord.xy), 2.2);
// Calculate tangent frame for applying normal map to vertex normals
float3x3 tangentFrame = float3x3(input.tangent, -input.bitangent, input.normal);
// Read normal map texture (based on MaterialID for current render node), apply it to vertex normals (through tangent frame)
float3 normal = normalize(mul(Textures[Materials[RenderNodes[ID].MaterialID].NormalsMap].Sample(AnisoSampler, input.texCoord.xy).xyz * 2.0f - 1.0f, tangentFrame));
// Read metallic texture (based on MaterialID for current render node)
float metallicMap = Textures[Materials[RenderNodes[ID].MaterialID].MetallicMap].Sample(AnisoSampler, input.texCoord.xy).x;
// Read roughness texture (based on MaterialID for current render node)
float roughnessMap = Textures[Materials[RenderNodes[ID].MaterialID].RoughnessMap].Sample(AnisoSampler, input.texCoord.xy).x;
// Set normal output to contain encoded normal (first 2 channels - see Normals.hlsli for details), metallic (1 channel) and roughness (1 channel)
result.normal = float4(EncodeNormal(normal), metallicMap, roughnessMap);
// Write depth
result.depth = input.clipPos.z / input.clipPos.w;
return result;
}