197 lines
7.2 KiB
HLSL
197 lines
7.2 KiB
HLSL
// This file contains functionality for reading the contents of URP GBuffers.
|
|
// Shaders using these functions must execute after the GBuffer pass, or else GBuffers will be invalid.
|
|
#ifndef UNIVERSAL_GBUFFERINPUT_INCLUDED
|
|
#define UNIVERSAL_GBUFFERINPUT_INCLUDED
|
|
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/GBufferCommon.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/SurfaceData.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/BRDF.hlsl"
|
|
|
|
#if defined(GBUFFER_FBFETCH_AVAILABLE)
|
|
// Native render pass / framebuffer fetch available!
|
|
// Use framebuffer input.
|
|
|
|
// Static index GBuffers:
|
|
FRAMEBUFFER_INPUT_X_HALF(GBUFFER_IDX_RGB_BASECOLOR_A_FLAGS);
|
|
FRAMEBUFFER_INPUT_X_HALF(GBUFFER_IDX_RGB_SPECULAR_R_METALLIC_A_OCCLUSION);
|
|
FRAMEBUFFER_INPUT_X_HALF(GBUFFER_IDX_RGB_NORMALS_A_SMOOTHNESS);
|
|
FRAMEBUFFER_INPUT_X_FLOAT(GBUFFER_IDX_R_DEPTH);
|
|
|
|
// Dynamic index GBuffer: Shadow mask
|
|
#if defined(GBUFFER_FEATURE_SHADOWMASK)
|
|
FRAMEBUFFER_INPUT_X_HALF(GBUFFER_IDX_RGBA_SHADOWMASK);
|
|
#endif
|
|
|
|
// Dynamic index GBuffer: Rendering layers
|
|
#if defined(GBUFFER_FEATURE_RENDERING_LAYERS)
|
|
FRAMEBUFFER_INPUT_X_HALF(GBUFFER_IDX_R_RENDERING_LAYERS);
|
|
#endif
|
|
|
|
#else
|
|
// Native render pass / framebuffer fetch is not available.
|
|
// Fall back to regular texture bindings.
|
|
|
|
// Helper macro to convert GBuffer index macro to texture slot name.
|
|
#define GBUFFER_TEX2D_NAME(index) _GBuffer##index
|
|
|
|
// Static index GBuffers:
|
|
TEXTURE2D_X_HALF(GBUFFER_TEX2D_NAME(GBUFFER_IDX_RGB_BASECOLOR_A_FLAGS));
|
|
TEXTURE2D_X_HALF(GBUFFER_TEX2D_NAME(GBUFFER_IDX_RGB_SPECULAR_R_METALLIC_A_OCCLUSION));
|
|
TEXTURE2D_X_HALF(GBUFFER_TEX2D_NAME(GBUFFER_IDX_RGB_NORMALS_A_SMOOTHNESS));
|
|
|
|
// We never bind GBUFFER_TEX2D_NAME(GBUFFER_IDX_R_DEPTH), instead we expect the depth to be bound to the _CameraDepthTexture slot.
|
|
TEXTURE2D_X_FLOAT(_CameraDepthTexture);
|
|
|
|
// Dynamic index GBuffer: Shadow mask
|
|
#if defined(GBUFFER_FEATURE_SHADOWMASK)
|
|
TEXTURE2D_X_HALF(GBUFFER_TEX2D_NAME(GBUFFER_IDX_AFTER(GBUFFER_IDX_RGBA_SHADOWMASK)));
|
|
#endif
|
|
|
|
// Dynamic index GBuffer: Rendering layers
|
|
#if defined(GBUFFER_FEATURE_RENDERING_LAYERS)
|
|
TEXTURE2D_X_HALF(GBUFFER_TEX2D_NAME(GBUFFER_IDX_AFTER(GBUFFER_IDX_R_RENDERING_LAYERS)));
|
|
#endif
|
|
|
|
#endif
|
|
|
|
// Load raw GBuffer data.
|
|
// Use this if overriding data in the GBuffers, otherwise use UnpackGBuffers().
|
|
// If shadow mask is not used, shadowMask defaults to (1, 1, 1, 1).
|
|
// If rendering layers is not used, renderingLayers defaults to 1.
|
|
// Note that unCoord2 is in pixel coordinates, not screen UVs.
|
|
void LoadGBuffers(uint2 unCoord2, out half4 gBuffer0, out half4 gBuffer1, out half4 gBuffer2, out float depth,
|
|
out float renderingLayers, out half4 shadowMask)
|
|
{
|
|
renderingLayers = 1;
|
|
shadowMask = half4(1, 1, 1, 1);
|
|
|
|
#if defined(GBUFFER_FBFETCH_AVAILABLE)
|
|
|
|
depth = LOAD_FRAMEBUFFER_X_INPUT(GBUFFER_IDX_R_DEPTH, unCoord2).x;
|
|
gBuffer0 = LOAD_FRAMEBUFFER_X_INPUT(GBUFFER_IDX_RGB_BASECOLOR_A_FLAGS, unCoord2);
|
|
gBuffer1 = LOAD_FRAMEBUFFER_X_INPUT(GBUFFER_IDX_RGB_SPECULAR_R_METALLIC_A_OCCLUSION, unCoord2);
|
|
gBuffer2 = LOAD_FRAMEBUFFER_X_INPUT(GBUFFER_IDX_RGB_NORMALS_A_SMOOTHNESS, unCoord2);
|
|
|
|
#if defined(GBUFFER_FEATURE_SHADOWMASK)
|
|
shadowMask = LOAD_FRAMEBUFFER_X_INPUT(GBUFFER_IDX_RGBA_SHADOWMASK, unCoord2);
|
|
#endif
|
|
|
|
#if defined(GBUFFER_FEATURE_RENDERING_LAYERS)
|
|
renderingLayers = LOAD_FRAMEBUFFER_X_INPUT(GBUFFER_IDX_R_RENDERING_LAYERS, unCoord2).x;
|
|
#endif
|
|
|
|
#else
|
|
|
|
depth = LOAD_TEXTURE2D_X(_CameraDepthTexture, unCoord2).x;
|
|
gBuffer0 = LOAD_TEXTURE2D_X(GBUFFER_TEX2D_NAME(GBUFFER_IDX_RGB_BASECOLOR_A_FLAGS), unCoord2);
|
|
gBuffer1 = LOAD_TEXTURE2D_X(GBUFFER_TEX2D_NAME(GBUFFER_IDX_RGB_SPECULAR_R_METALLIC_A_OCCLUSION), unCoord2);
|
|
gBuffer2 = LOAD_TEXTURE2D_X(GBUFFER_TEX2D_NAME(GBUFFER_IDX_RGB_NORMALS_A_SMOOTHNESS), unCoord2);
|
|
|
|
#if defined(GBUFFER_FEATURE_SHADOWMASK)
|
|
shadowMask = LOAD_TEXTURE2D_X(GBUFFER_TEX2D_NAME(GBUFFER_IDX_AFTER(GBUFFER_IDX_RGBA_SHADOWMASK)), unCoord2);
|
|
#endif
|
|
|
|
#if defined(GBUFFER_FEATURE_RENDERING_LAYERS)
|
|
renderingLayers = LOAD_TEXTURE2D_X(GBUFFER_TEX2D_NAME(GBUFFER_IDX_AFTER(GBUFFER_IDX_R_RENDERING_LAYERS)), unCoord2).x;
|
|
#endif
|
|
|
|
#endif
|
|
}
|
|
|
|
// Load raw GBuffer content and unpack into GBufferData.
|
|
// Note that unCoord2 is in pixel coordinates, not screen UVs.
|
|
GBufferData UnpackGBuffers(uint2 unCoord2)
|
|
{
|
|
half4 gBuffer0;
|
|
half4 gBuffer1;
|
|
half4 gBuffer2;
|
|
float depth;
|
|
float renderingLayers;
|
|
half4 shadowMask;
|
|
|
|
LoadGBuffers(unCoord2, gBuffer0, gBuffer1, gBuffer2, depth, renderingLayers, shadowMask);
|
|
|
|
GBufferData gBufferData;
|
|
ZERO_INITIALIZE(GBufferData, gBufferData);
|
|
|
|
gBufferData.baseColor = gBuffer0.rgb;
|
|
gBufferData.materialFlags = UnpackGBufferMaterialFlags(gBuffer0.a);
|
|
gBufferData.specularColor = gBuffer1.rgb;
|
|
gBufferData.occlusion = gBuffer1.a;
|
|
gBufferData.normalWS = normalize(UnpackGBufferNormal(gBuffer2.rgb));
|
|
gBufferData.smoothness = gBuffer2.a;
|
|
gBufferData.depth = depth;
|
|
gBufferData.shadowMask = shadowMask;
|
|
|
|
#if defined(GBUFFER_FEATURE_RENDERING_LAYERS)
|
|
gBufferData.meshRenderingLayers = DecodeMeshRenderingLayer(renderingLayers);
|
|
#else
|
|
gBufferData.meshRenderingLayers = 0xFFFF;
|
|
#endif
|
|
|
|
return gBufferData;
|
|
}
|
|
|
|
// Interpret SurfaceData from GBufferData.
|
|
// Used by SimpleLit materials.
|
|
SurfaceData GBufferDataToSurfaceData(GBufferData gBufferData)
|
|
{
|
|
SurfaceData surfaceData = (SurfaceData)0;
|
|
|
|
surfaceData.albedo = gBufferData.baseColor;
|
|
surfaceData.occlusion = 0.0;
|
|
surfaceData.specular = gBufferData.specularColor;
|
|
surfaceData.metallic = 0.0; // Not used by SimpleLit material.
|
|
surfaceData.alpha = 1.0; // GBuffer only contains opaque materials
|
|
surfaceData.smoothness = gBufferData.smoothness;
|
|
|
|
return surfaceData;
|
|
}
|
|
|
|
// Interpret BRDFData from GBufferData.
|
|
// Used by Lit materials.
|
|
BRDFData GBufferDataToBRDFData(GBufferData gBufferData)
|
|
{
|
|
half3 albedo = gBufferData.baseColor;
|
|
half3 specular = gBufferData.specularColor;
|
|
uint materialFlags = gBufferData.materialFlags;
|
|
half smoothness = gBufferData.smoothness;
|
|
|
|
BRDFData brdfData = (BRDFData)0;
|
|
half alpha = half(1.0); // NOTE: alpha can get modfied, forward writes it out (_ALPHAPREMULTIPLY_ON).
|
|
|
|
half3 brdfDiffuse;
|
|
half3 brdfSpecular;
|
|
half reflectivity;
|
|
half oneMinusReflectivity;
|
|
|
|
UNITY_BRANCH if ((materialFlags & kMaterialFlagSpecularSetup) != 0)
|
|
{
|
|
// Specular setup
|
|
reflectivity = ReflectivitySpecular(specular);
|
|
oneMinusReflectivity = half(1.0) - reflectivity;
|
|
brdfDiffuse = albedo * oneMinusReflectivity;
|
|
brdfSpecular = specular;
|
|
}
|
|
else
|
|
{
|
|
// Metallic setup
|
|
reflectivity = specular.r;
|
|
oneMinusReflectivity = 1.0 - reflectivity;
|
|
half metallic = MetallicFromReflectivity(reflectivity);
|
|
brdfDiffuse = albedo * oneMinusReflectivity;
|
|
brdfSpecular = lerp(kDielectricSpec.rgb, albedo, metallic);
|
|
}
|
|
|
|
InitializeBRDFDataDirect(albedo, brdfDiffuse, brdfSpecular, reflectivity, oneMinusReflectivity, smoothness, alpha, brdfData);
|
|
|
|
return brdfData;
|
|
}
|
|
|
|
#ifdef GBUFFER_TEX2D_NAME
|
|
#undef GBUFFER_TEX2D_NAME
|
|
#endif
|
|
|
|
#endif
|