Example #1
0
        public override void GenerateShader(MaterialGeneratorContext context)
        {
            if (DiffuseMap != null)
            {
                Vector4 diffuseMin = Vector4.Zero;
                Vector4 diffuseMax = Vector4.One;
                DiffuseMap.ClampFloat4(ref diffuseMin, ref diffuseMax);

                var computeColorSource = DiffuseMap.GenerateShaderSource(context, new MaterialComputeColorKeys(MaterialKeys.DiffuseMap, MaterialKeys.DiffuseValue, Color.White));
                var mixin = new ShaderMixinSource();
                mixin.Mixins.Add(new ShaderClassSource("MaterialSurfaceDiffuse"));
                mixin.AddComposition("diffuseMap", computeColorSource);
                context.UseStream(MaterialShaderStage.Pixel, DiffuseStream.Stream);
                context.UseStream(MaterialShaderStage.Pixel, ColorBaseStream.Stream);
                context.AddShaderSource(MaterialShaderStage.Pixel, mixin);
            }
        }
Example #2
0
        public void Visit(MaterialGeneratorContext context)
        {
            if (!Enabled)
            {
                return;
            }

            switch (context.Step)
            {
            case MaterialGeneratorStep.PassesEvaluation:
                MultipassGeneration(context);
                break;

            case MaterialGeneratorStep.GenerateShader:
                GenerateShader(context);
                break;
            }
        }
Example #3
0
        public override void VisitFeature(MaterialGeneratorContext context)
        {
            base.VisitFeature(context);

            if (HasAlreadyTessellationFeature)
            {
                return;
            }

            // set the tessellation method used enumeration
            context.Material.TessellationMethod |= XenkoTessellationMethod.Flat;

            // create and affect the shader source
            var tessellationShader = new ShaderMixinSource();

            tessellationShader.Mixins.Add(new ShaderClassSource("TessellationFlat"));

            context.Parameters.Set(MaterialKeys.TessellationShader, tessellationShader);
        }
Example #4
0
        public virtual void Visit(MaterialGeneratorContext context)
        {
            // If not enabled, or Material or BlendMap are null, skip this layer
            if (!Enabled || Material == null || BlendMap == null || context.FindAsset == null)
            {
                return;
            }

            // Find the material from the reference
            var material = context.FindAsset(Material) as IMaterialDescriptor;

            if (material == null)
            {
                context.Log.Error($"Unable to find material [{Material}]");
                return;
            }

            // Check that material is valid
            var materialName = context.GetAssetFriendlyName(Material);

            if (!context.PushMaterial(material, materialName))
            {
                return;
            }

            try
            {
                // TODO: Because we are not fully supporting Streams declaration in shaders, we have to workaround this limitation by using a dynamic shader (inline)
                // Push a layer for the sub-material
                context.PushOverrides(Overrides);
                context.PushLayer(BlendMap);

                // Generate the material shaders into the current context
                material.Visit(context);
            }
            finally
            {
                // Pop the stack
                context.PopLayer();
                context.PopOverrides();
                context.PopMaterial();
            }
        }
        private void AddMetalFlakesGlossiness(MaterialGeneratorContext context)
        {
            var surfaceToEyeDistance = LODDistance.GenerateShaderSource(context, new MaterialComputeColorKeys(MaterialKeys.GlossinessMap, MaterialKeys.GlossinessValue, Color.White));

            // Metal Flakes Glossiness Feature
            context.UseStream(MaterialShaderStage.Pixel, "matGlossiness");

            var baseGlossinessComputeColorMap = BasePaintGlossinessMap.GenerateShaderSource(context, new MaterialComputeColorKeys(MaterialKeys.GlossinessMap, MaterialKeys.GlossinessValue));

            var mixinGlossiness = new ShaderMixinSource();

            // Computes glossiness factor for the metal flakes layer (based on the eye to surface distance and the base glossiness value)
            mixinGlossiness.Mixins.Add(new ShaderClassSource("MaterialSurfaceGlossinessMapMetalFlakes", BasePaintGlossinessInvert));

            mixinGlossiness.AddComposition("glossinessMap", baseGlossinessComputeColorMap);
            mixinGlossiness.AddComposition("surfaceToEyeDistanceFactor", surfaceToEyeDistance);

            context.AddShaderSource(MaterialShaderStage.Pixel, mixinGlossiness);
        }
        private void AddMetalFlakesDiffuse(MaterialGeneratorContext context)
        {
            var surfaceToEyeDistance = LODDistance.GenerateShaderSource(context, new MaterialComputeColorKeys(MaterialKeys.GlossinessMap, MaterialKeys.GlossinessValue, Color.White));

            // Diffuse Feature (interpolated by the 'regular' diffuse map)
            var metalFlakesComputeColorSource = MetalFlakesDiffuseMap.GenerateShaderSource(context, new MaterialComputeColorKeys(MaterialKeys.DiffuseMap, MaterialKeys.DiffuseValue, Color.White));

            var mixinDiffuse = new ShaderMixinSource();

            // Diffuse uses a custom shader (to perform the interpolation)
            mixinDiffuse.Mixins.Add(new ShaderClassSource("MaterialSurfaceDiffuseMetalFlakes"));

            mixinDiffuse.AddComposition("diffuseMap", metalFlakesComputeColorSource);
            mixinDiffuse.AddComposition("surfaceToEyeDistanceFactor", surfaceToEyeDistance);

            context.UseStream(MaterialShaderStage.Pixel, MaterialDiffuseMapFeature.DiffuseStream.Stream);
            context.UseStream(MaterialShaderStage.Pixel, MaterialDiffuseMapFeature.ColorBaseStream.Stream);

            context.AddShaderSource(MaterialShaderStage.Pixel, mixinDiffuse);
        }
