2021-09-09 20:42:29 -04:00

171 lines
7.0 KiB
HLSL

#if (SHADERPASS != SHADERPASS_DEPTH_ONLY) && (SHADERPASS != SHADERPASS_DBUFFER_PROJECTOR) && (SHADERPASS != SHADERPASS_DBUFFER_MESH) && (SHADERPASS != SHADERPASS_FORWARD_EMISSIVE_PROJECTOR) && (SHADERPASS != SHADERPASS_FORWARD_EMISSIVE_MESH) && (SHADERPASS != SHADERPASS_FORWARD_PREVIEW)
#error SHADERPASS_is_not_correctly_define
#endif
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/VertMesh.hlsl"
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Decal/DecalPrepassBuffer.hlsl"
#if (SHADERPASS == SHADERPASS_DBUFFER_MESH)
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/DecalMeshBiasTypeEnum.cs.hlsl"
#endif
void MeshDecalsPositionZBias(inout VaryingsToPS input)
{
#if UNITY_REVERSED_Z
input.vmesh.positionCS.z -= _DecalMeshDepthBias;
#else
input.vmesh.positionCS.z += _DecalMeshDepthBias;
#endif
}
PackedVaryingsType Vert(AttributesMesh inputMesh)
{
VaryingsType varyingsType;
#if (SHADERPASS == SHADERPASS_DBUFFER_MESH)
float3 worldSpaceBias = 0.0f;
if (_DecalMeshBiasType == DECALMESHDEPTHBIASTYPE_VIEW_BIAS)
{
float3 positionRWS = TransformObjectToWorld(inputMesh.positionOS);
float3 V = GetWorldSpaceNormalizeViewDir(positionRWS);
worldSpaceBias = V * (_DecalMeshViewBias);
}
varyingsType.vmesh = VertMesh(inputMesh, worldSpaceBias);
if (_DecalMeshBiasType == DECALMESHDEPTHBIASTYPE_DEPTH_BIAS)
{
MeshDecalsPositionZBias(varyingsType);
}
#else
varyingsType.vmesh = VertMesh(inputMesh);
#endif
return PackVaryingsType(varyingsType);
}
void Frag( PackedVaryingsToPS packedInput,
#if (SHADERPASS == SHADERPASS_DBUFFER_PROJECTOR) || (SHADERPASS == SHADERPASS_DBUFFER_MESH)
OUTPUT_DBUFFER(outDBuffer)
#elif defined(SCENEPICKINGPASS) || (SHADERPASS == SHADERPASS_FORWARD_PREVIEW) // Only used for preview in shader graph and scene picking
out float4 outColor : SV_Target0
#else
out float4 outEmissive : SV_Target0
#endif
)
{
#ifdef SCENEPICKINGPASS
outColor = _SelectionID;
#else
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(packedInput);
FragInputs input = UnpackVaryingsToFragInputs(packedInput);
DecalSurfaceData surfaceData;
float clipValue = 1.0;
float angleFadeFactor = 1.0;
#if (SHADERPASS == SHADERPASS_DBUFFER_PROJECTOR) || (SHADERPASS == SHADERPASS_FORWARD_EMISSIVE_PROJECTOR)
float depth = LoadCameraDepth(input.positionSS.xy);
PositionInputs posInput = GetPositionInput(input.positionSS.xy, _ScreenSize.zw, depth, UNITY_MATRIX_I_VP, UNITY_MATRIX_V);
// Decal layer mask accepted by the receiving material
DecalPrepassData material;
ZERO_INITIALIZE(DecalPrepassData, material);
if (_EnableDecalLayers)
{
// Clip the decal if it does not pass the decal layer mask of the receiving material.
// Decal layer of the decal
uint decalLayerMask = uint(UNITY_ACCESS_INSTANCED_PROP(Decal, _DecalLayerMaskFromDecal).x);
DecodeFromDecalPrepass(posInput.positionSS, material);
if ((decalLayerMask & material.decalLayerMask) == 0)
clipValue -= 2.0;
}
// Transform from relative world space to decal space (DS) to clip the decal
float3 positionDS = TransformWorldToObject(posInput.positionWS);
positionDS = positionDS * float3(1.0, -1.0, 1.0) + float3(0.5, 0.5, 0.5);
if (!(all(positionDS.xyz > 0.0f) && all(1.0f - positionDS.xyz > 0.0f)))
{
clipValue -= 2.0; // helper lanes will be clipped
}
// call clip as early as possible
#ifndef SHADER_API_METAL
// Calling clip here instead of inside the condition above shouldn't make any performance difference
// but case save one clip call.
clip(clipValue);
#else
// Metal Shading Language declares that fragment discard invalidates
// derivatives for the rest of the quad, so we need to reorder when
// we discard during decal projection, or we get artifacts along the
// edges of the projection(any partial quads get bad partial derivatives
//regardless of whether they are computed implicitly or explicitly).
ZERO_INITIALIZE(DecalSurfaceData, surfaceData); // Require to quiet compiler warning with Metal
// Note we can't used dynamic branching here to avoid to pay the cost of texture fetch otherwise we need to calculate derivatives ourselves.
#endif
input.texCoord0.xy = positionDS.xz;
input.texCoord1.xy = positionDS.xz;
input.texCoord2.xy = positionDS.xz;
input.texCoord3.xy = positionDS.xz;
float3 V = GetWorldSpaceNormalizeViewDir(posInput.positionWS);
// For now we only allow angle fading when decal layers are enabled
// TODO: Reconstructing normal from depth buffer result in poor result.
// We may revisit it in the future
// This is example code: float3 vtxNormal = normalize(cross(ddy(posInput.positionWS), ddx(posInput.positionWS)));
// But better implementation (and costlier) can be find here: https://atyuwen.github.io/posts/normal-reconstruction/
if (_EnableDecalLayers)
{
// Check if this decal projector require angle fading
float4x4 normalToWorld = UNITY_ACCESS_INSTANCED_PROP(Decal, _NormalToWorld);
float2 angleFade = float2(normalToWorld[1][3], normalToWorld[2][3]);
if (angleFade.y < 0.0f) // if angle fade is enabled
{
float3 decalNormal = float3(normalToWorld[0].z, normalToWorld[1].z, normalToWorld[2].z);
float dotAngle = dot(material.geomNormalWS, decalNormal);
// See equation in DecalSystem.cs - simplified to a madd mul add here
angleFadeFactor = saturate(angleFade.x + angleFade.y * (dotAngle * (dotAngle - 2.0)));
}
}
#else // Decal mesh
// input.positionSS is SV_Position
PositionInputs posInput = GetPositionInput(input.positionSS.xy, _ScreenSize.zw, input.positionSS.z, input.positionSS.w, input.positionRWS.xyz, uint2(0, 0));
#ifdef VARYINGS_NEED_POSITION_WS
float3 V = GetWorldSpaceNormalizeViewDir(input.positionRWS);
#else
// Unused
float3 V = float3(1.0, 1.0, 1.0); // Avoid the division by 0
#endif
#endif
GetSurfaceData(input, V, posInput, angleFadeFactor, surfaceData);
#if ((SHADERPASS == SHADERPASS_DBUFFER_PROJECTOR) || (SHADERPASS == SHADERPASS_FORWARD_EMISSIVE_PROJECTOR)) && defined(SHADER_API_METAL)
clip(clipValue);
#endif
#if (SHADERPASS == SHADERPASS_DBUFFER_PROJECTOR) || (SHADERPASS == SHADERPASS_DBUFFER_MESH)
ENCODE_INTO_DBUFFER(surfaceData, outDBuffer);
#elif (SHADERPASS == SHADERPASS_FORWARD_PREVIEW) // Only used for preview in shader graph
outColor = 0;
// Evaluate directional light from the preview
uint i;
for (i = 0; i < _DirectionalLightCount; ++i)
{
DirectionalLightData light = _DirectionalLightDatas[i];
outColor.rgb += surfaceData.baseColor.rgb * light.color * saturate(dot(surfaceData.normalWS.xyz, -light.forward.xyz));
}
outColor.rgb += surfaceData.emissive;
outColor.w = 1.0;
#else
// Emissive need to be pre-exposed
outEmissive.rgb = surfaceData.emissive * GetCurrentExposureMultiplier();
outEmissive.a = 1.0;
#endif
#endif
}