예제 #1
0
        private static HashSet <string> GetActiveFieldsFromMasterNode(AbstractMaterialNode iMasterNode, Pass pass)
        {
            HashSet <string> activeFields = new HashSet <string>();

            DecalMasterNode masterNode = iMasterNode as DecalMasterNode;

            if (masterNode == null)
            {
                return(activeFields);
            }
            if (masterNode.affectsAlbedo.isOn)
            {
                activeFields.Add("Material.AffectsAlbedo");
            }
            if (masterNode.affectsNormal.isOn)
            {
                activeFields.Add("Material.AffectsNormal");
            }
            if (masterNode.affectsEmission.isOn)
            {
                activeFields.Add("Material.AffectsEmission");
            }
            return(activeFields);
        }
        private static HashSet <string> GetActiveFieldsFromMasterNode(AbstractMaterialNode iMasterNode, Pass pass)
        {
            HashSet <string> activeFields = new HashSet <string>();

            HairMasterNode masterNode = iMasterNode as HairMasterNode;

            if (masterNode == null)
            {
                return(activeFields);
            }

            if (masterNode.doubleSidedMode != DoubleSidedMode.Disabled)
            {
                activeFields.Add("DoubleSided");
                if (pass.ShaderPassName != "SHADERPASS_VELOCITY")   // HACK to get around lack of a good interpolator dependency system
                {                                                   // we need to be able to build interpolators using multiple input structs
                                                                    // also: should only require isFrontFace if Normals are required...
                    if (masterNode.doubleSidedMode == DoubleSidedMode.FlippedNormals)
                    {
                        activeFields.Add("DoubleSided.Flip");
                    }
                    else if (masterNode.doubleSidedMode == DoubleSidedMode.MirroredNormals)
                    {
                        activeFields.Add("DoubleSided.Mirror");
                    }
                    // Important: the following is used in SharedCode.template.hlsl for determining the normal flip mode
                    activeFields.Add("FragInputs.isFrontFace");
                }
            }

            switch (masterNode.materialType)
            {
            case HairMasterNode.MaterialType.KajiyaKay:
                activeFields.Add("Material.KajiyaKay");
                break;

            default:
                UnityEngine.Debug.LogError("Unknown material type: " + masterNode.materialType);
                break;
            }

            if (masterNode.alphaTest.isOn)
            {
                int count = 0;

                // If alpha test shadow is enable, we use it, otherwise we use the regular test
                if (pass.PixelShaderUsesSlot(HairMasterNode.AlphaClipThresholdShadowSlotId) && masterNode.alphaTestShadow.isOn)
                {
                    activeFields.Add("AlphaTestShadow");
                    ++count;
                }
                else if (pass.PixelShaderUsesSlot(HairMasterNode.AlphaClipThresholdSlotId))
                {
                    activeFields.Add("AlphaTest");
                    ++count;
                }
                // Other alpha test are suppose to be alone
                else if (pass.PixelShaderUsesSlot(HairMasterNode.AlphaClipThresholdDepthPrepassSlotId))
                {
                    activeFields.Add("AlphaTestPrepass");
                    ++count;
                }
                else if (pass.PixelShaderUsesSlot(HairMasterNode.AlphaClipThresholdDepthPostpassSlotId))
                {
                    activeFields.Add("AlphaTestPostpass");
                    ++count;
                }
                UnityEngine.Debug.Assert(count == 1, "Alpha test value not set correctly");
            }

            if (masterNode.surfaceType != SurfaceType.Opaque)
            {
                activeFields.Add("SurfaceType.Transparent");

                if (masterNode.alphaMode == AlphaMode.Alpha)
                {
                    activeFields.Add("BlendMode.Alpha");
                }
                else if (masterNode.alphaMode == AlphaMode.Premultiply)
                {
                    activeFields.Add("BlendMode.Premultiply");
                }
                else if (masterNode.alphaMode == AlphaMode.Additive)
                {
                    activeFields.Add("BlendMode.Add");
                }

                if (masterNode.blendPreserveSpecular.isOn)
                {
                    activeFields.Add("BlendMode.PreserveSpecular");
                }

                if (masterNode.transparencyFog.isOn)
                {
                    activeFields.Add("AlphaFog");
                }

                if (masterNode.transparentWritesVelocity.isOn)
                {
                    activeFields.Add("TransparentWritesVelocity");
                }
            }

            if (!masterNode.receiveDecals.isOn)
            {
                activeFields.Add("DisableDecals");
            }

            if (!masterNode.receiveSSR.isOn)
            {
                activeFields.Add("DisableSSR");
            }

            if (masterNode.specularAA.isOn && pass.PixelShaderUsesSlot(HairMasterNode.SpecularAAThresholdSlotId) && pass.PixelShaderUsesSlot(HairMasterNode.SpecularAAScreenSpaceVarianceSlotId))
            {
                activeFields.Add("Specular.AA");
            }

            if (masterNode.IsSlotConnected(HairMasterNode.BentNormalSlotId) && pass.PixelShaderUsesSlot(HairMasterNode.BentNormalSlotId))
            {
                activeFields.Add("BentNormal");
            }

            if (masterNode.IsSlotConnected(HairMasterNode.HairStrandDirectionSlotId) && pass.PixelShaderUsesSlot(HairMasterNode.HairStrandDirectionSlotId))
            {
                activeFields.Add("HairStrandDirection");
            }

            if (masterNode.transmission.isOn)
            {
                activeFields.Add("Material.Transmission");
            }

            if (masterNode.subsurfaceScattering.isOn && masterNode.surfaceType != SurfaceType.Transparent)
            {
                activeFields.Add("Material.SubsurfaceScattering");
            }

            switch (masterNode.specularOcclusionMode)
            {
            case SpecularOcclusionMode.Off:
                break;

            case SpecularOcclusionMode.FromAO:
                activeFields.Add("SpecularOcclusionFromAO");
                break;

            case SpecularOcclusionMode.FromAOAndBentNormal:
                activeFields.Add("SpecularOcclusionFromAOBentNormal");
                break;

            case SpecularOcclusionMode.Custom:
                activeFields.Add("SpecularOcclusionCustom");
                break;

            default:
                break;
            }

            if (pass.PixelShaderUsesSlot(HairMasterNode.AmbientOcclusionSlotId))
            {
                var occlusionSlot = masterNode.FindSlot <Vector1MaterialSlot>(HairMasterNode.AmbientOcclusionSlotId);

                bool connected = masterNode.IsSlotConnected(HairMasterNode.AmbientOcclusionSlotId);
                if (connected || occlusionSlot.value != occlusionSlot.defaultValue)
                {
                    activeFields.Add("AmbientOcclusion");
                }
            }

            if (masterNode.IsSlotConnected(HairMasterNode.LightingSlotId) && pass.PixelShaderUsesSlot(HairMasterNode.LightingSlotId))
            {
                activeFields.Add("LightingGI");
            }
            if (masterNode.IsSlotConnected(HairMasterNode.BackLightingSlotId) && pass.PixelShaderUsesSlot(HairMasterNode.LightingSlotId))
            {
                activeFields.Add("BackLightingGI");
            }

            return(activeFields);
        }
        private static HashSet <string> GetActiveFieldsFromMasterNode(AbstractMaterialNode iMasterNode, Pass pass)
        {
            HashSet <string> activeFields = new HashSet <string>();

            UnlitMasterNode masterNode = iMasterNode as UnlitMasterNode;

            if (masterNode == null)
            {
                return(activeFields);
            }

            if (masterNode.IsSlotConnected(UnlitMasterNode.AlphaThresholdSlotId) ||
                masterNode.GetInputSlots <Vector1MaterialSlot>().First(x => x.id == UnlitMasterNode.AlphaThresholdSlotId).value > 0.0f)
            {
                activeFields.Add("AlphaTest");
            }

            // Keywords for transparent
            // #pragma shader_feature _SURFACE_TYPE_TRANSPARENT
            if (masterNode.surfaceType != SurfaceType.Opaque)
            {
                // transparent-only defines
                activeFields.Add("SurfaceType.Transparent");

                // #pragma shader_feature _ _BLENDMODE_ALPHA _BLENDMODE_ADD _BLENDMODE_PRE_MULTIPLY
                if (masterNode.alphaMode == AlphaMode.Alpha)
                {
                    activeFields.Add("BlendMode.Alpha");
                }
                else if (masterNode.alphaMode == AlphaMode.Additive)
                {
                    activeFields.Add("BlendMode.Add");
                }
            }
            else
            {
                // opaque-only defines
            }

            return(activeFields);
        }
        private static HashSet <string> GetActiveFieldsFromMasterNode(INode iMasterNode, Pass pass)
        {
            HashSet <string> activeFields = new HashSet <string>();

            HDLitMasterNode masterNode = iMasterNode as HDLitMasterNode;

            if (masterNode == null)
            {
                return(activeFields);
            }

            if (masterNode.doubleSidedMode != DoubleSidedMode.Disabled)
            {
                activeFields.Add("DoubleSided");
                if (pass.ShaderPassName != "SHADERPASS_VELOCITY")   // HACK to get around lack of a good interpolator dependency system
                {                                                   // we need to be able to build interpolators using multiple input structs
                                                                    // also: should only require isFrontFace if Normals are required...
                    if (masterNode.doubleSidedMode == DoubleSidedMode.FlippedNormals)
                    {
                        activeFields.Add("DoubleSided.Flip");
                    }
                    else if (masterNode.doubleSidedMode == DoubleSidedMode.MirroredNormals)
                    {
                        activeFields.Add("DoubleSided.Mirror");
                    }

                    activeFields.Add("FragInputs.isFrontFace");     // will need this for determining normal flip mode
                }
            }

            switch (masterNode.materialType)
            {
            case HDLitMasterNode.MaterialType.Anisotropy:
                activeFields.Add("Material.Anisotropy");
                break;

            case HDLitMasterNode.MaterialType.Iridescence:
                activeFields.Add("Material.Iridescence");
                break;

            case HDLitMasterNode.MaterialType.SpecularColor:
                activeFields.Add("Material.SpecularColor");
                break;

            case HDLitMasterNode.MaterialType.Standard:
                activeFields.Add("Material.Standard");
                break;

            case HDLitMasterNode.MaterialType.SubsurfaceScattering:
            {
                activeFields.Add("Material.SubsurfaceScattering");
                if (masterNode.sssTransmission.isOn)
                {
                    activeFields.Add("Material.Transmission");
                }
            }
            break;

            case HDLitMasterNode.MaterialType.Translucent:
            {
                activeFields.Add("Material.Translucent");
                activeFields.Add("Material.Transmission");
            }
            break;

            default:
                UnityEngine.Debug.LogError("Unknown material type: " + masterNode.materialType);
                break;
            }

            if (masterNode.alphaTest.isOn)
            {
                int count = 0;
                if (pass.PixelShaderUsesSlot(HDLitMasterNode.AlphaThresholdSlotId))
                {
                    activeFields.Add("AlphaTest");
                    ++count;
                }
                if (pass.PixelShaderUsesSlot(HDLitMasterNode.AlphaThresholdDepthPrepassSlotId))
                {
                    activeFields.Add("AlphaTestPrepass");
                    ++count;
                }
                if (pass.PixelShaderUsesSlot(HDLitMasterNode.AlphaThresholdDepthPostpassSlotId))
                {
                    activeFields.Add("AlphaTestPostpass");
                    ++count;
                }
                UnityEngine.Debug.Assert(count == 1, "Alpha test value not set correctly");
            }

            if (masterNode.surfaceType != SurfaceType.Opaque)
            {
                activeFields.Add("SurfaceType.Transparent");

                if (masterNode.alphaMode == AlphaMode.Alpha)
                {
                    activeFields.Add("BlendMode.Alpha");
                }
                else if (masterNode.alphaMode == AlphaMode.Premultiply)
                {
                    activeFields.Add("BlendMode.Premultiply");
                }
                else if (masterNode.alphaMode == AlphaMode.Additive)
                {
                    activeFields.Add("BlendMode.Add");
                }

                if (masterNode.blendPreserveSpecular.isOn)
                {
                    activeFields.Add("BlendMode.PreserveSpecular");
                }

                if (masterNode.transparencyFog.isOn)
                {
                    activeFields.Add("AlphaFog");
                }
            }

            if (masterNode.receiveDecals.isOn)
            {
                activeFields.Add("Decals");
            }

            if (!masterNode.receiveSSR.isOn)
            {
                activeFields.Add("DisableSSR");
            }


            if (masterNode.specularAA.isOn && pass.PixelShaderUsesSlot(HDLitMasterNode.SpecularAAThresholdSlotId) && pass.PixelShaderUsesSlot(HDLitMasterNode.SpecularAAScreenSpaceVarianceSlotId))
            {
                activeFields.Add("Specular.AA");
            }

            if (masterNode.energyConservingSpecular.isOn)
            {
                activeFields.Add("Specular.EnergyConserving");
            }

            if (masterNode.HasRefraction())
            {
                activeFields.Add("Refraction");
                switch (masterNode.refractionModel)
                {
                case ScreenSpaceRefraction.RefractionModel.Box:
                    activeFields.Add("RefractionBox");
                    break;

                case ScreenSpaceRefraction.RefractionModel.Sphere:
                    activeFields.Add("RefractionSphere");
                    break;

                default:
                    UnityEngine.Debug.LogError("Unknown refraction model: " + masterNode.refractionModel);
                    break;
                }
            }

            if (masterNode.IsSlotConnected(HDLitMasterNode.BentNormalSlotId) && pass.PixelShaderUsesSlot(HDLitMasterNode.BentNormalSlotId))
            {
                activeFields.Add("BentNormal");
            }

            if (masterNode.IsSlotConnected(HDLitMasterNode.TangentSlotId) && pass.PixelShaderUsesSlot(HDLitMasterNode.TangentSlotId))
            {
                activeFields.Add("Tangent");
            }

            switch (masterNode.specularOcclusionMode)
            {
            case SpecularOcclusionMode.Off:
                break;

            case SpecularOcclusionMode.FromAO:
                activeFields.Add("SpecularOcclusionFromAO");
                break;

            case SpecularOcclusionMode.FromAOAndBentNormal:
                activeFields.Add("SpecularOcclusionFromAOBentNormal");
                break;

            case SpecularOcclusionMode.Custom:
                activeFields.Add("SpecularOcclusionCustom");
                break;

            default:
                break;
            }

            if (pass.PixelShaderUsesSlot(HDLitMasterNode.AmbientOcclusionSlotId))
            {
                var occlusionSlot = masterNode.FindSlot <Vector1MaterialSlot>(HDLitMasterNode.AmbientOcclusionSlotId);

                bool connected = masterNode.IsSlotConnected(HDLitMasterNode.AmbientOcclusionSlotId);
                if (connected || occlusionSlot.value != occlusionSlot.defaultValue)
                {
                    activeFields.Add("AmbientOcclusion");
                }
            }

            if (pass.PixelShaderUsesSlot(HDLitMasterNode.CoatMaskSlotId))
            {
                var coatMaskSlot = masterNode.FindSlot <Vector1MaterialSlot>(HDLitMasterNode.CoatMaskSlotId);

                bool connected = masterNode.IsSlotConnected(HDLitMasterNode.CoatMaskSlotId);
                if (connected || coatMaskSlot.value > 0.0f)
                {
                    activeFields.Add("CoatMask");
                }
            }

            return(activeFields);
        }
