Files
2022-01-22 20:13:49 -08:00

649 lines
20 KiB
HLSL
Vendored

// Alloy Physical Shader Framework
// Copyright 2013-2017 RUST LLC.
// http://www.alloy.rustltd.com/
///////////////////////////////////////////////////////////////////////////////
/// @file Forward.cginc
/// @brief Forward passes uber-header.
///////////////////////////////////////////////////////////////////////////////
#ifndef ALLOY_SHADERS_FRAMEWORK_FORWARD_CGINC
#define ALLOY_SHADERS_FRAMEWORK_FORWARD_CGINC
// Headers both for this file, and for all Definition and Feature modules.
#include "Assets/Alloy/Shaders/Framework/FeatureImpl.cginc"
#include "Assets/Alloy/Shaders/Framework/LightingImpl.cginc"
#include "Assets/Alloy/Shaders/Framework/TypeImpl.cginc"
#include "Assets/Alloy/Shaders/Framework/Unity.cginc"
#include "Assets/Alloy/Shaders/Framework/Utility.cginc"
#include "AutoLight.cginc"
#include "HLSLSupport.cginc"
#include "UnityCG.cginc"
#include "UnityGlobalIllumination.cginc"
#include "UnityImageBasedLighting.cginc"
#include "UnityInstancing.cginc"
#include "UnityLightingCommon.cginc"
#include "UnityShaderUtilities.cginc"
#include "UnityShaderVariables.cginc"
#include "UnityShadowLibrary.cginc"
#include "UnityStandardUtils.cginc"
// Support for two-sided effects in a single pass.
#ifndef A_TWO_SIDED_SHADER
#define A_FACING_SIGN_PARAM
#define A_FACING_SIGN 1.0h
#else
#define A_FACING_SIGN_PARAM ,half facingSign : VFACE
#define A_FACING_SIGN facingSign
#endif
// Shadows.
#if defined(SHADOWS_SCREEN) && !defined(UNITY_NO_SCREENSPACE_SHADOWS)
#define A_SCREENSPACE_SHADOWS_ON
#endif
// Lightmaps.
#if !defined(A_UV2_ON) && defined(DYNAMICLIGHTMAP_ON) && defined(A_INDIRECT_ON)
#define A_UV2_ON
#endif
#if defined(LIGHTMAP_ON) && defined(LIGHTMAP_SHADOW_MIXING) && !defined(SHADOWS_SHADOWMASK) && defined(SHADOWS_SCREEN)
#define A_LIGHTMAP_SHADOW_MIXING_ON
#endif
// Lighting vertex data.
#if defined(A_INDIRECT_ON) && defined(A_DIRECT_ON)
#define A_FORWARD_TEXCOORD0 half4 giData : TEXCOORD0;
#define A_FORWARD_TEXCOORD1 UNITY_SHADOW_COORDS(1)
#elif defined(A_INDIRECT_ON)
#define A_FORWARD_TEXCOORD0 half4 giData : TEXCOORD0;
#ifdef A_SHADOW_MASKS_BUFFER_ON
#define A_FORWARD_TEXCOORD1 UNITY_SHADOW_COORDS(1)
#endif
#elif defined(A_DIRECT_ON)
#define A_FORWARD_TEXCOORD0 UNITY_SHADOW_COORDS(0)
// Reduce v2f transfer cost for pure directional lights.
#if !defined(DIRECTIONAL) && !defined(A_LIGHTMAP_SHADOW_MIXING_ON)
#define A_FORWARD_TEXCOORD1 unityShadowCoord4 lightCoord : TEXCOORD1;
#ifndef USING_DIRECTIONAL_LIGHT
#define A_FORWARD_TEXCOORD2 float4 lightVectorRange : TEXCOORD2;
#endif
#endif
#endif
// Handle dependencies between vertex data.
#if !defined(A_TANGENT_ON) && defined(A_TANGENT_TO_WORLD_ON)
#define A_TANGENT_ON
#endif
#if !defined(A_NORMAL_WORLD_ON) && (defined(A_TANGENT_TO_WORLD_ON) || defined(A_REFLECTION_VECTOR_WORLD_ON))
#define A_NORMAL_WORLD_ON
#endif
#if !defined(A_VIEW_DIR_WORLD_ON) && (defined(A_VIEW_DIR_TANGENT_ON) || defined(A_REFLECTION_VECTOR_WORLD_ON))
#define A_VIEW_DIR_WORLD_ON
#endif
#if !defined(A_POSITION_WORLD_ON) && defined(A_VIEW_DIR_WORLD_ON)
#define A_POSITION_WORLD_ON
#endif
#if !defined(A_SCREEN_UV_ON) && defined(LOD_FADE_CROSSFADE)
#define A_SCREEN_UV_ON
#endif
// Enable specific packed texcoord channels.
#if !defined(A_POSITION_TEXCOORD_ON) && (defined(A_POSITION_WORLD_ON) || defined(A_VIEW_DEPTH_ON))
#define A_POSITION_TEXCOORD_ON
#endif
#if !defined(A_FOG_TEXCOORD_ON) && (defined(A_FOG_ON) || defined(A_SCREEN_UV_ON))
#define A_FOG_TEXCOORD_ON
#endif
#if !defined(A_TRANSFER_INSTANCE_ID_ON) && defined(A_WORLD_TO_OBJECT_ON) && defined(A_INSTANCING_PASS)
#define A_TRANSFER_INSTANCE_ID_ON
#endif
// Split vertex data conditions to reduce combinations.
// UV0-1, TBN, N.
#if defined(A_TANGENT_TO_WORLD_ON)
#define A_INNER_VERTEX_DATA2(A, B, C, D) \
float4 texcoords : TEXCOORD##A; \
half3 tangentWorld : TEXCOORD##B; \
half3 bitangentWorld : TEXCOORD##C; \
half3 normalWorld : TEXCOORD##D;
#elif defined(A_NORMAL_WORLD_ON)
#define A_INNER_VERTEX_DATA2(A, B, C, D) \
float4 texcoords : TEXCOORD##A; \
half3 normalWorld : TEXCOORD##B;
#else
#define A_INNER_VERTEX_DATA2(A, B, C, D) \
float4 texcoords : TEXCOORD##A;
#endif
// Vertex Color, Position, View Depth, Fog, and Screen UV.
#if defined(A_POSITION_TEXCOORD_ON) && defined(A_FOG_TEXCOORD_ON)
#define A_INNER_VERTEX_DATA1(A, B, C, D, E, F, G) \
half4 color : TEXCOORD##A; \
float4 positionWorldAndViewDepth : TEXCOORD##B; \
UNITY_FOG_COORDS_PACKED(C, half4) \
A_INNER_VERTEX_DATA2(D, E, F, G)
#elif defined(A_POSITION_TEXCOORD_ON)
#define A_INNER_VERTEX_DATA1(A, B, C, D, E, F, G) \
half4 color : TEXCOORD##A; \
float4 positionWorldAndViewDepth : TEXCOORD##B; \
A_INNER_VERTEX_DATA2(C, D, E, F)
#elif defined(A_FOG_TEXCOORD_ON)
#define A_INNER_VERTEX_DATA1(A, B, C, D, E, F, G) \
half4 color : TEXCOORD##A; \
UNITY_FOG_COORDS_PACKED(C, half4) \
A_INNER_VERTEX_DATA2(D, E, F, G)
#else
#define A_INNER_VERTEX_DATA1(A, B, C, D, E, F, G) \
half4 color : TEXCOORD##A; \
A_INNER_VERTEX_DATA2(B, C, D, E)
#endif
// Instancing.
#if defined(A_TRANSFER_INSTANCE_ID_ON) && defined(A_STEREO_INSTANCING_PASS)
#define A_INSTANCING_VERTEX_DATA(A, B, C, D, E, F, G) A_INNER_VERTEX_DATA1(A, B, C, D, E, F, G) UNITY_VERTEX_INPUT_INSTANCE_ID UNITY_VERTEX_OUTPUT_STEREO
#elif defined(A_TRANSFER_INSTANCE_ID_ON)
#define A_INSTANCING_VERTEX_DATA(A, B, C, D, E, F, G) A_INNER_VERTEX_DATA1(A, B, C, D, E, F, G) UNITY_VERTEX_INPUT_INSTANCE_ID
#elif defined(A_STEREO_INSTANCING_PASS)
#define A_INSTANCING_VERTEX_DATA(A, B, C, D, E, F, G) A_INNER_VERTEX_DATA1(A, B, C, D, E, F, G) UNITY_VERTEX_OUTPUT_STEREO
#else
#define A_INSTANCING_VERTEX_DATA(A, B, C, D, E, F, G) A_INNER_VERTEX_DATA1(A, B, C, D, E, F, G)
#endif
// Surface shader off.
#if defined(A_SURFACE_SHADER_OFF)
#define A_VERTEX_DATA(A, B, C, D, E, F, G)
#else
#define A_VERTEX_DATA(A, B, C, D, E, F, G) A_INSTANCING_VERTEX_DATA(A, B, C, D, E, F, G)
#endif
/// Configurable vertex input data from the application.
struct AVertexInput
{
float4 vertex : POSITION;
float4 uv0 : TEXCOORD0;
float4 uv1 : TEXCOORD1;
half3 normal : NORMAL;
#ifdef A_UV2_ON
float4 uv2 : TEXCOORD2;
#endif
#ifdef A_UV3_ON
float4 uv3 : TEXCOORD3;
#endif
#ifdef A_TANGENT_ON
half4 tangent : TANGENT;
#endif
half4 color : COLOR;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
/// Extensible fragment input data.
struct AFragmentInput {
#if defined(A_FORWARD_TEXCOORD0) && defined(A_FORWARD_TEXCOORD1) && defined(A_FORWARD_TEXCOORD2)
A_FORWARD_TEXCOORD0
A_FORWARD_TEXCOORD1
A_FORWARD_TEXCOORD2
A_VERTEX_DATA(3, 4, 5, 6, 7, 8, 9)
#elif defined(A_FORWARD_TEXCOORD0) && defined(A_FORWARD_TEXCOORD1)
A_FORWARD_TEXCOORD0
A_FORWARD_TEXCOORD1
A_VERTEX_DATA(2, 3, 4, 5, 6, 7, 8)
#elif defined(A_FORWARD_TEXCOORD0)
A_FORWARD_TEXCOORD0
A_VERTEX_DATA(1, 2, 3, 4, 5, 6, 7)
#else
A_VERTEX_DATA(0, 1, 2, 3, 4, 5, 6)
#endif
};
// TODO: Find a way to move this dependency!
#include "Assets/Alloy/Shaders/Framework/Tessellation.cginc"
/// Transfers the per-vertex lightmapping or SH data to the fragment shader.
/// @param[in,out] i Vertex to fragment transfer data.
/// @param[in] v Vertex input data.
void aVertexGi(
inout AFragmentInput i,
AVertexInput v)
{
#ifdef A_INDIRECT_ON
#ifdef LIGHTMAP_ON
i.giData.xy = v.uv1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
i.giData.zw = 0.0h;
#elif UNITY_SHOULD_SAMPLE_SH
// Add approximated illumination from non-important point lights
half3 normalWorld = i.normalWorld.xyz;
#ifdef VERTEXLIGHT_ON
i.giData.rgb = aShade4PointLights(i.positionWorldAndViewDepth.xyz, normalWorld);
#endif
i.giData.rgb = ShadeSHPerVertex(normalWorld, i.giData.rgb);
#endif
#ifdef DYNAMICLIGHTMAP_ON
i.giData.zw = v.uv2.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
#endif
#endif
}
/// Populates a UnityGI descriptor in the fragment shader.
/// @param i Vertex to fragment transfer data.
/// @param s Material surface data.
/// @param shadow Forward Base directional light shadow.
/// @return Initialized UnityGI descriptor.
UnityGI aFragmentGi(
AFragmentInput i,
ASurface s,
half shadow)
{
UnityGI gi;
UNITY_INITIALIZE_OUTPUT(UnityGI, gi);
#ifdef A_INDIRECT_ON
UnityGIInput d;
UNITY_INITIALIZE_OUTPUT(UnityGIInput, d);
d.worldPos = s.positionWorld;
d.worldViewDir = s.viewDirWorld; // ???
d.atten = shadow;
#if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON)
d.ambient = 0;
d.lightmapUV = i.giData;
#else
d.ambient = i.giData.rgb;
d.lightmapUV = 0;
#endif
d.probeHDR[0] = unity_SpecCube0_HDR;
d.probeHDR[1] = unity_SpecCube1_HDR;
#if defined(UNITY_SPECCUBE_BLENDING) || defined(UNITY_SPECCUBE_BOX_PROJECTION)
d.boxMin[0] = unity_SpecCube0_BoxMin; // .w holds lerp value for blending
#endif
#ifdef UNITY_SPECCUBE_BOX_PROJECTION
d.boxMax[0] = unity_SpecCube0_BoxMax;
d.probePosition[0] = unity_SpecCube0_ProbePosition;
d.boxMax[1] = unity_SpecCube1_BoxMax;
d.boxMin[1] = unity_SpecCube1_BoxMin;
d.probePosition[1] = unity_SpecCube1_ProbePosition;
#endif
// So we can extract shadow with baked occlusion.
#ifdef HANDLE_SHADOWS_BLENDING_IN_GI
d.light.color = A_WHITE;
#endif
// Pass 1.0 for occlusion so we can apply it later in indirect().
gi = UnityGI_Base(d, 1.0h, s.ambientNormalWorld);
#ifdef A_REFLECTION_PROBES_ON
Unity_GlossyEnvironmentData g;
g.reflUVW = s.reflectionVectorWorld;
g.roughness = s.roughness;
gi.indirect.specular = UnityGI_IndirectSpecular(d, 1.0h, s.normalWorld, g);
#endif
#endif
return gi;
}
/// Transforms the vertex data before transferring it to the pixel shader.
/// @param[in,out] v Vertex input data.
/// @param[out] o Vertex to fragment transfer data.
/// @param[out] opos Clip space position.
void aForwardVertexShader(
inout AVertexInput v,
out AFragmentInput o,
out float4 opos)
{
#ifdef A_SURFACE_SHADER_OFF
opos = 0.0h;
#else
UNITY_INITIALIZE_OUTPUT(AFragmentInput, o);
#ifdef A_INSTANCING_PASS
UNITY_SETUP_INSTANCE_ID(v);
#ifdef A_TRANSFER_INSTANCE_ID_ON
UNITY_TRANSFER_INSTANCE_ID(v, o);
#endif
#ifdef A_STEREO_INSTANCING_PASS
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
#endif
#endif
// Copy vertex data, and let shader type modify it.
AVertex vs = aNewVertex();
vs.positionObject = v.vertex;
vs.uv0 = v.uv0;
vs.uv1 = v.uv1;
vs.normalObject = v.normal;
#ifdef A_UV2_ON
vs.uv2 = v.uv2;
#endif
#ifdef A_UV3_ON
vs.uv3 = v.uv3;
#endif
#ifdef A_TANGENT_ON
vs.tangentObject = v.tangent;
#endif
vs.color = v.color;
aVertexShader(vs);
// Copy data back into original, in case outer shader needs it.
v.vertex = vs.positionObject;
v.uv0 = vs.uv0;
v.uv1 = vs.uv1;
v.normal = vs.normalObject;
#ifdef A_UV2_ON
v.uv2 = vs.uv2;
#endif
#ifdef A_UV3_ON
v.uv3 = vs.uv3;
#endif
#ifdef A_TANGENT_ON
v.tangent = vs.tangentObject;
#endif
v.color = vs.color;
// Fill V2F.
o.color = v.color; // Gamma-space vertex color, unless modified.
o.texcoords.xy = v.uv0.xy;
o.texcoords.zw = v.uv1.xy;
opos = UnityObjectToClipPos(v.vertex.xyz);
#ifdef A_POSITION_TEXCOORD_ON
#ifdef A_POSITION_WORLD_ON
o.positionWorldAndViewDepth.xyz = mul(unity_ObjectToWorld, v.vertex).xyz;
#endif
#ifdef A_VIEW_DEPTH_ON
COMPUTE_EYEDEPTH(o.positionWorldAndViewDepth.w);
#endif
#endif
#ifdef A_NORMAL_WORLD_ON
float3 normalWorld = UnityObjectToWorldNormal(v.normal);
#endif
#ifndef A_TANGENT_TO_WORLD_ON
#ifdef A_NORMAL_WORLD_ON
o.normalWorld = normalWorld;
#endif
#else
float3 tangentWorld = UnityObjectToWorldDir(v.tangent.xyz);
float3x3 tangentToWorld = CreateTangentToWorldPerVertex(normalWorld, tangentWorld, v.tangent.w);
o.tangentWorld = tangentToWorld[0];
o.bitangentWorld = tangentToWorld[1];
o.normalWorld = tangentToWorld[2];
#endif
#if defined(A_SCREEN_UV_ON) || (defined(A_DIRECT_ON) && defined(A_SCREENSPACE_SHADOWS_ON))
float4 screenPos = ComputeScreenPos(opos);
#endif
// Fog and Screen UV.
#ifdef A_FOG_TEXCOORD_ON
#ifdef A_SCREEN_UV_ON
o.fogCoord.yzw = screenPos.xyw;
#else
o.fogCoord.yzw = A_AXIS_Z;
#endif
#ifdef A_FOG_ON
UNITY_TRANSFER_FOG(o, opos);
#endif
#endif
// Lighting data.
aVertexGi(o, v);
#ifdef A_DIRECT_ON
// NOTE: Custom macro to skip calculations and remove dependency on o.pos!
#ifdef A_SCREENSPACE_SHADOWS_ON
o._ShadowCoord = screenPos;
#else
UNITY_TRANSFER_SHADOW(o, v.uv1);
#endif
#if !defined(DIRECTIONAL) && !defined(A_LIGHTMAP_SHADOW_MIXING_ON)
o.lightCoord = mul(unity_WorldToLight, unityShadowCoord4(o.positionWorldAndViewDepth.xyz, 1.0f));
#ifndef USING_DIRECTIONAL_LIGHT
o.lightVectorRange = UnityWorldSpaceLightDir(o.positionWorldAndViewDepth.xyz).xyzz;
aLightRange(o.lightVectorRange, o.lightCoord);
#endif
#endif
#endif
#endif
}
/// Create a surface populated with material data.
/// @param i Vertex to fragment transfer data.
/// @param facingSign Sign of front/back facing direction.
/// @return Initialized surface data object.
ASurface aForwardSurface(
AFragmentInput i,
half facingSign)
{
ASurface s = aNewSurface();
#ifndef A_SURFACE_SHADER_OFF
#ifdef A_TRANSFER_INSTANCE_ID_ON
UNITY_SETUP_INSTANCE_ID(i);
#endif
s.uv01 = i.texcoords;
s.vertexColor = i.color;
s.facingSign = facingSign;
#ifdef A_POSITION_TEXCOORD_ON
#ifdef A_POSITION_WORLD_ON
s.positionWorld = i.positionWorldAndViewDepth.xyz;
#endif
#ifdef A_VIEW_DEPTH_ON
s.viewDepth = i.positionWorldAndViewDepth.w;
#endif
#endif
#ifdef A_NORMAL_WORLD_ON
#ifdef A_TWO_SIDED_SHADER
i.normalWorld.xyz *= facingSign;
#endif
// Give these sane defaults in case the surface shader doesn't set them.
s.vertexNormalWorld = normalize(i.normalWorld);
s.normalWorld = s.vertexNormalWorld;
s.ambientNormalWorld = s.vertexNormalWorld;
#endif
#ifdef A_VIEW_DIR_WORLD_ON
// Cheaper to calculate in PS than to unpack from vertex, while also
// preventing distortion in POM and area light specular highlights.
s.viewDirWorld = normalize(UnityWorldSpaceViewDir(s.positionWorld));
#endif
#ifdef A_TANGENT_TO_WORLD_ON
half3 t = i.tangentWorld;
half3 b = i.bitangentWorld;
half3 n = i.normalWorld;
#if UNITY_TANGENT_ORTHONORMALIZE
n = normalize(n);
// ortho-normalize Tangent
t = normalize (t - n * dot(t, n));
// recalculate Binormal
half3 newB = cross(n, t);
b = newB * sign (dot (newB, b));
#endif
s.tangentToWorld = half3x3(t, b, n);
#if defined(A_VIEW_DIR_WORLD_ON) && defined(A_VIEW_DIR_TANGENT_ON)
s.viewDirTangent = normalize(mul(s.tangentToWorld, s.viewDirWorld));
#endif
#endif
#ifdef A_FOG_TEXCOORD_ON
#ifdef A_FOG_ON
s.fogCoord = i.fogCoord;
#endif
#ifdef A_SCREEN_UV_ON
s.screenPosition.xyw = i.fogCoord.yzw;
s.screenPosition.z = 0.0h;
s.screenUv.xy = s.screenPosition.xy / s.screenPosition.w;
#ifdef LOD_FADE_CROSSFADE
half2 projUV = s.screenUv.xy * _ScreenParams.xy * 0.25h;
projUV.y = frac(projUV.y) * 0.0625h /* 1/16 */ + unity_LODFade.y; // quantized lod fade by 16 levels
clip(tex2D(_DitherMaskLOD2D, projUV).a - 0.5f);
#endif
#endif
#endif
// Runs the shader and lighting type's surface code.
aBaseUvInit(s);
aUpdateViewData(s);
aSurfaceShader(s);
aPreLighting(s);
#endif
return s;
}
/// Final processing of the forward color before output.
/// @param s Material surface data.
/// @param color Lighting + Emission + Fog + etc.
/// @return Final HDR output color with alpha opacity.
half4 aForwardColor(
ASurface s,
half3 color)
{
half4 output;
#if defined(A_ALPHA_BLENDING_PASS) && defined(A_ALPHA_BLENDING_ON)
output.a = s.opacity;
#else
UNITY_OPAQUE_ALPHA(output.a);
#endif
output.rgb = color;
aColorShader(output, s);
return aHdrClamp(output);
}
/// Calculates forward lighting from surface and vertex data.
/// @param i Vertex to fragment transfer data.
/// @param facingSign Sign of front/back facing direction.
/// @return Forward direct and indirect lighting.
half4 aForwardLitColorShader(
AFragmentInput i,
half facingSign)
{
half3 illum = 0.0h;
ASurface s = aForwardSurface(i, facingSign);
#ifdef A_LIGHTING_ON
half shadow = UNITY_SHADOW_ATTENUATION(i, s.positionWorld);
#ifdef A_INDIRECT_ON
UnityGI gi = aFragmentGi(i, s, shadow);
illum = aUnityIndirectLighting(gi, s);
// Extract shadow with combined baked occlusion.
#ifdef HANDLE_SHADOWS_BLENDING_IN_GI
shadow = gi.light.color.g;
#endif
#endif
// Do lightmap shadow mixing guard here, since we need direct vertex data.
#if defined(A_DIRECT_ON) && !defined(A_LIGHTMAP_SHADOW_MIXING_ON)
// Reduce v2f transfer cost for pure directional lights.
#if defined(DIRECTIONAL)
illum += aUnityDirectLighting(s, shadow, _WorldSpaceLightPos0, A_ZERO4);
#elif defined(DIRECTIONAL_COOKIE)
illum += aUnityDirectLighting(s, shadow, _WorldSpaceLightPos0, i.lightCoord);
#else
illum += aUnityDirectLighting(s, shadow, i.lightVectorRange, i.lightCoord);
#endif
#endif
#endif
#if defined(A_BASE_PASS) && defined(A_EMISSIVE_COLOR_ON)
illum += s.emissiveColor;
#endif
return aForwardColor(s, illum);
}
/// Creates a G-Buffer from the provided surface data.
/// @param i Vertex to fragment transfer data.
/// @param facingSign Sign of front/back facing direction.
/// @return G-buffer with surface data and ambient illumination.
AGbuffer aForwardLitGbufferShader(
AFragmentInput i,
half facingSign)
{
half3 illum = 0.0h;
AGbuffer gb = aNewGbuffer();
ASurface s = aForwardSurface(i, facingSign);
#ifdef A_INDIRECT_ON
illum += aUnityIndirectLighting(aFragmentGi(i, s, 1.0h), s);
// Baked direct lighting occlusion if any.
#ifdef A_SHADOW_MASKS_BUFFER_ON
gb.shadowMasks = UnityGetRawBakedOcclusions(i.giData.xy, s.positionWorld);
#endif
#endif
#ifdef A_EMISSIVE_COLOR_ON
illum += s.emissiveColor;
#endif
#if defined(A_INDIRECT_ON) || defined(A_EMISSIVE_COLOR_ON)
illum = aHdrClamp(illum);
#endif
#ifndef UNITY_HDR_ON
illum = exp2(-illum);
#endif
gb.diffuseOcclusion = half4(s.albedo, s.specularOcclusion);
gb.specularSmoothness = half4(s.f0, 1.0h - s.roughness);
gb.normalType = half4(s.normalWorld * 0.5h + 0.5h, s.materialType);
gb.emissionSubsurface = half4(illum, s.subsurface);
aGbufferShader(gb, s);
return gb;
}
#endif // ALLOY_SHADERS_FRAMEWORK_FORWARD_CGINC