You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

202 lines
12 KiB

using System.Collections;
using UnityEditor.Graphing;
using UnityEditor.ShaderGraph.Drawing.Controls;
using UnityEngine;
namespace UnityEditor.ShaderGraph
{
[Title("Terrain", "Terrain Texture")]
// should do this so the node is only available in the correct subtargets
// unclear how to accomplish this with a cross pipeline node, but pipeline specific targets
[SubTargetFilterAttribute(new[] { typeof(ITerrainSubTarget)})]
class TerrainTexture : AbstractMaterialNode, IGeneratesBodyCode, IGeneratesFunction
{
public TerrainTexture()
{
name = "Terrain Texture";
UpdateNodeAfterDeserialization();
}
const int InputIndexId = 0;
const int OutputTextureId = 1;
const int OutputAvailableId = 2;
const int NormalScaleId = 3;
const int MetallicDefaultId = 4;
const int SmoothnessDefaultId = 5;
const int DiffuseRemapId = 6;
const int OpacityAsDensityId = 7;
const int MaskRemapOffsetId = 8;
const int MaskRemapScaleId = 9;
const string kInputIndexSlotName = "Index";
const string kOutputTextureSlotName = "Texture";
const string kOutputAvailableSlotName = "Available";
const string kOutputNormalScaleSlotName = "Normal Scale";
const string kOutputMetallicDefaultSlotName = "Metallic Default";
const string kOutputSmoothnessDefaultSlotName = "Smoothness Default";
const string kOutputDiffuseRemapSlotName = "Color Tint";
// in the terrainLitInput this is called "_DiffuseRemapScaleX" (0-3) and stored only in the W component
const string kOutputOpacityAsDensitySlotName = "Opacity As Density";
const string kOutputMaskRemapOffsetSlotName = "Channel Remapping Offset";
const string kOutputMaskRemapScaleSlotName = "Channel Remapping Scale";
internal enum TextureType
{
DiffuseMap = 0,
NormalMap = 1,
MaskMap = 2,
LayerMasks = 3,
Holes
}
[SerializeField]
private TextureType m_TextureType;
[EnumControl("")]
public TextureType textureType
{
get { return m_TextureType; }
set { m_TextureType = value; Dirty(ModificationScope.Graph); }
}
public sealed override void UpdateNodeAfterDeserialization()
{
AddSlot(new Vector1MaterialSlot(InputIndexId, kInputIndexSlotName, kInputIndexSlotName, SlotType.Input, 0, literal:true));
AddSlot(new Texture2DMaterialSlot(OutputTextureId, kOutputTextureSlotName, kOutputTextureSlotName, SlotType.Output));
AddSlot(new BooleanMaterialSlot(OutputAvailableId, kOutputAvailableSlotName, kOutputAvailableSlotName, SlotType.Output, false));
AddSlot(new Vector1MaterialSlot(NormalScaleId, kOutputNormalScaleSlotName, kOutputNormalScaleSlotName, SlotType.Output, 1));
AddSlot(new Vector1MaterialSlot(MetallicDefaultId, kOutputMetallicDefaultSlotName, kOutputMetallicDefaultSlotName, SlotType.Output, 0.0f));
AddSlot(new Vector1MaterialSlot(SmoothnessDefaultId, kOutputSmoothnessDefaultSlotName, kOutputSmoothnessDefaultSlotName, SlotType.Output, 0.5f));
AddSlot(new Vector3MaterialSlot(DiffuseRemapId, kOutputDiffuseRemapSlotName, kOutputDiffuseRemapSlotName, SlotType.Output, new Vector3(1.0f, 1.0f, 1.0f)));
AddSlot(new Vector1MaterialSlot(OpacityAsDensityId, kOutputOpacityAsDensitySlotName, kOutputOpacityAsDensitySlotName, SlotType.Output, 1.0f));
AddSlot(new Vector4MaterialSlot(MaskRemapOffsetId, kOutputMaskRemapOffsetSlotName, kOutputMaskRemapOffsetSlotName, SlotType.Output, new Vector4(0.0f, 0.0f, 0.0f, 0.0f)));
AddSlot(new Vector4MaterialSlot(MaskRemapScaleId, kOutputMaskRemapScaleSlotName, kOutputMaskRemapScaleSlotName, SlotType.Output, new Vector4(1.0f, 1.0f, 1.0f, 1.0f)));
RemoveSlotsNameNotMatching(new[] { InputIndexId, OutputTextureId, OutputAvailableId, NormalScaleId, MetallicDefaultId, SmoothnessDefaultId, DiffuseRemapId, OpacityAsDensityId, MaskRemapOffsetId, MaskRemapScaleId });
}
private bool Any(IEnumerable collection)
{
foreach (var x in collection)
return true;
return false;
}
public void GenerateNodeCode(ShaderStringBuilder s, GenerationMode generationMode)
{
var availableEdge = owner.GetEdges(FindOutputSlot<MaterialSlot>(OutputAvailableId).slotReference);
var textureEdge = owner.GetEdges(FindOutputSlot<MaterialSlot>(OutputTextureId).slotReference);
var indexValue = GetSlotValue(InputIndexId, generationMode);
GenerateAdditionalParameterOutputs(s, generationMode, indexValue);
var outputTextureSlotType = FindOutputSlot<Texture2DMaterialSlot>(OutputTextureId).concreteValueType.ToShaderString();
if (generationMode.IsPreview())
{
if (Any(availableEdge)) s.AppendLine("$precision {0} = 1;", GetVariableNameForSlot(OutputAvailableId));
if (Any(textureEdge)) s.AppendLine("{0} {1} = UnityBuildTexture2DStructNoScale(_TerrainPreviewTexture);", outputTextureSlotType, GetVariableNameForSlot(OutputTextureId));
return;
}
void TextureAvailable(string textureName)
{
s.AppendLine("#if defined(SHADERGRAPH_PREVIEW) || defined(SHADERGRAPH_PREVIEW_MAIN)");
s.AppendLine("$precision {0} = 1.0f;", GetVariableNameForSlot(OutputAvailableId));
s.AppendLine("#else");
s.AppendLine("$precision {0} = Unity_TerrainTextureAvailable({1}, {2});", GetVariableNameForSlot(OutputAvailableId), textureName, indexValue);
s.AppendLine("#endif");
}
void TextureOutput(string textureName)
{
s.AppendLine("#if defined(SHADERGRAPH_PREVIEW) || defined(SHADERGRAPH_PREVIEW_MAIN)");
s.AppendLine("{0} {1} = UnityBuildTexture2DStruct(_TerrainPreviewTexture);", outputTextureSlotType, GetVariableNameForSlot(OutputTextureId));
s.AppendLine("#else");
s.AppendLine("{0} {1} = TerrainBuildUnityTexture2DStruct({2}, {3});", outputTextureSlotType, GetVariableNameForSlot(OutputTextureId), textureName, indexValue);
s.AppendLine("#endif");
}
switch (m_TextureType)
{
case TextureType.DiffuseMap:
if (Any(availableEdge)) TextureAvailable("_Splat");
if (Any(textureEdge)) TextureOutput("_Splat");
break;
case TextureType.NormalMap:
if (Any(availableEdge)) TextureAvailable("_Normal");
if (Any(textureEdge)) TextureOutput("_Normal");
break;
case TextureType.MaskMap:
if (Any(availableEdge)) TextureAvailable("_Mask");
if (Any(textureEdge)) TextureOutput("_Mask");
break;
case TextureType.LayerMasks:
if (Any(availableEdge)) TextureAvailable("_Control");
if (Any(textureEdge))
{
s.AppendLine("#if defined(SHADERGRAPH_PREVIEW) || defined(SHADERGRAPH_PREVIEW_MAIN)");
s.AppendLine("{0} {1} = UnityBuildTexture2DStruct(_TerrainPreviewTexture);", outputTextureSlotType, GetVariableNameForSlot(OutputTextureId));
s.AppendLine("#else");
s.AppendLine("{0} {1} = TerrainBuildUnityTextureControl({2});", outputTextureSlotType, GetVariableNameForSlot(OutputTextureId), indexValue);
s.AppendLine("#endif");
}
break;
case TextureType.Holes:
if (Any(availableEdge)) TextureAvailable("_Holes");
if (Any(textureEdge))
{
s.AppendLine("#if defined(SHADERGRAPH_PREVIEW) || defined(SHADERGRAPH_PREVIEW_MAIN)");
s.AppendLine("{0} {1} = UnityBuildTexture2DStruct(_TerrainPreviewTexture);", outputTextureSlotType, GetVariableNameForSlot(OutputTextureId));
s.AppendLine("#else");
s.AppendLine("{0} {1} = TerrainBuildUnityTextureHoles({2});", outputTextureSlotType, GetVariableNameForSlot(OutputTextureId), indexValue);
s.AppendLine("#endif");
}
break;
}
}
private void GenerateAdditionalParameterOutputs(ShaderStringBuilder s, GenerationMode generationMode, string indexValue)
{
var hasNormalScaleEdge = Any(owner.GetEdges(FindOutputSlot<MaterialSlot>(NormalScaleId).slotReference));
var hasMetallicDefaultEdge = Any(owner.GetEdges(FindOutputSlot<MaterialSlot>(MetallicDefaultId).slotReference));
var hasSmoothnessDefaultEdge = Any(owner.GetEdges(FindOutputSlot<MaterialSlot>(SmoothnessDefaultId).slotReference));
var hasDiffuseRemapEdge = Any(owner.GetEdges(FindOutputSlot<MaterialSlot>(DiffuseRemapId).slotReference));
var hasOpacityAsDensityEdge = Any(owner.GetEdges(FindOutputSlot<MaterialSlot>(OpacityAsDensityId).slotReference));
var hasMaskRemapOffsetEdge = Any(owner.GetEdges(FindOutputSlot<MaterialSlot>(MaskRemapOffsetId).slotReference));
var hasMaskRemapScaleEdge = Any(owner.GetEdges(FindOutputSlot<MaterialSlot>(MaskRemapScaleId).slotReference));
if (generationMode.IsPreview() || m_TextureType == TextureType.LayerMasks)
{
if (hasNormalScaleEdge) s.AppendLine("$precision {0} = 1;", GetVariableNameForSlot(NormalScaleId));
if (hasMetallicDefaultEdge) s.AppendLine("$precision {0} = 0;", GetVariableNameForSlot(MetallicDefaultId));
if (hasSmoothnessDefaultEdge) s.AppendLine("$precision {0} = 0.5f;", GetVariableNameForSlot(SmoothnessDefaultId));
if (hasDiffuseRemapEdge) s.AppendLine("$precision3 {0} = $precision3(1,1,1);", GetVariableNameForSlot(DiffuseRemapId));
if (hasOpacityAsDensityEdge) s.AppendLine("$precision {0} = 1;", GetVariableNameForSlot(OpacityAsDensityId));
if (hasMaskRemapOffsetEdge) s.AppendLine("$precision4 {0} = $precision4(0,0,0,0);", GetVariableNameForSlot(MaskRemapOffsetId));
if (hasMaskRemapScaleEdge) s.AppendLine("$precision4 {0} = $precision4(1,1,1,1);", GetVariableNameForSlot(MaskRemapScaleId));
return;
}
void AdditionalParameterOutput(string functionName, int outputId, string defaultValue, string precisionString = "", string channels = "")
{
s.AppendLine("#if defined(SHADERGRAPH_PREVIEW) || defined(SHADERGRAPH_PREVIEW_MAIN)");
s.AppendLine("$precision{0} {1} = {2};", precisionString, GetVariableNameForSlot(outputId), defaultValue);
s.AppendLine("#else");
s.AppendLine("$precision{0} {1} = Unity_Terrain_{2}({3}){4};", precisionString, GetVariableNameForSlot(outputId), functionName, indexValue, channels);
s.AppendLine("#endif");
}
if (hasNormalScaleEdge) AdditionalParameterOutput("NormalScale", NormalScaleId, "1");
if (hasMetallicDefaultEdge) AdditionalParameterOutput("Metallic", MetallicDefaultId, "0");
if (hasSmoothnessDefaultEdge) AdditionalParameterOutput("Smoothness", SmoothnessDefaultId, "0.5f");
if (hasDiffuseRemapEdge) AdditionalParameterOutput("DiffuseRemapScale", DiffuseRemapId, "$precision3(1,1,1)", "3", ".rgb");
if (hasOpacityAsDensityEdge) AdditionalParameterOutput("DiffuseRemapScale", OpacityAsDensityId, "1", "", ".w");
if (hasMaskRemapOffsetEdge) AdditionalParameterOutput("MaskMapRemapOffset", MaskRemapOffsetId, "$precision4(0,0,0,0)", "4");
if (hasMaskRemapScaleEdge) AdditionalParameterOutput("MaskMapRemapScale", MaskRemapScaleId, "$precision4(1,1,1,1)", "4");
}
public void GenerateNodeFunction(FunctionRegistry registry, GenerationMode generationMode)
{
registry.RequiresIncludePath("Packages/com.unity.render-pipelines.core/ShaderLibrary/Texture.hlsl");
registry.RequiresIncludePath("Packages/com.unity.shadergraph/Editor/Generation/Targets/Terrain/Includes/TerrainTextureVariables.hlsl");
}
}
}