예제 #5
0
        private static HashSet <string> GetActiveFieldsFromMasterNode(INode iMasterNode, Pass pass)
        {
            HashSet <string> activeFields = new HashSet <string>();

            PBRMasterNode masterNode = iMasterNode as PBRMasterNode;

            if (masterNode == null)
            {
                return(activeFields);
            }

            if (masterNode.twoSided.isOn)
            {
                activeFields.Add("DoubleSided");
                if (pass.ShaderPassName != "SHADERPASS_VELOCITY")   // HACK to get around lack of a good interpolator dependency system
                {                                                   // we need to be able to build interpolators using multiple input structs
                                                                    // also: should only require isFrontFace if Normals are required...
                    activeFields.Add("DoubleSided.Mirror");         // TODO: change this depending on what kind of normal flip you want..
                    activeFields.Add("FragInputs.isFrontFace");     // will need this for determining normal flip mode
                }
            }

            switch (masterNode.model)
            {
            case PBRMasterNode.Model.Metallic:
                break;

            case PBRMasterNode.Model.Specular:
                activeFields.Add("Material.SpecularColor");
                break;

            default:
                // TODO: error!
                break;
            }

            if (masterNode.IsSlotConnected(PBRMasterNode.AlphaThresholdSlotId) ||
                masterNode.GetInputSlots <Vector1MaterialSlot>().First(x => x.id == PBRMasterNode.AlphaThresholdSlotId).value > 0.0f)
            {
                activeFields.Add("AlphaTest");
            }

            // Keywords for transparent
            // #pragma shader_feature _SURFACE_TYPE_TRANSPARENT
            if (masterNode.surfaceType != SurfaceType.Opaque)
            {
                // transparent-only defines
                activeFields.Add("SurfaceType.Transparent");

                // #pragma shader_feature _ _BLENDMODE_ALPHA _BLENDMODE_ADD _BLENDMODE_PRE_MULTIPLY
                if (masterNode.alphaMode == AlphaMode.Alpha)
                {
                    activeFields.Add("BlendMode.Alpha");
                }
                else if (masterNode.alphaMode == AlphaMode.Additive)
                {
                    activeFields.Add("BlendMode.Add");
                }
//                else if (masterNode.alphaMode == PBRMasterNode.AlphaMode.PremultiplyAlpha)            // TODO
//                {
//                    defines.AddShaderChunk("#define _BLENDMODE_PRE_MULTIPLY 1", true);
//                }
            }
            else
            {
                // opaque-only defines
            }

            // enable dithering LOD crossfade
            // #pragma multi_compile _ LOD_FADE_CROSSFADE
            // TODO: We should have this keyword only if VelocityInGBuffer is enable, how to do that ?
            //#pragma multi_compile VELOCITYOUTPUT_OFF VELOCITYOUTPUT_ON

            return(activeFields);
        }
