#undef LAYER_INDEX
#undef ADD_IDX
void ComputeMaskWeights(float3 inputMasks, out float outWeights[_MAX_LAYER])
void ComputeMaskWeights(float4 inputMasks, out float outWeights[_MAX_LAYER])
masks[0] = 1.0; // Layer 0 is always full
masks[0] = inputMasks.a; // Should be 1.0 in most case except when alpha masked and desnity mode is used
masks[1] = inputMasks.r;
masks[2] = inputMasks.g;
masks[3] = inputMasks.b;
#define SURFACEDATA_BLEND_VECTOR3(surfaceData, name, mask) BlendLayeredVector3(surfaceData##0.##name, surfaceData##1.##name, surfaceData##2.##name, surfaceData##3.##name, mask);
#define SURFACEDATA_BLEND_SCALAR(surfaceData, name, mask) BlendLayeredScalar(surfaceData##0.##name, surfaceData##1.##name, surfaceData##2.##name, surfaceData##3.##name, mask);
#define PROP_BLEND_SCALAR(name, mask) BlendLayeredScalar(name##0, name##1, name##2, name##3, mask);
float ApplyHeightBasedBlend(inout float inputFactor, float previousLayerHeight, float layerHeight, float heightOffset, float heightFactor, float edgeBlendStrength, float vertexColor)
{
float finalLayerHeight = heightFactor * layerHeight + heightOffset + _VertexColorHeightFactor * (vertexColor * 2.0 - 1.0);
edgeBlendStrength = max(0.00001, edgeBlendStrength);
if (previousLayerHeight >= finalLayerHeight)
{
inputFactor = 0.0;
}
else if (finalLayerHeight > previousLayerHeight && finalLayerHeight < previousLayerHeight + edgeBlendStrength)
{
inputFactor = inputFactor * pow((finalLayerHeight - previousLayerHeight) / edgeBlendStrength, 0.5);
}
return max(finalLayerHeight, previousLayerHeight);
}
float3 ApplyHeightBasedBlendV2(float3 inputMask, float3 inputHeight, float3 blendUsingHeight)
{
return saturate(lerp(inputMask * inputHeight * blendUsingHeight * 100, 1, inputMask * inputMask)); // 100 arbitrary scale to limit blendUsingHeight values.
}
void GetLayerTexCoord(float2 texCoord0, float2 texCoord1, float2 texCoord2, float2 texCoord3,
float3 positionWS, float3 normalWS, out LayerTexCoord layerTexCoord)
return inheritBaseColor * (baseColor0 - meanColor) + baseColor;
}
// Calculate displacement for per vertex displacement mapping
float ComputePerVertexDisplacement(LayerTexCoord layerTexCoord, float4 vertexColor, float lod)
// Caution: Blend mask are Layer 1 R - Layer 2 G - Layer 3 B - Main Layer A
float4 GetBlendMask(LayerTexCoord layerTexCoord, float4 vertexColor, bool useLodSampling = false, float lod = 0)
// Mask Values : Layer 1, 2, 3 are r, g, b. Always use layer0 parametrization for the mask
float3 inputMaskValues = SAMPLE_LAYER_TEXTURE2D_LOD(_LayerMaskMap, sampler_LayerMaskMap, layerTexCoord.base0, lod).rgb;
// Caution:
// Blend mask are Main Layer A - Layer 1 R - Layer 2 G - Layer 3 B
// Value for Mani layer is not use for blending itself but for alternate weighting like density.
// Settings this specific Main layer blend mask in alpha allow to be transparent in case we don't use it and 1 is provide by default.
float4 blendMasks = useLodSampling ? SAMPLE_LAYER_TEXTURE2D_LOD(_LayerMaskMap, sampler_LayerMaskMap, layerTexCoord.base0, lod) : SAMPLE_LAYER_TEXTURE2D(_LayerMaskMap, sampler_LayerMaskMap, layerTexCoord.base0);
/*
inputMaskValues *= vertexColor.rgb;
blendMasks *= vertexColor;
inputMaskValues = saturate(inputMaskValues + vertexColor.rgb * 2.0 - 1.0);
blendMasks = saturate(blendMasks + vertexColor * 2.0 - 1.0);
*/
return blendMasks;
}
// Calculate displacement for per vertex displacement mapping
float ComputePerVertexDisplacement(LayerTexCoord layerTexCoord, float4 vertexColor, float lod)
{
float4 blendMasks = GetBlendMask(layerTexCoord, vertexColor, true, lod);
ComputeMaskWeights(inputMaskValues, weights);
ComputeMaskWeights(blendMasks, weights);
float height0 = SampleHeightmapLod0(layerTexCoord, lod);
float height0 = SampleHeightmapLod0(layerTexCoord, lod, _HeightCenterOffset0, _HeightFactor0);
float height1 = SampleHeightmapLod1(layerTexCoord, lod, _HeightCenterOffset1, _HeightFactor1);
float height2 = SampleHeightmapLod2(layerTexCoord, lod, _HeightCenterOffset2, _HeightFactor2);
float height3 = SampleHeightmapLod3(layerTexCoord, lod, _HeightCenterOffset3, _HeightFactor3);
return heightResult;
}
float3 ApplyHeightBasedBlend(float3 inputMask, float3 inputHeight, float3 blendUsingHeight)
{
return saturate(lerp(inputMask * inputHeight * blendUsingHeight * 100, 1, inputMask * inputMask)); // 100 arbitrary scale to limit blendUsingHeight values.
}
// Mask Values : Layer 1, 2, 3 are r, g, b. Always use layer0 parametrization for the mask
float3 inputMaskValues = SAMPLE_LAYER_TEXTURE2D(_LayerMaskMap, sampler_LayerMaskMap, layerTexCoord.base0).rgb;
float4 blendMasks = GetBlendMask(layerTexCoord, input.color);
#if defined(_LAYER_MASK_VERTEX_COLOR_MUL)
inputMaskValues *= input.color.rgb;
#elif defined(_LAYER_MASK_VERTEX_COLOR_ADD)
inputMaskValues = saturate(inputMaskValues + input.color.rgb * 2.0 - 1.0);
#endif
// Note: blendMasks.argb because a is main layer
float4 minOpaParam = float4(_MinimumOpacity0, _MinimumOpacity1, _MinimumOpacity2, _MinimumOpacity3);
float4 remapedOpacity = lerp(minOpaParam, float4(1.0, 1.0, 1.0, 1.0), inputAlphaMask); // Remap opacity mask from [0..1] to [minOpa..1]
float4 opacityAsDensity = saturate((inputAlphaMask - (float4(1.0, 1.0, 1.0, 1.0) - blendMasks.argb)) * 20.0);
float3 minOpaParam = float3(_MinimumOpacity1, _MinimumOpacity2, _MinimumOpacity3);
float3 remapedOpacity = lerp(minOpaParam, float3(1.0, 1.0, 1.0), inputAlphaMask.yzw); // Remap opacity mask from [0..1] to [minOpa..1]
float3 opacityAsDensity = saturate((inputAlphaMask.yzw - (float3(1.0, 1.0, 1.0) - inputMaskValues)) * 20.0);
float3 useOpacityAsDensityParam = float3(_OpacityAsDensity1, _OpacityAsDensity2, _OpacityAsDensity3);
inputMaskValues = lerp(inputMaskValues * remapedOpacity, opacityAsDensity, useOpacityAsDensityParam);
float4 useOpacityAsDensityParam = float4(_OpacityAsDensity0, _OpacityAsDensity1, _OpacityAsDensity2, _OpacityAsDensity3);
blendMasks.argb = lerp(blendMasks.argb * remapedOpacity, opacityAsDensity, useOpacityAsDensityParam);
float height0 = SampleHeightmap0(layerTexCoord);
float height0 = SampleHeightmap0(layerTexCoord, _HeightCenterOffset0, _HeightFactor0);
#if !defined(_HEIGHT_BASED_BLEND_V2)
float baseLayerHeight = heights.x;
baseLayerHeight = ApplyHeightBasedBlend(inputMaskValues.r, baseLayerHeight, heights.y, _HeightOffset1, _HeightFactor1, _BlendSize1, input.color.r);
baseLayerHeight = ApplyHeightBasedBlend(inputMaskValues.g, baseLayerHeight, heights.z, _HeightOffset2 + _HeightOffset1, _HeightFactor2, _BlendSize2, input.color.g);
ApplyHeightBasedBlend(inputMaskValues.b, baseLayerHeight, heights.w, _HeightOffset3 + _HeightOffset2 + _HeightOffset1, _HeightFactor3, _BlendSize3, input.color.b);
#else
// HACK, use height0 to avoid compiler error for unused sampler
// To remove once we have POM
heights.y += (heights.x * 0.0001);
// HACK, use height0 to avoid compiler error for unused sampler
// To remove once we have POM
heights.y += (heights.x * 0.0001);
inputMaskValues = ApplyHeightBasedBlendV2(inputMaskValues, heights.yzw, float3(_BlendUsingHeight1, _BlendUsingHeight2, _BlendUsingHeight3));
#endif
// don't apply on main layer
blendMasks.rgb = ApplyHeightBasedBlend(blendMasks.rgb, heights.yzw, float3(_BlendUsingHeight1, _BlendUsingHeight2, _BlendUsingHeight3));
ComputeMaskWeights(inputMaskValues, outWeights);
ComputeMaskWeights(blendMasks, outWeights);
}
void GetSurfaceAndBuiltinData(FragInputs input, float3 V, inout PositionInputs posInput, out SurfaceData surfaceData, out BuiltinData builtinData)
float alpha1 = GetSurfaceData1(input, layerTexCoord, surfaceData1, normalTS1);
float alpha2 = GetSurfaceData2(input, layerTexCoord, surfaceData2, normalTS2);
float alpha3 = GetSurfaceData3(input, layerTexCoord, surfaceData3, normalTS3);
// For layering we kill pixel based on maximun alpha
#ifdef _ALPHATEST_ON
#if _LAYER_COUNT == 2
clip(max(alpha0, alpha1) - _AlphaCutoff);
#endif
#if _LAYER_COUNT == 3
clip(max3(alpha0, alpha1, alpha2) - _AlphaCutoff);
#endif
#if _LAYER_COUNT == 4
clip(max(alpha3, max3(alpha0, alpha1, alpha2)) - _AlphaCutoff);
#endif
#endif
float weights[_MAX_LAYER];
ComputeLayerWeights(input, layerTexCoord, float4(alpha0, alpha1, alpha2, alpha3), weights);