4 using System.Collections.Generic;
5 using System.Globalization;
8 using SiliconStudio.Assets;
9 using SiliconStudio.Core.Diagnostics;
10 using SiliconStudio.Core.Mathematics;
11 using SiliconStudio.Paradox.Assets.Materials.Nodes;
12 using SiliconStudio.Paradox.Effects;
13 using SiliconStudio.Paradox.Shaders;
15 namespace SiliconStudio.
Paradox.Assets.Materials.Processor.Visitors
19 #region Private constants
23 private const string BackgroundCompositionName =
"color1";
24 private const string ForegroundCompositionName =
"color2";
28 #region Private members
33 private Dictionary<string, ShaderBuildStatus> shaderBuildStatuses;
38 private bool shaderForReduction =
false;
43 private bool displacementShader =
false;
52 #region Public members
66 #region Public methods
70 shaderBuildStatuses = mat.Nodes.ToDictionary(x => x.Key, x => ShaderBuildStatus.None);
71 ModelShaderSources =
new Dictionary<string, ShaderSource>();
80 shaderForReduction =
true;
83 var allTextures = textureVisitor.GetAllTextureValues(materialNode);
84 textureVisitor.AssignDefaultTextureKeys(allTextures.Distinct(), null);
85 return GetShaderMixinSource(GetShaderSource(materialNode));
94 AssignModelTextureKeys();
95 ModelShaderSources =
new Dictionary<string, ShaderSource>();
97 shaderBuildStatuses = Material.Nodes.ToDictionary(x => x.Key, x => ShaderBuildStatus.None);
99 shaderForReduction =
false;
100 foreach (var reference
in Material.ColorNodes)
102 if (reference.Key != null)
104 if (reference.Value != null)
109 if (ModelShaderSources.TryGetValue(reference.Value, out shaderSource))
111 var sms = GetShaderMixinSource(shaderSource);
114 result.Add(reference.Key, sms);
119 Logger.Error(
"[Material] Shader creation failed. The key " + reference.Key.Name +
" did not produce any shader.");
123 Logger.Error(
"[Material] Shader creation failed. The key " + reference.Key.Name +
" in ColorNodes is not a ShaderMixinSource parameter key.");
126 constantValues.CopyTo(result);
132 #region Private methods
137 private void AssignModelTextureKeys()
140 var allTextures =
new List<MaterialTextureNode>();
141 var allSampler =
new List<NodeParameterSampler>();
142 foreach (var referenceName
in Material.ColorNodes.Select(x => x.Value))
144 var startNode = Material.FindNode(referenceName);
145 if (startNode != null)
147 allTextures.AddRange(textureVisitor.GetAllTextureValuesWithGenerics(startNode));
148 allSampler.AddRange(textureVisitor.GetAllSamplerValues(startNode));
151 textureVisitor.AssignDefaultTextureKeys(allTextures.Distinct(), allSampler.Distinct());
159 private void BeginShaderCreation(
string referenceName,
bool useForDisplacement)
161 if (referenceName == null || !shaderBuildStatuses.ContainsKey(referenceName))
164 displacementShader = useForDisplacement;
166 var status = shaderBuildStatuses[referenceName];
168 if (status == ShaderBuildStatus.None)
170 var node = Material.FindNode(referenceName);
173 Logger.Error(
"[Material] There is no node with the name " + referenceName +
".");
174 shaderBuildStatuses[referenceName] = ShaderBuildStatus.Completed;
178 shaderBuildStatuses[referenceName] = ShaderBuildStatus.InProgress;
179 ModelShaderSources[referenceName] = GetShaderSource(node);
180 shaderBuildStatuses[referenceName] = ShaderBuildStatus.Completed;
182 else if (status == ShaderBuildStatus.InProgress)
184 shaderBuildStatuses[referenceName] = ShaderBuildStatus.Completed;
185 Logger.Error(
"[Material] The node reference " + referenceName +
" is part of a cycle.");
194 private ShaderSource GetShaderSource(IMaterialNode node)
200 return GetShaderSource(node as MaterialFloatNode);
202 return GetShaderSource(node as MaterialFloat4Node);
204 return GetShaderSource(node as MaterialColorNode);
206 return GetShaderSource(node as MaterialTextureNode);
208 return GetShaderSource(node as MaterialShaderClassNode);
210 return GetShaderSource(node as MaterialBinaryNode);
213 var referenceName = (node as MaterialReferenceNode).Name;
214 if (shaderForReduction)
216 var refNode = Material.FindNode(referenceName);
217 return GetShaderSource(refNode);
221 if (referenceName == null)
223 Logger.Warning(
"[Material] The MaterialReferenceNode [" + node +
"] doesn't reference anything.");
227 BeginShaderCreation(referenceName, displacementShader);
230 if (!ModelShaderSources.TryGetValue(referenceName, out shaderSource))
238 throw new Exception(
"[Material] An unsupported material node was encountered during shader creation.");
246 private ShaderSource GetShaderSource(MaterialFloatNode node)
250 constantValues.Set(node.Key, node.Value);
262 private ShaderSource GetShaderSource(MaterialColorNode node)
266 constantValues.Set(node.Key, node.Value);
278 private ShaderSource GetShaderSource(MaterialFloat4Node node)
282 constantValues.Set(node.Key, node.Value);
294 private ShaderSource GetShaderSource(MaterialTextureNode node)
297 if (shaderForReduction)
298 usedTexcoord =
"TEXCOORD0";
300 usedTexcoord =
"TEXCOORD" + GetTextureIndex(node.
TexcoordIndex);
304 if (displacementShader)
321 private ShaderSource GetShaderSource(MaterialShaderClassNode node)
325 var mixinName = Path.GetFileNameWithoutExtension(node.MixinReference.Location);
327 object[] generics = null;
331 var mixinGenerics =
new List<object>();
334 var
generic = node.Generics[genericKey];
335 if (
generic is NodeParameterTexture)
337 var textureReference = ((NodeParameterTexture)
generic).Reference;
338 var foundNode = Material.FindNode(textureReference);
339 while (foundNode != null && !(foundNode is MaterialTextureNode))
341 var refNode = foundNode as MaterialReferenceNode;
345 foundNode = Material.FindNode(refNode.Name);
348 var foundTextureNode = foundNode as MaterialTextureNode;
349 if (foundTextureNode == null || foundTextureNode.UsedParameterKey == null)
351 Logger.Warning(
"[Material] The generic texture reference in node [" + node +
"] is incorrect.");
352 mixinGenerics.Add(
"Texturing.Texture0");
355 mixinGenerics.Add(foundTextureNode.UsedParameterKey.ToString());
357 else if (
generic is NodeParameterSampler)
359 var pk = ((NodeParameterSampler)
generic).SamplerParameterKey;
362 Logger.Warning(
"[Material] The generic sampler reference in node [" + node +
"] is incorrect.");
363 mixinGenerics.Add(
"Texturing.Sampler");
366 mixinGenerics.Add(pk.ToString());
368 else if (
generic is NodeParameterFloat)
369 mixinGenerics.Add(((NodeParameterFloat)
generic).Value.ToString(CultureInfo.InvariantCulture));
370 else if (
generic is NodeParameterInt)
371 mixinGenerics.Add(((NodeParameterInt)
generic).Value.ToString(CultureInfo.InvariantCulture));
372 else if (
generic is NodeParameterFloat2)
373 mixinGenerics.Add(GetAsShaderString(((NodeParameterFloat2)
generic).Value));
374 else if (
generic is NodeParameterFloat3)
375 mixinGenerics.Add(GetAsShaderString(((NodeParameterFloat3)
generic).Value));
376 else if (
generic is NodeParameterFloat4)
377 mixinGenerics.Add(GetAsShaderString(((NodeParameterFloat4)
generic).Value));
378 else if (
generic is NodeParameter)
379 mixinGenerics.Add(((NodeParameter)
generic).Reference);
381 throw new Exception(
"[Material] Unknown node type: " +
generic.GetType());
383 generics = mixinGenerics.ToArray();
389 return shaderClassSource;
392 mixin.Mixins.Add(shaderClassSource);
396 if (comp.Value != null)
398 var compShader = GetShaderSource(comp.Value);
399 if (compShader != null)
400 mixin.Compositions.Add(comp.Key, compShader);
412 private ShaderSource GetShaderSource(MaterialBinaryNode binaryNode)
414 var leftShaderSource = GetShaderSource(binaryNode.
LeftChild);
415 var rightShaderSource = GetShaderSource(binaryNode.
RightChild);
419 mixin.Mixins.Add(shaderSource);
420 if (leftShaderSource != null)
421 mixin.AddComposition(BackgroundCompositionName, leftShaderSource);
423 mixin.AddComposition(ForegroundCompositionName, rightShaderSource);
430 #region Private static methods
436 case TextureCoordinate.Texcoord0:
438 case TextureCoordinate.Texcoord1:
440 case TextureCoordinate.Texcoord2:
442 case TextureCoordinate.Texcoord3:
444 case TextureCoordinate.Texcoord4:
446 case TextureCoordinate.Texcoord5:
448 case TextureCoordinate.Texcoord6:
450 case TextureCoordinate.Texcoord7:
452 case TextureCoordinate.Texcoord8:
454 case TextureCoordinate.Texcoord9:
456 case TextureCoordinate.TexcoordNone:
458 throw new ArgumentOutOfRangeException(
"texcoord");
469 switch (materialBinaryOperand)
471 case MaterialBinaryOperand.Add:
472 return "ComputeColorAdd3ds";
473 case MaterialBinaryOperand.Average:
474 return "ComputeColorAverage";
475 case MaterialBinaryOperand.Color:
476 return "ComputeColorColor";
477 case MaterialBinaryOperand.ColorBurn:
478 return "ComputeColorColorBurn";
479 case MaterialBinaryOperand.ColorDodge:
480 return "ComputeColorColorDodge";
481 case MaterialBinaryOperand.Darken:
482 return "ComputeColorDarken3ds";
483 case MaterialBinaryOperand.Desaturate:
484 return "ComputeColorDesaturate";
485 case MaterialBinaryOperand.Difference:
486 return "ComputeColorDifference3ds";
487 case MaterialBinaryOperand.Divide:
488 return "ComputeColorDivide";
489 case MaterialBinaryOperand.Exclusion:
490 return "ComputeColorExclusion";
491 case MaterialBinaryOperand.HardLight:
492 return "ComputeColorHardLight";
493 case MaterialBinaryOperand.HardMix:
494 return "ComputeColorHardMix";
495 case MaterialBinaryOperand.Hue:
496 return "ComputeColorHue";
497 case MaterialBinaryOperand.Illuminate:
498 return "ComputeColorIlluminate";
499 case MaterialBinaryOperand.In:
500 return "ComputeColorIn";
501 case MaterialBinaryOperand.Lighten:
502 return "ComputeColorLighten3ds";
503 case MaterialBinaryOperand.LinearBurn:
504 return "ComputeColorLinearBurn";
505 case MaterialBinaryOperand.LinearDodge:
506 return "ComputeColorLinearDodge";
507 case MaterialBinaryOperand.Mask:
508 return "ComputeColorMask";
509 case MaterialBinaryOperand.Multiply:
510 return "ComputeColorMultiply";
511 case MaterialBinaryOperand.None:
512 return "ComputeColorNone";
513 case MaterialBinaryOperand.Opaque:
514 return "ComputeColorOpaque";
515 case MaterialBinaryOperand.Out:
516 return "ComputeColorOut";
517 case MaterialBinaryOperand.Over:
518 return "ComputeColorOver3ds";
519 case MaterialBinaryOperand.Overlay:
520 return "ComputeColorOverlay3ds";
521 case MaterialBinaryOperand.PinLight:
522 return "ComputeColorPinLight";
523 case MaterialBinaryOperand.Saturate:
524 return "ComputeColorSaturate";
525 case MaterialBinaryOperand.Saturation:
526 return "ComputeColorSaturation";
527 case MaterialBinaryOperand.Screen:
528 return "ComputeColorScreen";
529 case MaterialBinaryOperand.SoftLight:
530 return "ComputeColorSoftLight";
531 case MaterialBinaryOperand.Subtract:
532 return "ComputeColorSubtract3ds";
533 case MaterialBinaryOperand.SubstituteAlpha:
534 return "ComputeColorSubstituteAlpha";
536 throw new ArgumentOutOfRangeException(
"materialBinaryOperand");
540 private static string GetAsShaderString(
Vector2 v)
542 return String.Format(CultureInfo.InvariantCulture,
"float2({0}, {1})", v.X, v.Y);
545 private static string GetAsShaderString(
Vector3 v)
547 return String.Format(CultureInfo.InvariantCulture,
"float3({0}, {1}, {2})", v.X, v.Y, v.Z);
550 private static string GetAsShaderString(
Vector4 v)
552 return String.Format(CultureInfo.InvariantCulture,
"float4({0}, {1}, {2}, {3})", v.X, v.Y, v.Z, v.W);
555 private static string GetAsShaderString(
Color4 c)
557 return String.Format(CultureInfo.InvariantCulture,
"float4({0}, {1}, {2}, {3})", c.R, c.G, c.B, c.A);
560 private static string GetAsShaderString(
float f)
562 return String.Format(CultureInfo.InvariantCulture,
"float4({0}, {0}, {0}, {0})", f);
565 private static string GetAsShaderString(
object obj)
567 return obj.ToString();
580 mixin.Mixins.Add((ShaderClassSource)shaderSource);
584 return (ShaderMixinSource)shaderSource;
591 private enum ShaderBuildStatus
MaterialTreeShaderCreator(MaterialDescription mat)
T Value
The property to access the internal value
ParameterKey< SamplerState > SamplerParameterKey
The sampler key used in the shader.
TextureCoordinate TexcoordIndex
The texture coordinate used to sample the texture.
static readonly Vector2 Zero
A SiliconStudio.Core.Mathematics.Vector2 with all of its components set to zero.
A node that describe a binary operation between two IMaterialNode
Represents a two dimensional mathematical vector.
A mixin performing a combination of ShaderClassSource and other mixins.
SiliconStudio.Core.Diagnostics.LoggerResult LoggerResult
A logger that stores messages locally useful for internal log scenarios.
IMaterialNode LeftChild
The left (background) child node.
Dictionary< string, ShaderSource > ModelShaderSources
All the shaders.
Description of a material.
ParameterCollection GenerateModelShaders()
Generate all the shaders for this model, assign keys for texture and samplers.
Vector2 Offset
The offset in the texture coordinates.
Represents a three dimensional mathematical vector.
TextureCoordinate
The texture coordinate.
NodeParameterSampler Sampler
The sampler of the texture.
Represents a color in the form of rgba.
readonly LoggerResult Logger
The error logger.
Base implementation for ILogger.
static readonly Vector2 One
A SiliconStudio.Core.Mathematics.Vector2 with all of its components set to one.
MaterialBinaryOperand
Operands of the MaterialNode.
Represents a four dimensional mathematical vector.
ICollection< string > Keys
Vector2 Scale
The scale of the texture coordinates.
GenericDictionary Generics
The generics of this class.
ParameterKey< Graphics.Texture > UsedParameterKey
The parameter key used in the shader.
ShaderMixinSource GenerateShaderForReduction(IMaterialNode materialNode)
Generate one shader.
AssetReference< EffectShaderAsset > MixinReference
The shader.
ParameterKey< T > Key
The name of the parameter.
Base interface for all nodes in the material tree
static readonly ParameterKey< ShaderMixinSource > DisplacementMap
A container to handle a hierarchical collection of effect variables.
bool IsReducible
The flag to allow the node to be reducible.
A shader class used for mixin.
Dictionary< string, IMaterialNode > CompositionNodes
The compositions of this class.
IMaterialNode RightChild
The right (foreground) child node.
MaterialBinaryOperand Operand
The operation to blend the nodes.