public static void GenerateStandardTransforms( int interpolatorStartIndex, int maxInterpolators, ShaderStringBuilder vertexOutputStruct, ShaderStringBuilder vertexShader, ShaderStringBuilder vertexShaderDescriptionInputs, ShaderStringBuilder vertexShaderOutputs, ShaderStringBuilder pixelShader, ShaderStringBuilder pixelShaderSurfaceInputs, ShaderGraphRequirements pixelRequirements, ShaderGraphRequirements surfaceRequirements, ShaderGraphRequirements modelRequiements, ShaderGraphRequirements vertexRequirements, CoordinateSpace preferredCoordinateSpace) { // ----------------------------------------------------- // // SETUP // // ----------------------------------------------------- // // ------------------------------------- // Tangent space requires going via World space if (preferredCoordinateSpace == CoordinateSpace.Tangent) { preferredCoordinateSpace = CoordinateSpace.World; } // ------------------------------------- // Generate combined graph requirements var graphModelRequirements = pixelRequirements.Union(modelRequiements); var combinedRequirements = vertexRequirements.Union(graphModelRequirements); int interpolatorIndex = interpolatorStartIndex; // ----------------------------------------------------- // // GENERATE VERTEX > PIXEL PIPELINE // // ----------------------------------------------------- // // ------------------------------------- // If any stage requires component write into vertex stage // If model or pixel requires component write into interpolators and pixel stage // ------------------------------------- // Position if (combinedRequirements.requiresPosition > 0) { var name = preferredCoordinateSpace.ToVariableName(InterpolatorType.Position); var preferredSpacePosition = ConvertBetweenSpace("v.vertex", CoordinateSpace.Object, preferredCoordinateSpace, InputType.Position); vertexShader.AppendLine("float3 {0} = {1}.xyz;", name, preferredSpacePosition); if (graphModelRequirements.requiresPosition > 0) { vertexOutputStruct.AppendLine("float3 {0} : TEXCOORD{1};", name, interpolatorIndex); vertexShaderOutputs.AppendLine("o.{0} = {0};", name); pixelShader.AppendLine("float3 {0} = IN.{0};", name); interpolatorIndex++; } } // ------------------------------------- // Normal // Bitangent needs Normal for x product if (combinedRequirements.requiresNormal > 0 || combinedRequirements.requiresBitangent > 0) { var name = preferredCoordinateSpace.ToVariableName(InterpolatorType.Normal); vertexShader.AppendLine("float3 {0} = normalize({1});", name, ConvertBetweenSpace("v.normal", CoordinateSpace.Object, preferredCoordinateSpace, InputType.Normal)); if (graphModelRequirements.requiresNormal > 0 || graphModelRequirements.requiresBitangent > 0) { vertexOutputStruct.AppendLine("float3 {0} : TEXCOORD{1};", name, interpolatorIndex); vertexShaderOutputs.AppendLine("o.{0} = {0};", name); pixelShader.AppendLine("float3 {0} = IN.{0};", name); interpolatorIndex++; } } // ------------------------------------- // Tangent if (combinedRequirements.requiresTangent > 0 || combinedRequirements.requiresBitangent > 0) { var name = preferredCoordinateSpace.ToVariableName(InterpolatorType.Tangent); vertexShader.AppendLine("float3 {0} = normalize({1});", name, ConvertBetweenSpace("v.tangent.xyz", CoordinateSpace.Object, preferredCoordinateSpace, InputType.Vector)); if (graphModelRequirements.requiresTangent > 0 || graphModelRequirements.requiresBitangent > 0) { vertexOutputStruct.AppendLine("float3 {0} : TEXCOORD{1};", name, interpolatorIndex); vertexShaderOutputs.AppendLine("o.{0} = {0};", name); pixelShader.AppendLine("float3 {0} = IN.{0};", name); interpolatorIndex++; } } // ------------------------------------- // Bitangent if (combinedRequirements.requiresBitangent > 0) { var name = preferredCoordinateSpace.ToVariableName(InterpolatorType.BiTangent); vertexShader.AppendLine("float3 {0} = cross({1}, {2}.xyz) * {3};", name, preferredCoordinateSpace.ToVariableName(InterpolatorType.Normal), preferredCoordinateSpace.ToVariableName(InterpolatorType.Tangent), "v.tangent.w"); if (graphModelRequirements.requiresBitangent > 0) { vertexOutputStruct.AppendLine("float3 {0} : TEXCOORD{1};", name, interpolatorIndex); vertexShaderOutputs.AppendLine("o.{0} = {0};", name); pixelShader.AppendLine("float3 {0} = IN.{0};", name); interpolatorIndex++; } } // ------------------------------------- // View Direction if (combinedRequirements.requiresViewDir > 0) { var name = preferredCoordinateSpace.ToVariableName(InterpolatorType.ViewDirection); const string worldSpaceViewDir = "_WorldSpaceCameraPos.xyz - mul(GetObjectToWorldMatrix(), float4(v.vertex.xyz, 1.0)).xyz"; var preferredSpaceViewDir = ConvertBetweenSpace(worldSpaceViewDir, CoordinateSpace.World, preferredCoordinateSpace, InputType.Vector); vertexShader.AppendLine("float3 {0} = {1};", name, preferredSpaceViewDir); if (graphModelRequirements.requiresViewDir > 0) { vertexOutputStruct.AppendLine("float3 {0} : TEXCOORD{1};", name, interpolatorIndex); vertexShaderOutputs.AppendLine("o.{0} = {0};", name); pixelShader.AppendLine("float3 {0} = IN.{0};", name); interpolatorIndex++; } } // ------------------------------------- // Tangent space transform matrix if (combinedRequirements.NeedsTangentSpace()) { var tangent = preferredCoordinateSpace.ToVariableName(InterpolatorType.Tangent); var bitangent = preferredCoordinateSpace.ToVariableName(InterpolatorType.BiTangent); var normal = preferredCoordinateSpace.ToVariableName(InterpolatorType.Normal); if (vertexRequirements.NeedsTangentSpace()) { vertexShader.AppendLine("float3x3 tangentSpaceTransform = float3x3({0},{1},{2});", tangent, bitangent, normal); } if (graphModelRequirements.NeedsTangentSpace()) { pixelShader.AppendLine("float3x3 tangentSpaceTransform = float3x3({0},{1},{2});", tangent, bitangent, normal); } } // ------------------------------------- // Vertex Color if (combinedRequirements.requiresVertexColor) { var vertexColor = "v.color"; vertexShader.AppendLine("float4 {0} = {1};", ShaderGeneratorNames.VertexColor, vertexColor); if (graphModelRequirements.requiresVertexColor) { vertexOutputStruct.AppendLine("float4 {0} : COLOR;", ShaderGeneratorNames.VertexColor); vertexShaderOutputs.AppendLine("o.{0} = {0};", ShaderGeneratorNames.VertexColor); pixelShader.AppendLine("float4 {0} = IN.{0};", ShaderGeneratorNames.VertexColor); } } // ------------------------------------- // Screen Position if (combinedRequirements.requiresScreenPosition) { var screenPosition = "ComputeScreenPos(mul(GetWorldToHClipMatrix(), mul(GetObjectToWorldMatrix(), v.vertex)), _ProjectionParams.x)"; vertexShader.AppendLine("float4 {0} = {1};", ShaderGeneratorNames.ScreenPosition, screenPosition); if (graphModelRequirements.requiresScreenPosition) { vertexOutputStruct.AppendLine("float4 {0} : TEXCOORD{1};", ShaderGeneratorNames.ScreenPosition, interpolatorIndex); vertexShaderOutputs.AppendLine("o.{0} = {0};", ShaderGeneratorNames.ScreenPosition); pixelShader.AppendLine("float4 {0} = IN.{0};", ShaderGeneratorNames.ScreenPosition); interpolatorIndex++; } } // ------------------------------------- // UV foreach (var channel in combinedRequirements.requiresMeshUVs.Distinct()) { vertexShader.AppendLine("float4 {0} = v.texcoord{1};", channel.GetUVName(), (int)channel); } foreach (var channel in graphModelRequirements.requiresMeshUVs.Distinct()) { vertexOutputStruct.AppendLine("half4 {0} : TEXCOORD{1};", channel.GetUVName(), interpolatorIndex == 0 ? "" : interpolatorIndex.ToString()); vertexShaderOutputs.AppendLine("o.{0} = {0};", channel.GetUVName()); pixelShader.AppendLine("float4 {0} = IN.{0};", channel.GetUVName()); interpolatorIndex++; } // ----------------------------------------------------- // // TRANSLATE NEEDED SPACES // // ----------------------------------------------------- // // ------------------------------------- // Generate the space translations needed by the vertex description GenerateSpaceTranslations(vertexRequirements.requiresNormal, InterpolatorType.Normal, preferredCoordinateSpace, InputType.Normal, vertexShader, Dimension.Three); GenerateSpaceTranslations(vertexRequirements.requiresTangent, InterpolatorType.Tangent, preferredCoordinateSpace, InputType.Vector, vertexShader, Dimension.Three); GenerateSpaceTranslations(vertexRequirements.requiresBitangent, InterpolatorType.BiTangent, preferredCoordinateSpace, InputType.Vector, vertexShader, Dimension.Three); GenerateSpaceTranslations(vertexRequirements.requiresViewDir, InterpolatorType.ViewDirection, preferredCoordinateSpace, InputType.Vector, vertexShader, Dimension.Three); GenerateSpaceTranslations(vertexRequirements.requiresPosition, InterpolatorType.Position, preferredCoordinateSpace, InputType.Position, vertexShader, Dimension.Three); // ------------------------------------- // Generate the space translations needed by the surface description and model GenerateSpaceTranslations(graphModelRequirements.requiresNormal, InterpolatorType.Normal, preferredCoordinateSpace, InputType.Normal, pixelShader, Dimension.Three); GenerateSpaceTranslations(graphModelRequirements.requiresTangent, InterpolatorType.Tangent, preferredCoordinateSpace, InputType.Vector, pixelShader, Dimension.Three); GenerateSpaceTranslations(graphModelRequirements.requiresBitangent, InterpolatorType.BiTangent, preferredCoordinateSpace, InputType.Vector, pixelShader, Dimension.Three); GenerateSpaceTranslations(graphModelRequirements.requiresViewDir, InterpolatorType.ViewDirection, preferredCoordinateSpace, InputType.Vector, pixelShader, Dimension.Three); GenerateSpaceTranslations(graphModelRequirements.requiresPosition, InterpolatorType.Position, preferredCoordinateSpace, InputType.Position, pixelShader, Dimension.Three); // ----------------------------------------------------- // // START SURFACE DESCRIPTION // // ----------------------------------------------------- // // ------------------------------------- // Copy the locally defined values into the surface description // structure using the requirements for ONLY the shader graph pixel stage // additional requirements have come from the lighting model // and are not needed in the shader graph { var replaceString = "surfaceInput.{0} = {0};"; GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresNormal, InterpolatorType.Normal, pixelShaderSurfaceInputs, replaceString); GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresTangent, InterpolatorType.Tangent, pixelShaderSurfaceInputs, replaceString); GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresBitangent, InterpolatorType.BiTangent, pixelShaderSurfaceInputs, replaceString); GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresViewDir, InterpolatorType.ViewDirection, pixelShaderSurfaceInputs, replaceString); GenerateSpaceTranslationSurfaceInputs(surfaceRequirements.requiresPosition, InterpolatorType.Position, pixelShaderSurfaceInputs, replaceString); } if (pixelRequirements.requiresVertexColor) { pixelShaderSurfaceInputs.AppendLine("surfaceInput.{0} = {0};", ShaderGeneratorNames.VertexColor); } if (pixelRequirements.requiresScreenPosition) { pixelShaderSurfaceInputs.AppendLine("surfaceInput.{0} = {0};", ShaderGeneratorNames.ScreenPosition); } if (pixelRequirements.requiresFaceSign) { pixelShaderSurfaceInputs.AppendLine("surfaceInput.{0} = {0};", ShaderGeneratorNames.FaceSign); } foreach (var channel in pixelRequirements.requiresMeshUVs.Distinct()) { pixelShaderSurfaceInputs.AppendLine("surfaceInput.{0} = {0};", ShaderGeneratorNames.GetUVName(channel)); } // ----------------------------------------------------- // // START VERTEX DESCRIPTION // // ----------------------------------------------------- // // ------------------------------------- // Copy the locally defined values into the vertex description // structure using the requirements for ONLY the shader graph vertex stage // additional requirements have come from the lighting model // and are not needed in the shader graph { var replaceString = "vdi.{0} = {0};"; GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresNormal, InterpolatorType.Normal, vertexShaderDescriptionInputs, replaceString); GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresTangent, InterpolatorType.Tangent, vertexShaderDescriptionInputs, replaceString); GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresBitangent, InterpolatorType.BiTangent, vertexShaderDescriptionInputs, replaceString); GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresViewDir, InterpolatorType.ViewDirection, vertexShaderDescriptionInputs, replaceString); GenerateSpaceTranslationSurfaceInputs(vertexRequirements.requiresPosition, InterpolatorType.Position, vertexShaderDescriptionInputs, replaceString); } if (vertexRequirements.requiresVertexColor) { vertexShaderDescriptionInputs.AppendLine("vdi.{0} = {0};", ShaderGeneratorNames.VertexColor); } if (vertexRequirements.requiresScreenPosition) { vertexShaderDescriptionInputs.AppendLine("vdi.{0} = {0};", ShaderGeneratorNames.ScreenPosition); } foreach (var channel in vertexRequirements.requiresMeshUVs.Distinct()) { vertexShaderDescriptionInputs.AppendLine("vdi.{0} = {0};", channel.GetUVName(), (int)channel); } }
public static void GenerateStandardTransforms( int interpolatorStartIndex, int maxInterpolators, ShaderGenerator interpolators, ShaderGenerator vertexShader, ShaderGenerator pixelShader, ShaderGenerator surfaceInputs, ShaderGraphRequirements graphRequiements, ShaderGraphRequirements modelRequiements, CoordinateSpace preferedCoordinateSpace) { if (preferedCoordinateSpace == CoordinateSpace.Tangent) { preferedCoordinateSpace = CoordinateSpace.World; } // step 1: // *generate needed interpolators // *generate output from the vertex shader that writes into these interpolators // *generate the pixel shader code that declares needed variables in the local scope var combinedRequierments = graphRequiements.Union(modelRequiements); int interpolatorIndex = interpolatorStartIndex; // bitangent needs normal for x product if (combinedRequierments.requiresNormal > 0 || combinedRequierments.requiresBitangent > 0) { var name = preferedCoordinateSpace.ToVariableName(InterpolatorType.Normal); interpolators.AddShaderChunk(string.Format("float3 {0} : TEXCOORD{1};", name, interpolatorIndex), false); vertexShader.AddShaderChunk(string.Format("o.{0} = {1};", name, ConvertBetweenSpace("v.normal", CoordinateSpace.Object, preferedCoordinateSpace, InputType.Normal)), false); pixelShader.AddShaderChunk(string.Format("float3 {0} = normalize(IN.{0});", name), false); interpolatorIndex++; } if (combinedRequierments.requiresTangent > 0 || combinedRequierments.requiresBitangent > 0) { var name = preferedCoordinateSpace.ToVariableName(InterpolatorType.Tangent); interpolators.AddShaderChunk(string.Format("float3 {0} : TEXCOORD{1};", name, interpolatorIndex), false); vertexShader.AddShaderChunk(string.Format("o.{0} = {1};", name, ConvertBetweenSpace("v.tangent", CoordinateSpace.Object, preferedCoordinateSpace, InputType.Vector)), false); pixelShader.AddShaderChunk(string.Format("float3 {0} = IN.{0};", name), false); interpolatorIndex++; } if (combinedRequierments.requiresBitangent > 0) { var name = preferedCoordinateSpace.ToVariableName(InterpolatorType.BiTangent); interpolators.AddShaderChunk(string.Format("float3 {0} : TEXCOORD{1};", name, interpolatorIndex), false); vertexShader.AddShaderChunk(string.Format("o.{0} = normalize(cross(o.{1}, o.{2}.xyz) * {3});", name, preferedCoordinateSpace.ToVariableName(InterpolatorType.Normal), preferedCoordinateSpace.ToVariableName(InterpolatorType.Tangent), "v.tangent.w"), false); pixelShader.AddShaderChunk(string.Format("float3 {0} = IN.{0};", name), false); interpolatorIndex++; } if (combinedRequierments.requiresViewDir > 0) { var name = preferedCoordinateSpace.ToVariableName(InterpolatorType.ViewDirection); interpolators.AddShaderChunk(string.Format("float3 {0} : TEXCOORD{1};", name, interpolatorIndex), false); var worldSpaceViewDir = "SafeNormalize(_WorldSpaceCameraPos.xyz - mul(GetObjectToWorldMatrix(), float4(v.vertex.xyz, 1.0)).xyz)"; vertexShader.AddShaderChunk(string.Format("o.{0} = {1};", name, ConvertBetweenSpace(worldSpaceViewDir, CoordinateSpace.World, preferedCoordinateSpace, InputType.Vector)), false); pixelShader.AddShaderChunk(string.Format("float3 {0} = normalize(IN.{0});", name), false); interpolatorIndex++; } if (combinedRequierments.requiresPosition > 0) { var name = preferedCoordinateSpace.ToVariableName(InterpolatorType.Position); interpolators.AddShaderChunk(string.Format("float3 {0} : TEXCOORD{1};", name, interpolatorIndex), false); vertexShader.AddShaderChunk(string.Format("o.{0} = {1};", name, ConvertBetweenSpace("v.vertex", CoordinateSpace.Object, preferedCoordinateSpace, InputType.Position)), false); pixelShader.AddShaderChunk(string.Format("float3 {0} = IN.{0};", name), false); interpolatorIndex++; } if (combinedRequierments.NeedsTangentSpace()) { pixelShader.AddShaderChunk(string.Format("float3x3 tangentSpaceTransform = float3x3({0},{1},{2});", preferedCoordinateSpace.ToVariableName(InterpolatorType.Tangent), preferedCoordinateSpace.ToVariableName(InterpolatorType.BiTangent), preferedCoordinateSpace.ToVariableName(InterpolatorType.Normal)), false); } ShaderGenerator.GenerateSpaceTranslationPixelShader(combinedRequierments.requiresNormal, InterpolatorType.Normal, preferedCoordinateSpace, InputType.Normal, pixelShader, Dimension.Three); ShaderGenerator.GenerateSpaceTranslationPixelShader(combinedRequierments.requiresTangent, InterpolatorType.Tangent, preferedCoordinateSpace, InputType.Vector, pixelShader, Dimension.Three); ShaderGenerator.GenerateSpaceTranslationPixelShader(combinedRequierments.requiresBitangent, InterpolatorType.BiTangent, preferedCoordinateSpace, InputType.Vector, pixelShader, Dimension.Three); ShaderGenerator.GenerateSpaceTranslationPixelShader(combinedRequierments.requiresViewDir, InterpolatorType.ViewDirection, preferedCoordinateSpace, InputType.Vector, pixelShader, Dimension.Three); ShaderGenerator.GenerateSpaceTranslationPixelShader(combinedRequierments.requiresPosition, InterpolatorType.Position, preferedCoordinateSpace, InputType.Position, pixelShader, Dimension.Three); if (combinedRequierments.requiresVertexColor) { interpolators.AddShaderChunk(string.Format("float4 {0} : COLOR;", ShaderGeneratorNames.VertexColor), false); vertexShader.AddShaderChunk(string.Format("o.{0} = v.color;", ShaderGeneratorNames.VertexColor), false); pixelShader.AddShaderChunk(string.Format("float4 {0} = IN.{0};", ShaderGeneratorNames.VertexColor), false); } if (combinedRequierments.requiresScreenPosition) { interpolators.AddShaderChunk(string.Format("float4 {0} : TEXCOORD{1};", ShaderGeneratorNames.ScreenPosition, interpolatorIndex), false); vertexShader.AddShaderChunk(string.Format("o.{0} = ComputeScreenPos(UnityObjectToClipPos(v.vertex));", ShaderGeneratorNames.ScreenPosition), false); pixelShader.AddShaderChunk(string.Format("float4 {0} = IN.{0};", ShaderGeneratorNames.ScreenPosition), false); interpolatorIndex++; } foreach (var channel in combinedRequierments.requiresMeshUVs.Distinct()) { interpolators.AddShaderChunk(string.Format("half4 {0} : TEXCOORD{1};", channel.GetUVName(), interpolatorIndex == 0 ? "" : interpolatorIndex.ToString()), false); vertexShader.AddShaderChunk(string.Format("o.{0} = v.texcoord{1};", channel.GetUVName(), (int)channel), false); pixelShader.AddShaderChunk(string.Format("float4 {0} = IN.{0};", channel.GetUVName()), false); interpolatorIndex++; } // step 2 // copy the locally defined values into the surface description // structure using the requirements for ONLY the shader graph // additional requirements have come from the lighting model // and are not needed in the shader graph var replaceString = "surfaceInput.{0} = {0};"; GenerateSpaceTranslationSurfaceInputs(graphRequiements.requiresNormal, InterpolatorType.Normal, surfaceInputs, replaceString); GenerateSpaceTranslationSurfaceInputs(graphRequiements.requiresTangent, InterpolatorType.Tangent, surfaceInputs, replaceString); GenerateSpaceTranslationSurfaceInputs(graphRequiements.requiresBitangent, InterpolatorType.BiTangent, surfaceInputs, replaceString); GenerateSpaceTranslationSurfaceInputs(graphRequiements.requiresViewDir, InterpolatorType.ViewDirection, surfaceInputs, replaceString); GenerateSpaceTranslationSurfaceInputs(graphRequiements.requiresPosition, InterpolatorType.Position, surfaceInputs, replaceString); if (graphRequiements.requiresVertexColor) { surfaceInputs.AddShaderChunk(string.Format("surfaceInput.{0} = {0};", ShaderGeneratorNames.VertexColor), false); } if (graphRequiements.requiresScreenPosition) { surfaceInputs.AddShaderChunk(string.Format("surfaceInput.{0} = {0};", ShaderGeneratorNames.ScreenPosition), false); } foreach (var channel in graphRequiements.requiresMeshUVs.Distinct()) { surfaceInputs.AddShaderChunk(string.Format("surfaceInput.{0} = {0};", channel.GetUVName()), false); } }