예제 #6
0
        //
        // Reference for GetActiveFieldsFromMasterNode
        // -------------------------------------------
        //
        // Properties (enables etc):
        //
        //  ok+MFD -> material feature define: means we need a predicate, because we will transform it into a #define that match the material feature, shader_feature-defined, that the rest of the shader code uses.
        //
        //  ok+MFD masterNode.baseParametrization    --> even though we can just always transfer present fields (check with $SurfaceDescription.*) like specularcolor and metallic,
        //                                               we need to translate this into the _MATERIAL_FEATURE_SPECULAR_COLOR define.
        //
        //  ok masterNode.energyConservingSpecular
        //
        //  ~~~~ ok+MFD: these are almost all material features:
        //  masterNode.anisotropy
        //  masterNode.coat
        //  masterNode.coatNormal
        //  masterNode.dualSpecularLobe
        //  masterNode.dualSpecularLobeParametrization
        //  masterNode.capHazinessWrtMetallic           -> not a material feature define, as such, we will create a combined predicate for the HazyGlossMaxDielectricF0 slot dependency
        //                                                 instead of adding a #define in the template...
        //  masterNode.iridescence
        //  masterNode.subsurfaceScattering
        //  masterNode.transmission
        //
        //  ~~~~ ...ok+MFD: these are all material features
        //
        //  ok masterNode.receiveDecals
        //  ok masterNode.receiveSSR
        //  ok masterNode.geometricSpecularAA    --> check, a way to combine predicates and/or exclude passes: TODOTODO What about WRITE_NORMAL_BUFFER passes ? (ie smoothness)
        //  ok masterNode.specularOcclusion      --> no use for it though! see comments.
        //
        //  ~~~~ ok+D: these require translation to defines also...
        //
        //  masterNode.anisotropyForAreaLights
        //  masterNode.recomputeStackPerLight
        //  masterNode.shadeBaseUsingRefractedAngles
        //  masterNode.debug

        // Inputs: Most inputs don't need a specific predicate in addition to the "present field predicate", ie the $SurfaceDescription.*,
        //         but in some special cases we check connectivity to avoid processing the default value for nothing...
        //         (see specular occlusion with _MASKMAP and _BENTNORMALMAP in LitData, or _TANGENTMAP, _BENTNORMALMAP, etc. which act a bit like that
        //         although they also avoid sampling in that case, but default tiny texture map sampling isn't a big hit since they are all cached once
        //         a default "unityTexWhite" is sampled, it is cached for everyone defaulting to white...)
        //
        // ok+ means there's a specific additional predicate
        //
        // ok masterNode.BaseColorSlotId
        // ok masterNode.NormalSlotId
        //
        // ok+ masterNode.BentNormalSlotId     --> Dependency of the predicate on IsSlotConnected avoids processing even if the slots
        // ok+ masterNode.TangentSlotId            are always there so any pass that declares its use in PixelShaderSlots will have the field in SurfaceDescription,
        //                                         but it's not necessarily useful (if slot isnt connected, waste processing on potentially static expressions if
        //                                         shader compiler cant optimize...and even then, useless to have static override value for those.)
        //
        //                                         TODOTODO: Note you could have the same argument for NormalSlot (which we dont exclude with a predicate).
        //                                         Also and anyways, the compiler is smart enough not to do the TS to WS matrix multiply on a (0,0,1) vector.
        //
        // ok+ masterNode.CoatNormalSlotId       -> we already have a "material feature" coat normal map so can use that instead, although using that former, we assume the coat normal slot
        //                                         will be there, but it's ok, we can #ifdef the code on the material feature define, and use the $SurfaceDescription.CoatNormal predicate
        //                                         for the actual assignment,
        //                                         although for that one we could again
        //                                         use the "connected" condition like for tangent and bentnormal
        //
        // The following are all ok, no need beyond present field predicate, ie $SurfaceDescription.*,
        // except special cases where noted
        //
        // ok masterNode.SubsurfaceMaskSlotId
        // ok masterNode.ThicknessSlotId
        // ok masterNode.DiffusionProfileSlotId
        // ok masterNode.IridescenceMaskSlotId
        // ok masterNode.IridescenceThicknessSlotId
        // ok masterNode.SpecularColorSlotId
        // ok masterNode.DielectricIorSlotId
        // ok masterNode.MetallicSlotId
        // ok masterNode.EmissionSlotId
        // ok masterNode.SmoothnessASlotId
        // ok masterNode.SmoothnessBSlotId
        // ok+ masterNode.AmbientOcclusionSlotId    -> defined a specific predicate, but not used, see StackLitData.
        // ok masterNode.AlphaSlotId
        // ok masterNode.AlphaClipThresholdSlotId
        // ok masterNode.AnisotropyASlotId
        // ok masterNode.AnisotropyBSlotId
        // ok masterNode.SpecularAAScreenSpaceVarianceSlotId
        // ok masterNode.SpecularAAThresholdSlotId
        // ok masterNode.CoatSmoothnessSlotId
        // ok masterNode.CoatIorSlotId
        // ok masterNode.CoatThicknessSlotId
        // ok masterNode.CoatExtinctionSlotId
        // ok masterNode.LobeMixSlotId
        // ok masterNode.HazinessSlotId
        // ok masterNode.HazeExtentSlotId
        // ok masterNode.HazyGlossMaxDielectricF0SlotId     -> No need for a predicate, the needed predicate is the combined (capHazinessWrtMetallic + HazyGlossMaxDielectricF0)
        //                                                     "leaking case": if the 2 are true, but we're not in metallic mode, the capHazinessWrtMetallic property is wrong,
        //                                                     that means the master node is really misconfigured, spew an error, should never happen...
        //                                                     If it happens, it's because we forgot UpdateNodeAfterDeserialization() call when modifying the capHazinessWrtMetallic or baseParametrization
        //                                                     properties, maybe through debug etc.
        //
        // ok masterNode.DistortionSlotId            -> Warning: peculiarly, instead of using $SurfaceDescription.Distortion and DistortionBlur,
        // ok masterNode.DistortionBlurSlotId           we do an #if (SHADERPASS == SHADERPASS_DISTORTION) in the template, instead of
        //                                              relying on other passed NOT to include the DistortionSlotId in their PixelShaderSlots!!

        // Other to deal with, and
        // Common between Lit and StackLit:
        //
        // doubleSidedMode, alphaTest, receiveDecals,
        // surfaceType, alphaMode, blendPreserveSpecular, transparencyFog,
        // distortion, distortionMode, distortionDepthTest,
        // sortPriority (int)
        // geometricSpecularAA, energyConservingSpecular, specularOcclusion
        //

        private static HashSet <string> GetActiveFieldsFromMasterNode(INode iMasterNode, Pass pass)
        {
            HashSet <string> activeFields = new HashSet <string>();

            StackLitMasterNode masterNode = iMasterNode as StackLitMasterNode;

            if (masterNode == null)
            {
                return(activeFields);
            }

            if (masterNode.doubleSidedMode != DoubleSidedMode.Disabled)
            {
                activeFields.Add("DoubleSided");
                if (pass.ShaderPassName != "SHADERPASS_VELOCITY")   // HACK to get around lack of a good interpolator dependency system
                {                                                   // we need to be able to build interpolators using multiple input structs
                                                                    // also: should only require isFrontFace if Normals are required...
                    if (masterNode.doubleSidedMode == DoubleSidedMode.FlippedNormals)
                    {
                        activeFields.Add("DoubleSided.Flip");
                    }
                    else if (masterNode.doubleSidedMode == DoubleSidedMode.MirroredNormals)
                    {
                        activeFields.Add("DoubleSided.Mirror");
                    }
                    // Important: the following is used in SharedCode.template.hlsl for determining the normal flip mode
                    activeFields.Add("FragInputs.isFrontFace");
                }
            }

            if (masterNode.alphaTest.isOn)
            {
                if (pass.PixelShaderUsesSlot(StackLitMasterNode.AlphaClipThresholdSlotId))
                {
                    activeFields.Add("AlphaTest");
                }
            }

            if (masterNode.surfaceType != SurfaceType.Opaque)
            {
                activeFields.Add("SurfaceType.Transparent");

                if (masterNode.alphaMode == AlphaMode.Alpha)
                {
                    activeFields.Add("BlendMode.Alpha");
                }
                else if (masterNode.alphaMode == AlphaMode.Premultiply)
                {
                    activeFields.Add("BlendMode.Premultiply");
                }
                else if (masterNode.alphaMode == AlphaMode.Additive)
                {
                    activeFields.Add("BlendMode.Add");
                }

                if (masterNode.blendPreserveSpecular.isOn)
                {
                    activeFields.Add("BlendMode.PreserveSpecular");
                }

                if (masterNode.transparencyFog.isOn)
                {
                    activeFields.Add("AlphaFog");
                }
            }

            //
            // Predicates to change into defines:
            //

            // Even though we can just always transfer the present (check with $SurfaceDescription.*) fields like specularcolor
            // and metallic, we still need to know the baseParametrization in the template to translate into the
            // _MATERIAL_FEATURE_SPECULAR_COLOR define:
            if (masterNode.baseParametrization == StackLit.BaseParametrization.SpecularColor)
            {
                activeFields.Add("BaseParametrization.SpecularColor");
            }
            if (masterNode.energyConservingSpecular.isOn) // No defines, suboption of BaseParametrization.SpecularColor
            {
                activeFields.Add("EnergyConservingSpecular");
            }
            if (masterNode.anisotropy.isOn)
            {
                activeFields.Add("Material.Anisotropy");
            }
            if (masterNode.coat.isOn)
            {
                activeFields.Add("Material.Coat");
            }
            if (masterNode.coatNormal.isOn)
            {
                activeFields.Add("Material.CoatNormal");
            }
            if (masterNode.dualSpecularLobe.isOn)
            {
                activeFields.Add("Material.DualSpecularLobe");
                if (masterNode.dualSpecularLobeParametrization == StackLit.DualSpecularLobeParametrization.HazyGloss)
                {
                    activeFields.Add("DualSpecularLobeParametrization.HazyGloss");
                    // Option for baseParametrization == Metallic && DualSpecularLobeParametrization == HazyGloss:
                    if (masterNode.capHazinessWrtMetallic.isOn)
                    {
                        // assert metallic, but masternode should deal with having a consistent
                        // property config with UpdateNodeAfterDeserialization() etc.
                        if (pass.PixelShaderUsesSlot(StackLitMasterNode.HazyGlossMaxDielectricF0SlotId))
                        {
                            // Again we assume masternode has HazyGlossMaxDielectricF0 which should always be the case
                            // if capHazinessWrtMetallic.isOn.
                            activeFields.Add("CapHazinessIfNotMetallic");
                        }
                    }
                }
            }
            if (masterNode.iridescence.isOn)
            {
                activeFields.Add("Material.Iridescence");
            }
            if (masterNode.subsurfaceScattering.isOn && masterNode.surfaceType != SurfaceType.Transparent)
            {
                activeFields.Add("Material.SubsurfaceScattering");
            }
            if (masterNode.transmission.isOn)
            {
                activeFields.Add("Material.Transmission");
            }

            // Advanced:
            if (masterNode.anisotropyForAreaLights.isOn)
            {
                activeFields.Add("AnisotropyForAreaLights");
            }
            if (masterNode.recomputeStackPerLight.isOn)
            {
                activeFields.Add("RecomputeStackPerLight");
            }
            if (masterNode.shadeBaseUsingRefractedAngles.isOn)
            {
                activeFields.Add("ShadeBaseUsingRefractedAngles");
            }
            if (masterNode.debug.isOn)
            {
                activeFields.Add("StackLitDebug");
            }

            //
            // Other property predicates:
            //

            if (!masterNode.receiveDecals.isOn)
            {
                activeFields.Add("DisableDecals");
            }

            if (!masterNode.receiveSSR.isOn)
            {
                activeFields.Add("DisableSSR");
            }

            // Note here we combine an "enable"-like predicate and the $SurfaceDescription.(slotname) predicate
            // into a single $GeometricSpecularAA pedicate.
            //
            // ($SurfaceDescription.* predicates are useful to make sure the field is present in the struct in the template.
            // The field will be present if both the master node and pass have the slotid, see this set intersection we make
            // in GenerateSurfaceDescriptionStruct(), with HDSubShaderUtilities.FindMaterialSlotsOnNode().)
            //
            // Normally, since the feature enable adds the required slots, only the $SurfaceDescription.* would be required,
            // but some passes might not need it and not declare the PixelShaderSlot, or, inversely, the pass might not
            // declare it as a way to avoid it.
            //
            // IE this has also the side effect to disable geometricSpecularAA - even if "on" - for passes that don't explicitly
            // advertise these slots(eg for a general feature, with separate "enable" and "field present" predicates, the
            // template could take a default value and process it anyway if a feature is "on").
            //
            // (Note we can achieve the same results in the template on just single predicates by making defines out of them,
            // and using #if defined() && etc)
            bool haveSomeSpecularAA = false; // TODOTODO in prevision of normal texture filtering

            if (masterNode.geometricSpecularAA.isOn &&
                pass.PixelShaderUsesSlot(StackLitMasterNode.SpecularAAThresholdSlotId) &&
                pass.PixelShaderUsesSlot(StackLitMasterNode.SpecularAAScreenSpaceVarianceSlotId))
            {
                haveSomeSpecularAA = true;
                activeFields.Add("GeometricSpecularAA");
            }
            if (haveSomeSpecularAA)
            {
                activeFields.Add("SpecularAA");
            }

            if (masterNode.specularOcclusion.isOn)
            {
                // We don't optimize based eg on baked ambient occlusion missing a texture, this makes this baked, data-based
                // SpecularOcclusion a waste (non baked, SSAO-based SpecularOcclusion is always applied with the TriACE trick),
                // but the user should know better.
                // TODOTODO: rename the UI to "baked specular occlusion" and "baked AO" ?
                activeFields.Add("SpecularOcclusion");
            }

            //
            // Input special-casing predicates:
            //

            if (masterNode.IsSlotConnected(StackLitMasterNode.BentNormalSlotId) && pass.PixelShaderUsesSlot(StackLitMasterNode.BentNormalSlotId))
            {
                activeFields.Add("BentNormal");
            }

            if (masterNode.IsSlotConnected(StackLitMasterNode.TangentSlotId) && pass.PixelShaderUsesSlot(StackLitMasterNode.TangentSlotId))
            {
                activeFields.Add("Tangent");
            }

            // The following idiom enables an optimization on feature ports that don't have an enable switch in the settings
            // view, where the default value might not produce a visual result and incur a processing cost we want to avoid.
            // For ambient occlusion, this is the case for the SpecularOcclusion calculations which also depend on it,
            // where a value of 1 will produce no results.
            // See SpecularOcclusion, we don't optimize out this case...
            if (pass.PixelShaderUsesSlot(StackLitMasterNode.AmbientOcclusionSlotId))
            {
                bool connected            = masterNode.IsSlotConnected(StackLitMasterNode.AmbientOcclusionSlotId);
                var  ambientOcclusionSlot = masterNode.FindSlot <Vector1MaterialSlot>(StackLitMasterNode.AmbientOcclusionSlotId);
                // master node always has it, assert ambientOcclusionSlot != null
                if (connected || ambientOcclusionSlot.value != ambientOcclusionSlot.defaultValue)
                {
                    activeFields.Add("AmbientOcclusion");
                }
            }

            if (masterNode.IsSlotConnected(StackLitMasterNode.CoatNormalSlotId) && pass.PixelShaderUsesSlot(StackLitMasterNode.CoatNormalSlotId))
            {
                activeFields.Add("CoatNormal");
            }

            return(activeFields);
        }