Example #7
0
        public override void VisitFeature(MaterialGeneratorContext context)
        {
            var alpha = Alpha ?? new ComputeFloat(1f);
            var tint  = Tint ?? new ComputeColor(Color.White);

            // Use pre-multiplied alpha to support both additive and alpha blending
            var blendDesc = new BlendStateDescription(Blend.One, Blend.InverseSourceAlpha);

            context.Material.HasTransparency = true;
            context.Parameters.Set(Effect.BlendStateKey, BlendState.NewFake(blendDesc));

            context.SetStream(AlphaBlendStream.Stream, alpha, MaterialKeys.DiffuseSpecularAlphaBlendMap, MaterialKeys.DiffuseSpecularAlphaBlendValue, Color.White);
            context.SetStream(AlphaBlendColorStream.Stream, tint, MaterialKeys.AlphaBlendColorMap, MaterialKeys.AlphaBlendColorValue, Color.White);

            if (!context.Tags.Get(HasFinalCallback))
            {
                context.Tags.Set(HasFinalCallback, true);
                context.AddFinalCallback(MaterialShaderStage.Pixel, AddDiffuseSpecularAlphaBlendColor);
            }
        }
        public override void GenerateShader(MaterialGeneratorContext context)
        {
            // Exclude ambient occlusion from uv-scale overrides
            var revertOverrides = new MaterialOverrides();

            revertOverrides.UVScale = 1.0f / context.CurrentOverrides.UVScale;

            context.PushOverrides(revertOverrides);
            context.SetStream(OcclusionStream.Stream, AmbientOcclusionMap, MaterialKeys.AmbientOcclusionMap, MaterialKeys.AmbientOcclusionValue, Color.White);
            context.PopOverrides();

            context.SetStream("matAmbientOcclusionDirectLightingFactor", DirectLightingFactor, null, MaterialKeys.AmbientOcclusionDirectLightingFactorValue);

            if (CavityMap != null)
            {
                context.SetStream(CavityStream.Stream, CavityMap, MaterialKeys.CavityMap, MaterialKeys.CavityValue, Color.White);
                context.SetStream("matCavityDiffuse", DiffuseCavity, null, MaterialKeys.CavityDiffuseValue);
                context.SetStream("matCavitySpecular", SpecularCavity, null, MaterialKeys.CavitySpecularValue);
            }
        }
