浏览代码

Merge pull request #465 from Unity-Technologies/Add-Per-Pixel-Scale-Seb-Test

Add per pixel scale seb test
/stochastic_alpha_test
GitHub 7 年前
当前提交
3f0ee0ec
共有 7 个文件被更改,包括 274 次插入207 次删除
  1. 97
      ScriptableRenderPipeline/HDRenderPipeline/Material/LayeredLit/Editor/LayeredLitUI.cs
  2. 1
      ScriptableRenderPipeline/HDRenderPipeline/Material/LayeredLit/LayeredLit.shader
  3. 3
      ScriptableRenderPipeline/HDRenderPipeline/Material/LayeredLit/LayeredLitTessellation.shader
  4. 7
      ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Editor/LitUI.cs
  5. 368
      ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitData.hlsl
  6. 3
      ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitProperties.hlsl
  7. 2
      ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitTessellation.shader

97
ScriptableRenderPipeline/HDRenderPipeline/Material/LayeredLit/Editor/LayeredLitUI.cs


public readonly GUIContent heightOffset = new GUIContent("Height Offset", "Offset applied to the height before layering.");
public readonly GUIContent heightTransition = new GUIContent("Height Transition", "Size in world units of the smooth transition between layers.");
public readonly GUIContent perPixelDisplacementLayersWarning = new GUIContent("For pixel displacement to work correctly, all layers with a heightmap must use the same UV mapping");
public readonly GUIContent materialReferencesText = new GUIContent("Material References");
public StylesLayer()

bool mainLayerInfluenceEnable = useMainLayerInfluence.floatValue > 0.0f;
bool heightBasedBlend = useHeightBasedBlend.floatValue > 0.0f;
EditorGUILayout.LabelField(styles.layeringOptionText, EditorStyles.boldLabel);
EditorGUI.indentLevel++;
if(layerIndex > 0 || heightBasedBlend )
if (layerIndex > 0)
EditorGUILayout.LabelField(styles.layeringOptionText, EditorStyles.boldLabel);
EditorGUI.indentLevel++;
// influence
if (layerIndex > 0)
{
int paramIndex = layerIndex - 1;
int paramIndex = layerIndex - 1;
m_MaterialEditor.ShaderProperty(opacityAsDensity[layerIndex], styles.opacityAsDensityText);
m_MaterialEditor.ShaderProperty(opacityAsDensity[layerIndex], styles.opacityAsDensityText);
if (mainLayerInfluenceEnable)
{
m_MaterialEditor.ShaderProperty(inheritBaseColor[paramIndex], styles.inheritBaseColorText);
m_MaterialEditor.ShaderProperty(inheritBaseNormal[paramIndex], styles.inheritBaseNormalText);
// Main height influence is only available if the shader use the heightmap for displacement (per vertex or per level)
// We always display it as it can be tricky to know when per pixel displacement is enabled or not
m_MaterialEditor.ShaderProperty(inheritBaseHeight[paramIndex], styles.inheritBaseHeightText);
}
if (mainLayerInfluenceEnable)
{
m_MaterialEditor.ShaderProperty(inheritBaseColor[paramIndex], styles.inheritBaseColorText);
m_MaterialEditor.ShaderProperty(inheritBaseNormal[paramIndex], styles.inheritBaseNormalText);
// Main height influence is only available if the shader use the heightmap for displacement (per vertex or per level)
// We always display it as it can be tricky to know when per pixel displacement is enabled or not
m_MaterialEditor.ShaderProperty(inheritBaseHeight[paramIndex], styles.inheritBaseHeightText);
if (heightBasedBlend)
}
else
{
if (!useMainLayerInfluence.hasMixedValue && useMainLayerInfluence.floatValue != 0.0f)
m_MaterialEditor.ShaderProperty(heightOffset[layerIndex], styles.heightOffset);
m_MaterialEditor.TexturePropertySingleLine(styles.layerInfluenceMapMaskText, layerInfluenceMaskMap);
}
EditorGUI.indentLevel--;
EditorGUILayout.Space();
if (heightBasedBlend)
{
m_MaterialEditor.ShaderProperty(heightOffset[layerIndex], styles.heightOffset);
EditorGUI.indentLevel--;
EditorGUILayout.Space();
DoLayerGUI(material, layerIndex);

{
useMainLayerInfluence.floatValue = mainLayerModeInfluenceEnable ? 1.0f : 0.0f;
}
if (!useMainLayerInfluence.hasMixedValue && useMainLayerInfluence.floatValue != 0.0f)
{
EditorGUI.indentLevel++;
m_MaterialEditor.TexturePropertySingleLine(styles.layerInfluenceMapMaskText, layerInfluenceMaskMap);
EditorGUI.indentLevel--;
}
EditorGUI.BeginChangeCheck();
EditorGUI.showMixedValue = useHeightBasedBlend.hasMixedValue;

SetKeyword(material, "_HEIGHTMAP" + i, material.GetTexture(kHeightMap + i));
}
SetKeyword(material, "_INFLUENCEMASK_MAP", material.GetTexture(kLayerInfluenceMaskMap) && material.GetFloat(kkUseMainLayerInfluence) != 0.0f);
SetKeyword(material, "_EMISSIVE_COLOR_MAP", material.GetTexture(kEmissiveColorMap));
SetKeyword(material, "_ENABLESPECULAROCCLUSION", material.GetFloat(kEnableSpecularOcclusion) > 0.0f);

{
optionsChanged = true;
}
// In case of pixel displacement and layered shader, all layers must used the same texture mapping for layer that have a heightmap
// (Else the algorithm will not work correctly)
if ((DisplacementMode)displacementMode.floatValue == DisplacementMode.Pixel)
{
float compareValue = -1.0f;
bool match = true;
if (material.GetTexture(kHeightMap + 0))
{
compareValue = UVBase[0].floatValue;
}
if (material.GetTexture(kHeightMap + 1))
{
if (compareValue == -1.0f)
compareValue = UVBase[1].floatValue;
else if (compareValue != UVBase[1].floatValue)
match = false;
}
if (material.GetTexture(kHeightMap + 2))
{
if (compareValue == -1.0f)
compareValue = UVBase[2].floatValue;
else if (compareValue != UVBase[2].floatValue)
match = false;
}
if (material.GetTexture(kHeightMap + 3))
{
if (compareValue == -1.0f)
compareValue = UVBase[3].floatValue;
else if (compareValue != UVBase[3].floatValue)
match = false;
}
if (!match)
{
EditorGUILayout.HelpBox(styles.perPixelDisplacementLayersWarning.text, MessageType.Warning);
}
}
bool layerChanged = DoLayersGUI(materialImporter);
DoEmissiveGUI(material);

1
ScriptableRenderPipeline/HDRenderPipeline/Material/LayeredLit/LayeredLit.shader


#pragma shader_feature _DETAIL_MAP3
#pragma shader_feature _ _LAYER_MASK_VERTEX_COLOR_MUL _LAYER_MASK_VERTEX_COLOR_ADD
#pragma shader_feature _MAIN_LAYER_INFLUENCE_MODE
#pragma shader_feature _INFLUENCEMASK_MAP
#pragma shader_feature _DENSITY_MODE
#pragma shader_feature _HEIGHT_BASED_BLEND
#pragma shader_feature _ _LAYEREDLIT_3_LAYERS _LAYEREDLIT_4_LAYERS

3
ScriptableRenderPipeline/HDRenderPipeline/Material/LayeredLit/LayeredLitTessellation.shader


[Enum(None, 0, Mirror, 1, Flip, 2)] _DoubleSidedNormalMode("Double sided normal mode", Float) = 1
[HideInInspector] _DoubleSidedConstants("_DoubleSidedConstants", Vector) = (1, 1, -1, 0)
[Enum(None, 0, PreTessellation displacement, 1, Pixel displacement, 2, PostTessellation displacement, 3)] _DisplacementMode("DisplacementMode", Int) = 0
[Enum(None, 0, Vertex displacement, 1, Pixel displacement, 2, Tessellation displacement, 3)] _DisplacementMode("DisplacementMode", Int) = 0
[ToggleOff] _DisplacementLockObjectScale("displacement lock object scale", Float) = 1.0
[ToggleOff] _DisplacementLockTilingScale("displacement lock tiling scale", Float) = 1.0

#pragma shader_feature _DETAIL_MAP3
#pragma shader_feature _ _LAYER_MASK_VERTEX_COLOR_MUL _LAYER_MASK_VERTEX_COLOR_ADD
#pragma shader_feature _MAIN_LAYER_INFLUENCE_MODE
#pragma shader_feature _INFLUENCEMASK_MAP
#pragma shader_feature _DENSITY_MODE
#pragma shader_feature _HEIGHT_BASED_BLEND
#pragma shader_feature _ _LAYEREDLIT_3_LAYERS _LAYEREDLIT_4_LAYERS

7
ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Editor/LitUI.cs


// Transparency absorption
public static GUIContent transmittanceColorText = new GUIContent("Transmittance Color", "Absorption color (RGB)");
public static GUIContent atDistanceText = new GUIContent("Transmittance Absorption Distance", "Absorption distance reference");
public static GUIContent perPixelDisplacementDetailsWarning = new GUIContent("For pixel displacement to work correctly, details and base map must use same UV mapping");
}
// Lit shader is not layered but some layered materials inherit from it. In order to share code we need LitUI to account for this.