예제 #7
0
        private static HashSet <string> GetActiveFieldsFromMasterNode(AbstractMaterialNode iMasterNode, Pass pass)
        {
            HashSet <string> activeFields = new HashSet <string>();

            HDUnlitMasterNode masterNode = iMasterNode as HDUnlitMasterNode;

            if (masterNode == null)
            {
                return(activeFields);
            }

            if (masterNode.alphaTest.isOn && pass.PixelShaderUsesSlot(HDUnlitMasterNode.AlphaThresholdSlotId))
            {
                activeFields.Add("AlphaTest");
            }

            if (masterNode.surfaceType != SurfaceType.Opaque)
            {
                activeFields.Add("SurfaceType.Transparent");

                if (masterNode.alphaMode == AlphaMode.Alpha)
                {
                    activeFields.Add("BlendMode.Alpha");
                }
                else if (masterNode.alphaMode == AlphaMode.Premultiply)
                {
                    activeFields.Add("BlendMode.Premultiply");
                }
                else if (masterNode.alphaMode == AlphaMode.Additive)
                {
                    activeFields.Add("BlendMode.Add");
                }

                if (masterNode.transparencyFog.isOn)
                {
                    activeFields.Add("AlphaFog");
                }
            }

            return(activeFields);
        }
예제 #8
0
        private static bool GenerateShaderPass(PBRMasterNode masterNode, Pass pass, GenerationMode mode, SurfaceMaterialOptions materialOptions, ShaderGenerator result)
        {
            var templateLocation = Path.Combine(Path.Combine(Path.Combine(HDEditorUtils.GetHDRenderPipelinePath(), "Editor"), "ShaderGraph"), pass.TemplateName);

            if (!File.Exists(templateLocation))
            {
                // TODO: produce error here
                return(false);
            }

            // grab all of the active nodes
            var activeNodeList = ListPool <INode> .Get();

            NodeUtils.DepthFirstCollectNodesFromNode(activeNodeList, masterNode, NodeUtils.IncludeSelf.Include, pass.PixelShaderSlots);

            // graph requirements describe what the graph itself requires
            var graphRequirements = ShaderGraphRequirements.FromNodes(activeNodeList, ShaderStageCapability.Fragment);

            ShaderStringBuilder graphNodeFunctions = new ShaderStringBuilder();

            graphNodeFunctions.IncreaseIndent();
            var functionRegistry = new FunctionRegistry(graphNodeFunctions);

            // Build the list of active slots based on what the pass requires
            // TODO: this can be a shared function -- From here through GraphUtil.GenerateSurfaceDescription(..)
            var activeSlots = new List <MaterialSlot>();

            foreach (var id in pass.PixelShaderSlots)
            {
                MaterialSlot slot = masterNode.FindSlot <MaterialSlot>(id);
                if (slot != null)
                {
                    activeSlots.Add(slot);
                }
            }

            // build the graph outputs structure to hold the results of each active slots (and fill out activeFields to indicate they are active)
            string graphInputStructName           = "SurfaceDescriptionInputs";
            string graphOutputStructName          = "SurfaceDescription";
            string graphEvalFunctionName          = "SurfaceDescriptionFunction";
            ShaderStringBuilder graphEvalFunction = new ShaderStringBuilder();
            ShaderStringBuilder graphOutputs      = new ShaderStringBuilder();
            PropertyCollector   graphProperties   = new PropertyCollector();

            // build the graph outputs structure, and populate activeFields with the fields of that structure
            HashSet <string> activeFields = new HashSet <string>();

            GraphUtil.GenerateSurfaceDescriptionStruct(graphOutputs, activeSlots, true);
            //GraphUtil.GenerateSurfaceDescriptionStruct(graphOutputs, activeSlots, true, graphOutputStructName, activeFields);

            // Build the graph evaluation code, to evaluate the specified slots
            GraphUtil.GenerateSurfaceDescriptionFunction(
                activeNodeList,
                masterNode,
                masterNode.owner as AbstractMaterialGraph,
                graphEvalFunction,
                functionRegistry,
                graphProperties,
                graphRequirements,  // TODO : REMOVE UNUSED
                mode,
                graphEvalFunctionName,
                graphOutputStructName,
                null,
                activeSlots,
                graphInputStructName);

            var blendCode     = new ShaderStringBuilder();
            var cullCode      = new ShaderStringBuilder();
            var zTestCode     = new ShaderStringBuilder();
            var zWriteCode    = new ShaderStringBuilder();
            var stencilCode   = new ShaderStringBuilder();
            var colorMaskCode = new ShaderStringBuilder();

            HDSubShaderUtilities.BuildRenderStatesFromPassAndMaterialOptions(pass, materialOptions, blendCode, cullCode, zTestCode, zWriteCode, stencilCode, colorMaskCode);

            if (masterNode.twoSided.isOn)
            {
                activeFields.Add("DoubleSided");
                if (pass.ShaderPassName != "SHADERPASS_VELOCITY")   // HACK to get around lack of a good interpolator dependency system
                {                                                   // we need to be able to build interpolators using multiple input structs
                                                                    // also: should only require isFrontFace if Normals are required...
                    activeFields.Add("DoubleSided.Mirror");         // TODO: change this depending on what kind of normal flip you want..
                    activeFields.Add("FragInputs.isFrontFace");     // will need this for determining normal flip mode
                }
            }

            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);
                    }
                }
            }

            var packedInterpolatorCode = new ShaderGenerator();
            var graphInputs            = new ShaderGenerator();

            HDRPShaderStructs.Generate(
                packedInterpolatorCode,
                graphInputs,
                graphRequirements,
                pass.RequiredFields,
                CoordinateSpace.World,
                activeFields);

            // debug output all active fields
            var interpolatorDefines = new ShaderGenerator();
            {
                interpolatorDefines.AddShaderChunk("// ACTIVE FIELDS:");
                foreach (string f in activeFields)
                {
                    interpolatorDefines.AddShaderChunk("//   " + f);
                }
            }

            ShaderGenerator defines = new ShaderGenerator();
            {
                defines.AddShaderChunk(string.Format("#define SHADERPASS {0}", pass.ShaderPassName), true);
                if (pass.ExtraDefines != null)
                {
                    foreach (var define in pass.ExtraDefines)
                    {
                        defines.AddShaderChunk(define);
                    }
                }
                defines.AddGenerator(interpolatorDefines);
            }

            var shaderPassIncludes = new ShaderGenerator();

            if (pass.Includes != null)
            {
                foreach (var include in pass.Includes)
                {
                    shaderPassIncludes.AddShaderChunk(include);
                }
            }


            // 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();

            // build the hash table of all named fragments      TODO: could make this Dictionary<string, ShaderGenerator / string>  ?
            Dictionary <string, string> namedFragments = new Dictionary <string, string>();

            namedFragments.Add("${Defines}", defines.GetShaderString(2, false));
            namedFragments.Add("${Graph}", graph.GetShaderString(2, false));
            namedFragments.Add("${LightMode}", pass.LightMode);
            namedFragments.Add("${PassName}", pass.Name);
            namedFragments.Add("${Includes}", shaderPassIncludes.GetShaderString(2, false));
            namedFragments.Add("${InterpolatorPacking}", packedInterpolatorCode.GetShaderString(2, false));
            namedFragments.Add("${Blending}", blendCode.ToString());
            namedFragments.Add("${Culling}", cullCode.ToString());
            namedFragments.Add("${ZTest}", zTestCode.ToString());
            namedFragments.Add("${ZWrite}", zWriteCode.ToString());
            namedFragments.Add("${Stencil}", stencilCode.ToString());
            namedFragments.Add("${ColorMask}", colorMaskCode.ToString());
            namedFragments.Add("${LOD}", materialOptions.lod.ToString());
            namedFragments.Add("${VariantDefines}", GetVariantDefines(masterNode));

            // process the template to generate the shader code for this pass   TODO: could make this a shared function
            string[] templateLines            = File.ReadAllLines(templateLocation);
            System.Text.StringBuilder builder = new System.Text.StringBuilder();
            foreach (string line in templateLines)
            {
                ShaderSpliceUtil.PreprocessShaderCode(line, activeFields, namedFragments, builder);
                builder.AppendLine();
            }

            result.AddShaderChunk(builder.ToString(), false);

            return(true);
        }
