123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282 |
- #ifndef UNIVERSAL_GBUFFERUTIL_INCLUDED
- #define UNIVERSAL_GBUFFERUTIL_INCLUDED
-
- #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/SurfaceData.hlsl"
- #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
-
- // inspired from [builtin_shaders]/CGIncludes/UnityGBuffer.cginc
-
- // Non-static meshes with real-time lighting need to write shadow mask, which in that case stores per-object occlusion probe values.
- #if !defined(LIGHTMAP_ON) && defined(LIGHTMAP_SHADOW_MIXING) && !defined(SHADOWS_SHADOWMASK)
- #define OUTPUT_SHADOWMASK 1 // subtractive
- #elif defined(SHADOWS_SHADOWMASK)
- #define OUTPUT_SHADOWMASK 2 // shadow mask
- #elif defined(_DEFERRED_MIXED_LIGHTING)
- #define OUTPUT_SHADOWMASK 3 // we don't know if it's subtractive or just shadowMap (from deferred lighting shader, LIGHTMAP_ON does not need to be defined)
- #else
- #endif
-
- #if _RENDER_PASS_ENABLED
- #define GBUFFER_OPTIONAL_SLOT_1 GBuffer4
- #define GBUFFER_OPTIONAL_SLOT_1_TYPE float
- #if OUTPUT_SHADOWMASK && (defined(_WRITE_RENDERING_LAYERS) || defined(_LIGHT_LAYERS))
- #define GBUFFER_OPTIONAL_SLOT_2 GBuffer5
- #define GBUFFER_OPTIONAL_SLOT_3 GBuffer6
- #define GBUFFER_LIGHT_LAYERS GBuffer5
- #define GBUFFER_SHADOWMASK GBuffer6
- #elif OUTPUT_SHADOWMASK
- #define GBUFFER_OPTIONAL_SLOT_2 GBuffer5
- #define GBUFFER_SHADOWMASK GBuffer5
- #elif (defined(_WRITE_RENDERING_LAYERS) || defined(_LIGHT_LAYERS))
- #define GBUFFER_OPTIONAL_SLOT_2 GBuffer5
- #define GBUFFER_LIGHT_LAYERS GBuffer5
- #endif //#if OUTPUT_SHADOWMASK && defined(_WRITE_RENDERING_LAYERS)
- #else
- #define GBUFFER_OPTIONAL_SLOT_1_TYPE half4
- #if OUTPUT_SHADOWMASK && (defined(_WRITE_RENDERING_LAYERS) || defined(_LIGHT_LAYERS))
- #define GBUFFER_OPTIONAL_SLOT_1 GBuffer4
- #define GBUFFER_OPTIONAL_SLOT_2 GBuffer5
- #define GBUFFER_LIGHT_LAYERS GBuffer4
- #define GBUFFER_SHADOWMASK GBuffer5
- #elif OUTPUT_SHADOWMASK
- #define GBUFFER_OPTIONAL_SLOT_1 GBuffer4
- #define GBUFFER_SHADOWMASK GBuffer4
- #elif (defined(_WRITE_RENDERING_LAYERS) || defined(_LIGHT_LAYERS))
- #define GBUFFER_OPTIONAL_SLOT_1 GBuffer4
- #define GBUFFER_LIGHT_LAYERS GBuffer4
- #endif //#if OUTPUT_SHADOWMASK && defined(_WRITE_RENDERING_LAYERS)
- #endif //#if _RENDER_PASS_ENABLED
- #define kLightingInvalid -1 // No dynamic lighting: can aliase any other material type as they are skipped using stencil
- #define kLightingLit 1 // lit shader
- #define kLightingSimpleLit 2 // Simple lit shader
- // clearcoat 3
- // backscatter 4
- // skin 5
-
- // Material flags
- #define kMaterialFlagReceiveShadowsOff 1 // Does not receive dynamic shadows
- #define kMaterialFlagSpecularHighlightsOff 2 // Does not receivce specular
- #define kMaterialFlagSubtractiveMixedLighting 4 // The geometry uses subtractive mixed lighting
- #define kMaterialFlagSpecularSetup 8 // Lit material use specular setup instead of metallic setup
-
- // Light flags.
- #define kLightFlagSubtractiveMixedLighting 4 // The light uses subtractive mixed lighting.
-
- struct FragmentOutput
- {
- half4 GBuffer0 : SV_Target0;
- half4 GBuffer1 : SV_Target1;
- half4 GBuffer2 : SV_Target2;
- half4 GBuffer3 : SV_Target3; // Camera color attachment
-
- #ifdef GBUFFER_OPTIONAL_SLOT_1
- GBUFFER_OPTIONAL_SLOT_1_TYPE GBuffer4 : SV_Target4;
- #endif
- #ifdef GBUFFER_OPTIONAL_SLOT_2
- half4 GBuffer5 : SV_Target5;
- #endif
- #ifdef GBUFFER_OPTIONAL_SLOT_3
- half4 GBuffer6 : SV_Target6;
- #endif
- };
-
- float PackMaterialFlags(uint materialFlags)
- {
- return materialFlags * (1.0h / 255.0h);
- }
-
- uint UnpackMaterialFlags(float packedMaterialFlags)
- {
- return uint((packedMaterialFlags * 255.0h) + 0.5h);
- }
-
- #ifdef _GBUFFER_NORMALS_OCT
- half3 PackNormal(half3 n)
- {
- float2 octNormalWS = PackNormalOctQuadEncode(n); // values between [-1, +1], must use fp32 on some platforms.
- float2 remappedOctNormalWS = saturate(octNormalWS * 0.5 + 0.5); // values between [ 0, +1]
- return half3(PackFloat2To888(remappedOctNormalWS)); // values between [ 0, +1]
- }
-
- half3 UnpackNormal(half3 pn)
- {
- half2 remappedOctNormalWS = half2(Unpack888ToFloat2(pn)); // values between [ 0, +1]
- half2 octNormalWS = remappedOctNormalWS.xy * half(2.0) - half(1.0);// values between [-1, +1]
- return half3(UnpackNormalOctQuadEncode(octNormalWS)); // values between [-1, +1]
- }
-
- #else
- half3 PackNormal(half3 n)
- { return n; } // values between [-1, +1]
-
- half3 UnpackNormal(half3 pn)
- { return pn; } // values between [-1, +1]
- #endif
-
- // This will encode SurfaceData into GBuffer
- FragmentOutput SurfaceDataToGbuffer(SurfaceData surfaceData, InputData inputData, half3 globalIllumination, int lightingMode)
- {
- half3 packedNormalWS = PackNormal(inputData.normalWS);
-
- uint materialFlags = 0;
-
- // SimpleLit does not use _SPECULARHIGHLIGHTS_OFF to disable specular highlights.
-
- #ifdef _RECEIVE_SHADOWS_OFF
- materialFlags |= kMaterialFlagReceiveShadowsOff;
- #endif
-
- #if defined(LIGHTMAP_ON) && defined(_MIXED_LIGHTING_SUBTRACTIVE)
- materialFlags |= kMaterialFlagSubtractiveMixedLighting;
- #endif
-
- FragmentOutput output;
- output.GBuffer0 = half4(surfaceData.albedo.rgb, PackMaterialFlags(materialFlags)); // albedo albedo albedo materialFlags (sRGB rendertarget)
- output.GBuffer1 = half4(surfaceData.specular.rgb, surfaceData.occlusion); // specular specular specular occlusion
- output.GBuffer2 = half4(packedNormalWS, surfaceData.smoothness); // encoded-normal encoded-normal encoded-normal smoothness
- output.GBuffer3 = half4(globalIllumination, 1); // GI GI GI unused (lighting buffer)
- #if _RENDER_PASS_ENABLED
- output.GBuffer4 = inputData.positionCS.z;
- #endif
- #if OUTPUT_SHADOWMASK
- output.GBUFFER_SHADOWMASK = inputData.shadowMask; // will have unity_ProbesOcclusion value if subtractive lighting is used (baked)
- #endif
- #ifdef _WRITE_RENDERING_LAYERS
- uint renderingLayers = GetMeshRenderingLayer();
- output.GBUFFER_LIGHT_LAYERS = float4(EncodeMeshRenderingLayer(renderingLayers), 0.0, 0.0, 0.0);
- #endif
-
- return output;
- }
-
- // This decodes the Gbuffer into a SurfaceData struct
- SurfaceData SurfaceDataFromGbuffer(half4 gbuffer0, half4 gbuffer1, half4 gbuffer2, int lightingMode)
- {
- SurfaceData surfaceData;
-
- surfaceData.albedo = gbuffer0.rgb;
- uint materialFlags = UnpackMaterialFlags(gbuffer0.a);
- surfaceData.occlusion = 1.0; // Not used by SimpleLit material.
- surfaceData.specular = gbuffer1.rgb;
- half smoothness = gbuffer2.a;
-
- surfaceData.metallic = 0.0; // Not used by SimpleLit material.
- surfaceData.alpha = 1.0; // gbuffer only contains opaque materials
- surfaceData.smoothness = smoothness;
-
- surfaceData.emission = (half3)0; // Note: this is not made available at lighting pass in this renderer - emission contribution is included (with GI) in the value GBuffer3.rgb, that is used as a renderTarget during lighting
- surfaceData.normalTS = (half3)0; // Note: does this normalTS member need to be in SurfaceData? It looks like an intermediate value
-
- return surfaceData;
- }
-
- // This will encode SurfaceData into GBuffer
- FragmentOutput BRDFDataToGbuffer(BRDFData brdfData, InputData inputData, half smoothness, half3 globalIllumination, half occlusion = 1.0)
- {
- half3 packedNormalWS = PackNormal(inputData.normalWS);
-
- uint materialFlags = 0;
-
- #ifdef _RECEIVE_SHADOWS_OFF
- materialFlags |= kMaterialFlagReceiveShadowsOff;
- #endif
-
- half3 packedSpecular;
-
- #ifdef _SPECULAR_SETUP
- materialFlags |= kMaterialFlagSpecularSetup;
- packedSpecular = brdfData.specular.rgb;
- #else
- packedSpecular.r = brdfData.reflectivity;
- packedSpecular.gb = 0.0;
- #endif
-
- #ifdef _SPECULARHIGHLIGHTS_OFF
- // During the next deferred shading pass, we don't use a shader variant to disable specular calculations.
- // Instead, we can either silence specular contribution when writing the gbuffer, and/or reserve a bit in the gbuffer
- // and use this during shading to skip computations via dynamic branching. Fastest option depends on platforms.
- materialFlags |= kMaterialFlagSpecularHighlightsOff;
- packedSpecular = 0.0.xxx;
- #endif
-
- #if defined(LIGHTMAP_ON) && defined(_MIXED_LIGHTING_SUBTRACTIVE)
- materialFlags |= kMaterialFlagSubtractiveMixedLighting;
- #endif
-
- FragmentOutput output;
- output.GBuffer0 = half4(brdfData.albedo.rgb, PackMaterialFlags(materialFlags)); // diffuse diffuse diffuse materialFlags (sRGB rendertarget)
- output.GBuffer1 = half4(packedSpecular, occlusion); // metallic/specular specular specular occlusion
- output.GBuffer2 = half4(packedNormalWS, smoothness); // encoded-normal encoded-normal encoded-normal smoothness
- output.GBuffer3 = half4(globalIllumination, 1); // GI GI GI unused (lighting buffer)
- #if _RENDER_PASS_ENABLED
- output.GBuffer4 = inputData.positionCS.z;
- #endif
- #if OUTPUT_SHADOWMASK
- output.GBUFFER_SHADOWMASK = inputData.shadowMask; // will have unity_ProbesOcclusion value if subtractive lighting is used (baked)
- #endif
- #ifdef _WRITE_RENDERING_LAYERS
- uint renderingLayers = GetMeshRenderingLayer();
- output.GBUFFER_LIGHT_LAYERS = float4(EncodeMeshRenderingLayer(renderingLayers), 0.0, 0.0, 0.0);
- #endif
-
- return output;
- }
-
- // This decodes the Gbuffer into a SurfaceData struct
- BRDFData BRDFDataFromGbuffer(half4 gbuffer0, half4 gbuffer1, half4 gbuffer2)
- {
- half3 albedo = gbuffer0.rgb;
- half3 specular = gbuffer1.rgb;
- uint materialFlags = UnpackMaterialFlags(gbuffer0.a);
- half smoothness = gbuffer2.a;
-
- 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;
-
- 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;
- }
-
- InputData InputDataFromGbufferAndWorldPosition(half4 gbuffer2, float3 wsPos)
- {
- InputData inputData = (InputData)0;
-
- inputData.positionWS = wsPos;
- inputData.normalWS = normalize(UnpackNormal(gbuffer2.xyz)); // normalize() is required because terrain shaders use additive blending for normals (not unit-length anymore)
-
- inputData.viewDirectionWS = GetWorldSpaceNormalizeViewDir(wsPos.xyz);
-
- // TODO: pass this info?
- inputData.shadowCoord = (float4)0;
- inputData.fogCoord = (half )0;
- inputData.vertexLighting = (half3 )0;
-
- inputData.bakedGI = (half3)0; // Note: this is not made available at lighting pass in this renderer - bakedGI contribution is included (with emission) in the value GBuffer3.rgb, that is used as a renderTarget during lighting
-
- return inputData;
- }
-
- #endif // UNIVERSAL_GBUFFERUTIL_INCLUDED
|