UVDetailsMappingMask[layerIndex].colorValue = new Color(X, Y, Z, W);
m_MaterialEditor.TextureScaleOffsetProperty(detailMap[layerIndex]);
if ((DisplacementMode)displacementMode.floatValue == DisplacementMode.Pixel && (UVDetail[layerIndex].floatValue != UVBase[layerIndex].floatValue))
{
if (material.GetTexture(kDetailMap + layerIndex))
EditorGUILayout.HelpBox(Styles.perPixelDisplacementDetailsWarning.text, MessageType.Warning);
}
m_MaterialEditor.ShaderProperty(detailAlbedoScale[layerIndex], Styles.detailAlbedoScaleText);
m_MaterialEditor.ShaderProperty(detailNormalScale[layerIndex], Styles.detailNormalScaleText);
m_MaterialEditor.ShaderProperty(detailSmoothnessScale[layerIndex], Styles.detailSmoothnessScaleText);

368
ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitData.hlsl


float2 uv;
};
// Calculate displacement for per vertex displacement mapping
float ComputePerPixelHeightDisplacement(float2 texOffsetCurrent, float lod, PerPixelHeightDisplacementParam param)
{
// Note: No multiply by amplitude here. This is include in the maxHeight provide to POM

float2 minUvSize = GetMinUvSize(layerTexCoord);
float lod = ComputeTextureLOD(minUvSize);
// TODO: precompute uvSpaceScale
float2 scaleOffsetDetails = _DetailMap_ST.xy;
PerPixelHeightDisplacementParam ppdParam;

float3 viewDirUV = normalize(float3(viewDirTS.xy * uvSpaceScale, viewDirTS.z)); // TODO: skip normalize
float unitAngle = saturate(FastACosPos(viewDirUV.z) * INV_HALF_PI); // TODO: optimize
int numSteps = (int)lerp(_PPDMinSamples, _PPDMaxSamples, unitAngle);
float2 offset = ParallaxOcclusionMapping(lod, _PPDLodThreshold, numSteps, viewDirUV, 1, ppdParam, planeHeight);
float2 offset = ParallaxOcclusionMapping(lod, _PPDLodThreshold, numSteps, viewDirUV, 1.0, ppdParam, planeHeight);
layerTexCoord.details.uvZY += offset;
layerTexCoord.details.uvZY += offset * scaleOffsetDetails;
height += layerTexCoord.triplanarWeights.x * planeHeight;
NdotV += layerTexCoord.triplanarWeights.x * viewDirTS.z;
}

