public void AddShaderSource(MaterialShaderStage stage, ShaderSource shaderSource) { if (shaderSource == null) { throw new ArgumentNullException(nameof(shaderSource)); } currentLayerContext.GetContextPerStage(stage).ShaderSources.Add(shaderSource); }
private void BlendStreams(MaterialBlendLayerContext layer) { // Generate Vertex and Pixel surface shaders foreach (MaterialShaderStage stage in Enum.GetValues(typeof(MaterialShaderStage))) { // If we don't have any stream set, we have nothing to blend var stageContext = layer.GetContextPerStage(stage); if (stageContext.Streams.Count == 0) { continue; } // Blend setup for this layer layer.SetStreamBlend(stage, layer.BlendMap); // Generate a dynamic shader name // Create a mixin var shaderMixinSource = new ShaderMixinSource(); shaderMixinSource.Mixins.Add(new ShaderClassSource("MaterialSurfaceStreamsBlend")); // Add all streams that we need to blend foreach (var stream in stageContext.Streams) { shaderMixinSource.AddCompositionToArray("blends", GetStreamBlendShaderSource(stream)); } stageContext.Streams.Clear(); // Squash all ShaderSources to a single shader source var materialBlendLayerMixin = stageContext.ComputeShaderSource(); stageContext.ShaderSources.Clear(); // Add the shader to the mixin shaderMixinSource.AddComposition("layer", materialBlendLayerMixin); // Squash the shader sources stageContext.ShaderSources.Add(shaderMixinSource); } }
private void ProcessRootLayer(MaterialBlendLayerContext layer) { // Make sure that any pending source are actually copied to the current Pixel ShaderSources var currentPixelLayerContext = layer.GetContextPerStage(MaterialShaderStage.Pixel); if (layer.PendingPixelLayerContext.ShaderSources.Count > 0) { currentPixelLayerContext.ShaderSources.AddRange(layer.PendingPixelLayerContext.ShaderSources); layer.PendingPixelLayerContext.Reset(); } // Need to merge top level layer last if (layer.ShadingModels.Count > 0) { // Add shading foreach (var shaderSource in layer.ShadingModels.Generate(this)) { currentPixelLayerContext.ShaderSources.Add(shaderSource); } } foreach (var modifierKey in finalInputStreamModifiers.Keys) { currentLayerContext.GetContextPerStage(modifierKey.Key).ShaderSources.Add(finalInputStreamModifiers[modifierKey]); } // Clear final callback foreach (var callbackKeyPair in finalCallbacks) { var stage = callbackKeyPair.Key; var callbacks = callbackKeyPair.Value; foreach (var callback in callbacks) { callback(stage, this); } callbacks.Clear(); } }
/// <summary> /// Processes the intermediate layer. /// </summary> /// <param name="layer">The layer.</param> /// <param name="isLastLayer">if set to <c>true</c> the layer is the last children of the parent layer.</param> private void ProcessIntermediateLayer(MaterialBlendLayerContext layer, bool isLastLayer) { // note: SM = Shading Model var parent = layer.Parent; // Check if SM is changing relative to the state of the parent layer bool sameShadingModel = true; if (parent.ShadingModelCount > 0) { sameShadingModel = layer.ShadingModels.Equals(parent.ShadingModels); } else if (layer.ShadingModelCount > 0) { // If the current layer has a SM, copy it to the parent layer.ShadingModels.CopyTo(parent.ShadingModels); layer.ShadingModels.Clear(); parent.ShadingModelCount++; } // If SM is the same, we can blend attributes if (sameShadingModel) { // If shading model is not changing, we generate the BlendStream shaders BlendStreams(layer); } else { parent.ShadingModelCount++; } var parentPixelLayerContext = parent.GetContextPerStage(MaterialShaderStage.Pixel); var pendingPixelLayerContext = parent.PendingPixelLayerContext; // -------------------------------------------- // Copy streams to parent, but not for the PixelLayer if SM is changing // -------------------------------------------- foreach (MaterialShaderStage stage in Enum.GetValues(typeof(MaterialShaderStage))) { var stageContext = layer.GetContextPerStage(stage); var parentStageContext = parent.GetContextPerStage(stage); // the Initializers parentStageContext.StreamInitializers.AddRange(stageContext.StreamInitializers); // skip pixel shader if shading model need to be blended if (stage == MaterialShaderStage.Pixel) { if (!sameShadingModel) { continue; } // If same shading model, use temporarely the ParentPixelLayerContext parentStageContext = pendingPixelLayerContext; } // Add shaders except Pixels if we have a different ShadingModel parentStageContext.ShaderSources.AddRange(stageContext.ShaderSources); } // -------------------------------------------- // Apply shading: with 1) blending or 2) no blending // -------------------------------------------- // Check if we need to force shading var forceShading = isLastLayer && (parent.ShadingModelCount > 1 || !sameShadingModel); if (!sameShadingModel || forceShading) { // true if the current layer has been blended already bool currentLayerAlreadyBlended = false; // If we need to shade but there is not yet a blend map setup (e.g: a single layer with a new SM != from parent SM) if (forceShading && parent.BlendMapForShadingModel == null) { // Do we have a pending SM, if yes, we need to perform shading for the pending SM if (!sameShadingModel) { foreach (var shaderSource in pendingPixelLayerContext.ShaderSources) { parentPixelLayerContext.ShaderSources.Add(shaderSource); } pendingPixelLayerContext.Reset(); foreach (var shaderSource in parent.ShadingModels.Generate(this)) { parentPixelLayerContext.ShaderSources.Add(shaderSource); } parent.ShadingModels.Clear(); layer.ShadingModels.CopyTo(parent.ShadingModels); } // Setup a blend map so that we will blend SM just after parent.BlendMapForShadingModel = layer.BlendMap; // Copy pixel shaders to pending so it will be picked up by BlendShadingModel var currentPixelLayerContext = layer.GetContextPerStage(MaterialShaderStage.Pixel); pendingPixelLayerContext.ShaderSources.AddRange(currentPixelLayerContext.ShaderSources); currentLayerAlreadyBlended = true; } // Do we need to blend shading model? if (parent.BlendMapForShadingModel != null) { BlendShadingModel(parent, pendingPixelLayerContext, parentPixelLayerContext); } else { // Else, we just expect to shade the current SM foreach (var shaderSource in pendingPixelLayerContext.ShaderSources) { parentPixelLayerContext.ShaderSources.Add(shaderSource); } pendingPixelLayerContext.Reset(); foreach (var shaderSource in parent.ShadingModels.Generate(this)) { parentPixelLayerContext.ShaderSources.Add(shaderSource); } parent.ShadingModels.Clear(); } // If we changed the SM and the current layer has not been already blended if (!sameShadingModel && !currentLayerAlreadyBlended) { // Save the BlendMap of the current layer for future blending parent.BlendMapForShadingModel = layer.BlendMap; // Copy the SM of the current layer to the parent layer parent.ShadingModels.Clear(); layer.ShadingModels.CopyTo(parent.ShadingModels); // If the shading model is different, the current attributes of the layer are not part of this blending // So they will contribute to the next blending var currentPixelLayerContext = layer.GetContextPerStage(MaterialShaderStage.Pixel); pendingPixelLayerContext.ShaderSources.AddRange(currentPixelLayerContext.ShaderSources); // If this is the last layer and we have more than 1 SM already, we force to blend the shading models if (isLastLayer && parent.ShadingModelCount > 1) { BlendShadingModel(parent, pendingPixelLayerContext, parentPixelLayerContext); } } } }
private void ProcessIntermediateLayer(MaterialBlendLayerContext layer, bool isLastChild) { var parent = layer.Parent; var hasParentShadingModel = parent.ShadingModelCount > 0; // If current shading model is not set, if (!hasParentShadingModel && layer.ShadingModelCount > 0) { layer.ShadingModels.CopyTo(parent.ShadingModels); hasParentShadingModel = true; parent.ShadingModelCount++; } var sameShadingModel = hasParentShadingModel && layer.ShadingModels.Equals(parent.ShadingModels); if (sameShadingModel) { // If shading model is not changing, we generate the BlendStream shaders BlendStreams(layer); } else { parent.ShadingModelCount++; } var parentPixelLayerContext = parent.GetContextPerStage(MaterialShaderStage.Pixel); var pendingPixelLayerContext = parent.PendingPixelLayerContext; // Copy streams to parent foreach (MaterialShaderStage stage in Enum.GetValues(typeof(MaterialShaderStage))) { var stageContext = layer.GetContextPerStage(stage); var parentStageContext = parent.GetContextPerStage(stage); // the Initializers parentStageContext.StreamInitializers.AddRange(stageContext.StreamInitializers); // skip pixel shader if shading model need to be blended if (stage == MaterialShaderStage.Pixel) { if (!sameShadingModel) { continue; } // If same shading model, use temporarely the ParentPixelLayerContext parentStageContext = pendingPixelLayerContext; } // Add shaders except Pixels if we have a different ShadingModel parentStageContext.ShaderSources.AddRange(stageContext.ShaderSources); } var forceBlendingShadingModel = isLastChild && (parent.ShadingModelCount > 1 || !sameShadingModel); if (!sameShadingModel || forceBlendingShadingModel) { if (forceBlendingShadingModel && parent.BlendMapForShadingModel == null) { if (!sameShadingModel) { foreach (var shaderSource in pendingPixelLayerContext.ShaderSources) { parentPixelLayerContext.ShaderSources.Add(shaderSource); } pendingPixelLayerContext.Reset(); foreach (var shaderSource in parent.ShadingModels.Generate(this)) { parentPixelLayerContext.ShaderSources.Add(shaderSource); } parent.ShadingModels.Clear(); layer.ShadingModels.CopyTo(parent.ShadingModels); } parent.BlendMapForShadingModel = layer.BlendMap; var currentPixelLayerContext = layer.GetContextPerStage(MaterialShaderStage.Pixel); pendingPixelLayerContext.ShaderSources.AddRange(currentPixelLayerContext.ShaderSources); } // Do we need to blend shading model? if (parent.BlendMapForShadingModel != null) { var shaderBlendingSource = new ShaderMixinSource(); shaderBlendingSource.Mixins.Add(new ShaderClassSource("MaterialSurfaceShadingBlend")); parent.SetStreamBlend(MaterialShaderStage.Pixel, parent.BlendMapForShadingModel); // Add shader source already setup for the parent foreach (var shaderSource in pendingPixelLayerContext.ShaderSources) { shaderBlendingSource.AddCompositionToArray("layers", shaderSource); } // Add shader source generated for blending this layer foreach (var shaderSource in parent.ShadingModels.Generate(this)) { shaderBlendingSource.AddCompositionToArray("layers", shaderSource); } parent.ShadingModels.Clear(); parentPixelLayerContext.ShaderSources.Add(shaderBlendingSource); pendingPixelLayerContext.Reset(); parent.BlendMapForShadingModel = null; } else { foreach (var shaderSource in pendingPixelLayerContext.ShaderSources) { parentPixelLayerContext.ShaderSources.Add(shaderSource); } pendingPixelLayerContext.Reset(); foreach (var shaderSource in parent.ShadingModels.Generate(this)) { parentPixelLayerContext.ShaderSources.Add(shaderSource); } parent.ShadingModels.Clear(); parent.BlendMapForShadingModel = layer.BlendMap; // Copy the shading model of this layer to the parent layer.ShadingModels.CopyTo(parent.ShadingModels); } // If the shading model is different, the current attributes of the layer are not part of this blending // So they will contribute to the next blending if (!sameShadingModel && !forceBlendingShadingModel) { var currentPixelLayerContext = layer.GetContextPerStage(MaterialShaderStage.Pixel); pendingPixelLayerContext.ShaderSources.AddRange(currentPixelLayerContext.ShaderSources); } } }