Please check my understanding of the material/effect system

Hi Paradox Team,

I’ve been attempting to unravel the material and effect system and would greatly appreciate a quick sanity check of my current understanding. Let’s say I set glossiness to a scalar in the editor. I believe the editor must be using the IMaterialFeature ‘nodes’ to generate the mixins [based on metadata in the material descriptors]. Assuming yes, does the shader code below roughly mimic what

SiliconStudio.Paradox.Rendering.Materials.MaterialGlossinessMapFeature.Visit(MaterialGeneratorContext context)

does when compiling a trivial scalar glossiness effect?

// var computeColorSource = GlossinessMap.GenerateShaderSource(context, new MaterialComputeColorKeys(MaterialKeys.GlossinessMap, MaterialKeys.GlossinessValue));
class MyComputeColor : ComputeColor
{
    override float4 Compute()
    {
        return 0.1;
    }
};

shader MyEffect
{
	// var mixin = new ShaderMixinSource();
        // mixin.Mixins.Add(new ShaderClassSource("MaterialSurfaceGlossinessMap", Invert));
        // mixin.AddComposition("glossinessMap", computeColorSource);
	// context.AddSurfaceShader(MaterialShaderStage.Pixel, mixin);
	mixin MaterialSurfaceGlossinessMap;
	mixin compose glossinessMap = MyComputeColor;
	
	// ...
}

Indeed it does generate something quite similar to the part you have extracted.

If you look at the generated hlsl log, you will find at the beginning the keys that are actually used to compile an effect. For a typical material, the generated pixel shader mixin is actually like this (this is a dump of the log, not written in shader language as you did):

Material.PixelStageSurfaceShaders: 
mixin MaterialSurfaceArray [
{layers = [mixin MaterialSurfaceDiffuse [
    {diffuseMap = ComputeColorConstantColorLink}
    ], mixin MaterialSurfaceNormalMap [
    {normalMap = ComputeColorTextureScaledOffsetDynamicSampler}
    ], mixin MaterialSurfaceGlossinessMap [
    {glossinessMap = ComputeColorConstantFloatLink}
    ], mixin MaterialSurfaceMetalness [
    {metalnessMap = ComputeColorConstantFloatLink}
    ], mixin MaterialSurfaceSetStreamFromComputeColor [
    {computeColorSource = ComputeColorConstantColorLink}
    ], mixin MaterialSurfaceSetStreamFromComputeColor [
    {computeColorSource = ComputeColorConstantFloatLink}
    ], mixin MaterialSurfaceLightingAndShading [
    {surfaces = [MaterialSurfaceShadingDiffuseLambert, mixin MaterialSurfaceShadingSpecularMicrofacet [
        {fresnelFunction = MaterialSpecularMicrofacetFresnelSchlick}
        ,
        {geometricShadowingFunction = MaterialSpecularMicrofacetVisibilitySmithSchlickGGX}
        ,
        {normalDistributionFunction = MaterialSpecularMicrofacetNormalDistributionGGX}
    ]]}
], MaterialSurfaceEmissiveShading]}
]

This key is then used at ParadoxForwardShadingEffect.pdxfx:23 when compiling the final shader for this particular material.

Thanks very much Alexandre! As you brought up the forward shading effect I’d like to ask a semi-related question. Here’s one of the more perplexing bits for me thus far:

        var directLightGroups = LightingKeys.DirectLightGroups;
        if (directLightGroups != null)
        {
            foreach(var directLightGroup in directLightGroups)
            {
                // Use parenthesis (...) to avoid lightGroup to be interpreted as a mixin named "lightGroup"
                mixin compose directLightGroups += (directLightGroup);
            }
        }

The amount of indirection here is making my head spin ;-P. Thus, I’m wondering (hoping!) if I can view this as a sort of “uber shader” such that in my case – I know precisely the number and type of lights – I can cut through this swath of indirection and just compose the mixins directly to get my desired “permutation”. If that make sense, any possibility of a rough sketch of what that look like (let’s I have a similar setup to the forward shading demo, i.e. 2 dir lights, 1 spot light…)? Thanks again for the help!