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.
 
 
 
 

412 lines
18 KiB

using System;
using UnityEngine.Serialization;
using static Unity.Mathematics.math;
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.SceneManagement;
#endif
namespace UnityEngine.Rendering.HighDefinition
{
/// <summary>The scaling mode to apply to Local Volumetric Fog.</summary>
public enum LocalVolumetricFogScaleMode
{
/// <summary>Ignores the transformation hierarchy and uses the scale values in the Local Volumetric Fog component directly.</summary>
[InspectorName("Scale Invariant")]
ScaleInvariant,
/// <summary>Multiplies the lossy scale of the Transform with the Local Volumetric Fog's size then applies this to the Local Volumetric Fog component.</summary>
[InspectorName("Inherit from Hierarchy")]
InheritFromHierarchy,
}
/// <summary>Artist-friendly Local Volumetric Fog parametrization.</summary>
[Serializable]
public partial struct LocalVolumetricFogArtistParameters
{
/// <summary>Single scattering albedo: [0, 1]. Alpha is ignored.</summary>
[ColorUsage(false)]
public Color albedo;
/// <summary>Mean free path, in meters: [1, inf].</summary>
public float meanFreePath; // Should be chromatic - this is an optimization!
/// <summary>
/// Specifies how the fog in the volume will interact with the fog.
/// </summary>
public LocalVolumetricFogBlendingMode blendingMode;
/// <summary>
/// Rendering priority of the volume, higher priority will be rendered first.
/// </summary>
public int priority;
/// <summary>Anisotropy of the phase function: [-1, 1]. Positive values result in forward scattering, and negative values - in backward scattering.</summary>
[FormerlySerializedAs("asymmetry")]
public float anisotropy; // . Not currently available for Local Volumetric Fog
/// <summary>Texture containing density values.</summary>
public Texture volumeMask;
/// <summary>Scrolling speed of the density texture.</summary>
public Vector3 textureScrollingSpeed;
/// <summary>Tiling rate of the density texture.</summary>
public Vector3 textureTiling;
/// <summary>Edge fade factor along the positive X, Y and Z axes.</summary>
[FormerlySerializedAs("m_PositiveFade")]
public Vector3 positiveFade;
/// <summary>Edge fade factor along the negative X, Y and Z axes.</summary>
[FormerlySerializedAs("m_NegativeFade")]
public Vector3 negativeFade;
[SerializeField, FormerlySerializedAs("m_UniformFade")]
internal float m_EditorUniformFade;
[SerializeField]
internal Vector3 m_EditorPositiveFade;
[SerializeField]
internal Vector3 m_EditorNegativeFade;
[SerializeField, FormerlySerializedAs("advancedFade"), FormerlySerializedAs("m_AdvancedFade")]
internal bool m_EditorAdvancedFade;
/// <summary>The scaling mode to apply to Local Volumetric Fog.</summary>
public LocalVolumetricFogScaleMode scaleMode;
/// <summary>Dimensions of the volume.</summary>
public Vector3 size;
/// <summary>Inverts the fade gradient.</summary>
public bool invertFade;
/// <summary>Distance at which density fading starts.</summary>
public float distanceFadeStart;
/// <summary>Distance at which density fading ends.</summary>
public float distanceFadeEnd;
/// <summary>Allows translation of the tiling density texture.</summary>
[SerializeField, FormerlySerializedAs("volumeScrollingAmount")]
public Vector3 textureOffset;
/// <summary>When Blend Distance is above 0, controls which kind of falloff is applied to the transition area.</summary>
public LocalVolumetricFogFalloffMode falloffMode;
/// <summary>The mask mode to use when writing this volume in the volumetric fog.</summary>
public LocalVolumetricFogMaskMode maskMode;
/// <summary>The material used to mask the local volumetric fog when the mask mode is set to Material. The material needs to use the "Fog Volume" material type in Shader Graph.</summary>
public Material materialMask;
/// <summary>Minimum fog distance you can set in the meanFreePath parameter</summary>
internal const float kMinFogDistance = 0.05f;
/// <summary>Constructor.</summary>
/// <param name="color">Single scattering albedo.</param>
/// <param name="_meanFreePath">Mean free path.</param>
/// <param name="_anisotropy">Anisotropy.</param>
public LocalVolumetricFogArtistParameters(Color color, float _meanFreePath, float _anisotropy)
{
albedo = color;
meanFreePath = _meanFreePath;
blendingMode = LocalVolumetricFogBlendingMode.Additive;
priority = 0;
anisotropy = _anisotropy;
volumeMask = null;
materialMask = null;
textureScrollingSpeed = Vector3.zero;
textureTiling = Vector3.one;
textureOffset = textureScrollingSpeed;
scaleMode = LocalVolumetricFogScaleMode.ScaleInvariant;
size = Vector3.one;
positiveFade = Vector3.one * 0.1f;
negativeFade = Vector3.one * 0.1f;
invertFade = false;
distanceFadeStart = 10000;
distanceFadeEnd = 10000;
falloffMode = LocalVolumetricFogFalloffMode.Linear;
maskMode = LocalVolumetricFogMaskMode.Texture;
m_EditorPositiveFade = positiveFade;
m_EditorNegativeFade = negativeFade;
m_EditorUniformFade = 0.1f;
m_EditorAdvancedFade = false;
}
internal void Update(float time)
{
//Update scrolling based on deltaTime
if (volumeMask != null)
{
// Switch from right-handed to left-handed coordinate system.
textureOffset = -(textureScrollingSpeed * time);
}
}
internal void Constrain()
{
albedo.r = Mathf.Clamp01(albedo.r);
albedo.g = Mathf.Clamp01(albedo.g);
albedo.b = Mathf.Clamp01(albedo.b);
albedo.a = 1.0f;
meanFreePath = Mathf.Clamp(meanFreePath, kMinFogDistance, float.MaxValue);
anisotropy = Mathf.Clamp(anisotropy, -1.0f, 1.0f);
textureOffset = Vector3.zero;
distanceFadeStart = Mathf.Max(0, distanceFadeStart);
distanceFadeEnd = Mathf.Max(distanceFadeStart, distanceFadeEnd);
}
internal LocalVolumetricFogEngineData ConvertToEngineData()
{
LocalVolumetricFogEngineData data = new LocalVolumetricFogEngineData();
data.scattering = VolumeRenderingUtils.ScatteringFromExtinctionAndAlbedo(VolumeRenderingUtils.ExtinctionFromMeanFreePath(meanFreePath), (Vector4)albedo);
data.blendingMode = blendingMode;
data.textureScroll = textureOffset;
data.textureTiling = textureTiling;
// Clamp to avoid NaNs.
Vector3 positiveFade = this.positiveFade;
Vector3 negativeFade = this.negativeFade;
data.rcpPosFaceFade.x = Mathf.Min(1.0f / positiveFade.x, float.MaxValue);
data.rcpPosFaceFade.y = Mathf.Min(1.0f / positiveFade.y, float.MaxValue);
data.rcpPosFaceFade.z = Mathf.Min(1.0f / positiveFade.z, float.MaxValue);
data.rcpNegFaceFade.y = Mathf.Min(1.0f / negativeFade.y, float.MaxValue);
data.rcpNegFaceFade.x = Mathf.Min(1.0f / negativeFade.x, float.MaxValue);
data.rcpNegFaceFade.z = Mathf.Min(1.0f / negativeFade.z, float.MaxValue);
data.invertFade = invertFade ? 1 : 0;
data.falloffMode = falloffMode;
float distFadeLen = Mathf.Max(distanceFadeEnd - distanceFadeStart, 0.00001526f);
data.rcpDistFadeLen = 1.0f / distFadeLen;
data.endTimesRcpDistFadeLen = distanceFadeEnd * data.rcpDistFadeLen;
return data;
}
} // class LocalVolumetricFogParameters
/// <summary>Local Volumetric Fog class.</summary>
[HDRPHelpURLAttribute("create-a-local-fog-effect")]
[ExecuteAlways]
[AddComponentMenu("Rendering/Local Volumetric Fog")]
[Icon("Packages/com.unity.render-pipelines.core/Editor/Icons/Processed/LocalVolumetricFog Icon.asset")]
public partial class LocalVolumetricFog : MonoBehaviour
{
/// <summary>Local Volumetric Fog parameters.</summary>
public LocalVolumetricFogArtistParameters parameters = new LocalVolumetricFogArtistParameters(Color.white, 10.0f, 0.0f);
/// <summary>Action shich should be performed after updating the texture.</summary>
public Action OnTextureUpdated;
[NonSerialized]
MaterialPropertyBlock m_RenderingProperties;
[NonSerialized]
int m_GlobalIndex;
[NonSerialized]
internal Material textureMaterial;
/// <summary>stores the current effective scale, Vector3.one if the component is Scale Invariant, or lossy scale if the component Inherit From Hiearchy.</summary>
internal Vector3 effectiveScale;
/// <summary>stores the final scale of the local volumetric fog component.</summary>
internal Vector3 scaledSize;
/// <summary>Gather and Update any parameters that may have changed.</summary>
internal void PrepareParameters(float time)
{
parameters.Update(time);
}
private void OnEnable()
{
LocalVolumetricFogManager.manager.RegisterVolume(this);
#if UNITY_EDITOR
// Handle scene visibility
SceneVisibilityManager.visibilityChanged -= UpdateLocalVolumetricFogVisibility;
SceneVisibilityManager.visibilityChanged += UpdateLocalVolumetricFogVisibility;
SceneView.duringSceneGui -= UpdateLocalVolumetricFogVisibilityPrefabStage;
SceneView.duringSceneGui += UpdateLocalVolumetricFogVisibilityPrefabStage;
#endif
}
internal int GetGlobalIndex() => m_GlobalIndex;
internal void PrepareDrawCall(int globalIndex)
{
m_GlobalIndex = globalIndex;
if (!LocalVolumetricFogManager.manager.IsInitialized())
return;
if (m_RenderingProperties == null)
m_RenderingProperties = new MaterialPropertyBlock();
m_RenderingProperties.Clear();
m_RenderingProperties.SetInteger(HDShaderIDs._VolumetricFogGlobalIndex, m_GlobalIndex);
Material material = parameters.materialMask;
// Setup parameters for the default volumetric fog ShaderGraph
if (parameters.maskMode == LocalVolumetricFogMaskMode.Texture)
{
bool alphaTexture = false;
if (textureMaterial == null && HDRenderPipelineGlobalSettings.instance != null)
{
var runtimeShaders = GraphicsSettings.GetRenderPipelineSettings<HDRenderPipelineRuntimeShaders>();
textureMaterial = CoreUtils.CreateEngineMaterial(runtimeShaders.defaultFogVolumeShader);
}
// Setup properties for material:
FogVolumeAPI.SetupFogVolumeBlendMode(textureMaterial, parameters.blendingMode);
material = textureMaterial;
if (parameters.volumeMask != null)
{
m_RenderingProperties.SetTexture(HDShaderIDs._VolumetricMask, parameters.volumeMask);
textureMaterial.EnableKeyword("_ENABLE_VOLUMETRIC_FOG_MASK");
if (parameters.volumeMask is Texture3D t3d)
alphaTexture = t3d.format == TextureFormat.Alpha8;
}
else
{
textureMaterial.DisableKeyword("_ENABLE_VOLUMETRIC_FOG_MASK");
}
m_RenderingProperties.SetVector(HDShaderIDs._VolumetricScrollSpeed, parameters.textureScrollingSpeed);
m_RenderingProperties.SetVector(HDShaderIDs._VolumetricTiling, parameters.textureTiling);
m_RenderingProperties.SetFloat(HDShaderIDs._AlphaOnlyTexture, alphaTexture ? 1 : 0);
m_RenderingProperties.SetFloat(FogVolumeAPI.k_FogDistanceProperty, parameters.meanFreePath);
m_RenderingProperties.SetColor(FogVolumeAPI.k_SingleScatteringAlbedoProperty, parameters.albedo.gamma);
}
if (material == null)
return;
// We can put this in global
m_RenderingProperties.SetBuffer(HDShaderIDs._VolumetricMaterialData, LocalVolumetricFogManager.manager.volumetricMaterialDataBuffer);
effectiveScale = GetEffectiveScale(this.transform);
scaledSize = GetScaledSize(this.transform);
// Send local properties inside constants instead of structured buffer to optimize GPU reads
var engineData = parameters.ConvertToEngineData();
var tr = transform;
var position = tr.position;
var bounds = new OrientedBBox(Matrix4x4.TRS(position, tr.rotation, scaledSize));
m_RenderingProperties.SetVector(HDShaderIDs._VolumetricMaterialObbRight, bounds.right);
m_RenderingProperties.SetVector(HDShaderIDs._VolumetricMaterialObbUp, bounds.up);
m_RenderingProperties.SetVector(HDShaderIDs._VolumetricMaterialObbExtents, new Vector3(bounds.extentX, bounds.extentY, bounds.extentZ));
m_RenderingProperties.SetVector(HDShaderIDs._VolumetricMaterialObbCenter, bounds.center);
m_RenderingProperties.SetVector(HDShaderIDs._VolumetricMaterialRcpPosFaceFade, engineData.rcpPosFaceFade);
m_RenderingProperties.SetVector(HDShaderIDs._VolumetricMaterialRcpNegFaceFade, engineData.rcpNegFaceFade);
m_RenderingProperties.SetInteger(HDShaderIDs._VolumetricMaterialInvertFade, engineData.invertFade);
m_RenderingProperties.SetFloat(HDShaderIDs._VolumetricMaterialRcpDistFadeLen, engineData.rcpDistFadeLen);
m_RenderingProperties.SetFloat(HDShaderIDs._VolumetricMaterialEndTimesRcpDistFadeLen, engineData.endTimesRcpDistFadeLen);
m_RenderingProperties.SetInteger(HDShaderIDs._VolumetricMaterialFalloffMode, (int)engineData.falloffMode);
var AABBExtents = abs(bounds.right * bounds.extentX) +
abs(bounds.up * bounds.extentY) +
abs(bounds.forward * bounds.extentZ);
var AABB = new Bounds(bounds.center, AABBExtents * 2f);
var renderParams = new RenderParams
{
layer = gameObject.layer,
rendererPriority = parameters.priority,
worldBounds = AABB,
motionVectorMode = MotionVectorGenerationMode.ForceNoMotion,
reflectionProbeUsage = ReflectionProbeUsage.Off,
renderingLayerMask = 0xFFFFFFFF,
material = material,
matProps = m_RenderingProperties,
shadowCastingMode = ShadowCastingMode.Off,
receiveShadows = false,
lightProbeUsage = LightProbeUsage.Off,
#if UNITY_EDITOR
overrideSceneCullingMask = true,
sceneCullingMask = gameObject.sceneCullingMask,
#endif
};
Graphics.RenderPrimitivesIndexedIndirect(renderParams, MeshTopology.Triangles, LocalVolumetricFogManager.manager.volumetricMaterialIndexBuffer, LocalVolumetricFogManager.manager.globalIndirectBuffer, 1, m_GlobalIndex);
}
internal Vector3 GetEffectiveScale(Transform tr)
{
return (parameters.scaleMode == LocalVolumetricFogScaleMode.InheritFromHierarchy) ? tr.lossyScale : Vector3.one;
}
internal Vector3 GetScaledSize(Transform tr)
{
return Vector3.Max(Vector3.one * 0.001f, Vector3.Scale(parameters.size, GetEffectiveScale(tr)));
}
#if UNITY_EDITOR
void UpdateLocalVolumetricFogVisibility()
{
bool isVisible = !SceneVisibilityManager.instance.IsHidden(gameObject);
UpdateLocalVolumetricFogVisibility(isVisible);
}
void UpdateLocalVolumetricFogVisibilityPrefabStage(SceneView sv)
{
var stage = PrefabStageUtility.GetCurrentPrefabStage();
if (stage != null)
{
bool isVisible = true;
bool isInPrefabStage = gameObject.scene == stage.scene;
if (!isInPrefabStage && stage.mode == PrefabStage.Mode.InIsolation)
isVisible = false;
if (!isInPrefabStage && CoreUtils.IsSceneViewPrefabStageContextHidden())
isVisible = false;
UpdateLocalVolumetricFogVisibility(isVisible);
}
}
void UpdateLocalVolumetricFogVisibility(bool isVisible)
{
if (isVisible)
{
if (!LocalVolumetricFogManager.manager.ContainsVolume(this))
LocalVolumetricFogManager.manager.RegisterVolume(this);
}
else
{
if (LocalVolumetricFogManager.manager.ContainsVolume(this))
LocalVolumetricFogManager.manager.DeRegisterVolume(this);
}
}
#endif
private void OnDisable()
{
LocalVolumetricFogManager.manager.DeRegisterVolume(this);
#if UNITY_EDITOR
SceneVisibilityManager.visibilityChanged -= UpdateLocalVolumetricFogVisibility;
SceneView.duringSceneGui -= UpdateLocalVolumetricFogVisibilityPrefabStage;
#endif
}
private void OnValidate()
{
parameters.Constrain();
}
}
}