|
|
|
|
|
|
using System; |
|
|
|
using System.Collections.Generic; |
|
|
|
using System.Reflection; |
|
|
|
[Serializable] |
|
|
|
[Title("Pixel Shader Node")] |
|
|
|
public class PixelShaderNode : AbstractMaterialNode, IGeneratesBodyCode |
|
|
|
[Serializable][Title("Math/Add Node")] |
|
|
|
public abstract class AbstractSurfaceMasterNode : AbstractMasterNode |
|
|
|
[SerializeField] |
|
|
|
private SerializationHelper.JSONSerializedElement m_SerializedLightFunction; |
|
|
|
|
|
|
|
[NonSerialized] |
|
|
|
private BaseLightFunction m_LightFunction = new PBRMetalicLightFunction(); |
|
|
|
|
|
|
|
private static List<BaseLightFunction> s_LightFunctions; |
|
|
|
|
|
|
|
public BaseLightFunction lightFunction |
|
|
|
{ |
|
|
|
get { return m_LightFunction; } |
|
|
|
set |
|
|
|
{ |
|
|
|
if (m_LightFunction == value) |
|
|
|
return; |
|
|
|
|
|
|
|
m_LightFunction = value; |
|
|
|
UpdateNodeAfterDeserialization(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public PixelShaderNode() |
|
|
|
{ |
|
|
|
name = "PixelMaster"; |
|
|
|
UpdateNodeAfterDeserialization(); |
|
|
|
} |
|
|
|
|
|
|
|
public sealed override void UpdateNodeAfterDeserialization() |
|
|
|
{ |
|
|
|
m_LightFunction.DoSlotsForConfiguration(this); |
|
|
|
} |
|
|
|
|
|
|
|
protected override bool generateDefaultInputs { get { return false; } } |
|
|
|
|
|
|
|
// public override bool canDeleteNode { get { return false; } }
|
|
|
|
|
|
|
|
public static List<BaseLightFunction> GetLightFunctions() |
|
|
|
{ |
|
|
|
if (s_LightFunctions == null) |
|
|
|
{ |
|
|
|
s_LightFunctions = new List<BaseLightFunction>(); |
|
|
|
|
|
|
|
foreach (Type type in Assembly.GetAssembly(typeof(BaseLightFunction)).GetTypes()) |
|
|
|
{ |
|
|
|
if (type.IsClass && !type.IsAbstract && (type.IsSubclassOf(typeof(BaseLightFunction)))) |
|
|
|
{ |
|
|
|
var func = Activator.CreateInstance(type) as BaseLightFunction; |
|
|
|
s_LightFunctions.Add(func); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
return s_LightFunctions; |
|
|
|
} |
|
|
|
|
|
|
|
public virtual void GenerateLightFunction(ShaderGenerator visitor) |
|
|
|
{ |
|
|
|
lightFunction.GenerateLightFunctionName(visitor); |
|
|
|
lightFunction.GenerateLightFunctionBody(visitor); |
|
|
|
} |
|
|
|
public const string AlbedoSlotName = "Albedo"; |
|
|
|
public const string NormalSlotName = "Normal"; |
|
|
|
public const string EmissionSlotName = "Emission"; |
|
|
|
public const string SmoothnessSlotName = "Smoothness"; |
|
|
|
public const string OcclusionSlotName = "Occlusion"; |
|
|
|
public const string AlphaSlotName = "Alpha"; |
|
|
|
public void GenerateSurfaceOutput(ShaderGenerator visitor) |
|
|
|
{ |
|
|
|
lightFunction.GenerateSurfaceOutputStructureName(visitor); |
|
|
|
} |
|
|
|
public const int AlbedoSlotId = 0; |
|
|
|
public const int NormalSlotId = 1; |
|
|
|
public const int EmissionSlotId = 3; |
|
|
|
public const int SmoothnessSlotId = 4; |
|
|
|
public const int OcclusionSlotId = 5; |
|
|
|
public const int AlphaSlotId = 6; |
|
|
|
public void GenerateNodeCode(ShaderGenerator shaderBody, GenerationMode generationMode) |
|
|
|
public override void GenerateNodeCode(ShaderGenerator shaderBody, GenerationMode generationMode) |
|
|
|
var firstPassSlotId = lightFunction.GetFirstPassSlotId(); |
|
|
|
// do the normal slot first so that it can be used later in the shader :)
|
|
|
|
var firstPassSlot = FindInputSlot<MaterialSlot>(firstPassSlotId); |
|
|
|
NodeUtils.DepthFirstCollectNodesFromNode(nodes, this, firstPassSlotId, NodeUtils.IncludeSelf.Exclude); |
|
|
|
|
|
|
|
for (int index = 0; index < nodes.Count; index++) |
|
|
|
{ |
|
|
|
var node = nodes[index]; |
|
|
|
if (node is IGeneratesBodyCode) |
|
|
|
(node as IGeneratesBodyCode).GenerateNodeCode(shaderBody, generationMode); |
|
|
|
} |
|
|
|
|
|
|
|
foreach (var edge in owner.GetEdges(firstPassSlot.slotReference)) |
|
|
|
{ |
|
|
|
var outputRef = edge.outputSlot; |
|
|
|
var fromNode = owner.GetNodeFromGuid<AbstractMaterialNode>(outputRef.nodeGuid); |
|
|
|
if (fromNode == null) |
|
|
|
continue; |
|
|
|
|
|
|
|
shaderBody.AddShaderChunk("o." + firstPassSlot.shaderOutputName + " = " + fromNode.GetVariableNameForSlot(outputRef.slotId) + ";", true); |
|
|
|
} |
|
|
|
|
|
|
|
// track the last index of nodes... they have already been processed :)
|
|
|
|
int pass2StartIndex = nodes.Count; |
|
|
|
for (var i = pass2StartIndex; i < nodes.Count; i++) |
|
|
|
for (var i = 0; i < nodes.Count; i++) |
|
|
|
{ |
|
|
|
var node = nodes[i]; |
|
|
|
if (node is IGeneratesBodyCode) |
|
|
|
|
|
|
|
|
|
|
foreach (var slot in GetInputSlots<MaterialSlot>()) |
|
|
|
{ |
|
|
|
if (slot == firstPassSlot) |
|
|
|
continue; |
|
|
|
|
|
|
|
foreach (var edge in owner.GetEdges(slot.slotReference)) |
|
|
|
{ |
|
|
|
var outputRef = edge.outputSlot; |
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
/* public override float GetNodeUIHeight(float width) |
|
|
|
{ |
|
|
|
return EditorGUIUtility.singleLineHeight; |
|
|
|
} |
|
|
|
[Serializable] |
|
|
|
[Title("Master/Metallic")] |
|
|
|
public class MetallicMasterNode : AbstractSurfaceMasterNode |
|
|
|
{ |
|
|
|
public const string MetallicSlotName = "Metallic"; |
|
|
|
public const int MetallicSlotId = 2; |
|
|
|
public override GUIModificationType NodeUI(Rect drawArea) |
|
|
|
{ |
|
|
|
var lightFunctions = GetLightFunctions(); |
|
|
|
var lightFunction = GetLightFunction(); |
|
|
|
public const string LightFunctionName = "Standard"; |
|
|
|
public const string SurfaceOutputStructureName = "SurfaceOutputStandard"; |
|
|
|
|
|
|
|
public MetallicMasterNode() |
|
|
|
{ |
|
|
|
name = "MetallicMasterNode"; |
|
|
|
UpdateNodeAfterDeserialization(); |
|
|
|
} |
|
|
|
int lightFuncIndex = 0; |
|
|
|
if (lightFunction != null) |
|
|
|
lightFuncIndex = lightFunctions.IndexOf(lightFunction); |
|
|
|
public sealed override void UpdateNodeAfterDeserialization() |
|
|
|
{ |
|
|
|
AddSlot(new MaterialSlot(AlbedoSlotId, AlbedoSlotName, AlbedoSlotName, SlotType.Input, SlotValueType.Vector3, Vector4.zero)); |
|
|
|
AddSlot(new MaterialSlot(NormalSlotId, NormalSlotName, NormalSlotName, SlotType.Input, SlotValueType.Vector3, Vector4.zero)); |
|
|
|
AddSlot(new MaterialSlot(EmissionSlotId, EmissionSlotName, EmissionSlotName, SlotType.Input, SlotValueType.Vector3, Vector4.zero)); |
|
|
|
AddSlot(new MaterialSlot(MetallicSlotId, MetallicSlotName, MetallicSlotName, SlotType.Input, SlotValueType.Vector1, Vector4.zero)); |
|
|
|
AddSlot(new MaterialSlot(SmoothnessSlotId, SmoothnessSlotName, SmoothnessSlotName, SlotType.Input, SlotValueType.Vector1, Vector4.zero)); |
|
|
|
AddSlot(new MaterialSlot(OcclusionSlotId, OcclusionSlotName, OcclusionSlotName, SlotType.Input, SlotValueType.Vector1, Vector4.zero)); |
|
|
|
AddSlot(new MaterialSlot(AlphaSlotId, AlphaSlotName, AlphaSlotName, SlotType.Input, SlotValueType.Vector1, Vector4.zero)); |
|
|
|
EditorGUI.BeginChangeCheck(); |
|
|
|
lightFuncIndex = EditorGUI.Popup(new Rect(drawArea.x, drawArea.y, drawArea.width, EditorGUIUtility.singleLineHeight), lightFuncIndex, lightFunctions.Select(x => x.GetLightFunctionName()).ToArray(), EditorStyles.popup); |
|
|
|
lightFunctionClassName = lightFunctions[lightFuncIndex].GetType().ToString(); |
|
|
|
if (EditorGUI.EndChangeCheck()) |
|
|
|
{ |
|
|
|
var function = GetLightFunction(); |
|
|
|
function.DoSlotsForConfiguration(this); |
|
|
|
owner.ValidateGraph(); |
|
|
|
return GUIModificationType.ModelChanged; |
|
|
|
} |
|
|
|
return GUIModificationType.None; |
|
|
|
}*/ |
|
|
|
// clear out slot names that do not match the slots
|
|
|
|
// we support
|
|
|
|
RemoveSlotsNameNotMatching( |
|
|
|
new[] |
|
|
|
{ |
|
|
|
AlbedoSlotId, |
|
|
|
NormalSlotId, |
|
|
|
EmissionSlotId, |
|
|
|
MetallicSlotId, |
|
|
|
SmoothnessSlotId, |
|
|
|
OcclusionSlotId, |
|
|
|
AlphaSlotId |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
public override void GenerateSurfaceOutput(ShaderGenerator surfaceOutput) |
|
|
|
{ |
|
|
|
surfaceOutput.AddPragmaChunk(SurfaceOutputStructureName); |
|
|
|
} |
|
|
|
public override IEnumerable<ISlot> GetInputsWithNoConnection() |
|
|
|
public override void GenerateLightFunction(ShaderGenerator lightFunction) |
|
|
|
return new List<ISlot>(); |
|
|
|
lightFunction.AddPragmaChunk(LightFunctionName); |
|
|
|
} |
|
|
|
public override bool hasPreview |
|
|
|
[Serializable] |
|
|
|
[Title("Master/Specular")] |
|
|
|
public class SpecularMasterNode : AbstractSurfaceMasterNode |
|
|
|
{ |
|
|
|
public const string SpecularSlotName = "Specular"; |
|
|
|
public const int SpecularSlotId = 2; |
|
|
|
|
|
|
|
public const string LightFunctionName = "StandardSpecular"; |
|
|
|
public const string SurfaceOutputStructureName = "SurfaceOutputStandardSpecular"; |
|
|
|
|
|
|
|
public SpecularMasterNode() |
|
|
|
get { return true; } |
|
|
|
name = "SpecularMasterNode"; |
|
|
|
UpdateNodeAfterDeserialization(); |
|
|
|
public override void OnBeforeSerialize() |
|
|
|
public sealed override void UpdateNodeAfterDeserialization() |
|
|
|
base.OnBeforeSerialize(); |
|
|
|
try |
|
|
|
{ |
|
|
|
m_SerializedLightFunction = SerializationHelper.Serialize(m_LightFunction); |
|
|
|
} |
|
|
|
catch (Exception e) |
|
|
|
{ |
|
|
|
Debug.LogException(e); |
|
|
|
} |
|
|
|
AddSlot(new MaterialSlot(AlbedoSlotId, AlbedoSlotName, AlbedoSlotName, SlotType.Input, SlotValueType.Vector3, Vector4.zero)); |
|
|
|
AddSlot(new MaterialSlot(NormalSlotId, NormalSlotName, NormalSlotName, SlotType.Input, SlotValueType.Vector3, Vector4.zero)); |
|
|
|
AddSlot(new MaterialSlot(EmissionSlotId, EmissionSlotName, EmissionSlotName, SlotType.Input, SlotValueType.Vector3, Vector4.zero)); |
|
|
|
AddSlot(new MaterialSlot(SpecularSlotId, SpecularSlotName, SpecularSlotName, SlotType.Input, SlotValueType.Vector1, Vector4.zero)); |
|
|
|
AddSlot(new MaterialSlot(SmoothnessSlotId, SmoothnessSlotName, SmoothnessSlotName, SlotType.Input, SlotValueType.Vector1, Vector4.zero)); |
|
|
|
AddSlot(new MaterialSlot(OcclusionSlotId, OcclusionSlotName, OcclusionSlotName, SlotType.Input, SlotValueType.Vector1, Vector4.zero)); |
|
|
|
AddSlot(new MaterialSlot(AlphaSlotId, AlphaSlotName, AlphaSlotName, SlotType.Input, SlotValueType.Vector1, Vector4.zero)); |
|
|
|
|
|
|
|
// clear out slot names that do not match the slots
|
|
|
|
// we support
|
|
|
|
RemoveSlotsNameNotMatching( |
|
|
|
new[] |
|
|
|
{ |
|
|
|
AlbedoSlotId, |
|
|
|
NormalSlotId, |
|
|
|
EmissionSlotId, |
|
|
|
SpecularSlotId, |
|
|
|
SmoothnessSlotId, |
|
|
|
OcclusionSlotId, |
|
|
|
AlphaSlotId |
|
|
|
}); |
|
|
|
public override void OnAfterDeserialize() |
|
|
|
public override void GenerateSurfaceOutput(ShaderGenerator surfaceOutput) |
|
|
|
try |
|
|
|
{ |
|
|
|
m_LightFunction = SerializationHelper.Deserialize<BaseLightFunction>(m_SerializedLightFunction); |
|
|
|
} |
|
|
|
catch (Exception e) |
|
|
|
{ |
|
|
|
Debug.LogException(e); |
|
|
|
} |
|
|
|
surfaceOutput.AddPragmaChunk(SurfaceOutputStructureName); |
|
|
|
} |
|
|
|
base.OnAfterDeserialize(); |
|
|
|
public override void GenerateLightFunction(ShaderGenerator lightFunction) |
|
|
|
{ |
|
|
|
lightFunction.AddPragmaChunk(LightFunctionName); |
|
|
|
} |
|
|
|
/* |
|
|
|
protected override bool UpdatePreviewShader() |
|
|
|
[Serializable] |
|
|
|
public abstract class AbstractMasterNode : AbstractMaterialNode, IGeneratesBodyCode |
|
|
|
{ |
|
|
|
protected override bool generateDefaultInputs { get { return false; } } |
|
|
|
|
|
|
|
public override IEnumerable<ISlot> GetInputsWithNoConnection() |
|
|
|
if (hasError) |
|
|
|
return false; |
|
|
|
return new List<ISlot>(); |
|
|
|
} |
|
|
|
var shaderName = "Hidden/PreviewShader/" + name + "_" + guid.ToString().Replace("-","_"); |
|
|
|
List<PropertyGenerator.TextureInfo> defaultTextures; |
|
|
|
//TODO: Fix me
|
|
|
|
var resultShader = string.Empty;//ShaderGenerator.GenerateSurfaceShader(materialGraphOwner.owner, shaderName, true, out defaultTextures);
|
|
|
|
m_GeneratedShaderMode = PreviewMode.Preview3D; |
|
|
|
hasError = !InternalUpdatePreviewShader(resultShader); |
|
|
|
return true; |
|
|
|
}*/ |
|
|
|
public override bool hasPreview |
|
|
|
{ |
|
|
|
get { return true; } |
|
|
|
} |
|
|
|
|
|
|
|
public abstract void GenerateNodeCode(ShaderGenerator visitor, GenerationMode generationMode); |
|
|
|
public abstract void GenerateSurfaceOutput (ShaderGenerator surfaceOutput); |
|
|
|
public abstract void GenerateLightFunction(ShaderGenerator lightFunction); |
|
|
|
} |
|
|
|
} |