float3 viewDirUV = normalize(float3(viewDirTS.xy * uvSpaceScale, viewDirTS.z)); // TODO: skip normalize
float unitAngle = saturate(FastACosPos(viewDirUV.z) * INV_HALF_PI); // TODO: optimize
int numSteps = (int)lerp(_PPDMinSamples, _PPDMaxSamples, unitAngle);
float2 offset = ParallaxOcclusionMapping(lod, _PPDLodThreshold, numSteps, viewDirUV, 1, ppdParam, planeHeight);
float2 offset = ParallaxOcclusionMapping(lod, _PPDLodThreshold, numSteps, viewDirUV, 1.0, ppdParam, planeHeight);
layerTexCoord.details.uvXZ += offset;
layerTexCoord.details.uvXZ += offset * scaleOffsetDetails;
height += layerTexCoord.triplanarWeights.y * planeHeight;
NdotV += layerTexCoord.triplanarWeights.y * viewDirTS.z;
}

float3 viewDirUV = normalize(float3(viewDirTS.xy * uvSpaceScale, viewDirTS.z)); // TODO: skip normalize
float unitAngle = saturate(FastACosPos(viewDirUV.z) * INV_HALF_PI); // TODO: optimize
int numSteps = (int)lerp(_PPDMinSamples, _PPDMaxSamples, unitAngle);
float2 offset = ParallaxOcclusionMapping(lod, _PPDLodThreshold, numSteps, viewDirUV, 1, ppdParam, planeHeight);
float2 offset = ParallaxOcclusionMapping(lod, _PPDLodThreshold, numSteps, viewDirUV, 1.0, ppdParam, planeHeight);
layerTexCoord.details.uvXY += offset;
layerTexCoord.details.uvXY += offset * scaleOffsetDetails;
height += layerTexCoord.triplanarWeights.z * planeHeight;
NdotV += layerTexCoord.triplanarWeights.z * viewDirTS.z;
}

float3 viewDirUV = normalize(float3(viewDirTS.xy * uvSpaceScale, viewDirTS.z)); // TODO: skip normalize
float unitAngle = saturate(FastACosPos(viewDirUV.z) * INV_HALF_PI); // TODO: optimize
int numSteps = (int)lerp(_PPDMinSamples, _PPDMaxSamples, unitAngle);
float2 offset = ParallaxOcclusionMapping(lod, _PPDLodThreshold, numSteps, viewDirUV, 1, ppdParam, height);
float2 offset = ParallaxOcclusionMapping(lod, _PPDLodThreshold, numSteps, viewDirUV, 1.0, ppdParam, height);
layerTexCoord.details.uv += isPlanar ? offset : _UVDetailsMappingMask.x * offset; // Only apply offset if details map use UVSet0 _UVDetailsMappingMask.x will be 1 in this case, else 0
// Note: Applying offset on detail uv is only correct if it use the same UVSet or is planar or triplanar. It is up to the user to do the correct thing.
layerTexCoord.details.uv += offset * scaleOffsetDetails;
return verticalDisplacement / NdotV;
return verticalDisplacement / max(NdotV, 0.001);
}
// Calculate displacement for per vertex displacement mapping

// Define a helper macro
#define ADD_ZERO_IDX(Name) Name##0
// include LitDataInternal multiple time to define the variation of GetSurfaceData for each layer

