Rasagar/Library/PackageCache/com.unity.shadergraph/Editor/Generation/ShaderGraphVfxAsset.cs
2024-08-26 23:07:20 +03:00

250 lines
8.0 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor.Graphing;
using UnityEditor.ShaderGraph.Serialization;
using UnityEngine;
using TextureDimension = UnityEngine.Rendering.TextureDimension;
namespace UnityEditor.ShaderGraph.Internal
{
[Serializable]
public struct TextureInfo
{
public TextureInfo(string name, Texture texture, TextureDimension dimension)
{
this.name = name;
this.texture = texture;
this.dimension = dimension;
Debug.Assert(texture == null || texture.dimension == dimension);
}
public string name;
public Texture texture;
public TextureDimension dimension;
public int instanceID => texture != null ? texture.GetInstanceID() : 0;
}
public sealed class ShaderGraphVfxAsset : ScriptableObject, ISerializationCallbackReceiver
{
private class ShaderGraphVfxAssetData : JsonObject
{
public List<JsonData<ShaderInput>> m_Properties = new();
}
public const int BaseColorSlotId = 1;
public const int MetallicSlotId = 2;
public const int SmoothnessSlotId = 3;
public const int NormalSlotId = 8;
public const int AlphaSlotId = 4;
public const int EmissiveSlotId = 5;
public const int ColorSlotId = 6;
public const int AlphaThresholdSlotId = 7;
[SerializeField]
public bool generatesWithShaderGraph;
[SerializeField]
public bool lit;
[SerializeField]
public bool alphaClipping;
[SerializeField]
internal ShaderStageCapability[] m_PropertiesStages;
[SerializeField]
internal GraphCompilationResult compilationResult;
[SerializeField]
internal ShaderGraphRequirements[] portRequirements;
[SerializeField]
string m_EvaluationFunctionName;
[SerializeField]
string m_InputStructName;
[SerializeField]
string m_OutputStructName;
[SerializeField]
ConcretePrecision m_ConcretePrecision = ConcretePrecision.Single;
ShaderGraphVfxAssetData m_Data = new ShaderGraphVfxAssetData();
[HideInInspector]
[SerializeField]
private SerializationHelper.JSONSerializedElement m_SerializedVfxAssetData;
[SerializeField]
internal IntArray[] outputPropertyIndices;
internal ConcretePrecision concretePrecision
{
get => m_ConcretePrecision;
set => m_ConcretePrecision = value;
}
[SerializeField]
OutputMetadata[] m_Outputs;
[SerializeField]
TextureInfo[] m_TextureInfos;
public IEnumerable<TextureInfo> textureInfos { get => m_TextureInfos; }
internal void SetTextureInfos(IList<PropertyCollector.TextureInfo> textures)
{
m_TextureInfos = textures.Select(t => new TextureInfo(t.name, EditorUtility.InstanceIDToObject(t.textureId) as Texture, t.dimension)).ToArray();
}
internal void SetOutputs(OutputMetadata[] outputs)
{
m_Outputs = outputs;
}
public OutputMetadata GetOutput(int id)
{
return m_Outputs.FirstOrDefault(t => t.id == id);
}
public bool HasOutput(int id)
{
return m_Outputs.Any(t => t.id == id);
}
public string evaluationFunctionName
{
get { return m_EvaluationFunctionName; }
internal set { m_EvaluationFunctionName = value; }
}
public string inputStructName
{
get { return m_InputStructName; }
internal set { m_InputStructName = value; }
}
public string outputStructName
{
get { return m_OutputStructName; }
internal set { m_OutputStructName = value; }
}
public List<ShaderInput> properties
{
get
{
EnsureProperties();
return m_Data.m_Properties.SelectValue().ToList();
}
}
public List<AbstractShaderProperty> fragmentProperties
{
get
{
EnsureProperties();
var allProperties = m_Data.m_Properties.SelectValue().ToList();
var fragProperties = new List<AbstractShaderProperty>();
for (var i = 0; i < allProperties.Count(); i++)
{
if (allProperties[i] is AbstractShaderProperty property
&& (m_PropertiesStages[i] & ShaderStageCapability.Fragment) != 0)
fragProperties.Add(property);
}
return fragProperties;
}
}
public List<AbstractShaderProperty> vertexProperties
{
get
{
EnsureProperties();
var allProperties = m_Data.m_Properties.SelectValue().ToList();
var vertexProperties = new List<AbstractShaderProperty>();
for (var i = 0; i < allProperties.Count(); i++)
{
if (allProperties[i] is AbstractShaderProperty property
&& (m_PropertiesStages[i] & ShaderStageCapability.Vertex) != 0)
vertexProperties.Add(property);
}
return vertexProperties;
}
}
internal void SetProperties(List<ShaderInput> propertiesList)
{
m_Data.m_Properties.Clear();
foreach (var property in propertiesList)
{
m_Data.m_Properties.Add(property);
}
var json = MultiJson.Serialize(m_Data);
m_SerializedVfxAssetData = new SerializationHelper.JSONSerializedElement() { JSONnodeData = json };
m_Data = null;
}
void EnsureProperties()
{
if ((m_Data == null || m_Data.m_Properties == null || !m_Data.m_Properties.Any()) && !String.IsNullOrEmpty(m_SerializedVfxAssetData.JSONnodeData))
{
m_Data = new ShaderGraphVfxAssetData();
MultiJson.Deserialize(m_Data, m_SerializedVfxAssetData.JSONnodeData);
}
foreach (var property in m_Data.m_Properties.SelectValue())
{
if (property is AbstractShaderProperty shaderProperty)
shaderProperty.SetupConcretePrecision(m_ConcretePrecision);
}
}
void ISerializationCallbackReceiver.OnAfterDeserialize()
{
m_Data = null;
}
void ISerializationCallbackReceiver.OnBeforeSerialize() { }
public GraphCode GetCode(OutputMetadata[] outputs)
{
var graphCode = new GraphCode();
graphCode.requirements = ShaderGraphRequirements.none;
var outputIndices = new int[outputs.Length];
for (var i = 0; i < outputs.Length; i++)
{
if (!outputs[i].isValid)
{
throw new ArgumentException($"Invalid {nameof(OutputMetadata)} at index {i}.", nameof(outputs));
}
outputIndices[i] = outputs[i].index;
graphCode.requirements = graphCode.requirements.Union(portRequirements[outputs[i].index]);
}
graphCode.code = compilationResult.GenerateCode(outputIndices);
var propertyIndexSet = new HashSet<int>();
foreach (var outputIndex in outputIndices)
{
foreach (var propertyIndex in outputPropertyIndices[outputIndex].array)
{
propertyIndexSet.Add(propertyIndex);
}
}
var propertyIndices = propertyIndexSet.ToArray();
Array.Sort(propertyIndices);
var filteredProperties = propertyIndices.Select(i => properties[i]).OfType<AbstractShaderProperty>().ToArray();
graphCode.properties = filteredProperties;
return graphCode;
}
}
}