Example #9
0
        /// <summary>
        /// Initializes a new instance of <see cref="MaterialBlendLayerContext"/>.
        /// </summary>
        /// <param name="context">The material generator context</param>
        /// <param name="parentLayerContext">The parent layer context</param>
        /// <param name="blendMap">The blend map used for this layer</param>
        public MaterialBlendLayerContext(MaterialGeneratorContext context, MaterialBlendLayerContext parentLayerContext, IComputeScalar blendMap)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }
            Context  = context;
            Parent   = parentLayerContext;
            BlendMap = blendMap;

            Children      = new List <MaterialBlendLayerContext>();
            ShadingModels = new MaterialShadingModelCollection();

            ContextPerStage = new Dictionary <MaterialShaderStage, MaterialBlendLayerPerStageContext>();
            foreach (MaterialShaderStage stage in Enum.GetValues(typeof(MaterialShaderStage)))
            {
                ContextPerStage[stage] = new MaterialBlendLayerPerStageContext();
            }

            PendingPixelLayerContext = new MaterialBlendLayerPerStageContext();
        }
        public override void GenerateShader(MaterialGeneratorContext context)
        {
            base.GenerateShader(context);

            var attributes = context.CurrentMaterialDescriptor.Attributes;

            int glassPassIndex = context.PassIndex % 2;

            if (attributes.CullMode == CullMode.None)
            {
                context.MaterialPass.CullMode = context.PassIndex < 2 ? CullMode.Back : CullMode.Front;
            }
            else
            {
                context.MaterialPass.CullMode = attributes.CullMode;
            }

            // Compute transmittance
            context.GetShading(this).LightDependentExtraModels.Add(new ShaderClassSource("MaterialTransmittanceReflectanceStream"));

            context.Parameters.Set(MaterialTransmittanceReflectanceStreamKeys.RefractiveIndex, RefractiveIndex);
            context.MaterialPass.HasTransparency = true;
            if (glassPassIndex == 0)
            {
                // Transmittance pass
                context.MaterialPass.BlendState = new BlendStateDescription(Blend.Zero, Blend.SourceColor)
                {
                    RenderTarget0 = { AlphaSourceBlend = Blend.One, AlphaDestinationBlend = Blend.Zero }
                };

                // Shader output is matTransmittance
                // Note: we make sure to run after MaterialTransparencyBlendFeature so that shadingColorAlpha is fully updated
                context.AddFinalCallback(MaterialShaderStage.Pixel, AddMaterialSurfaceTransmittanceShading, MaterialTransparencyBlendFeature.ShadingColorAlphaFinalCallbackOrder + 1);
            }
            else if (glassPassIndex == 1)
            {
                // Reflectance pass
                context.MaterialPass.BlendState = BlendStates.Additive;
            }
        }
        protected virtual void GenerateShaderCompositions(MaterialGeneratorContext context, ShaderMixinSource shaderSource)
        {
            if (Fresnel != null)
            {
                shaderSource.AddComposition("fresnelFunction", Fresnel.Generate(context));
            }

            if (Visibility != null)
            {
                shaderSource.AddComposition("geometricShadowingFunction", Visibility.Generate(context));
            }

            if (NormalDistribution != null)
            {
                shaderSource.AddComposition("normalDistributionFunction", NormalDistribution.Generate(context));
            }

            if (Environment != null)
            {
                shaderSource.AddComposition("environmentFunction", Environment.Generate(context));
            }
        }
        public override void VisitFeature(MaterialGeneratorContext context)
        {
            var shaderSource = new ShaderMixinSource();

            shaderSource.Mixins.Add(new ShaderClassSource("MaterialSurfaceShadingSpecularMicrofacet"));

            if (Fresnel != null)
            {
                shaderSource.AddComposition("fresnelFunction", Fresnel.Generate());
            }

            if (Visibility != null)
            {
                shaderSource.AddComposition("geometricShadowingFunction", Visibility.Generate());
            }

            if (NormalDistribution != null)
            {
                shaderSource.AddComposition("normalDistributionFunction", NormalDistribution.Generate());
            }

            context.AddShading(this, shaderSource);
        }
Example #13
0
        public override void VisitFeature(MaterialGeneratorContext context)
        {
            base.VisitFeature(context);

            if (HasAlreadyTessellationFeature)
            {
                return;
            }

            // set the tessellation method used enumeration
            context.Material.TessellationMethod |= XenkoTessellationMethod.PointNormal;

            // create and affect the shader source
            var tessellationShader = new ShaderMixinSource();

            tessellationShader.Mixins.Add(new ShaderClassSource("TessellationPN"));
            if (AdjacentEdgeAverage)
            {
                tessellationShader.Mixins.Add(new ShaderClassSource("TessellationAE4", "PositionWS"));
            }

            context.Parameters.Set(MaterialKeys.TessellationShader, tessellationShader);
        }
