浏览代码

Generate correct depth and shadow passes for LW with alpha clip (#1590)

* Add minimal surface definition to LWRP depth and shadow passes
* Update changelog
* Fix LW Unlit subshader shadow/depth clip
/main
GitHub 6 年前
当前提交
868aeec4
共有 5 个文件被更改,包括 126 次插入331 次删除
  1. 183
      com.unity.render-pipelines.lightweight/LWRP/Editor/ShaderGraph/LightWeightPBRSubShader.cs
  2. 183
      com.unity.render-pipelines.lightweight/LWRP/Editor/ShaderGraph/LightWeightUnlitSubShader.cs
  3. 44
      com.unity.render-pipelines.lightweight/LWRP/Editor/ShaderGraph/lightweightPBRExtraPasses.template
  4. 44
      com.unity.render-pipelines.lightweight/LWRP/Editor/ShaderGraph/lightweightUnlitExtraPasses.template
  5. 3
      com.unity.shadergraph/CHANGELOG.md

183
com.unity.render-pipelines.lightweight/LWRP/Editor/ShaderGraph/LightWeightPBRSubShader.cs


}
};
Pass m_DepthShadowPass = new Pass()
{
Name = "",
PixelShaderSlots = new List<int>()
{
PBRMasterNode.AlphaSlotId,
PBRMasterNode.AlphaThresholdSlotId
},
VertexShaderSlots = new List<int>()
{
PBRMasterNode.PositionSlotId
}
};
public string GetSubshader(IMasterNode inMasterNode, GenerationMode mode, List<string> sourceAssetDependencyPaths = null)
{
if (sourceAssetDependencyPaths != null)

mode,
materialOptions));
subShader.AppendLines(GetExtraPassesFromTemplate(extraTemplate, masterNode, pass, mode, materialOptions));
subShader.AppendLines(GetShaderPassFromTemplate(
extraTemplate,
masterNode,
m_DepthShadowPass,
mode,
materialOptions));
}
return subShader.ToString();

