using System ;
using System.Collections.Generic ;
using System.IO ;
using System.Linq ;
namespace UnityEditor.Experimental.Rendering.HDPipeline
{
// [Serializable] ??
public class HDUnlitSubShader : IUnlitSubShader
{
Pass m_PassDepthOnly = new Pass ( )
{
UnlitMasterNode . AlphaSlotId ,
UnlitMasterNode . AlphaThresholdSlotId
} ,
VertexShaderSlots = new List < int > ( )
{
PBRMasterNode . PositionSlotId
}
} ;
UnlitMasterNode . ColorSlotId ,
UnlitMasterNode . AlphaSlotId ,
UnlitMasterNode . AlphaThresholdSlotId
} ,
VertexShaderSlots = new List < int > ( )
{
PBRMasterNode . PositionSlotId
}
} ;
UnlitMasterNode . ColorSlotId ,
UnlitMasterNode . AlphaSlotId ,
UnlitMasterNode . AlphaThresholdSlotId
} ,
VertexShaderSlots = new List < int > ( )
{
PBRMasterNode . PositionSlotId
}
} ;
{
PBRMasterNode . AlphaSlotId ,
PBRMasterNode . AlphaThresholdSlotId
}
} ,
VertexShaderSlots = new List < int > ( )
{
PBRMasterNode . PositionSlotId
} ,
} ;
private static string GetVariantDefines ( UnlitMasterNode masterNode )
return defines . GetShaderString ( 2 ) ;
}
private static bool GenerateShaderPass ( UnlitMasterNode masterNode , Pass pass , GenerationMode mode , SurfaceMaterialOptions materialOptions , ShaderGenerator result )
// TODO: this can be a shared function I think
private static bool GenerateShaderPassUnlit ( UnlitMasterNode masterNode , Pass pass , GenerationMode mode , SurfaceMaterialOptions materialOptions , ShaderGenerator result )
var templateLocation = ShaderGenerator . GetTemplatePath ( pass . TemplateName ) ;
var templateLocation = Path . Combine ( Path . Combine ( Path . Combine ( HDEditorUtils . GetHDRenderPipelinePath ( ) , "Editor" ) , "ShaderGraph" ) , pass . TemplateName ) ;
if ( ! File . Exists ( templateLocation ) )
{
// TODO: produce error here
// grab all of the active nodes
var activeNodeList = ListPool < INode > . Get ( ) ;
NodeUtils . DepthFirstCollectNodesFromNode ( activeNodeList , masterNode , NodeUtils . IncludeSelf . Include , pass . PixelShaderSlots ) ;
// grab all of the active nodes (for pixel and vertex graphs)
var vertexNodes = ListPool < AbstractMaterialNode > . Get ( ) ;
NodeUtils . DepthFirstCollectNodesFromNode ( vertexNodes , masterNode , NodeUtils . IncludeSelf . Include , pass . VertexShaderSlots ) ;
// graph requirements describe what the graph itself requires
var graphRequirements = ShaderGraphRequirements . FromNodes ( activeNodeList , ShaderStageCapability . All , false ) ; // TODO: capability.all ?? fragment only?
var pixelNodes = ListPool < INode > . Get ( ) ;
NodeUtils . DepthFirstCollectNodesFromNode ( pixelNodes , masterNode , NodeUtils . IncludeSelf . Include , pass . PixelShaderSlots ) ;
// graph requirements describe what the graph itself requires
var pixelRequirements = ShaderGraphRequirements . FromNodes ( pixelNodes , ShaderStageCapability . Fragment , false ) ; // TODO: is ShaderStageCapability.Fragment correct?
var vertexRequirements = ShaderGraphRequirements . FromNodes ( vertexNodes , ShaderStageCapability . Vertex , false ) ;
// Function Registry tracks functions to remove duplicates, it wraps a string builder that stores the combined function string
// TODO: this can be a shared function for all HDRP master nodes -- From here through GraphUtil.GenerateSurfaceDescription(..)
// TODO: this can be a shared function -- From here through GraphUtil.GenerateSurfaceDescription(..)
// var pixelSlots = HDSubShaderUtilities.FindSlotsOnMasterNode(pass.PixelShaderSlots, masterNode); // TODO: need to have a generic interface for masterNode.FindSlot<> ?
var pixelSlots = HDSubShaderUtilities . FindMaterialSlotsOnNode ( pass . PixelShaderSlots , masterNode ) ;
var vertexSlots = HDSubShaderUtilities . FindMaterialSlotsOnNode ( pass . VertexShaderSlots , masterNode ) ;
var activeSlots = new List < MaterialSlot > ( ) ;
foreach ( var id in pass . PixelShaderSlots )
{
MaterialSlot slot = masterNode . FindSlot < MaterialSlot > ( id ) ;
if ( slot ! = null )
{
activeSlots . Add ( slot ) ;
}
}
// properties used by either pixel and vertex shader
PropertyCollector sharedProperties = new PropertyCollector ( ) ;
string graphInputStructName = "SurfaceDescriptionInputs" ;
string graphOutputStructName = "SurfaceDescription" ;
string graphEvalFunctionName = "SurfaceDescriptionFunction" ;
var graphEvalFunction = new ShaderStringBuilder ( ) ;
var graphOutputs = new ShaderStringBuilder ( ) ;
PropertyCollector graphProperties = new PropertyCollector ( ) ;
string pixelGraphInputStructName = "SurfaceDescriptionInputs" ;
string pixelGraphOutputStructName = "SurfaceDescription" ;
string pixelGraphEvalFunctionName = "SurfaceDescriptionFunction" ;
ShaderStringBuilder pixelGraphEvalFunction = new ShaderStringBuilder ( ) ;
ShaderStringBuilder pixelGraphOutputs = new ShaderStringBuilder ( ) ;
// dependency tracker -- set of active fields
HashSet < string > activeFields = new HashSet < string > ( ) ;
// build initial requirements
HDRPShaderStructs . AddActiveFieldsFromPixelGraphRequirements ( activeFields , pixelRequirements ) ;
HashSet < string > activeFields = new HashSet < string > ( ) ;
GraphUtil . GenerateSurfaceDescriptionStruct ( graphOutputs , activeSlots , true ) ;
GraphUtil . GenerateSurfaceDescriptionStruct ( pixelGraphOutputs , pixelSlots , true , pixelGraphOutputStructName , activeFields ) ;
activeNodeList ,
pixelNodes ,
graphEvalFunction ,
pixelGraphEvalFunction ,
graphProperties ,
graphRequirements , // TODO : REMOVE UNUSED
sharedProperties ,
pixelRequirements , // TODO : REMOVE UNUSED
graphEvalFunctionName ,
graphOutputStructName ,
pixelGraphEvalFunctionName ,
pixelGraphOutputStructName ,
activeSlots ,
graphInputStructName ) ;
pixelSlots ,
pixelGraphInputStructName ) ;
string vertexGraphInputStructName = "VertexDescriptionInputs" ;
string vertexGraphOutputStructName = "VertexDescription" ;
string vertexGraphEvalFunctionName = "VertexDescriptionFunction" ;
ShaderStringBuilder vertexGraphEvalFunction = new ShaderStringBuilder ( ) ;
ShaderStringBuilder vertexGraphOutputs = new ShaderStringBuilder ( ) ;
// check for vertex animation -- enables HAVE_VERTEX_MODIFICATION
bool vertexActive = false ;
if ( masterNode . IsSlotConnected ( PBRMasterNode . PositionSlotId ) )
{
vertexActive = true ;
activeFields . Add ( "features.modifyMesh" ) ;
HDRPShaderStructs . AddActiveFieldsFromVertexGraphRequirements ( activeFields , vertexRequirements ) ;
// -------------------------------------
// Generate Output structure for Vertex Description function
GraphUtil . GenerateVertexDescriptionStruct ( vertexGraphOutputs , vertexSlots , vertexGraphOutputStructName , activeFields ) ;
// -------------------------------------
// Generate Vertex Description function
GraphUtil . GenerateVertexDescriptionFunction (
masterNode . owner as AbstractMaterialGraph ,
vertexGraphEvalFunction ,
functionRegistry ,
sharedProperties ,
mode ,
vertexNodes ,
vertexSlots ,
vertexGraphInputStructName ,
vertexGraphEvalFunctionName ,
vertexGraphOutputStructName ) ;
}
var blendCode = new ShaderStringBuilder ( ) ;
var cullCode = new ShaderStringBuilder ( ) ;
}
}
if ( pass . PixelShaderSlots ! = null )
{
foreach ( var slotId in pass . PixelShaderSlots )
{
var slot = masterNode . FindSlot < MaterialSlot > ( slotId ) ;
if ( slot ! = null )
{
var rawSlotName = slot . RawDisplayName ( ) . ToString ( ) ;
var descriptionVar = string . Format ( "{0}.{1}" , graphOutputStructName , rawSlotName ) ;
activeFields . Add ( descriptionVar ) ;
}
}
}
// build initial requirements
HDRPShaderStructs . AddActiveFieldsFromPixelGraphRequirements ( activeFields , graphRequirements ) ;
// apply dependencies to the active fields, and build interpolators (TODO: split this function)
// build graph inputs structures
var graphInputs = new ShaderGenerator ( ) ;
ShaderSpliceUtil . BuildType ( typeof ( HDRPShaderStructs . SurfaceDescriptionInputs ) , activeFields , graphInputs ) ;
// debug output all active fields
var interpolatorDefines = new ShaderGenerator ( ) ;
}
}
// build graph inputs structures
ShaderGenerator pixelGraphInputs = new ShaderGenerator ( ) ;
ShaderSpliceUtil . BuildType ( typeof ( HDRPShaderStructs . SurfaceDescriptionInputs ) , activeFields , pixelGraphInputs ) ;
ShaderGenerator vertexGraphInputs = new ShaderGenerator ( ) ;
ShaderSpliceUtil . BuildType ( typeof ( HDRPShaderStructs . VertexDescriptionInputs ) , activeFields , vertexGraphInputs ) ;
ShaderGenerator defines = new ShaderGenerator ( ) ;
{
defines . AddShaderChunk ( string . Format ( "#define SHADERPASS {0}" , pass . ShaderPassName ) , true ) ;
// build graph code
var graph = new ShaderGenerator ( ) ;
graph . AddShaderChunk ( "// Graph Inputs" ) ;
graph . Indent ( ) ;
graph . AddGenerator ( graphInputs ) ;
graph . Deindent ( ) ;
graph . AddShaderChunk ( "// Graph Outputs" ) ;
graph . Indent ( ) ;
graph . AddShaderChunk ( graphOutputs . ToString ( ) ) ;
//graph.AddGenerator(graphOutputs);
graph . Deindent ( ) ;
graph . AddShaderChunk ( "// Graph Properties (uniform inputs)" ) ;
graph . AddShaderChunk ( graphProperties . GetPropertiesDeclaration ( 1 ) ) ;
graph . AddShaderChunk ( "// Graph Node Functions" ) ;
graph . AddShaderChunk ( graphNodeFunctions . ToString ( ) ) ;
graph . AddShaderChunk ( "// Graph Evaluation" ) ;
graph . Indent ( ) ;
graph . AddShaderChunk ( graphEvalFunction . ToString ( ) ) ;
//graph.AddGenerator(graphEvalFunction);
graph . Deindent ( ) ;
{
graph . AddShaderChunk ( "// Shared Graph Properties (uniform inputs)" ) ;
graph . AddShaderChunk ( sharedProperties . GetPropertiesDeclaration ( 1 ) ) ;
graph . AddShaderChunk ( "// Shared Graph Node Functions" ) ;
graph . AddShaderChunk ( graphNodeFunctions . ToString ( ) ) ;
if ( vertexActive )
{
graph . AddShaderChunk ( "// Vertex Graph Inputs" ) ;
graph . Indent ( ) ;
graph . AddGenerator ( vertexGraphInputs ) ;
graph . Deindent ( ) ;
graph . AddShaderChunk ( "// Vertex Graph Outputs" ) ;
graph . Indent ( ) ;
graph . AddShaderChunk ( vertexGraphOutputs . ToString ( ) ) ;
graph . Deindent ( ) ;
graph . AddShaderChunk ( "// Vertex Graph Evaluation" ) ;
graph . Indent ( ) ;
graph . AddShaderChunk ( vertexGraphEvalFunction . ToString ( ) ) ;
graph . Deindent ( ) ;
}
graph . AddShaderChunk ( "// Pixel Graph Inputs" ) ;
graph . Indent ( ) ;
graph . AddGenerator ( pixelGraphInputs ) ;
graph . Deindent ( ) ;
graph . AddShaderChunk ( "// Pixel Graph Outputs" ) ;
graph . Indent ( ) ;
graph . AddShaderChunk ( pixelGraphOutputs . ToString ( ) ) ;
graph . Deindent ( ) ;
graph . AddShaderChunk ( "// Pixel Graph Evaluation" ) ;
graph . Indent ( ) ;
graph . AddShaderChunk ( pixelGraphEvalFunction . ToString ( ) ) ;
graph . Deindent ( ) ;
}
// build the hash table of all named fragments TODO: could make this Dictionary<string, ShaderGenerator / string> ?
Dictionary < string , string > namedFragments = new Dictionary < string , string > ( ) ;
// bool transparent = (masterNode.surfaceType != SurfaceType.Opaque);
bool distortionActive = false ;
GenerateShaderPass ( masterNode , m_PassDepthOnly , mode , materialOptions , subShader ) ;
GenerateShaderPass ( masterNode , m_PassForward , mode , materialOptions , subShader ) ;
GenerateShaderPass ( masterNode , m_PassMETA , mode , materialOptions , subShader ) ;
GenerateShaderPassUnlit ( masterNode , m_PassDepthOnly , mode , materialOptions , subShader ) ;
GenerateShaderPassUnlit ( masterNode , m_PassForward , mode , materialOptions , subShader ) ;
GenerateShaderPassUnlit ( masterNode , m_PassMETA , mode , materialOptions , subShader ) ;
GenerateShaderPass ( masterNode , m_PassDistortion , mode , materialOptions , subShader ) ;
GenerateShaderPassUnlit ( masterNode , m_PassDistortion , mode , materialOptions , subShader ) ;
}
}
subShader . Deindent ( ) ;