You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

147 lines
8.9 KiB

void ApplyDecalToSurfaceDataNoNormal(DecalSurfaceData decalSurfaceData, inout SurfaceData surfaceData)
{
// using alpha compositing https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch23.html
surfaceData.diffuseColor.xyz = surfaceData.diffuseColor.xyz * decalSurfaceData.baseColor.w + decalSurfaceData.baseColor.xyz;
#ifdef DECALS_4RT // only smoothness in 3RT mode
// Don't apply any metallic modification
surfaceData.ambientOcclusion = surfaceData.ambientOcclusion * decalSurfaceData.MAOSBlend.y + decalSurfaceData.mask.y;
#endif
surfaceData.perceptualSmoothness = surfaceData.perceptualSmoothness * decalSurfaceData.mask.w + decalSurfaceData.mask.z;
}
void BuildSurfaceData(FragInputs fragInputs, inout SurfaceDescription surfaceDescription, float3 V, PositionInputs posInput, out SurfaceData surfaceData, out float3 bentNormalWS)
{
// setup defaults -- these are used if the graph doesn't output a value
ZERO_INITIALIZE(SurfaceData, surfaceData);
// specularOcclusion need to be init ahead of decal to quiet the compiler that modify the SurfaceData struct
// however specularOcclusion can come from the graph, so need to be init here so it can be override.
surfaceData.specularOcclusion = 1.0;
// copy across graph values, if defined
$SurfaceDescription.BaseColor: surfaceData.diffuseColor = surfaceDescription.BaseColor;
$SurfaceDescription.AbsorptionCoefficient: surfaceData.absorption = surfaceDescription.AbsorptionCoefficient;
$SurfaceDescription.Eumelanin: surfaceData.eumelanin = surfaceDescription.Eumelanin;
$SurfaceDescription.Pheomelanin: surfaceData.pheomelanin = surfaceDescription.Pheomelanin;
\
$SurfaceDescription.SpecularOcclusion: surfaceData.specularOcclusion = surfaceDescription.SpecularOcclusion;
$SurfaceDescription.Smoothness: surfaceData.perceptualSmoothness = surfaceDescription.Smoothness;
$SurfaceDescription.Occlusion: surfaceData.ambientOcclusion = surfaceDescription.Occlusion;
$SurfaceDescription.Transmittance: surfaceData.transmittance = surfaceDescription.Transmittance;
$SurfaceDescription.RimTransmissionIntensity: surfaceData.rimTransmissionIntensity = surfaceDescription.RimTransmissionIntensity;
$SurfaceDescription.SpecularTint: surfaceData.specularTint = surfaceDescription.SpecularTint;
$SurfaceDescription.SpecularShift: surfaceData.specularShift = surfaceDescription.SpecularShift;
$SurfaceDescription.SecondarySmoothness: surfaceData.secondaryPerceptualSmoothness = surfaceDescription.SecondarySmoothness;
$SurfaceDescription.SecondarySpecularTint: surfaceData.secondarySpecularTint = surfaceDescription.SecondarySpecularTint;
$SurfaceDescription.SecondarySpecularShift: surfaceData.secondarySpecularShift = surfaceDescription.SecondarySpecularShift;
$SurfaceDescription.RadialSmoothness: surfaceData.perceptualRadialSmoothness = surfaceDescription.RadialSmoothness;
$SurfaceDescription.PrimaryReflectionSmoothness: surfaceData.primaryReflectionSmoothness = surfaceDescription.PrimaryReflectionSmoothness;
$SurfaceDescription.CuticleAngle: surfaceData.cuticleAngle = surfaceDescription.CuticleAngle;
$SurfaceDescription.StrandCountProbe: surfaceData.strandCountProbe = surfaceDescription.StrandCountProbe;
// These static material feature allow compile time optimization
surfaceData.materialFeatures = 0;
// Transform the preprocess macro into a material feature
#ifdef _MATERIAL_FEATURE_HAIR_KAJIYA_KAY
surfaceData.materialFeatures |= MATERIALFEATUREFLAGS_HAIR_KAJIYA_KAY;
#endif
#ifdef _MATERIAL_FEATURE_HAIR_MARSCHNER
surfaceData.materialFeatures |= MATERIALFEATUREFLAGS_HAIR_MARSCHNER;
#endif
#ifdef _MATERIAL_FEATURE_HAIR_MARSCHNER_CINEMATIC
surfaceData.materialFeatures |= MATERIALFEATUREFLAGS_HAIR_MARSCHNER_CINEMATIC;
#endif
float3 doubleSidedConstants = GetDoubleSidedConstants();
ApplyDecalAndGetNormal(fragInputs, posInput, surfaceDescription, surfaceData);
surfaceData.geomNormalWS = fragInputs.tangentToWorld[2];
// For a typical Unity quad, you have tangent vectors pointing to the right (X axis),
// and bitangent vectors pointing up (Y axis).
// The current hair setup uses mesh cards (e.g. quads).
// Hair is usually painted top-down, from the root to the tip.
// Therefore, DefaultHairStrandTangent = -MeshCardBitangent.
// Both the SurfaceData and the BSDFData store the hair tangent
// (which represents the hair strand direction, root to tip).
surfaceData.hairStrandDirectionWS = -fragInputs.tangentToWorld[1].xyz;
// The hair strand direction texture contains tangent-space vectors.
// We use the same convention for the texture, which means that
// to get the default behavior (DefaultHairStrandTangent = -MeshCardBitangent),
// the artist has to paint (0, -1, 0).
// TODO: pending artist feedback...
$HairStrandDirection: surfaceData.hairStrandDirectionWS = TransformTangentToWorld(surfaceDescription.HairStrandDirection, fragInputs.tangentToWorld);
// The original Kajiya-Kay BRDF model expects an orthonormal TN frame.
// Since we use the tangent shift hack (http://web.engr.oregonstate.edu/~mjb/cs519/Projects/Papers/HairRendering.pdf),
// we may as well not bother to orthonormalize anymore.
// The tangent should still be a unit vector, though.
surfaceData.hairStrandDirectionWS = normalize(surfaceData.hairStrandDirectionWS);
// Small digression about hair and normals [NOTE-HAIR-NORMALS].
// Since a hair strand is (approximately) a cylinder,
// there is a whole "circle" of normals corresponding to any given tangent vector.
// Since we use the Kajiya-Kay shading model,
// the way we compute and use normals is a bit complicated.
// We need 4 separate sets of normals.
// For shadow bias, we use the geometric normal.
// For direct lighting, we either (conceptually) use the "light-facing" normal
// or the user-provided normal.
// For reflected GI (light probes and reflection probes), we use the normal most aligned
// with the view vector (the "view-facing" normal), or the user-provided normal.
// We reflect this normal for transmitted GI.
// For the highlight shift hack (along the tangent), we use the user-provided normal.
#if (_USE_LIGHT_FACING_NORMAL)
float3 viewFacingNormalWS = ComputeViewFacingNormal(V, surfaceData.hairStrandDirectionWS);
float3 N = viewFacingNormalWS; // Not affected by decals
#else
float3 N = surfaceData.normalWS;
#endif
bentNormalWS = N;
$BentNormal: GetNormalWS(fragInputs, surfaceDescription.BentNormal, bentNormalWS, doubleSidedConstants);
#ifdef DEBUG_DISPLAY
#if !defined(SHADER_STAGE_RAY_TRACING)
// Mipmap mode debugging isn't supported with ray tracing as it relies on derivatives
if (_DebugMipMapMode != DEBUGMIPMAPMODE_NONE)
{
#ifdef FRAG_INPUTS_USE_TEXCOORD0
surfaceData.diffuseColor = GET_TEXTURE_STREAMING_DEBUG(posInput.positionSS, fragInputs.texCoord0);
#else
surfaceData.diffuseColor = GET_TEXTURE_STREAMING_DEBUG_NO_UV(posInput.positionSS);
#endif
}
#endif
// We need to call ApplyDebugToSurfaceData after filling the surfarcedata and before filling builtinData
// as it can modify attribute use for static lighting
ApplyDebugToSurfaceData(fragInputs.tangentToWorld, surfaceData);
#endif
#if defined(_SPECULAR_OCCLUSION_CUSTOM)
// Just use the value passed through via the slot (not active otherwise)
#elif defined(_SPECULAR_OCCLUSION_FROM_AO_BENT_NORMAL)
// If we have bent normal and ambient occlusion, process a specular occlusion
surfaceData.specularOcclusion = GetSpecularOcclusionFromBentAO(V, bentNormalWS, N, surfaceData.ambientOcclusion, PerceptualSmoothnessToPerceptualRoughness(surfaceData.perceptualSmoothness));
#elif defined(_AMBIENT_OCCLUSION) && defined(_SPECULAR_OCCLUSION_FROM_AO)
surfaceData.specularOcclusion = GetSpecularOcclusionFromAmbientOcclusion(ClampNdotV(dot(N, V)), surfaceData.ambientOcclusion, PerceptualSmoothnessToRoughness(surfaceData.perceptualSmoothness));
#endif
#if defined(_ENABLE_GEOMETRIC_SPECULAR_AA) && !defined(SHADER_STAGE_RAY_TRACING)
surfaceData.perceptualSmoothness = GeometricNormalFiltering(surfaceData.perceptualSmoothness, fragInputs.tangentToWorld[2], surfaceDescription.SpecularAAScreenSpaceVariance, surfaceDescription.SpecularAAThreshold);
#endif
}