resultPass = resultPass.Replace("${PixelShader}", pixelShader.ToString());
resultPass = resultPass.Replace("${PixelShaderSurfaceInputs}", pixelShaderSurfaceInputs.ToString());
resultPass = resultPass.Replace("${PixelShaderSurfaceRemap}", pixelShaderSurfaceRemap.ToString());
return resultPass;
}
static string GetExtraPassesFromTemplate(string template, PBRMasterNode masterNode, Pass pass, GenerationMode mode, SurfaceMaterialOptions materialOptions)
{
// ----------------------------------------------------- //
// SETUP //
// ----------------------------------------------------- //
// -------------------------------------
// String builders
var dummyBuilder = new ShaderStringBuilder(0);
var shaderProperties = new PropertyCollector();
var functionBuilder = new ShaderStringBuilder(1);
var functionRegistry = new FunctionRegistry(functionBuilder);
var defines = new ShaderStringBuilder(2);
var graph = new ShaderStringBuilder(0);
var vertexDescriptionInputStruct = new ShaderStringBuilder(1);
var vertexDescriptionStruct = new ShaderStringBuilder(1);
var vertexDescriptionFunction = new ShaderStringBuilder(1);
var vertexInputStruct = new ShaderStringBuilder(1);
var vertexShader = new ShaderStringBuilder(2);
var vertexDescriptionInputs = new ShaderStringBuilder(2);
// -------------------------------------
// Get Slot and Node lists per stage
var vertexSlots = pass.VertexShaderSlots.Select(masterNode.FindSlot<MaterialSlot>).ToList();
var vertexNodes = ListPool<INode>.Get();
NodeUtils.DepthFirstCollectNodesFromNode(vertexNodes, masterNode, NodeUtils.IncludeSelf.Include, pass.VertexShaderSlots);
// -------------------------------------
// Get requirements
var vertexRequirements = ShaderGraphRequirements.FromNodes(vertexNodes, ShaderStageCapability.Vertex, false);
var modelRequiements = ShaderGraphRequirements.none;
modelRequiements.requiresNormal |= m_VertexCoordinateSpace;
modelRequiements.requiresPosition |= m_VertexCoordinateSpace;
modelRequiements.requiresMeshUVs.Add(UVChannel.UV1);
// ----------------------------------------------------- //
// START SHADER GENERATION //
// ----------------------------------------------------- //
// -------------------------------------
// Calculate material options
var cullingBuilder = new ShaderStringBuilder(1);
materialOptions.GetCull(cullingBuilder);
// -------------------------------------
// Generate defines
if (masterNode.IsSlotConnected(PBRMasterNode.AlphaThresholdSlotId))
defines.AppendLine("#define _AlphaClip 1");
// ----------------------------------------------------- //
// START VERTEX DESCRIPTION //
// ----------------------------------------------------- //
// -------------------------------------
// Generate Input structure for Vertex Description function
// TODO - Vertex Description Input requirements are needed to exclude intermediate translation spaces
vertexDescriptionInputStruct.AppendLine("struct VertexDescriptionInputs");
using (vertexDescriptionInputStruct.BlockSemicolonScope())
{
ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresNormal, InterpolatorType.Normal, vertexDescriptionInputStruct);
ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresTangent, InterpolatorType.Tangent, vertexDescriptionInputStruct);
ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresBitangent, InterpolatorType.BiTangent, vertexDescriptionInputStruct);
ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresViewDir, InterpolatorType.ViewDirection, vertexDescriptionInputStruct);
ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresPosition, InterpolatorType.Position, vertexDescriptionInputStruct);
if (vertexRequirements.requiresVertexColor)
vertexDescriptionInputStruct.AppendLine("float4 {0};", ShaderGeneratorNames.VertexColor);
if (vertexRequirements.requiresScreenPosition)
vertexDescriptionInputStruct.AppendLine("float4 {0};", ShaderGeneratorNames.ScreenPosition);
foreach (var channel in vertexRequirements.requiresMeshUVs.Distinct())
vertexDescriptionInputStruct.AppendLine("half4 {0};", channel.GetUVName());
}
// -------------------------------------
// Generate Output structure for Vertex Description function
GraphUtil.GenerateVertexDescriptionStruct(vertexDescriptionStruct, vertexSlots);
// -------------------------------------
// Generate Vertex Description function
GraphUtil.GenerateVertexDescriptionFunction(
masterNode.owner as AbstractMaterialGraph,
vertexDescriptionFunction,
functionRegistry,
shaderProperties,
mode,
vertexNodes,
vertexSlots);
// ----------------------------------------------------- //
// GENERATE VERTEX > PIXEL PIPELINE //
// ----------------------------------------------------- //
// -------------------------------------
// Generate Input structure for Vertex shader
GraphUtil.GenerateApplicationVertexInputs(vertexRequirements.Union(modelRequiements), vertexInputStruct);
// -------------------------------------
// Generate standard transformations
// This method ensures all required transform data is available in vertex and pixel stages
ShaderGenerator.GenerateStandardTransforms(
3,
10,
dummyBuilder,
vertexShader,
vertexDescriptionInputs,
dummyBuilder,
dummyBuilder,
dummyBuilder,
ShaderGraphRequirements.none,
ShaderGraphRequirements.none,
modelRequiements,
vertexRequirements,
CoordinateSpace.World);
// ----------------------------------------------------- //
// FINALIZE //
// ----------------------------------------------------- //
// -------------------------------------
// Combine Graph sections
graph.AppendLine(shaderProperties.GetPropertiesDeclaration(1));
graph.AppendLine(vertexDescriptionInputStruct.ToString());
graph.AppendLine(functionBuilder.ToString());
graph.AppendLine(vertexDescriptionStruct.ToString());
graph.AppendLine(vertexDescriptionFunction.ToString());
graph.AppendLine(vertexInputStruct.ToString());
// -------------------------------------
// Generate final subshader
var resultPass = template.Replace("${Culling}", cullingBuilder.ToString());
resultPass = resultPass.Replace("${Defines}", defines.ToString());
resultPass = resultPass.Replace("${Graph}", graph.ToString());
resultPass = resultPass.Replace("${VertexShader}", vertexShader.ToString());
resultPass = resultPass.Replace("${VertexShaderDescriptionInputs}", vertexDescriptionInputs.ToString());
return resultPass;
}

