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.
120 lines
4.8 KiB
120 lines
4.8 KiB
using System.Linq;
|
|
using UnityEngine;
|
|
using UnityEditor.Graphing;
|
|
using UnityEditor.ShaderGraph.Internal;
|
|
using UnityEditor.ShaderGraph.Drawing.Controls;
|
|
|
|
namespace UnityEditor.ShaderGraph
|
|
{
|
|
[Title("Input", "Texture", "Calculate Level Of Detail Texture 2D")]
|
|
class CalculateLevelOfDetailTexture2DNode : AbstractMaterialNode, IGeneratesBodyCode, IMayRequireMeshUV
|
|
{
|
|
[SerializeField]
|
|
bool m_Clamp = true;
|
|
|
|
[ToggleControl]
|
|
public ToggleData clamp
|
|
{
|
|
get => new ToggleData(m_Clamp);
|
|
set
|
|
{
|
|
m_Clamp = value.isOn;
|
|
Dirty(ModificationScope.Node);
|
|
}
|
|
}
|
|
|
|
public const int OutputSlotLODId = 0;
|
|
public const int TextureInputId = 1;
|
|
public const int UVInput = 2;
|
|
public const int SamplerInput = 3;
|
|
|
|
const string kOutputSlotLODName = "LOD";
|
|
const string kTextureInputName = "Texture";
|
|
const string kUVInputName = "UV";
|
|
const string kSamplerInputName = "Sampler";
|
|
|
|
public override bool hasPreview { get { return true; } }
|
|
|
|
public CalculateLevelOfDetailTexture2DNode()
|
|
{
|
|
name = "Calculate Level Of Detail Texture 2D";
|
|
UpdateNodeAfterDeserialization();
|
|
}
|
|
|
|
public sealed override void UpdateNodeAfterDeserialization()
|
|
{
|
|
AddSlot(new Vector1MaterialSlot(OutputSlotLODId, kOutputSlotLODName, kOutputSlotLODName, SlotType.Output, 0, ShaderStageCapability.Fragment));
|
|
AddSlot(new Texture2DInputMaterialSlot(TextureInputId, kTextureInputName, kTextureInputName));
|
|
AddSlot(new UVMaterialSlot(UVInput, kUVInputName, kUVInputName, UVChannel.UV0));
|
|
AddSlot(new SamplerStateMaterialSlot(SamplerInput, kSamplerInputName, kSamplerInputName, SlotType.Input));
|
|
|
|
RemoveSlotsNameNotMatching(new[] { OutputSlotLODId, TextureInputId, UVInput, SamplerInput });
|
|
}
|
|
|
|
public override void Setup()
|
|
{
|
|
base.Setup();
|
|
var textureSlot = FindInputSlot<Texture2DInputMaterialSlot>(TextureInputId);
|
|
textureSlot.defaultType = Texture2DShaderProperty.DefaultType.White;
|
|
}
|
|
|
|
// Node generations
|
|
public virtual void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode)
|
|
{
|
|
var uvName = GetSlotValue(UVInput, generationMode);
|
|
|
|
//Sampler input slot
|
|
var samplerSlot = FindInputSlot<MaterialSlot>(SamplerInput);
|
|
var edgesSampler = owner.GetEdges(samplerSlot.slotReference);
|
|
|
|
var id = GetSlotValue(TextureInputId, generationMode);
|
|
|
|
sb.AppendLine("#if (SHADER_TARGET >= 41)");
|
|
{
|
|
var func = m_Clamp ? "CalculateLevelOfDetail" : "CalculateLevelOfDetailUnclamped";
|
|
sb.AppendLine(string.Format("$precision {0} = {1}.tex.{2}({3}.samplerstate, {4});"
|
|
, GetVariableNameForSlot(OutputSlotLODId)
|
|
, id
|
|
, func
|
|
, edgesSampler.Any() ? GetSlotValue(SamplerInput, generationMode) : id
|
|
, uvName));
|
|
}
|
|
sb.AppendLine("#else");
|
|
{
|
|
var dUVdx = string.Format("ddx({0} * {1}.texelSize.zw)", uvName, id);
|
|
var dUVdy = string.Format("ddy({0} * {1}.texelSize.zw)", uvName, id);
|
|
var delta_max_sqr = string.Format("max(dot({0}, {0}), dot({1}, {1}))", dUVdx, dUVdy);
|
|
sb.AppendLine(string.Format("$precision {0};", GetVariableNameForSlot(OutputSlotLODId)));
|
|
sb.AppendLine(string.Format("{0} = 0.5f*log2({1});", GetVariableNameForSlot(OutputSlotLODId), delta_max_sqr));
|
|
sb.AppendLine(string.Format("{0} = max({0}, 0);", GetVariableNameForSlot(OutputSlotLODId)));
|
|
if (m_Clamp)
|
|
{
|
|
sb.AppendLine("#if defined(MIP_COUNT_SUPPORTED)");
|
|
sb.AppendLine(string.Format("{0} = min({0}, GetMipCount(TEXTURE2D_ARGS({1}.tex, {2}.samplerstate))-1);", GetVariableNameForSlot(OutputSlotLODId), id, edgesSampler.Any() ? GetSlotValue(SamplerInput, generationMode) : id));
|
|
sb.AppendLine("#endif");
|
|
}
|
|
}
|
|
sb.AppendLine("#endif");
|
|
}
|
|
|
|
public bool RequiresMeshUV(UVChannel channel, ShaderStageCapability stageCapability)
|
|
{
|
|
using (var tempSlots = PooledList<MaterialSlot>.Get())
|
|
{
|
|
GetInputSlots(tempSlots);
|
|
var result = false;
|
|
foreach (var slot in tempSlots)
|
|
{
|
|
if (slot.RequiresMeshUV(channel))
|
|
{
|
|
result = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
tempSlots.Clear();
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
}
|