예제 #9
0
 private static void AddPixelShaderSlotsForWriteNormalBufferPasses(StackLitMasterNode masterNode, ref Pass pass)
 {
     // See StackLit.hlsl:ConvertSurfaceDataToNormalData()
     // Note: We remove the slots we're adding as the editor will constantly regenerate the shader but
     // without recreating the nodes thus the passes in the subshader object.
     if (masterNode.coat.isOn)
     {
         // Check ConvertSurfaceDataToNormalData, in this case, we only need those:
         pass.PixelShaderSlots.Remove(StackLitMasterNode.CoatSmoothnessSlotId);
         pass.PixelShaderSlots.Add(StackLitMasterNode.CoatSmoothnessSlotId);
         pass.PixelShaderSlots.Remove(StackLitMasterNode.CoatNormalSlotId);
         pass.PixelShaderSlots.Add(StackLitMasterNode.CoatNormalSlotId);
     }
     else
     {
         pass.PixelShaderSlots.Remove(StackLitMasterNode.NormalSlotId);
         pass.PixelShaderSlots.Add(StackLitMasterNode.NormalSlotId);
         pass.PixelShaderSlots.Remove(StackLitMasterNode.LobeMixSlotId);
         pass.PixelShaderSlots.Add(StackLitMasterNode.LobeMixSlotId);
         pass.PixelShaderSlots.Remove(StackLitMasterNode.SmoothnessASlotId);
         pass.PixelShaderSlots.Add(StackLitMasterNode.SmoothnessASlotId);
         pass.PixelShaderSlots.Remove(StackLitMasterNode.SmoothnessBSlotId);
         pass.PixelShaderSlots.Add(StackLitMasterNode.SmoothnessBSlotId);
     }
     // Also, when geometricSpecularAA.isOn, might want to add SpecularAAScreenSpaceVarianceSlotId and SpecularAAThresholdSlotId,
     // since they affect smoothnesses in surfaceData directly. This is an implicit behavior for Lit, via the GBuffer pass.
     // Versus performance, might not be important for what it is used for, but SSR uses the roughness too so for now,
     // add them.
     if (masterNode.geometricSpecularAA.isOn) // TODOTODO || Normal Map Filtering is on
     {
         pass.PixelShaderSlots.Remove(StackLitMasterNode.SpecularAAScreenSpaceVarianceSlotId);
         pass.PixelShaderSlots.Add(StackLitMasterNode.SpecularAAScreenSpaceVarianceSlotId);
         pass.PixelShaderSlots.Remove(StackLitMasterNode.SpecularAAThresholdSlotId);
         pass.PixelShaderSlots.Add(StackLitMasterNode.SpecularAAThresholdSlotId);
     }
 }
        private static bool GenerateShaderPassLit(AbstractMaterialNode masterNode, Pass pass, GenerationMode mode, SurfaceMaterialOptions materialOptions, ShaderGenerator result, List <string> sourceAssetDependencyPaths)
        {
            var templateLocation = Path.Combine(Path.Combine(Path.Combine(HDEditorUtils.GetHDRenderPipelinePath(), "Editor"), "ShaderGraph"), pass.TemplateName);

            if (!File.Exists(templateLocation))
            {
                // TODO: produce error here
                return(false);
            }

            if (sourceAssetDependencyPaths != null)
            {
                sourceAssetDependencyPaths.Add(templateLocation);
            }

            // grab all of the active nodes (for pixel and vertex graphs)
            var vertexNodes = ListPool <INode> .Get();

            NodeUtils.DepthFirstCollectNodesFromNode(vertexNodes, masterNode, NodeUtils.IncludeSelf.Include, pass.VertexShaderSlots);

            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
            ShaderStringBuilder graphNodeFunctions = new ShaderStringBuilder();

            graphNodeFunctions.IncreaseIndent();
            var functionRegistry = new FunctionRegistry(graphNodeFunctions);

            // TODO: this can be a shared function for all HDRP master nodes -- From here through GraphUtil.GenerateSurfaceDescription(..)

            // Build the list of active slots based on what the pass requires
            var pixelSlots  = HDSubShaderUtilities.FindMaterialSlotsOnNode(pass.PixelShaderSlots, masterNode);
            var vertexSlots = HDSubShaderUtilities.FindMaterialSlotsOnNode(pass.VertexShaderSlots, masterNode);

            // properties used by either pixel and vertex shader
            PropertyCollector sharedProperties = new PropertyCollector();

            // build the graph outputs structure to hold the results of each active slots (and fill out activeFields to indicate they are active)
            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 = GetActiveFieldsFromMasterNode(masterNode, pass);

            // build initial requirements
            HDRPShaderStructs.AddActiveFieldsFromPixelGraphRequirements(activeFields, pixelRequirements);

            // build the graph outputs structure, and populate activeFields with the fields of that structure
            GraphUtil.GenerateSurfaceDescriptionStruct(pixelGraphOutputs, pixelSlots, true, pixelGraphOutputStructName, activeFields);

            // Build the graph evaluation code, to evaluate the specified slots
            GraphUtil.GenerateSurfaceDescriptionFunction(
                pixelNodes,
                masterNode,
                masterNode.owner as AbstractMaterialGraph,
                pixelGraphEvalFunction,
                functionRegistry,
                sharedProperties,
                pixelRequirements,  // TODO : REMOVE UNUSED
                mode,
                pixelGraphEvalFunctionName,
                pixelGraphOutputStructName,
                null,
                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();
            var zTestCode     = new ShaderStringBuilder();
            var zWriteCode    = new ShaderStringBuilder();
            var stencilCode   = new ShaderStringBuilder();
            var colorMaskCode = new ShaderStringBuilder();

            HDSubShaderUtilities.BuildRenderStatesFromPassAndMaterialOptions(pass, materialOptions, blendCode, cullCode, zTestCode, zWriteCode, stencilCode, colorMaskCode);

            HDRPShaderStructs.AddRequiredFields(pass.RequiredFields, activeFields);

            // apply dependencies to the active fields, and build interpolators (TODO: split this function)
            var packedInterpolatorCode = new ShaderGenerator();

            HDRPShaderStructs.Generate(
                packedInterpolatorCode,
                activeFields);

            // debug output all active fields
            var interpolatorDefines = new ShaderGenerator();
            {
                interpolatorDefines.AddShaderChunk("// ACTIVE FIELDS:");
                foreach (string f in activeFields)
                {
                    interpolatorDefines.AddShaderChunk("//   " + f);
                }
            }

            // 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);
                if (pass.ExtraDefines != null)
                {
                    foreach (var define in pass.ExtraDefines)
                    {
                        defines.AddShaderChunk(define);
                    }
                }
                defines.AddGenerator(interpolatorDefines);
            }

            var shaderPassIncludes = new ShaderGenerator();

            if (pass.Includes != null)
            {
                foreach (var include in pass.Includes)
                {
                    shaderPassIncludes.AddShaderChunk(include);
                }
            }


            // build graph code
            var graph = new ShaderGenerator();
            {
                graph.AddShaderChunk("// Shared Graph Properties (uniform inputs)");
                graph.AddShaderChunk(sharedProperties.GetPropertiesDeclaration(1));

                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("// 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("// Shared Graph Node Functions");
                graph.AddShaderChunk(graphNodeFunctions.ToString());

                if (vertexActive)
                {
                    graph.AddShaderChunk("// Vertex Graph Evaluation");
                    graph.Indent();
                    graph.AddShaderChunk(vertexGraphEvalFunction.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>();

            namedFragments.Add("${Defines}", defines.GetShaderString(2, false));
            namedFragments.Add("${Graph}", graph.GetShaderString(2, false));
            namedFragments.Add("${LightMode}", pass.LightMode);
            namedFragments.Add("${PassName}", pass.Name);
            namedFragments.Add("${Includes}", shaderPassIncludes.GetShaderString(2, false));
            namedFragments.Add("${InterpolatorPacking}", packedInterpolatorCode.GetShaderString(2, false));
            namedFragments.Add("${Blending}", blendCode.ToString());
            namedFragments.Add("${Culling}", cullCode.ToString());
            namedFragments.Add("${ZTest}", zTestCode.ToString());
            namedFragments.Add("${ZWrite}", zWriteCode.ToString());
            namedFragments.Add("${Stencil}", stencilCode.ToString());
            namedFragments.Add("${ColorMask}", colorMaskCode.ToString());
            namedFragments.Add("${LOD}", materialOptions.lod.ToString());

            // process the template to generate the shader code for this pass   TODO: could make this a shared function
            string[] templateLines            = File.ReadAllLines(templateLocation);
            System.Text.StringBuilder builder = new System.Text.StringBuilder();
            foreach (string line in templateLines)
            {
                ShaderSpliceUtil.PreprocessShaderCode(line, activeFields, namedFragments, builder);
                builder.AppendLine();
            }

            result.AddShaderChunk(builder.ToString(), false);

            return(true);
        }
        public static void GetBlendMode(ShaderGraph.SurfaceType surfaceType, AlphaMode alphaMode, ref Pass pass)
        {
            if (surfaceType == ShaderGraph.SurfaceType.Opaque)
            {
                pass.BlendOverride = "Blend One Zero, One Zero";
            }
            else
            {
                switch (alphaMode)
                {
                case AlphaMode.Alpha:
                    pass.BlendOverride = "Blend One OneMinusSrcAlpha, One OneMinusSrcAlpha";
                    break;

                case AlphaMode.Additive:
                    pass.BlendOverride = "Blend One One, One One";
                    break;

                case AlphaMode.Premultiply:
                    pass.BlendOverride = "Blend One OneMinusSrcAlpha, One OneMinusSrcAlpha";
                    break;

                // This isn't supported in HDRP.
                case AlphaMode.Multiply:
                default:
                    pass.BlendOverride = "Blend One OneMinusSrcAlpha, One OneMinusSrcAlpha";
                    break;
                }
            }
        }
        private static HashSet <string> GetActiveFieldsFromMasterNode(INode iMasterNode, Pass pass)
        {
            HashSet <string> activeFields = new HashSet <string>();

            PBRMasterNode masterNode = iMasterNode as PBRMasterNode;

            if (masterNode == null)
            {
                return(activeFields);
            }

            if (masterNode.twoSided.isOn)
            {
                activeFields.Add("DoubleSided");
                if (pass.ShaderPassName != "SHADERPASS_VELOCITY")   // HACK to get around lack of a good interpolator dependency system
                {                                                   // we need to be able to build interpolators using multiple input structs
                                                                    // also: should only require isFrontFace if Normals are required...
                    activeFields.Add("DoubleSided.Mirror");         // TODO: change this depending on what kind of normal flip you want..
                    activeFields.Add("FragInputs.isFrontFace");     // will need this for determining normal flip mode
                }
            }

            switch (masterNode.model)
            {
            case PBRMasterNode.Model.Metallic:
                break;

            case PBRMasterNode.Model.Specular:
                activeFields.Add("Material.SpecularColor");
                break;

            default:
                // TODO: error!
                break;
            }

            float constantAlpha = 0.0f;

            if (masterNode.IsSlotConnected(PBRMasterNode.AlphaThresholdSlotId) ||
                (float.TryParse(masterNode.GetSlotValue(PBRMasterNode.AlphaThresholdSlotId, GenerationMode.ForReals), out constantAlpha) && (constantAlpha > 0.0f)))
            {
                activeFields.Add("AlphaTest");
            }

//             if (kTesselationMode != TessellationMode.None)
//             {
//                 defines.AddShaderChunk("#define _TESSELLATION_PHONG 1", true);
//             }

            // #pragma shader_feature _ _VERTEX_DISPLACEMENT _PIXEL_DISPLACEMENT
//             switch (kDisplacementMode)
//             {
//                 case DisplacementMode.None:
//                     break;
//                 case DisplacementMode.Vertex:
//                     defines.AddShaderChunk("#define _VERTEX_DISPLACEMENT 1", true);
//                     break;
//                 case DisplacementMode.Pixel:
//                     defines.AddShaderChunk("#define _PIXEL_DISPLACEMENT 1", true);
            // Depth offset is only enabled if per pixel displacement is
//                     if (kDepthOffsetEnable)
//                     {
//                         // #pragma shader_feature _DEPTHOFFSET_ON
//                         defines.AddShaderChunk("#define _DEPTHOFFSET_ON 1", true);
//                     }
//                     break;
//                 case DisplacementMode.Tessellation:
//                     if (kTessellationEnabled)
//                     {
//                         defines.AddShaderChunk("#define _TESSELLATION_DISPLACEMENT 1", true);
//                     }
//                     break;
//             }

            // #pragma shader_feature _VERTEX_DISPLACEMENT_LOCK_OBJECT_SCALE
            // #pragma shader_feature _DISPLACEMENT_LOCK_TILING_SCALE
            // #pragma shader_feature _PIXEL_DISPLACEMENT_LOCK_OBJECT_SCALE
            // #pragma shader_feature _VERTEX_WIND
            // #pragma shader_feature _ _REFRACTION_PLANE _REFRACTION_SPHERE
            //
            // #pragma shader_feature _ _MAPPING_PLANAR _MAPPING_TRIPLANAR          // MOVE to a node
            // #pragma shader_feature _NORMALMAP_TANGENT_SPACE
            // #pragma shader_feature _ _REQUIRE_UV2 _REQUIRE_UV3

            // #pragma shader_feature _MASKMAP
            // #pragma shader_feature _BENTNORMALMAP
            // #pragma shader_feature _EMISSIVE_COLOR_MAP
            // #pragma shader_feature _ENABLESPECULAROCCLUSION
            // #pragma shader_feature _HEIGHTMAP
            // #pragma shader_feature _TANGENTMAP
            // #pragma shader_feature _ANISOTROPYMAP
            // #pragma shader_feature _SUBSURFACE_RADIUS_MAP
            // #pragma shader_feature _THICKNESSMAP
            // #pragma shader_feature _SPECULARCOLORMAP
            // #pragma shader_feature _TRANSMITTANCECOLORMAP

            // Keywords for transparent
            // #pragma shader_feature _SURFACE_TYPE_TRANSPARENT
            if (masterNode.surfaceType != SurfaceType.Opaque)
            {
                // transparent-only defines
                activeFields.Add("SurfaceType.Transparent");

                // #pragma shader_feature _ _BLENDMODE_ALPHA _BLENDMODE_ADD _BLENDMODE_PRE_MULTIPLY
                if (masterNode.alphaMode == AlphaMode.Alpha)
                {
                    activeFields.Add("BlendMode.Alpha");
                }
                else if (masterNode.alphaMode == AlphaMode.Additive)
                {
                    activeFields.Add("BlendMode.Add");
                }
//                else if (masterNode.alphaMode == PBRMasterNode.AlphaMode.PremultiplyAlpha)            // TODO
//                {
//                    defines.AddShaderChunk("#define _BLENDMODE_PRE_MULTIPLY 1", true);
//                }

                // #pragma shader_feature _BLENDMODE_PRESERVE_SPECULAR_LIGHTING
//                 if (kEnableBlendModePreserveSpecularLighting)
//                 {
//                     defines.AddShaderChunk("#define _BLENDMODE_PRESERVE_SPECULAR_LIGHTING 1", true);
//                 }

                // #pragma shader_feature _ENABLE_FOG_ON_TRANSPARENT
//                 if (kEnableFogOnTransparent)
//                 {
//                     defines.AddShaderChunk("#define _ENABLE_FOG_ON_TRANSPARENT 1", true);
//                 }
            }
            else
            {
                // opaque-only defines
            }

            // enable dithering LOD crossfade
            // #pragma multi_compile _ LOD_FADE_CROSSFADE
            // TODO: We should have this keyword only if VelocityInGBuffer is enable, how to do that ?
            //#pragma multi_compile VELOCITYOUTPUT_OFF VELOCITYOUTPUT_ON

            return(activeFields);
        }
예제 #13
0
        private static HashSet <string> GetActiveFieldsFromMasterNode(AbstractMaterialNode iMasterNode, Pass pass)
        {
            HashSet <string> activeFields = new HashSet <string>();

            FabricMasterNode masterNode = iMasterNode as FabricMasterNode;

            if (masterNode == null)
            {
                return(activeFields);
            }

            if (masterNode.doubleSidedMode != DoubleSidedMode.Disabled)
            {
                activeFields.Add("DoubleSided");
                if (pass.ShaderPassName != "SHADERPASS_VELOCITY")   // HACK to get around lack of a good interpolator dependency system
                {                                                   // we need to be able to build interpolators using multiple input structs
                                                                    // also: should only require isFrontFace if Normals are required...
                    if (masterNode.doubleSidedMode == DoubleSidedMode.FlippedNormals)
                    {
                        activeFields.Add("DoubleSided.Flip");
                    }
                    else if (masterNode.doubleSidedMode == DoubleSidedMode.MirroredNormals)
                    {
                        activeFields.Add("DoubleSided.Mirror");
                    }
                    // Important: the following is used in SharedCode.template.hlsl for determining the normal flip mode
                    activeFields.Add("FragInputs.isFrontFace");
                }
            }

            switch (masterNode.materialType)
            {
            case FabricMasterNode.MaterialType.CottonWool:
                activeFields.Add("Material.CottonWool");
                break;

            case FabricMasterNode.MaterialType.Silk:
                activeFields.Add("Material.Silk");
                break;

            default:
                UnityEngine.Debug.LogError("Unknown material type: " + masterNode.materialType);
                break;
            }

            if (masterNode.alphaTest.isOn)
            {
                if (pass.PixelShaderUsesSlot(FabricMasterNode.AlphaClipThresholdSlotId))
                {
                    activeFields.Add("AlphaTest");
                }
            }

            if (masterNode.surfaceType != SurfaceType.Opaque)
            {
                activeFields.Add("SurfaceType.Transparent");

                if (masterNode.alphaMode == AlphaMode.Alpha)
                {
                    activeFields.Add("BlendMode.Alpha");
                }
                else if (masterNode.alphaMode == AlphaMode.Premultiply)
                {
                    activeFields.Add("BlendMode.Premultiply");
                }
                else if (masterNode.alphaMode == AlphaMode.Additive)
                {
                    activeFields.Add("BlendMode.Add");
                }

                if (masterNode.blendPreserveSpecular.isOn)
                {
                    activeFields.Add("BlendMode.PreserveSpecular");
                }

                if (masterNode.transparencyFog.isOn)
                {
                    activeFields.Add("AlphaFog");
                }
            }

            if (!masterNode.receiveDecals.isOn)
            {
                activeFields.Add("DisableDecals");
            }

            if (!masterNode.receiveSSR.isOn)
            {
                activeFields.Add("DisableSSR");
            }

            if (masterNode.energyConservingSpecular.isOn)
            {
                activeFields.Add("Specular.EnergyConserving");
            }

            if (masterNode.transmission.isOn)
            {
                activeFields.Add("Material.Transmission");
            }

            if (masterNode.subsurfaceScattering.isOn && masterNode.surfaceType != SurfaceType.Transparent)
            {
                activeFields.Add("Material.SubsurfaceScattering");
            }

            if (masterNode.IsSlotConnected(FabricMasterNode.BentNormalSlotId) && pass.PixelShaderUsesSlot(FabricMasterNode.BentNormalSlotId))
            {
                activeFields.Add("BentNormal");
            }

            if (masterNode.IsSlotConnected(FabricMasterNode.TangentSlotId) && pass.PixelShaderUsesSlot(FabricMasterNode.TangentSlotId))
            {
                activeFields.Add("Tangent");
            }

            switch (masterNode.specularOcclusionMode)
            {
            case SpecularOcclusionMode.Off:
                break;

            case SpecularOcclusionMode.FromAO:
                activeFields.Add("SpecularOcclusionFromAO");
                break;

            case SpecularOcclusionMode.FromAOAndBentNormal:
                activeFields.Add("SpecularOcclusionFromAOBentNormal");
                break;

            case SpecularOcclusionMode.Custom:
                activeFields.Add("SpecularOcclusionCustom");
                break;

            default:
                break;
            }

            if (pass.PixelShaderUsesSlot(FabricMasterNode.AmbientOcclusionSlotId))
            {
                var occlusionSlot = masterNode.FindSlot <Vector1MaterialSlot>(FabricMasterNode.AmbientOcclusionSlotId);

                bool connected = masterNode.IsSlotConnected(FabricMasterNode.AmbientOcclusionSlotId);
                if (connected || occlusionSlot.value != occlusionSlot.defaultValue)
                {
                    activeFields.Add("AmbientOcclusion");
                }
            }

            if (masterNode.IsSlotConnected(FabricMasterNode.LightingSlotId) && pass.PixelShaderUsesSlot(FabricMasterNode.LightingSlotId))
            {
                activeFields.Add("LightingGI");
            }
            if (masterNode.IsSlotConnected(FabricMasterNode.BackLightingSlotId) && pass.PixelShaderUsesSlot(FabricMasterNode.BackLightingSlotId))
            {
                activeFields.Add("BackLightingGI");
            }

            return(activeFields);
        }
예제 #14
0
        private static HashSet <string> GetActiveFieldsFromMasterNode(INode iMasterNode, Pass pass)
        {
            HashSet <string> activeFields = new HashSet <string>();

            PBRMasterNode masterNode = iMasterNode as PBRMasterNode;

            if (masterNode == null)
            {
                return(activeFields);
            }

            if (masterNode.twoSided.isOn)
            {
                activeFields.Add("DoubleSided");
                if (pass.ShaderPassName != "SHADERPASS_VELOCITY")   // HACK to get around lack of a good interpolator dependency system
                {                                                   // we need to be able to build interpolators using multiple input structs
                                                                    // also: should only require isFrontFace if Normals are required...
                    activeFields.Add("DoubleSided.Mirror");         // TODO: change this depending on what kind of normal flip you want..
                    activeFields.Add("FragInputs.isFrontFace");     // will need this for determining normal flip mode
                }
            }

            switch (masterNode.model)
            {
            case PBRMasterNode.Model.Metallic:
                break;

            case PBRMasterNode.Model.Specular:
                activeFields.Add("Material.SpecularColor");
                break;

            default:
                // TODO: error!
                break;
            }

            if (masterNode.IsSlotConnected(PBRMasterNode.AlphaThresholdSlotId) ||
                masterNode.GetInputSlots <Vector1MaterialSlot>().First(x => x.id == PBRMasterNode.AlphaThresholdSlotId).value > 0.0f)
            {
                activeFields.Add("AlphaTest");
            }

            if (masterNode.surfaceType != SurfaceType.Opaque)
            {
                activeFields.Add("SurfaceType.Transparent");

                if (masterNode.alphaMode == AlphaMode.Alpha)
                {
                    activeFields.Add("BlendMode.Alpha");
                }
                else if (masterNode.alphaMode == AlphaMode.Additive)
                {
                    activeFields.Add("BlendMode.Add");
                }

                // By default PBR node will take the fog
                activeFields.Add("AlphaFog");
            }
            else
            {
                // opaque-only defines
            }

            return(activeFields);
        }
예제 #15
0
        private static HashSet <string> GetActiveFieldsFromMasterNode(INode iMasterNode, Pass pass)
        {
            HashSet <string> activeFields = new HashSet <string>();

            UnlitMasterNode masterNode = iMasterNode as UnlitMasterNode;

            if (masterNode == null)
            {
                return(activeFields);
            }

            if (masterNode.IsSlotConnected(UnlitMasterNode.AlphaThresholdSlotId) ||
                masterNode.GetInputSlots <Vector1MaterialSlot>().First(x => x.id == UnlitMasterNode.AlphaThresholdSlotId).value > 0.0f)
            {
                activeFields.Add("AlphaTest");
            }

            // Keywords for transparent
            // #pragma shader_feature _SURFACE_TYPE_TRANSPARENT
            if (masterNode.surfaceType != SurfaceType.Opaque)
            {
                // transparent-only defines
                activeFields.Add("SurfaceType.Transparent");

                // #pragma shader_feature _ _BLENDMODE_ALPHA _BLENDMODE_ADD _BLENDMODE_PRE_MULTIPLY
                if (masterNode.alphaMode == AlphaMode.Alpha)
                {
                    activeFields.Add("BlendMode.Alpha");
                }
                else if (masterNode.alphaMode == AlphaMode.Additive)
                {
                    activeFields.Add("BlendMode.Add");
                }
//                else if (masterNode.alphaMode == UnlitMasterNode.AlphaMode.PremultiplyAlpha)            // TODO
//                {
//                    defines.AddShaderChunk("#define _BLENDMODE_PRE_MULTIPLY 1", true);
//                }
            }
            else
            {
                // opaque-only defines
            }

            // enable dithering LOD crossfade
            // #pragma multi_compile _ LOD_FADE_CROSSFADE
            // TODO: We should have this keyword only if VelocityInGBuffer is enable, how to do that ?
            //#pragma multi_compile VELOCITYOUTPUT_OFF VELOCITYOUTPUT_ON

            return(activeFields);
        }
예제 #16
0
        private static HashSet <string> GetActiveFieldsFromMasterNode(AbstractMaterialNode iMasterNode, Pass pass)
        {
            HashSet <string> activeFields = new HashSet <string>();

            HDUnlitMasterNode masterNode = iMasterNode as HDUnlitMasterNode;

            if (masterNode == null)
            {
                return(activeFields);
            }

            if (masterNode.alphaTest.isOn && pass.PixelShaderUsesSlot(HDUnlitMasterNode.AlphaThresholdSlotId))
            {
                activeFields.Add("AlphaTest");
            }

            if (masterNode.surfaceType != SurfaceType.Opaque)
            {
                if (masterNode.transparencyFog.isOn)
                {
                    activeFields.Add("AlphaFog");
                }
            }

            if (masterNode.addPrecomputedVelocity.isOn)
            {
                activeFields.Add("AddPrecomputedVelocity");
            }

            return(activeFields);
        }