183
com.unity.render-pipelines.lightweight/LWRP/Editor/ShaderGraph/LightWeightUnlitSubShader.cs


}
};
Pass m_DepthShadowPass = new Pass()
{
Name = "",
PixelShaderSlots = new List<int>()
{
PBRMasterNode.AlphaSlotId,
PBRMasterNode.AlphaThresholdSlotId
},
VertexShaderSlots = new List<int>()
{
PBRMasterNode.PositionSlotId
}
};
public string GetSubshader(IMasterNode inMasterNode, GenerationMode mode, List<string> sourceAssetDependencyPaths = null)
{
if (sourceAssetDependencyPaths != null)

mode,
materialOptions));
subShader.AppendLines(GetExtraPassesFromTemplate(extraTemplate, masterNode, pass, mode, materialOptions));
subShader.AppendLines(GetShaderPassFromTemplate(
extraTemplate,
masterNode,
m_DepthShadowPass,
mode,
materialOptions));
}
return subShader.ToString();

resultPass = resultPass.Replace("${PixelShader}", pixelShader.ToString());
resultPass = resultPass.Replace("${PixelShaderSurfaceInputs}", pixelShaderSurfaceInputs.ToString());
resultPass = resultPass.Replace("${PixelShaderSurfaceRemap}", pixelShaderSurfaceRemap.ToString());
return resultPass;
}
static string GetExtraPassesFromTemplate(string template, UnlitMasterNode masterNode, Pass pass, GenerationMode mode, SurfaceMaterialOptions materialOptions)
{
// ----------------------------------------------------- //
// SETUP //
// ----------------------------------------------------- //
// -------------------------------------
// String builders
var dummyBuilder = new ShaderStringBuilder(0);
var shaderProperties = new PropertyCollector();
var functionBuilder = new ShaderStringBuilder(1);
var functionRegistry = new FunctionRegistry(functionBuilder);
var defines = new ShaderStringBuilder(2);
var graph = new ShaderStringBuilder(0);
var vertexDescriptionInputStruct = new ShaderStringBuilder(1);
var vertexDescriptionStruct = new ShaderStringBuilder(1);
var vertexDescriptionFunction = new ShaderStringBuilder(1);
var vertexInputStruct = new ShaderStringBuilder(1);
var vertexShader = new ShaderStringBuilder(2);
var vertexDescriptionInputs = new ShaderStringBuilder(2);
// -------------------------------------
// Get Slot and Node lists per stage
var vertexSlots = pass.VertexShaderSlots.Select(masterNode.FindSlot<MaterialSlot>).ToList();
var vertexNodes = ListPool<INode>.Get();
NodeUtils.DepthFirstCollectNodesFromNode(vertexNodes, masterNode, NodeUtils.IncludeSelf.Include, pass.VertexShaderSlots);
// -------------------------------------
// Get requirements
var vertexRequirements = ShaderGraphRequirements.FromNodes(vertexNodes, ShaderStageCapability.Vertex, false);
var modelRequiements = ShaderGraphRequirements.none;
modelRequiements.requiresNormal |= m_VertexCoordinateSpace;
modelRequiements.requiresPosition |= m_VertexCoordinateSpace;
modelRequiements.requiresMeshUVs.Add(UVChannel.UV1);
// ----------------------------------------------------- //
// START SHADER GENERATION //
// ----------------------------------------------------- //
// -------------------------------------
// Calculate material options
var cullingBuilder = new ShaderStringBuilder(1);
materialOptions.GetCull(cullingBuilder);
// -------------------------------------
// Generate defines
if (masterNode.IsSlotConnected(PBRMasterNode.AlphaThresholdSlotId))
defines.AppendLine("#define _AlphaClip 1");
// ----------------------------------------------------- //
// START VERTEX DESCRIPTION //
// ----------------------------------------------------- //
// -------------------------------------
// Generate Input structure for Vertex Description function
// TODO - Vertex Description Input requirements are needed to exclude intermediate translation spaces
vertexDescriptionInputStruct.AppendLine("struct VertexDescriptionInputs");
using (vertexDescriptionInputStruct.BlockSemicolonScope())
{
ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresNormal, InterpolatorType.Normal, vertexDescriptionInputStruct);
ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresTangent, InterpolatorType.Tangent, vertexDescriptionInputStruct);
ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresBitangent, InterpolatorType.BiTangent, vertexDescriptionInputStruct);
ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresViewDir, InterpolatorType.ViewDirection, vertexDescriptionInputStruct);
ShaderGenerator.GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresPosition, InterpolatorType.Position, vertexDescriptionInputStruct);
if (vertexRequirements.requiresVertexColor)
vertexDescriptionInputStruct.AppendLine("float4 {0};", ShaderGeneratorNames.VertexColor);
if (vertexRequirements.requiresScreenPosition)
vertexDescriptionInputStruct.AppendLine("float4 {0};", ShaderGeneratorNames.ScreenPosition);
foreach (var channel in vertexRequirements.requiresMeshUVs.Distinct())
vertexDescriptionInputStruct.AppendLine("half4 {0};", channel.GetUVName());
}
// -------------------------------------
// Generate Output structure for Vertex Description function
GraphUtil.GenerateVertexDescriptionStruct(vertexDescriptionStruct, vertexSlots);
// -------------------------------------
// Generate Vertex Description function
GraphUtil.GenerateVertexDescriptionFunction(
masterNode.owner as AbstractMaterialGraph,
vertexDescriptionFunction,
functionRegistry,
shaderProperties,
mode,
vertexNodes,
vertexSlots);
// ----------------------------------------------------- //
// GENERATE VERTEX > PIXEL PIPELINE //
// ----------------------------------------------------- //
// -------------------------------------
// Generate Input structure for Vertex shader
GraphUtil.GenerateApplicationVertexInputs(vertexRequirements.Union(modelRequiements), vertexInputStruct);
// -------------------------------------
// Generate standard transformations
// This method ensures all required transform data is available in vertex and pixel stages
ShaderGenerator.GenerateStandardTransforms(
3,
10,
dummyBuilder,
vertexShader,
vertexDescriptionInputs,
dummyBuilder,
dummyBuilder,
dummyBuilder,
ShaderGraphRequirements.none,
ShaderGraphRequirements.none,
modelRequiements,
vertexRequirements,
CoordinateSpace.World);
// ----------------------------------------------------- //
// FINALIZE //
// ----------------------------------------------------- //
// -------------------------------------
// Combine Graph sections
graph.AppendLine(shaderProperties.GetPropertiesDeclaration(1));
graph.AppendLine(vertexDescriptionInputStruct.ToString());
graph.AppendLine(functionBuilder.ToString());
graph.AppendLine(vertexDescriptionStruct.ToString());
graph.AppendLine(vertexDescriptionFunction.ToString());
graph.AppendLine(vertexInputStruct.ToString());
// -------------------------------------
// Generate final subshader
var resultPass = template.Replace("${Culling}", cullingBuilder.ToString());
resultPass = resultPass.Replace("${Defines}", defines.ToString());
resultPass = resultPass.Replace("${Graph}", graph.ToString());
resultPass = resultPass.Replace("${VertexShader}", vertexShader.ToString());
resultPass = resultPass.Replace("${VertexShaderDescriptionInputs}", vertexDescriptionInputs.ToString());
return resultPass;
}