void ApplyDisplacementTileScale(inout float height0, inout float height1, inout float height2, inout float height3)
{
// When we change the tiling, we have want to conserve the ratio with the displacement (and this is consistent with per pixel displacement)
#if _DISPLACEMENT_LOCK_TILING_SCALE
#ifdef _DISPLACEMENT_LOCK_TILING_SCALE
float tileObjectScale = 1.0;
#ifdef _LAYER_TILING_COUPLED_WITH_UNIFORM_OBJECT_SCALE
// Extract scaling from world transform

float GetInfluenceMask(LayerTexCoord layerTexCoord, bool useLodSampling = false, float lod = 0)
{
return useLodSampling ? SAMPLE_UVMAPPING_TEXTURE2D_LOD(_LayerInfluenceMaskMap, sampler_LayerMaskMap, layerTexCoord.blendMask, lod).r : SAMPLE_UVMAPPING_TEXTURE2D(_LayerInfluenceMaskMap, sampler_LayerMaskMap, layerTexCoord.blendMask).r;
// Sample influence mask with same mapping as Main layer
return useLodSampling ? SAMPLE_UVMAPPING_TEXTURE2D_LOD(_LayerInfluenceMaskMap, sampler_LayerInfluenceMaskMap, layerTexCoord.base0, lod).r : SAMPLE_UVMAPPING_TEXTURE2D(_LayerInfluenceMaskMap, sampler_LayerInfluenceMaskMap, layerTexCoord.base0).r;
}
float GetMaxHeight(float4 heights)
{
float maxHeight = max(heights.r, heights.g);
#ifdef _LAYEREDLIT_4_LAYERS
maxHeight = max(Max3(heights.r, heights.g, heights.b), heights.a);
#endif
#ifdef _LAYEREDLIT_3_LAYERS
maxHeight = Max3(heights.r, heights.g, heights.b);
#endif
return maxHeight;
}
// Returns layering blend mask after application of height based blend.
float4 ApplyHeightBlend(float4 heights, float4 blendMask)
{
// Add offsets for all the layers.
heights = heights + float4(_HeightOffset0, _HeightOffset1, _HeightOffset2, _HeightOffset3);
// We need to mask out inactive layers so that their height does not impact the result.
float4 maskedHeights = heights * blendMask.argb;
float maxHeight = GetMaxHeight(maskedHeights);
// Make sure that transition is not zero otherwise the next computation will be wrong.
// The epsilon here also has to be bigger than the epsilon in the next computation.
float transition = max(_HeightTransition, 1e-5);
// The goal here is to have all but the highest layer at negative heights, then we add the transition so that if the next highest layer is near transition it will have a positive value.
// Then we clamp this to zero and normalize everything so that highest layer has a value of 1.
maskedHeights = maskedHeights - maxHeight.xxxx;
// We need to add an epsilon here for active layers (hence the blendMask again) so that at least a layer shows up if everything's too low.
maskedHeights = (max(0, maskedHeights + transition) + 1e-6) * blendMask.argb;
// Normalize
maxHeight = GetMaxHeight(maskedHeights);
maskedHeights = maskedHeights / maxHeight.xxxx;
return maskedHeights.yzwx;
}
// Return the maximun amplitude use by all enabled heightmap

return minUvSize;
}
#if defined(_PIXEL_DISPLACEMENT) && LAYERS_HEIGHTMAP_ENABLE
float weights[_MAX_LAYER];
float4 blendMasks;
float mainHeightInfluence;
float2 uvSpaceScale[_MAX_LAYER];
#if defined(_MAIN_LAYER_INFLUENCE_MODE) && defined(_HEIGHTMAP0)
float heightInfluence[_MAX_LAYER];
#endif
#if defined(_HEIGHTMAP0) || defined(_HEIGHTMAP1) || (_LAYER_COUNT > 2 && defined(_HEIGHTMAP2)) || (_LAYER_COUNT > 3 && defined(_HEIGHTMAP3))
// Note: No multiply by amplitude here, this is bake into the weights and apply in BlendLayeredScalar
// The amplitude is normalize to be able to work with POM algorithm
// Tiling is automatically handled correctly here as we use 4 differents uv even if they come from the same UVSet (they include the tiling)
float height0 = SAMPLE_TEXTURE2D_LOD(_HeightMap0, SAMPLER_HEIGHTMAP_IDX, param.uv[0] + texOffsetCurrent, lod).r;
float height1 = SAMPLE_TEXTURE2D_LOD(_HeightMap1, SAMPLER_HEIGHTMAP_IDX, param.uv[1] + texOffsetCurrent, lod).r;
float height2 = SAMPLE_TEXTURE2D_LOD(_HeightMap2, SAMPLER_HEIGHTMAP_IDX, param.uv[2] + texOffsetCurrent, lod).r;
float height3 = SAMPLE_TEXTURE2D_LOD(_HeightMap3, SAMPLER_HEIGHTMAP_IDX, param.uv[3] + texOffsetCurrent, lod).r;
SetEnabledHeightByLayer(height0, height1, height2, height3); // Not needed as already put in weights but paranoid mode
return BlendLayeredScalar(height0, height1, height2, height3, param.weights) + height0 * param.mainHeightInfluence;
#else
return 0.0;
// See function ComputePerVertexDisplacement() for comment about the weights/influenceMask/BlendMask
// Note: Amplitude is handled in uvSpaceScale, no need to multiply by it here.
float height0 = SAMPLE_TEXTURE2D_LOD(_HeightMap0, SAMPLER_HEIGHTMAP_IDX, param.uv[0] + texOffsetCurrent * param.uvSpaceScale[0], lod).r;
float height1 = SAMPLE_TEXTURE2D_LOD(_HeightMap1, SAMPLER_HEIGHTMAP_IDX, param.uv[1] + texOffsetCurrent * param.uvSpaceScale[1], lod).r;
float height2 = SAMPLE_TEXTURE2D_LOD(_HeightMap2, SAMPLER_HEIGHTMAP_IDX, param.uv[2] + texOffsetCurrent * param.uvSpaceScale[2], lod).r;
float height3 = SAMPLE_TEXTURE2D_LOD(_HeightMap3, SAMPLER_HEIGHTMAP_IDX, param.uv[3] + texOffsetCurrent * param.uvSpaceScale[3], lod).r;
SetEnabledHeightByLayer(height0, height1, height2, height3);
float4 blendMasks = param.blendMasks;
#if defined(_HEIGHT_BASED_BLEND)
// Modify blendMask to take into account the height of the layer. Higher height should be more visible.
blendMasks = ApplyHeightBlend(float4(height0, height1, height2, height3), param.blendMasks);
float weights[_MAX_LAYER];
ComputeMaskWeights(blendMasks, weights);
#if defined(_MAIN_LAYER_INFLUENCE_MODE) && defined(_HEIGHTMAP0)
float influenceMask = blendMasks.a;
#ifdef _INFLUENCEMASK_MAP
influenceMask *= SAMPLE_TEXTURE2D_LOD(_LayerInfluenceMaskMap, sampler_BaseColorMap0, param.uv[0], lod).r;
#endif
height1 += height0 * _InheritBaseHeight1 * influenceMask;
height2 += height0 * _InheritBaseHeight2 * influenceMask;
height3 += height0 * _InheritBaseHeight3 * influenceMask;
#endif
return BlendLayeredScalar(height0, height1, height2, height3, weights);
#endif // defined(_PIXEL_DISPLACEMENT) && LAYERS_HEIGHTMAP_ENABLE
// PPD is affecting only one mapping at the same time, mean we need to execute it for each mapping (UV0, UV1, 3 times for triplanar etc..)
// We chose to not support all this case that are extremely hard to manage (for example mixing different mapping, mean it also require different tangent space that is not supported in Unity)

