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.
344 lines
15 KiB
344 lines
15 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using UnityEngine.Rendering.HighDefinition;
|
|
using UnityEditor.ShaderGraph;
|
|
using UnityEditor.ShaderGraph.Internal;
|
|
using UnityEditor.Rendering.Fullscreen.ShaderGraph;
|
|
using UnityEngine;
|
|
using static UnityEngine.Rendering.HighDefinition.HDMaterial;
|
|
using static UnityEditor.Rendering.HighDefinition.HDFields;
|
|
using static UnityEngine.Rendering.HighDefinition.FogVolumeAPI;
|
|
|
|
namespace UnityEditor.Rendering.HighDefinition.ShaderGraph
|
|
{
|
|
using BlendMode = UnityEngine.Rendering.BlendMode;
|
|
using BlendOp = UnityEditor.ShaderGraph.BlendOp;
|
|
|
|
sealed partial class FogVolumeSubTarget : HDSubTarget, IRequiresData<FogVolumeData>
|
|
{
|
|
public FogVolumeSubTarget() => displayName = "Fog Volume";
|
|
|
|
static readonly GUID kSubTargetSourceCodeGuid = new GUID("0e63daeaa7722194d90b56081aa39ae6"); // FogVolumeSubTarget.cs
|
|
|
|
protected override string[] templateMaterialDirectories => new string[]
|
|
{
|
|
$"{HDUtils.GetHDRenderPipelinePath()}Editor/Material/FogVolume/ShaderGraph/"
|
|
};
|
|
protected override GUID subTargetAssetGuid => kSubTargetSourceCodeGuid;
|
|
protected override string customInspector => "Rendering.HighDefinition.FogVolumeShaderGUI";
|
|
internal override MaterialResetter setupMaterialKeywordsAndPassFunc => ShaderGraphAPI.ValidateFogVolumeMaterial;
|
|
protected override string renderType => HDRenderTypeTags.HDFogVolumeShader.ToString();
|
|
protected override string renderQueue { get; }
|
|
protected override string disableBatchingTag { get; }
|
|
protected override ShaderID shaderID => ShaderID.SG_FogVolume;
|
|
protected override FieldDescriptor subShaderField => new FieldDescriptor(kSubShader, "Fog Volume Subshader", "");
|
|
protected override string subShaderInclude => null;
|
|
protected override string templatePath => $"{HDUtils.GetHDRenderPipelinePath()}Editor/Material/FogVolume/ShaderGraph/Templates/FogVolume.template";
|
|
protected override bool supportRaytracing => false;
|
|
protected override bool supportPathtracing => false;
|
|
|
|
static readonly string k_SrcColorBlend = $"[{k_SrcColorBlendProperty}]";
|
|
static readonly string k_DstColorBlend = $"[{k_DstColorBlendProperty}]";
|
|
static readonly string k_SrcAlphaBlend = $"[{k_SrcAlphaBlendProperty}]";
|
|
static readonly string k_DstAlphaBlend = $"[{k_DstAlphaBlendProperty}]";
|
|
static readonly string k_ColorBlendOp = $"[{k_ColorBlendOpProperty}]";
|
|
static readonly string k_AlphaBlendOp = $"[{k_AlphaBlendOpProperty}]";
|
|
|
|
// Material Data
|
|
FogVolumeData m_FogVolumeData;
|
|
|
|
// Interface Properties
|
|
FogVolumeData IRequiresData<FogVolumeData>.data
|
|
{
|
|
get => m_FogVolumeData;
|
|
set => m_FogVolumeData = value;
|
|
}
|
|
|
|
// Public properties
|
|
public FogVolumeData fogVolumeData
|
|
{
|
|
get => m_FogVolumeData;
|
|
set => m_FogVolumeData = value;
|
|
}
|
|
|
|
protected override IEnumerable<SubShaderDescriptor> EnumerateSubShaders()
|
|
{
|
|
var subShader = new SubShaderDescriptor()
|
|
{
|
|
generatesPreview = true,
|
|
passes = new PassCollection
|
|
{
|
|
GetVoxelizePasses(),
|
|
ShaderGraphPreviewPass(),
|
|
ShaderGraphOverdrawDebugPass(),
|
|
}
|
|
};
|
|
yield return PostProcessSubShader(subShader);
|
|
}
|
|
|
|
protected override IEnumerable<KernelDescriptor> EnumerateKernels()
|
|
{
|
|
yield break;
|
|
}
|
|
|
|
public static StructDescriptor Varyings = new StructDescriptor()
|
|
{
|
|
name = "Varyings",
|
|
packFields = true,
|
|
populateWithCustomInterpolators = false,
|
|
fields = new FieldDescriptor[]
|
|
{
|
|
StructFields.Varyings.positionCS,
|
|
StructFields.Varyings.instanceID, // We always need both instanceId and vertexId
|
|
StructFields.Attributes.vertexID,
|
|
}
|
|
};
|
|
|
|
public static Blend BlendModeToBlend(BlendMode mode)
|
|
{
|
|
switch (mode)
|
|
{
|
|
case BlendMode.Zero: return Blend.Zero;
|
|
case BlendMode.One: return Blend.One;
|
|
case BlendMode.DstColor: return Blend.DstColor;
|
|
case BlendMode.SrcColor: return Blend.SrcColor;
|
|
case BlendMode.OneMinusDstColor: return Blend.OneMinusDstColor;
|
|
case BlendMode.SrcAlpha: return Blend.SrcAlpha;
|
|
case BlendMode.OneMinusSrcColor: return Blend.OneMinusSrcColor;
|
|
case BlendMode.DstAlpha: return Blend.DstAlpha;
|
|
case BlendMode.OneMinusDstAlpha: return Blend.OneMinusDstAlpha;
|
|
case BlendMode.SrcAlphaSaturate: return Blend.SrcAlpha;
|
|
case BlendMode.OneMinusSrcAlpha: return Blend.OneMinusSrcAlpha;
|
|
default: return Blend.Zero;
|
|
}
|
|
}
|
|
|
|
public static BlendOp BlendOpToBlendOp(UnityEngine.Rendering.BlendOp op)
|
|
{
|
|
switch (op)
|
|
{
|
|
case UnityEngine.Rendering.BlendOp.Add: return BlendOp.Add;
|
|
case UnityEngine.Rendering.BlendOp.Subtract: return BlendOp.Sub;
|
|
case UnityEngine.Rendering.BlendOp.ReverseSubtract: return BlendOp.RevSub;
|
|
case UnityEngine.Rendering.BlendOp.Min: return BlendOp.Min;
|
|
case UnityEngine.Rendering.BlendOp.Max: return BlendOp.Max;
|
|
default: return BlendOp.Add;
|
|
}
|
|
}
|
|
|
|
public static RenderStateCollection GetRenderState(LocalVolumetricFogBlendingMode mode)
|
|
{
|
|
return new RenderStateCollection{
|
|
{ RenderState.Cull(Cull.Off) },
|
|
{ RenderState.ZTest("Off") },
|
|
{ RenderState.ZWrite(ZWrite.Off) },
|
|
{ RenderState.Blend(k_SrcColorBlend, k_DstColorBlend, k_SrcAlphaBlend, k_DstAlphaBlend) },
|
|
{ RenderState.BlendOp(k_ColorBlendOp, k_AlphaBlendOp) }
|
|
};
|
|
}
|
|
|
|
StructDescriptor GetAttributes() => new StructDescriptor
|
|
{
|
|
name = "Attributes",
|
|
packFields = false,
|
|
fields = new FieldDescriptor[]
|
|
{
|
|
StructFields.Attributes.instanceID,
|
|
StructFields.Attributes.vertexID,
|
|
StructFields.Attributes.positionOS,
|
|
}
|
|
};
|
|
|
|
DefineCollection GetBlendModeDefine(LocalVolumetricFogBlendingMode mode)
|
|
{
|
|
return new DefineCollection
|
|
{
|
|
{ new KeywordDescriptor{ displayName = ToStringInvariant(mode), referenceName = $"FOG_VOLUME_BLENDING_{ ToStringInvariant(mode).ToUpper(CultureInfo.InvariantCulture)}" }, 1 },
|
|
};
|
|
}
|
|
|
|
private string ToStringInvariant(LocalVolumetricFogBlendingMode value)
|
|
{
|
|
return Enum.GetName(typeof(LocalVolumetricFogBlendingMode), value)?.ToString(CultureInfo.InvariantCulture);
|
|
}
|
|
|
|
PassCollection GetVoxelizePasses()
|
|
{
|
|
// Unfortunately we need to generate one pass per blend mode because we can't override the render state for one draw call :(
|
|
var blendModePasses = new PassCollection();
|
|
|
|
blendModePasses.Add(new PassDescriptor
|
|
{
|
|
// Definition
|
|
displayName = HDShaderPassNames.s_FogVolumeVoxelizeStr,
|
|
referenceName = "SHADERPASS_FOGVOLUME_VOXELIZATION",
|
|
lightMode = HDShaderPassNames.s_FogVolumeVoxelizeStr,
|
|
useInPreview = false,
|
|
|
|
// Port mask
|
|
validVertexBlocks = Array.Empty<BlockFieldDescriptor>(),
|
|
validPixelBlocks = FogVolumeBlocks.FragmentDefault,
|
|
|
|
structs = HDShaderPasses.GenerateStructs(new StructCollection
|
|
{
|
|
{ GetAttributes() },
|
|
{ Varyings },
|
|
}, TargetsVFX(), false),
|
|
pragmas = HDShaderPasses.GeneratePragmas(null, TargetsVFX(), false, false),
|
|
defines = HDShaderPasses.GenerateDefines(GetBlendModeDefine(fogVolumeData.blendMode), TargetsVFX(), false),
|
|
renderStates = GetRenderState(fogVolumeData.blendMode),
|
|
includes = FogVolumeIncludes.Voxelize,
|
|
});
|
|
|
|
return blendModePasses;
|
|
}
|
|
|
|
PassDescriptor ShaderGraphPreviewPass()
|
|
{
|
|
var pass = new PassDescriptor
|
|
{
|
|
// Definition
|
|
displayName = "ShaderGraphPreview",
|
|
referenceName = "SHADERPASS_FOGVOLUME_PREVIEW",
|
|
lightMode = "ShaderGraphPreview",
|
|
useInPreview = true,
|
|
|
|
// Port mask
|
|
validVertexBlocks = new BlockFieldDescriptor[0],
|
|
validPixelBlocks = FogVolumeBlocks.FragmentDefault,
|
|
|
|
structs = HDShaderPasses.GenerateStructs(new StructCollection
|
|
{
|
|
{ GetAttributes() },
|
|
{ Varyings },
|
|
}, TargetsVFX(), false),
|
|
pragmas = HDShaderPasses.GeneratePragmas(null, TargetsVFX(), false, false),
|
|
defines = HDShaderPasses.GenerateDefines(null, TargetsVFX(), false),
|
|
renderStates = GetRenderState(LocalVolumetricFogBlendingMode.Additive), // We can't change the blend mode in ShaderGraph
|
|
includes = FogVolumeIncludes.Preview,
|
|
};
|
|
|
|
return pass;
|
|
}
|
|
|
|
PassDescriptor ShaderGraphOverdrawDebugPass()
|
|
{
|
|
var pass = new PassDescriptor
|
|
{
|
|
// Definition
|
|
displayName = HDShaderPassNames.s_VolumetricFogVFXOverdrawDebugStr,
|
|
referenceName = "SHADERPASS_FOGVOLUME_OVERDRAW_DEBUG",
|
|
lightMode = HDShaderPassNames.s_VolumetricFogVFXOverdrawDebugStr,
|
|
useInPreview = true,
|
|
|
|
// Port mask
|
|
validVertexBlocks = new BlockFieldDescriptor[0],
|
|
validPixelBlocks = FogVolumeBlocks.FragmentDefault,
|
|
|
|
structs = HDShaderPasses.GenerateStructs(new StructCollection
|
|
{
|
|
{ GetAttributes() },
|
|
{ Varyings },
|
|
}, TargetsVFX(), false),
|
|
pragmas = HDShaderPasses.GeneratePragmas(null, TargetsVFX(), false, false),
|
|
defines = HDShaderPasses.GenerateDefines(null, TargetsVFX(), false),
|
|
renderStates = GetRenderState(LocalVolumetricFogBlendingMode.Additive), // Overdraw always uses additive blending
|
|
includes = FogVolumeIncludes.OverdrawDebug,
|
|
};
|
|
|
|
return pass;
|
|
}
|
|
|
|
public override void GetFields(ref TargetFieldContext context)
|
|
{
|
|
context.AddField(Fields.GraphVertex);
|
|
context.AddField(HDStructFields.FragInputs.positionRWS);
|
|
}
|
|
|
|
public override void GetActiveBlocks(ref TargetActiveBlockContext context)
|
|
{
|
|
context.AddBlock(BlockFields.SurfaceDescription.BaseColor);
|
|
context.AddBlock(BlockFields.SurfaceDescription.Alpha);
|
|
}
|
|
|
|
protected override void AddInspectorPropertyBlocks(SubTargetPropertiesGUI blockList)
|
|
{
|
|
blockList.AddPropertyBlock(new FogVolumePropertyBlock(fogVolumeData));
|
|
}
|
|
|
|
public override void CollectShaderProperties(PropertyCollector collector, GenerationMode generationMode)
|
|
{
|
|
base.CollectShaderProperties(collector, generationMode);
|
|
|
|
ComputeBlendParameters(fogVolumeData.blendMode, out var srcColorBlend, out var srcAlphaBlend, out var dstColorBlend, out var dstAlphaBlend, out var colorBlendOp, out var alphaBlendOp);
|
|
|
|
collector.AddEnumProperty(k_BlendModeProperty, fogVolumeData.blendMode, HLSLDeclaration.UnityPerMaterial);
|
|
collector.AddEnumProperty(k_DstColorBlendProperty, dstColorBlend);
|
|
collector.AddEnumProperty(k_SrcColorBlendProperty, srcColorBlend);
|
|
collector.AddEnumProperty(k_DstAlphaBlendProperty, dstAlphaBlend);
|
|
collector.AddEnumProperty(k_SrcAlphaBlendProperty, srcAlphaBlend);
|
|
collector.AddEnumProperty(k_ColorBlendOpProperty, colorBlendOp);
|
|
collector.AddEnumProperty(k_AlphaBlendOpProperty, alphaBlendOp);
|
|
|
|
collector.AddShaderProperty(new ColorShaderProperty
|
|
{
|
|
hidden = true,
|
|
value = Color.white,
|
|
overrideReferenceName = k_SingleScatteringAlbedoProperty,
|
|
generatePropertyBlock = true,
|
|
});
|
|
collector.AddFloatProperty(k_FogDistanceProperty, 10, HLSLDeclaration.UnityPerMaterial);
|
|
}
|
|
|
|
#region BlockMasks
|
|
static class FogVolumeBlocks
|
|
{
|
|
public static BlockFieldDescriptor[] FragmentDefault =
|
|
{
|
|
BlockFields.SurfaceDescription.BaseColor,
|
|
BlockFields.SurfaceDescription.Alpha,
|
|
};
|
|
}
|
|
#endregion
|
|
|
|
#region Includes
|
|
static class FogVolumeIncludes
|
|
{
|
|
const string kPacking = "Packages/com.unity.render-pipelines.core/ShaderLibrary/Packing.hlsl";
|
|
const string kColor = "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl";
|
|
const string kFunctions = "Packages/com.unity.shadergraph/ShaderGraphLibrary/Functions.hlsl";
|
|
const string kVoxelizePass = "Packages/com.unity.render-pipelines.high-definition/Editor/Material/FogVolume/ShaderGraph/ShaderPassVoxelize.hlsl";
|
|
const string kPreviewPass = "Packages/com.unity.render-pipelines.high-definition/Editor/Material/FogVolume/ShaderGraph/ShaderPassPreview.hlsl";
|
|
const string kOverdrawPass = "Packages/com.unity.render-pipelines.high-definition/Editor/Material/FogVolume/ShaderGraph/OverdrawDebug.hlsl";
|
|
|
|
public static IncludeCollection Voxelize = new IncludeCollection
|
|
{
|
|
{ kPacking, IncludeLocation.Pregraph },
|
|
{ kColor, IncludeLocation.Pregraph },
|
|
{ kFunctions, IncludeLocation.Pregraph },
|
|
{ CoreIncludes.MinimalCorePregraph },
|
|
{ kVoxelizePass, IncludeLocation.Postgraph },
|
|
};
|
|
|
|
public static IncludeCollection Preview = new IncludeCollection
|
|
{
|
|
{ kPacking, IncludeLocation.Pregraph },
|
|
{ kColor, IncludeLocation.Pregraph },
|
|
{ kFunctions, IncludeLocation.Pregraph },
|
|
{ CoreIncludes.MinimalCorePregraph },
|
|
{ kPreviewPass, IncludeLocation.Postgraph },
|
|
};
|
|
|
|
public static IncludeCollection OverdrawDebug = new IncludeCollection
|
|
{
|
|
{ kPacking, IncludeLocation.Pregraph },
|
|
{ kColor, IncludeLocation.Pregraph },
|
|
{ kFunctions, IncludeLocation.Pregraph },
|
|
{ CoreIncludes.MinimalCorePregraph },
|
|
{ kOverdrawPass, IncludeLocation.Postgraph },
|
|
};
|
|
}
|
|
#endregion
|
|
}
|
|
}
|