Example #14
0
        public override void VisitFeature(MaterialGeneratorContext context)
        {
            if (NormalMap != null)
            {
                // Inform the context that we are using matNormal (from the MaterialSurfaceNormalMap shader)
                context.UseStreamWithCustomBlend(MaterialShaderStage.Pixel, NormalStream.Stream, new ShaderClassSource("MaterialStreamNormalBlend"));
                context.Parameters.Set(MaterialKeys.HasNormalMap, true);

                var normalMap = NormalMap;
                // Workaround to make sure that normal map are setup
                var computeTextureColor = normalMap as ComputeTextureColor;
                if (computeTextureColor != null)
                {
                    if (computeTextureColor.FallbackValue.Value == Color.White)
                    {
                        computeTextureColor.FallbackValue.Value = DefaultNormalColor;
                    }
                }
                else
                {
                    var computeColor = normalMap as ComputeColor;
                    if (computeColor != null)
                    {
                        if (computeColor.Value == Color.Black || computeColor.Value == Color.White)
                        {
                            computeColor.Value = DefaultNormalColor;
                        }
                    }
                }

                var computeColorSource = NormalMap.GenerateShaderSource(context, new MaterialComputeColorKeys(MaterialKeys.NormalMap, MaterialKeys.NormalValue, DefaultNormalColor, false));
                var mixin = new ShaderMixinSource();
                mixin.Mixins.Add(new ShaderClassSource("MaterialSurfaceNormalMap", IsXYNormal, ScaleAndBias));
                mixin.AddComposition("normalMap", computeColorSource);
                context.AddShaderSource(MaterialShaderStage.Pixel, mixin);
            }
        }
        public override void GenerateShader(MaterialGeneratorContext context)
        {
            // Make sure the parameters are not out of range
            ClampInputs();

            // Set the blend state for both pass
            context.MaterialPass.BlendState = BlendStates.Additive;

            var isMetalFlakesPass = (context.PassIndex == 0);

            if (isMetalFlakesPass)
            {
                // Do the Base Paint first
                AddBaseDiffuse(context);
                AddBaseGlossiness(context);

                // Then the Metal Flakes
                AddMetalFlakesDiffuse(context);
                AddMetalFlakesNormal(context);
                AddMetalFlakesGlossiness(context);
                AddMetalFlakesMetalness(context);
            }
            else
            {
                // TODO Add reflections desaturation for environment reflections?
                // Ideally, this should be done on top of the regular specular model.
                // Unfortunately, after some tests, it seems that overriding the ComputeEnvironmentLightContribution is the only way to do so

                // Enable transparency for clear coat pass only
                context.MaterialPass.HasTransparency = true;

                AddClearCoatNormalMap(context);
                AddClearCoatGlossinessMap(context);
                AddClearCoatMetalnessMap(context);
            }
        }
        public override void VisitFeature(MaterialGeneratorContext context)
        {
            if (DisplacementMap == null)
            {
                return;
            }

            var materialStage = (MaterialShaderStage)Stage;

            // reset the displacement streams at the beginning of the stage
            context.AddStreamInitializer(materialStage, "MaterialDisplacementStream");

            // set the blending mode of displacement map to additive (and not default linear blending)
            context.UseStreamWithCustomBlend(materialStage, DisplacementStream, new ShaderClassSource("MaterialStreamAdditiveBlend", DisplacementStream));

            // build the displacement computer
            var displacement = DisplacementMap;

            if (ScaleAndBias) // scale and bias should be done by layer
            {
                displacement = new ComputeBinaryScalar(displacement, new ComputeFloat(2f), BinaryOperator.Multiply);
                displacement = new ComputeBinaryScalar(displacement, new ComputeFloat(1f), BinaryOperator.Subtract);
            }
            displacement = new ComputeBinaryScalar(displacement, Intensity, BinaryOperator.Multiply);

            // Workaround to inform compute colors that sampling is occurring from a vertex shader
            context.IsNotPixelStage = materialStage != MaterialShaderStage.Pixel;
            context.SetStream(materialStage, DisplacementStream, displacement, MaterialKeys.DisplacementMap, MaterialKeys.DisplacementValue);
            context.IsNotPixelStage = false;

            var scaleNormal    = materialStage != MaterialShaderStage.Vertex;
            var positionMember = materialStage == MaterialShaderStage.Vertex ? "Position" : "PositionWS";
            var normalMember   = materialStage == MaterialShaderStage.Vertex ? "meshNormal" : "normalWS";

            context.SetStreamFinalModifier <MaterialDisplacementMapFeature>(materialStage, new ShaderClassSource("MaterialSurfaceDisplacement", positionMember, normalMember, scaleNormal));
        }
 /// <summary>
 /// Generates the for the feature shader.
 /// </summary>
 /// <param name="context">The context.</param>
 public abstract void VisitFeature(MaterialGeneratorContext context);