44
com.unity.render-pipelines.lightweight/LWRP/Editor/ShaderGraph/lightweightPBRExtraPasses.template


{
float2 uv : TEXCOORD0;
float4 clipPos : SV_POSITION;
// Interpolators defined by graph
${VertexOutputStruct}
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};

VertexDescription vd = PopulateVertexData(vdi);
v.vertex.xyz = vd.Position;
o.uv = uv1;
// Vertex shader outputs defined by graph
${VertexShaderOutputs}
float3 positionWS = TransformObjectToWorld(v.vertex.xyz);
float3 normalWS = TransformObjectToWorldDir(v.normal);

half4 ShadowPassFragment(VertexOutput IN) : SV_TARGET
{
UNITY_SETUP_INSTANCE_ID(IN);
// Pixel transformations performed by graph
${PixelShader}
SurfaceDescriptionInputs surfaceInput = (SurfaceDescriptionInputs)0;
// Surface description inputs defined by graph
${PixelShaderSurfaceInputs}
SurfaceDescription surf = PopulateSurfaceData(surfaceInput);
float Alpha = 1;
float AlphaClipThreshold = 0;
// Surface description remap performed by graph
${PixelShaderSurfaceRemap}
#if _AlphaClip
clip(Alpha - AlphaClipThreshold);
#endif
return 0;
}

