171 lines
7.0 KiB
HLSL
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
|
|
}
|