// - Blend Mask use same mapping as main layer (UVO, Planar, Triplanar)
// From these rules it mean that PPD is enable only if the user 1) ask for it, 2) if there is one heightmap enabled on active layer, 3) if mapping is the same for all layer respecting 2), 4) if mapping is UV0, planar or triplanar mapping
// Most contraint are handled by the inspector (i.e the UI) like the mapping constraint and is assumed in the shader.
float ApplyPerPixelDisplacement(FragInputs input, float3 V, inout LayerTexCoord layerTexCoord, float influenceMask)
float ApplyPerPixelDisplacement(FragInputs input, float3 V, inout LayerTexCoord layerTexCoord, float4 blendMasks)
{
#if defined(_PIXEL_DISPLACEMENT) && LAYERS_HEIGHTMAP_ENABLE
bool isPlanar = false;

#endif
#endif
// Even if we use same mapping we can have different tiling. For per pixel displacement we will perform the ray marching with already tiled uv
float maxHeight = GetMaxDisplacement();
// Compute lod as we will sample inside a loop(so can't use regular sampling)
// Note: It appear that CALCULATE_TEXTURE2D_LOD only return interger lod. We want to use float lod to have smoother transition and fading, so do our own calculation.
// Approximation of lod to used. Be conservative here, we will take the highest mip of all layers.

// Calculate blend weights
float4 blendMasks = GetBlendMask(layerTexCoord, input.color);
// TODO: Here we calculate the scale transform from world to UV space , which is what we have done in GetLayerTexCoord but without the texBias.
// Mean we must also apply the same "additionalTiling", currently not apply Also precompute all this!
float maxHeight0 = abs(_HeightAmplitude0);
float maxHeight1 = abs(_HeightAmplitude1);
float maxHeight2 = abs(_HeightAmplitude2);
float maxHeight3 = abs(_HeightAmplitude3);
ApplyDisplacementTileScale(maxHeight0, maxHeight1, maxHeight2, maxHeight3);
#if defined(_MAIN_LAYER_INFLUENCE_MODE) && defined(_HEIGHTMAP0)
maxHeight1 += abs(_HeightAmplitude0) * _InheritBaseHeight1;
maxHeight2 += abs(_HeightAmplitude0) * _InheritBaseHeight2;
maxHeight3 += abs(_HeightAmplitude0) * _InheritBaseHeight3;
#endif
float maxHeight = BlendLayeredScalar(maxHeight0, maxHeight1, maxHeight2, maxHeight3, weights);
// Be sure we are not considering weight here were there is no heightmap
SetEnabledHeightByLayer(weights[0], weights[1], weights[2], weights[3]);
float2 worldScale0 = (isPlanar || isTriplanar) ? _TexWorldScale0.xx : _InvPrimScale.xy;
float2 worldScale1 = (isPlanar || isTriplanar) ? _TexWorldScale1.xx : _InvPrimScale.xy;
float2 worldScale2 = (isPlanar || isTriplanar) ? _TexWorldScale2.xx : _InvPrimScale.xy;
float2 worldScale3 = (isPlanar || isTriplanar) ? _TexWorldScale3.xx : _InvPrimScale.xy;
#if defined(_MAIN_LAYER_INFLUENCE_MODE)
// For per pixel displacement we need to have normalized height scale to calculate the interesection (required by the algorithm we use)
// mean that we will normalize by the highest amplitude.
// We store this normalization factor with the weights as it will be multiply by the readed height.
ppdParam.weights[0] = weights[0] * (_HeightAmplitude0) / maxHeight;
ppdParam.weights[1] = weights[1] * (_HeightAmplitude1 + _HeightAmplitude0 * _InheritBaseHeight1) / maxHeight;
ppdParam.weights[2] = weights[2] * (_HeightAmplitude2 + _HeightAmplitude0 * _InheritBaseHeight2) / maxHeight;
ppdParam.weights[3] = weights[3] * (_HeightAmplitude3 + _HeightAmplitude0 * _InheritBaseHeight3) / maxHeight;
ppdParam.blendMasks = blendMasks;
ppdParam.uvSpaceScale[0] = _BaseColorMap0_ST.xy * worldScale0;// *maxHeight0;
ppdParam.uvSpaceScale[1] = _BaseColorMap1_ST.xy * worldScale1;// *maxHeight1;
ppdParam.uvSpaceScale[2] = _BaseColorMap2_ST.xy * worldScale2;// *maxHeight2;
ppdParam.uvSpaceScale[3] = _BaseColorMap3_ST.xy * worldScale3;// *maxHeight3;
// Think that inheritbasedheight will be 0 if height0 is fully visible in weights. So there is no double contribution of height0
float mainHeightInfluence = BlendLayeredScalar(0.0, _InheritBaseHeight1, _InheritBaseHeight2, _InheritBaseHeight3, weights) * influenceMask;
ppdParam.mainHeightInfluence = mainHeightInfluence;
#else
[unroll]
for (int i = 0; i < _MAX_LAYER; ++i)
{
ppdParam.weights[i] = weights[i];
}
ppdParam.mainHeightInfluence = 0.0;
#endif
float uvSpaceScale = BlendLayeredScalar(ppdParam.uvSpaceScale[0], ppdParam.uvSpaceScale[1], ppdParam.uvSpaceScale[2], ppdParam.uvSpaceScale[3], weights);
float2 scaleOffsetDetails0 =_DetailMap0_ST.xy;
float2 scaleOffsetDetails1 =_DetailMap1_ST.xy;
float2 scaleOffsetDetails2 =_DetailMap2_ST.xy;
float2 scaleOffsetDetails3 =_DetailMap3_ST.xy;
float height; // final height processed
float NdotV;

// We need to calculate the texture space direction. It depends on the mapping.
if (isTriplanar)
{
// TODO: implement. Require 3 call to POM + dedicated viewDirTS based on triplanar convention
// apply the 3 offset on all layers
/*
ppdParam.uv[0] = layerTexCoord.base0.uvZY;
ppdParam.uv[1] = layerTexCoord.base1.uvYZ;
ppdParam.uv[2] = layerTexCoord.base2.uvYZ;
ppdParam.uv[3] = layerTexCoord.base3.uvYZ;
float3 viewDirTS = ;
int numSteps = (int)lerp(_PPDMaxSamples, _PPDMinSamples, abs(viewDirTS.z));
ParallaxOcclusionMapping(lod, _PPDLodThreshold, numSteps, viewDirTS, maxHeight, ppdParam);
// Apply to all uvZY
// Repeat for uvXZ
// Repeat for uvXY
// Apply to all layer that used triplanar
*/
height = 1;
NdotV = 1;
height = 1.0;
NdotV = 1.0;
// For planar it is uv too, not uvXZ
float3x3 worldToTangent = input.worldToTangent;
// Note: The TBN is not normalize as it is based on mikkt. We should normalize it, but POM is always use on simple enough surfarce that mean it is not required (save 2 normalize). Tag: SURFACE_GRADIENT
// For planar the view vector is the world view vector (unless we want to support object triplanar ? and in this case used TransformWorldToObject)
// TODO: do we support object triplanar ? See ComputeLayerTexCoord
float3 viewDirTS = isPlanar ? float3(uvXZ, V.y) : TransformWorldToTangent(V, worldToTangent);
// Note: The TBN is not normalize as it is based on mikkt. We should normalize it, but POM is always use on simple enough surface that mean it is not required (save 2 normalize). Tag: SURFACE_GRADIENT
// Note: worldToTangent is only define for UVSet0, so we expect that layer that use POM have UVSet0
float3 viewDirTS = isPlanar ? float3(uvXZ, V.y) : TransformWorldToTangent(V, input.worldToTangent) * GetDisplacementObjectScale(false).xzy; // Switch from Y-up to Z-up (as we move to tangent space)
int numSteps = (int)lerp(_PPDMaxSamples, _PPDMinSamples, viewDirTS.z);
float2 offset = ParallaxOcclusionMapping(lod, _PPDLodThreshold, numSteps, viewDirTS, maxHeight, ppdParam, height);
// Apply offset to all planar UV if applicable
float4 planarWeight = float4( layerTexCoord.base0.mappingType == UV_MAPPING_PLANAR ? 1.0 : 0.0,
layerTexCoord.base1.mappingType == UV_MAPPING_PLANAR ? 1.0 : 0.0,
layerTexCoord.base2.mappingType == UV_MAPPING_PLANAR ? 1.0 : 0.0,
layerTexCoord.base3.mappingType == UV_MAPPING_PLANAR ? 1.0 : 0.0);
// _UVMappingMask0.x will be 1.0 is UVSet0 is used;
float4 offsetWeights = isPlanar ? planarWeight : float4(_UVMappingMask0.x, _UVMappingMask1.x, _UVMappingMask2.x, _UVMappingMask3.x);
layerTexCoord.base0.uv += offsetWeights.x * offset;
layerTexCoord.base1.uv += offsetWeights.y * offset;
layerTexCoord.base2.uv += offsetWeights.z * offset;
layerTexCoord.base3.uv += offsetWeights.w * offset;
// Transform the view vector into the UV space.
float3 viewDirUV = float3(viewDirTS.xy, viewDirTS.z);
float unitAngle = saturate(FastACosPos(viewDirUV.z) * INV_HALF_PI); // TODO: optimize
int numSteps = (int)lerp(_PPDMinSamples, _PPDMaxSamples, unitAngle);
float2 offset = ParallaxOcclusionMapping(lod, _PPDLodThreshold, numSteps, viewDirUV, maxHeight, ppdParam, height);
offset *= uvSpaceScale;
offsetWeights = isPlanar ? planarWeight : float4(_UVDetailsMappingMask0.x, _UVDetailsMappingMask1.x, _UVDetailsMappingMask2.x, _UVDetailsMappingMask3.x);
layerTexCoord.base0.uv += offset;
layerTexCoord.base1.uv += offset;
layerTexCoord.base2.uv += offset;
layerTexCoord.base3.uv += offset;
layerTexCoord.details0.uv += offsetWeights.x * offset;
layerTexCoord.details1.uv += offsetWeights.y * offset;
layerTexCoord.details2.uv += offsetWeights.z * offset;
layerTexCoord.details3.uv += offsetWeights.w * offset;
layerTexCoord.details0.uv += offset * scaleOffsetDetails0;
layerTexCoord.details1.uv += offset * scaleOffsetDetails1;
layerTexCoord.details2.uv += offset * scaleOffsetDetails2;
layerTexCoord.details3.uv += offset * scaleOffsetDetails3;
// Since the result is used as a 'depthOffsetVS', it needs to be positive, so we flip the sign.
// Since the result is used as a 'depthOffsetVS', it needs to be positive, so we flip the sign. { height = -height + 1 }.
// IDEA: precompute the tiling scale? MOV-MUL vs MOV-MOV-MAX-RCP-MUL.
float tilingScale = rcp(max(_BaseColorMap0_ST.x, _BaseColorMap0_ST.y));
return tilingScale * verticalDisplacement / max(NdotV, 0.001);
return verticalDisplacement / max(NdotV, 0.001);
float GetMaxHeight(float4 heights)
{
float maxHeight = max(heights.r, heights.g);
#ifdef _LAYEREDLIT_4_LAYERS
maxHeight = max(Max3(heights.r, heights.g, heights.b), heights.a);
#endif
#ifdef _LAYEREDLIT_3_LAYERS
maxHeight = Max3(heights.r, heights.g, heights.b);
#endif
return maxHeight;
}
// Returns layering blend mask after application of height based blend.
float4 ApplyHeightBlend(float4 heights, float4 blendMask)
{
// Add offsets for all the layers.
heights = heights + float4(_HeightOffset0, _HeightOffset1, _HeightOffset2, _HeightOffset3);
// We need to mask out inactive layers so that their height does not impact the result.
float4 maskedHeights = heights * blendMask.argb;
float maxHeight = GetMaxHeight(maskedHeights);
// Make sure that transition is not zero otherwise the next computation will be wrong.
// The epsilon here also has to be bigger than the epsilon in the next computation.
float transition = max(_HeightTransition, 1e-5);
// The goal here is to have all but the highest layer at negative heights, then we add the transition so that if the next highest layer is near transition it will have a positive value.
// Then we clamp this to zero and normalize everything so that highest layer has a value of 1.
maskedHeights = maskedHeights - maxHeight.xxxx;
// We need to add an epsilon here for active layers (hence the blendMask again) so that at least a layer shows up if everything's too low.
maskedHeights = (max(0, maskedHeights + transition) + 1e-6) * blendMask.argb;
// Normalize
maxHeight = GetMaxHeight(maskedHeights);
maskedHeights = maskedHeights / maxHeight.xxxx;
return maskedHeights.yzwx;
}
// Calculate displacement for per vertex displacement mapping
float3 ComputePerVertexDisplacement(LayerTexCoord layerTexCoord, float4 vertexColor, float lod)
{

// Height is affected by tiling property and by object scale (depends on option).
// Apply scaling from tiling properties (TexWorldScale and tiling from BaseColor)
ApplyDisplacementTileScale(height0, height1, height2, height3);
// Nullify height that are not used, so compiler can remove unused case
SetEnabledHeightByLayer(height0, height1, height2, height3);
#if defined(_MAIN_LAYER_INFLUENCE_MODE) && defined(_HEIGHTMAP0)
// Add main layer influence if any (simply add main layer add on other layer)
// We multiply by the input mask for the first layer (blendMask.a) because if the mask here is black it means that the layer
// is not actually underneath any visible layer so we don't want to inherit its height.
float influenceMask = blendMasks.a * GetInfluenceMask(layerTexCoord, true, lod);
height1 += height0 * _InheritBaseHeight1 * influenceMask;
height2 += height0 * _InheritBaseHeight2 * influenceMask;
height3 += height0 * _InheritBaseHeight3 * influenceMask;
#endif
SetEnabledHeightByLayer(height0, height1, height2, height3);
#if defined(_HEIGHT_BASED_BLEND)
// Modify blendMask to take into account the height of the layer. Higher height should be more visible.

float weights[_MAX_LAYER];
ComputeMaskWeights(blendMasks, weights);
// _MAIN_LAYER_INFLUENCE_MODE is a pure visual mode that doesn't contribute to the weights of a layer
// The motivation is like this: if a layer is visible, then we will apply influence on top of it (so it is only visual).
// This is what is done for normal and baseColor and we do the same for height.
// Note that if we apply influence before ApplyHeightBlend, then have a different behavior.
#if defined(_MAIN_LAYER_INFLUENCE_MODE) && defined(_HEIGHTMAP0)
// Add main layer influence if any (simply add main layer add on other layer)
// We multiply by the input mask for the first layer (blendMask.a) because if the mask here is black it means that the layer
// is not actually underneath any visible layer so we don't want to inherit its height.
float influenceMask = blendMasks.a;
#ifdef _INFLUENCEMASK_MAP
influenceMask *= GetInfluenceMask(layerTexCoord, true, lod);
#endif
height1 += height0 * _InheritBaseHeight1 * influenceMask;
height2 += height0 * _InheritBaseHeight2 * influenceMask;
height3 += height0 * _InheritBaseHeight3 * influenceMask;
#endif
float heightResult = BlendLayeredScalar(height0, height1, height2, height3, weights).xxx;
return BlendLayeredVector3( height0.xxx * ((layerTexCoord.base0.mappingType == UV_MAPPING_UVSET) ? objectScale : float3(1.0, 1.0, 1.0)),
height1.xxx * ((layerTexCoord.base0.mappingType == UV_MAPPING_UVSET) ? objectScale : float3(1.0, 1.0, 1.0)),
height2.xxx * ((layerTexCoord.base0.mappingType == UV_MAPPING_UVSET) ? objectScale : float3(1.0, 1.0, 1.0)),
height3.xxx * ((layerTexCoord.base0.mappingType == UV_MAPPING_UVSET) ? objectScale : float3(1.0, 1.0, 1.0)), weights);
return heightResult.xxx * BlendLayeredVector3( ((layerTexCoord.base0.mappingType == UV_MAPPING_UVSET) ? objectScale : float3(1.0, 1.0, 1.0)),
((layerTexCoord.base1.mappingType == UV_MAPPING_UVSET) ? objectScale : float3(1.0, 1.0, 1.0)),
((layerTexCoord.base2.mappingType == UV_MAPPING_UVSET) ? objectScale : float3(1.0, 1.0, 1.0)),
((layerTexCoord.base3.mappingType == UV_MAPPING_UVSET) ? objectScale : float3(1.0, 1.0, 1.0)), weights);
return BlendLayeredScalar(height0, height1, height2, height3, weights).xxx;
return heightResult.xxx;
#endif
#else
return float3(0.0, 0.0, 0.0);

blendMasks.argb = lerp(blendMasks.argb, opacityAsDensity, useOpacityAsDensityParam);
#endif
// If no heightmap is set on any layer, we don't need to try and blend them based on height...
#if defined(_HEIGHT_BASED_BLEND) && LAYERS_HEIGHTMAP_ENABLE
#if LAYERS_HEIGHTMAP_ENABLE
// Height is affected by tiling property and by object scale (depends on option).
// Apply scaling from tiling properties (TexWorldScale and tiling from BaseColor)
ApplyDisplacementTileScale(height0, height1, height2, height3);
// Nullify height that are not used, so compiler can remove unused case
float4 heights = float4(height0, height1, height2, height3);
blendMasks = ApplyHeightBlend(heights, blendMasks);
// Reminder: _MAIN_LAYER_INFLUENCE_MODE is a purely visual mode, it is not take into account for the blendMasks
// As it is purely visual, it is not apply in ComputeLayerWeights
#if defined(_HEIGHT_BASED_BLEND)
// Modify blendMask to take into account the height of the layer. Higher height should be more visible.
blendMasks = ApplyHeightBlend(float4(height0, height1, height2, height3), blendMasks);
#endif
#endif
ComputeMaskWeights(blendMasks, outWeights);

ZERO_INITIALIZE(LayerTexCoord, layerTexCoord);
GetLayerTexCoord(input, layerTexCoord);
float influenceMask = 0.0f;
#if defined(_MAIN_LAYER_INFLUENCE_MODE)
influenceMask = GetInfluenceMask(layerTexCoord);
#endif
float depthOffset = ApplyPerPixelDisplacement(input, V, layerTexCoord, influenceMask);
float4 blendMasks = GetBlendMask(layerTexCoord, input.color);
float depthOffset = ApplyPerPixelDisplacement(input, V, layerTexCoord, blendMasks);
#ifdef _DEPTHOFFSET_ON
ApplyDepthOffsetPositionInput(V, depthOffset, GetWorldToHClipMatrix(), posInput);

float alpha3 = GetSurfaceData3(input, layerTexCoord, surfaceData3, normalTS3, bentNormalTS3);
// Note: If per pixel displacement is enabled it mean we will fetch again the various heightmaps at the intersection location. Not sure the compiler can optimize.
float4 blendMasks = GetBlendMask(layerTexCoord, input.color);
float weights[_MAX_LAYER];
ComputeLayerWeights(input, layerTexCoord, float4(alpha0, alpha1, alpha2, alpha3), blendMasks, weights);

float3 bentNormalTS;
float3 bentNormalWS;
#if defined(_MAIN_LAYER_INFLUENCE_MODE)
#ifdef _INFLUENCEMASK_MAP
float influenceMask = GetInfluenceMask(layerTexCoord);
#else
float influenceMask = 0.0;
#endif
if (influenceMask > 0.0f)
{
surfaceData.baseColor = ComputeMainBaseColorInfluence(influenceMask, surfaceData0.baseColor, surfaceData1.baseColor, surfaceData2.baseColor, surfaceData3.baseColor, layerTexCoord, blendMasks.a, weights);

3
ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitProperties.hlsl


PROP_DECL_TEX2D(_DetailMap);
TEXTURE2D(_LayerMaskMap);
SAMPLER2D(sampler_LayerMaskMap);
SAMPLER2D(sampler_LayerMaskMap);
SAMPLER2D(sampler_LayerInfluenceMaskMap);
#endif

2
ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitTessellation.shader


[Enum(Subsurface Scattering, 0, Standard, 1, Anisotropy, 2, ClearCoat, 3, Specular Color, 4)] _MaterialID("MaterialId", Int) = 1 // MaterialId.RegularLighting
[Enum(None, 0, PreTessellation displacement, 1, Pixel displacement, 2, PostTessellation displacement, 3)] _DisplacementMode("DisplacementMode", Int) = 0
[Enum(None, 0, Vertex displacement, 1, Pixel displacement, 2, Tessellation displacement, 3)] _DisplacementMode("DisplacementMode", Int) = 0
[ToggleOff] _DisplacementLockObjectScale("displacement lock object scale", Float) = 1.0
[ToggleOff] _DisplacementLockTilingScale("displacement lock tiling scale", Float) = 1.0

正在加载...
取消
保存