UnityGame/Library/PackageCache/com.unity.shadergraph/Editor/Data/Graphs/VirtualTextureShaderProperty.cs
2024-10-27 10:53:47 +03:00

227 lines
9.4 KiB
C#

using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using UnityEditor.ShaderGraph.Drawing.Controls;
using UnityEngine;
using UnityEditor.Graphing;
using UnityEditor.ShaderGraph.Internal;
namespace UnityEditor.ShaderGraph
{
[Serializable]
[BlackboardInputInfo(60)]
class VirtualTextureShaderProperty : AbstractShaderProperty<SerializableVirtualTexture>
{
public VirtualTextureShaderProperty()
{
displayName = "VirtualTexture";
value = new SerializableVirtualTexture();
// add at least one layer
value.layers = new List<SerializableVirtualTextureLayer>();
value.layers.Add(new SerializableVirtualTextureLayer("Layer0", new SerializableTexture()));
value.layers.Add(new SerializableVirtualTextureLayer("Layer1", new SerializableTexture()));
}
public override PropertyType propertyType => PropertyType.VirtualTexture;
internal override bool isExposable => true; // the textures are exposable at least..
internal override bool isRenamable => true;
internal override void GetPropertyReferenceNames(List<string> result)
{
result.Add(referenceName);
for (int layer = 0; layer < value.layers.Count; layer++)
{
result.Add(value.layers[layer].layerRefName);
}
}
internal override void GetPropertyDisplayNames(List<string> result)
{
result.Add(displayName);
for (int layer = 0; layer < value.layers.Count; layer++)
{
result.Add(value.layers[layer].layerName);
}
}
// this is used for properties exposed to the Material in the shaderlab Properties{} block
internal override void AppendPropertyBlockStrings(ShaderStringBuilder builder)
{
if (!value.procedural)
{
// adds properties in this format so: [TextureStack.MyStack(0)] [NoScaleOffset] Layer0("Layer0", 2D) = "white" {}
for (int layer = 0; layer < value.layers.Count; layer++)
{
string layerName = value.layers[layer].layerName;
string layerRefName = value.layers[layer].layerRefName;
builder.AppendLine($"{hideTagString}[TextureStack.{referenceName}({layer})][NoScaleOffset]{layerRefName}(\"{layerName}\", 2D) = \"white\" {{}}");
}
}
else
{
// For procedural VT, we only need to expose a single property, indicating the referenceName and the number of layers
// Adds a property as:
// [ProceduralTextureStack.MyStack(1)] [NoScaleOffset] MyStack("Procedural Virtual Texture", 2D) = "white" {}
// or:
// [GlobalProceduralTextureStack.MyStack(2)] [NoScaleOffset] MyStack("Procedural Virtual Texture", 2D) = "white" {}
string prefixString = value.shaderDeclaration == HLSLDeclaration.UnityPerMaterial
? "ProceduralTextureStack"
: "GlobalProceduralTextureStack";
int numLayers = value.layers.Count;
builder.AppendLine($"{hideTagString}[{prefixString}.{referenceName}({numLayers})][NoScaleOffset]{referenceName}(\"{"Procedural Virtual Texture"}\", 2D) = \"white\" {{}}");
}
}
internal override string GetPropertyBlockString()
{
// this should not be called, as it is replaced by the Append*PropertyBlockStrings function above
throw new NotSupportedException();
}
internal override bool AllowHLSLDeclaration(HLSLDeclaration decl) => false; // disable UI, nothing to choose
internal override void ForeachHLSLProperty(Action<HLSLProperty> action)
{
int numLayers = value.layers.Count;
if (numLayers > 0)
{
HLSLDeclaration decl = (value.procedural) ? value.shaderDeclaration : HLSLDeclaration.UnityPerMaterial;
action(new HLSLProperty(HLSLType._CUSTOM, referenceName + "_CBDecl", decl, concretePrecision)
{
customDeclaration = (ssb) =>
{
ssb.TryAppendIndentation();
ssb.Append("DECLARE_STACK_CB(");
ssb.Append(referenceName);
ssb.Append(");");
ssb.AppendNewLine();
}
});
if (!value.procedural)
{
//declare regular texture properties (for fallback case)
for (int i = 0; i < numLayers; i++)
{
string layerRefName = value.layers[i].layerRefName;
action(new HLSLProperty(HLSLType._Texture2D, layerRefName, HLSLDeclaration.Global));
action(new HLSLProperty(HLSLType._SamplerState, "sampler" + layerRefName, HLSLDeclaration.Global));
}
}
Action<ShaderStringBuilder> customDecl = (builder) =>
{
// declare texture stack
builder.TryAppendIndentation();
builder.Append("DECLARE_STACK");
builder.Append((numLayers <= 1) ? "" : numLayers.ToString());
builder.Append("(");
builder.Append(referenceName);
builder.Append(",");
for (int i = 0; i < value.layers.Count; i++)
{
if (i != 0) builder.Append(",");
builder.Append(value.layers[i].layerRefName);
}
builder.Append(");");
builder.AppendNewLine();
// declare the actual virtual texture property "variable" as a macro define to the BuildVTProperties function
builder.TryAppendIndentation();
builder.Append("#define ");
builder.Append(referenceName);
builder.Append(" AddTextureType(BuildVTProperties_");
builder.Append(referenceName);
builder.Append("()");
for (int i = 0; i < value.layers.Count; i++)
{
builder.Append(",");
builder.Append("TEXTURETYPE_");
builder.Append(value.layers[i].layerTextureType.ToString().ToUpper());
}
builder.Append(")");
builder.AppendNewLine();
};
action(new HLSLProperty(HLSLType._CUSTOM, referenceName + "_Global", HLSLDeclaration.Global, concretePrecision)
{
customDeclaration = customDecl
});
}
}
// argument string used to pass this property to a subgraph
internal override string GetPropertyAsArgumentString(string precisionString)
{
return "VTPropertyWithTextureType " + referenceName;
}
// if a blackboard property is deleted, or copy/pasted, all node instances of it are replaced with this:
internal override AbstractMaterialNode ToConcreteNode()
{
return null; // return null to indicate there is NO concrete form of a VT property
}
internal override PreviewProperty GetPreviewMaterialProperty()
{
return new PreviewProperty(propertyType)
{
name = referenceName,
vtProperty = this
};
}
internal override ShaderInput Copy()
{
var vt = new VirtualTextureShaderProperty
{
displayName = displayName,
value = new SerializableVirtualTexture(),
};
// duplicate layer data, but reset reference names (they should be unique)
for (int layer = 0; layer < value.layers.Count; layer++)
{
var guid = Guid.NewGuid();
vt.value.layers.Add(new SerializableVirtualTextureLayer(value.layers[layer]));
}
return vt;
}
internal void AddTextureInfo(List<PropertyCollector.TextureInfo> infos)
{
for (int layer = 0; layer < value.layers.Count; layer++)
{
string layerRefName = value.layers[layer].layerRefName;
var layerTexture = value.layers[layer].layerTexture;
var texture = layerTexture != null ? layerTexture.texture : null;
var textureInfo = new PropertyCollector.TextureInfo
{
name = layerRefName,
textureId = texture != null ? texture.GetInstanceID() : 0,
dimension = texture != null ? texture.dimension : UnityEngine.Rendering.TextureDimension.Any,
modifiable = true
};
infos.Add(textureInfo);
}
}
internal override bool isAlwaysExposed => true;
internal override bool isCustomSlotAllowed => false;
public override void OnAfterDeserialize(string json)
{
// VT shader properties must be exposed so they can be picked up by the native-side VT system
generatePropertyBlock = true;
}
}
}