Example #18
0
 public ShaderSource Generate(MaterialGeneratorContext context)
 {
     return(new ShaderClassSource("MaterialSpecularMicrofacetVisibilityNeumann"));
 }
Example #19
0
 public ShaderSource Generate(MaterialGeneratorContext context)
 {
     return(new ShaderClassSource("MaterialSpecularMicrofacetNormalDistributionBlinnPhong"));
 }
Example #20
0
 public ShaderSource Generate(MaterialGeneratorContext context)
 {
     return(new ShaderClassSource("MaterialSpecularMicrofacetEnvironmentGGXPolynomial"));
 }
 private void AddDiffuseSpecularAlphaBlendColor(MaterialShaderStage stage, MaterialGeneratorContext context)
 {
     context.AddShaderSource(MaterialShaderStage.Pixel, new ShaderClassSource("MaterialSurfaceDiffuseSpecularAlphaBlendColor"));
 }
Example #22
0
        public static MaterialShaderResult Generate(MaterialDescriptor materialDescriptor, MaterialGeneratorContext context, string rootMaterialFriendlyName)
        {
            if (materialDescriptor == null)
            {
                throw new ArgumentNullException("materialDescriptor");
            }
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            var result = new MaterialShaderResult();

            context.Log = result;

            var material = context.Material;

            result.Material = context.Material;

            context.Parameters = material.Parameters;
            context.PushMaterial(materialDescriptor, rootMaterialFriendlyName);
            context.PushLayer();
            materialDescriptor.Visit(context);
            context.PopLayer();
            context.PopMaterial();

            if (!material.Parameters.ContainsKey(MaterialKeys.TessellationShader))
            {
                material.Parameters.Set(MaterialKeys.TessellationShader, null);
            }

            material.Parameters.Set(MaterialKeys.VertexStageSurfaceShaders, context.GenerateSurfaceShader(MaterialShaderStage.Vertex));
            material.Parameters.Set(MaterialKeys.DomainStageSurfaceShaders, context.GenerateSurfaceShader(MaterialShaderStage.Domain));
            material.Parameters.Set(MaterialKeys.PixelStageSurfaceShaders, context.GenerateSurfaceShader(MaterialShaderStage.Pixel));

            material.Parameters.Set(MaterialKeys.VertexStageStreamInitializer, context.GenerateStreamInitializer(MaterialShaderStage.Vertex));
            material.Parameters.Set(MaterialKeys.DomainStageStreamInitializer, context.GenerateStreamInitializer(MaterialShaderStage.Domain));
            material.Parameters.Set(MaterialKeys.PixelStageStreamInitializer, context.GenerateStreamInitializer(MaterialShaderStage.Pixel));

            return(result);
        }
