227 lines
9.4 KiB
C#
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;
|
||
|
}
|
||
|
}
|
||
|
}
|