{
float2 uv : TEXCOORD0;
float4 clipPos : SV_POSITION;
// Interpolators defined by graph
${VertexOutputStruct}
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};

VertexDescription vd = PopulateVertexData(vdi);
v.vertex.xyz = vd.Position;
o.uv = uv1;
// Vertex shader outputs defined by graph
${VertexShaderOutputs}
o.clipPos = TransformObjectToHClip(v.vertex.xyz);
return o;
}

UNITY_SETUP_INSTANCE_ID(IN);
// Pixel transformations performed by graph
${PixelShader}
SurfaceDescriptionInputs surfaceInput = (SurfaceDescriptionInputs)0;
// Surface description inputs defined by graph
${PixelShaderSurfaceInputs}
SurfaceDescription surf = PopulateSurfaceData(surfaceInput);
float Alpha = 1;
float AlphaClipThreshold = 0;
// Surface description remap performed by graph
${PixelShaderSurfaceRemap}
#if _AlphaClip
clip(Alpha - AlphaClipThreshold);
#endif
return 0;
}
ENDHLSL

44
com.unity.render-pipelines.lightweight/LWRP/Editor/ShaderGraph/lightweightUnlitExtraPasses.template


{
float2 uv : TEXCOORD0;
float4 clipPos : SV_POSITION;
// Interpolators defined by graph
${VertexOutputStruct}
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};

VertexDescription vd = PopulateVertexData(vdi);
v.vertex.xyz = vd.Position;
o.uv = uv1;
// Vertex shader outputs defined by graph
${VertexShaderOutputs}
float3 positionWS = TransformObjectToWorld(v.vertex.xyz);
float3 normalWS = TransformObjectToWorldDir(v.normal);

half4 ShadowPassFragment(VertexOutput IN) : SV_TARGET
{
UNITY_SETUP_INSTANCE_ID(IN);
// Pixel transformations performed by graph
${PixelShader}
SurfaceDescriptionInputs surfaceInput = (SurfaceDescriptionInputs)0;
// Surface description inputs defined by graph
${PixelShaderSurfaceInputs}
SurfaceDescription surf = PopulateSurfaceData(surfaceInput);
float Alpha = 1;
float AlphaClipThreshold = 0;
// Surface description remap performed by graph
${PixelShaderSurfaceRemap}
#if _AlphaClip
clip(Alpha - AlphaClipThreshold);
#endif
return 0;
}

{
float2 uv : TEXCOORD0;
float4 clipPos : SV_POSITION;
// Interpolators defined by graph
${VertexOutputStruct}
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};

VertexDescription vd = PopulateVertexData(vdi);
v.vertex.xyz = vd.Position;
o.uv = uv1;
// Vertex shader outputs defined by graph
${VertexShaderOutputs}
o.clipPos = TransformObjectToHClip(v.vertex.xyz);
return o;
}

UNITY_SETUP_INSTANCE_ID(IN);
// Pixel transformations performed by graph
${PixelShader}
SurfaceDescriptionInputs surfaceInput = (SurfaceDescriptionInputs)0;
// Surface description inputs defined by graph
${PixelShaderSurfaceInputs}
SurfaceDescription surf = PopulateSurfaceData(surfaceInput);
float Alpha = 1;
float AlphaClipThreshold = 0;
// Surface description remap performed by graph
${PixelShaderSurfaceRemap}
#if _AlphaClip
clip(Alpha - AlphaClipThreshold);
#endif
return 0;
}
ENDHLSL

3
com.unity.shadergraph/CHANGELOG.md


- If the current render pipeline is not compatible, master nodes now display an error badge.
- The preview shader now only considers the current render pipeline. Because of this there is less code to compile, and therefore the preview shader will compile faster.
- When you rename a shader graph or sub shader graph locally on your disk, the title of the Shader Graph window, black board, and preview also updates.
- `Normal Create` node has been renamed to `Normal From Texture`.
- Shader graphs using alpha clip now generate correct depth and shadow passes.
- `Normal Create` node has been renamed to `Normal From Texture`.
正在加载...
取消
保存