Example #23
0
        public void Visit(MaterialGeneratorContext context)
        {
            if (!Enabled)
            {
                return;
            }

            // Push overrides of this attributes
            context.PushOverrides(Overrides);

            // Order is important, as some features are dependent on other
            // (For example, Specular can depend on Diffuse in case of Metalness)
            // We may be able to describe a dependency system here, but for now, assume
            // that it won't change much so it is hardcoded

            // If Specular has energy conservative, copy this to the diffuse lambertian model
            // TODO: Should we apply it to any Diffuse Model?
            var isEnergyConservative = (Specular as MaterialSpecularMapFeature)?.IsEnergyConservative ?? false;

            var lambert = DiffuseModel as IEnergyConservativeDiffuseModelFeature;

            if (lambert != null)
            {
                lambert.IsEnergyConservative = isEnergyConservative;
            }

            // Diffuse - these 2 features are always used as a pair
            context.Visit(Diffuse);
            if (Diffuse != null)
            {
                context.Visit(DiffuseModel);
            }

            // Surface Geometry
            context.Visit(Tessellation);
            context.Visit(Displacement);
            context.Visit(Surface);
            context.Visit(MicroSurface);

            // Specular - these 2 features are always used as a pair
            context.Visit(Specular);
            if (Specular != null)
            {
                context.Visit(SpecularModel);
            }

            // Misc
            context.Visit(Occlusion);
            context.Visit(Emissive);
            context.Visit(Transparency);

            // Pop overrides
            context.PopOverrides();

            // Only set the cullmode to something
            if (context.Step == MaterialGeneratorStep.GenerateShader && CullMode != CullMode.Back)
            {
                if (context.MaterialPass.CullMode == null)
                {
                    context.MaterialPass.CullMode = CullMode;
                }
            }
        }
 public ShaderSource Generate(MaterialGeneratorContext context)
 {
     return(new ShaderClassSource("MaterialSpecularMicrofacetFresnelSchlick"));
 }
Example #25
0
 private void AddDiscardFromLuminance(MaterialShaderStage stage, MaterialGeneratorContext context)
 {
     context.AddShaderSource(MaterialShaderStage.Pixel, new ShaderClassSource("MaterialSurfaceTransparentAlphaDiscard"));
 }
 public ShaderSource Generate(MaterialGeneratorContext context)
 {
     return(new ShaderClassSource("MaterialCelShadingLightDefault", IsBlackAndWhite));
 }
        public override void VisitFeature(MaterialGeneratorContext context)
        {
            var shaderSource = new ShaderClassSource("MaterialSurfaceShadingDiffuseLambert", IsEnergyConservative);

            context.AddShading(this, shaderSource);
        }
Example #28
0
 private void AddMaterialSurfaceTransmittanceShading(MaterialShaderStage stage, MaterialGeneratorContext context)
 {
     context.AddShaderSource(stage, new ShaderClassSource("MaterialSurfaceTransmittanceShading"));
 }
Example #29
0
        public static MaterialShaderResult Generate(MaterialDescriptor materialDescriptor, MaterialGeneratorContext context, string rootMaterialFriendlyName)
        {
            if (materialDescriptor == null)
            {
                throw new ArgumentNullException("materialDescriptor");
            }
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            var result = new MaterialShaderResult();

            context.Log = result;

            result.Material = context.Material;

            context.PushMaterial(materialDescriptor, rootMaterialFriendlyName);

            context.Step = MaterialGeneratorStep.PassesEvaluation;
            materialDescriptor.Visit(context);

            context.Step = MaterialGeneratorStep.GenerateShader;
            for (int pass = 0; pass < context.PassCount; ++pass)
            {
                var materialPass = context.PushPass();

                context.PushLayer(null);
                materialDescriptor.Visit(context);
                context.PopLayer();

                materialPass.Parameters.Set(MaterialKeys.VertexStageSurfaceShaders, context.ComputeShaderSource(MaterialShaderStage.Vertex));
                materialPass.Parameters.Set(MaterialKeys.DomainStageSurfaceShaders, context.ComputeShaderSource(MaterialShaderStage.Domain));
                materialPass.Parameters.Set(MaterialKeys.PixelStageSurfaceShaders, context.ComputeShaderSource(MaterialShaderStage.Pixel));

                materialPass.Parameters.Set(MaterialKeys.VertexStageStreamInitializer, context.GenerateStreamInitializers(MaterialShaderStage.Vertex));
                materialPass.Parameters.Set(MaterialKeys.DomainStageStreamInitializer, context.GenerateStreamInitializers(MaterialShaderStage.Domain));
                materialPass.Parameters.Set(MaterialKeys.PixelStageStreamInitializer, context.GenerateStreamInitializers(MaterialShaderStage.Pixel));

                context.PopPass();
            }
            context.PopMaterial();

            return(result);
        }
        public override void MultipassGeneration(MaterialGeneratorContext context)
        {
            const int passCount = 2;

            context.SetMultiplePasses("ClearCoat", passCount);
        }