This commit is contained in:
2025-05-16 23:31:59 +08:00
parent 9e4fef3f1e
commit d891e3f0ee
1198 changed files with 274242 additions and 1558 deletions

View File

@@ -0,0 +1,621 @@
#if DEBUG
//#define DEBUG_SHOW_MESH_NORMALS
#endif
#define FORCE_CURRENT_CAMERA_DEPTH_TEXTURE_MODE
#if UNITY_2018_1_OR_NEWER
#define VLB_SRP_SUPPORT // Comment this to disable SRP support
#endif
using UnityEngine;
using System.Collections;
#pragma warning disable 0429, 0162 // Unreachable expression code detected (because of Noise3D.isSupported on mobile)
namespace VLB
{
[AddComponentMenu("")] // hide it from Component search
[ExecuteInEditMode]
[HelpURL(Consts.Help.SD.UrlBeam)]
public class BeamGeometrySD : BeamGeometryAbstractBase, MaterialModifier.Interface
{
VolumetricLightBeamSD m_Master = null;
MeshType m_CurrentMeshType = MeshType.Shared;
MaterialModifier.Callback m_MaterialModifierCallback = null;
Coroutine m_CoFadeOut = null;
protected override VolumetricLightBeamAbstractBase GetMaster() { return m_Master; }
bool visible
{
get { return meshRenderer.enabled; }
set { meshRenderer.enabled = value; }
}
public int sortingLayerID
{
get { return meshRenderer.sortingLayerID; }
set { meshRenderer.sortingLayerID = value; }
}
public int sortingOrder
{
get { return meshRenderer.sortingOrder; }
set { meshRenderer.sortingOrder = value; }
}
public bool _INTERNAL_IsFadeOutCoroutineRunning { get { return m_CoFadeOut != null; } }
float ComputeFadeOutFactor(Transform camTransform)
{
if (m_Master.isFadeOutEnabled)
{
float distanceCamToBeam = Vector3.SqrMagnitude(meshRenderer.bounds.center - camTransform.position);
return Mathf.InverseLerp(m_Master.fadeOutEnd * m_Master.fadeOutEnd, m_Master.fadeOutBegin * m_Master.fadeOutBegin, distanceCamToBeam);
}
else
{
return 1.0f;
}
}
IEnumerator CoUpdateFadeOut()
{
while (m_Master.isFadeOutEnabled)
{
ComputeFadeOutFactor();
yield return null;
}
SetFadeOutFactorProp(1.0f);
m_CoFadeOut = null;
}
void ComputeFadeOutFactor()
{
var camTransform = Config.Instance.fadeOutCameraTransform;
if (camTransform)
{
float fadeOutFactor = ComputeFadeOutFactor(camTransform);
SetFadeOutFactorProp(fadeOutFactor);
}
else
{
SetFadeOutFactorProp(1.0f);
}
}
void SetFadeOutFactorProp(float value)
{
if (value > 0)
{
meshRenderer.enabled = true;
MaterialChangeStart();
SetMaterialProp(ShaderProperties.SD.FadeOutFactor, value);
MaterialChangeStop();
}
else
{
meshRenderer.enabled = false;
}
}
void StopFadeOutCoroutine()
{
if (m_CoFadeOut != null)
{
StopCoroutine(m_CoFadeOut);
m_CoFadeOut = null;
}
}
public void RestartFadeOutCoroutine()
{
#if UNITY_EDITOR
if (Application.isPlaying)
#endif
{
StopFadeOutCoroutine();
if (m_Master && m_Master.isFadeOutEnabled)
{
m_CoFadeOut = StartCoroutine(CoUpdateFadeOut());
}
}
}
public void OnMasterEnable()
{
visible = true;
RestartFadeOutCoroutine();
}
public void OnMasterDisable()
{
StopFadeOutCoroutine();
visible = false;
}
#if VLB_SRP_SUPPORT
Camera m_CurrentCameraRenderingSRP = null;
void OnDisable()
{
SRPHelper.UnregisterOnBeginCameraRendering(OnBeginCameraRenderingSRP);
m_CurrentCameraRenderingSRP = null;
}
public static bool isCustomRenderPipelineSupported { get { return true; } }
#else
public static bool isCustomRenderPipelineSupported { get { return false; } }
#endif
bool shouldUseGPUInstancedMaterial
{ get {
return m_Master._INTERNAL_DynamicOcclusionMode != MaterialManager.SD.DynamicOcclusion.DepthTexture // sampler cannot be passed to shader as instanced property
&& Config.Instance.GetActualRenderingMode(ShaderMode.SD) == RenderingMode.GPUInstancing;
}}
void OnEnable()
{
// When a GAO is disabled, all its coroutines are killed, so renable them on OnEnable.
RestartFadeOutCoroutine();
#if VLB_SRP_SUPPORT
SRPHelper.RegisterOnBeginCameraRendering(OnBeginCameraRenderingSRP);
#endif
}
public void Initialize(VolumetricLightBeamSD master)
{
Debug.Assert(master != null);
var customHideFlags = Consts.Internal.ProceduralObjectsHideFlags;
m_Master = master;
transform.SetParent(master.transform, false);
meshRenderer = gameObject.GetOrAddComponent<MeshRenderer>();
meshRenderer.hideFlags = customHideFlags;
meshRenderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
meshRenderer.receiveShadows = false;
meshRenderer.reflectionProbeUsage = UnityEngine.Rendering.ReflectionProbeUsage.Off; // different reflection probes could break batching with GPU Instancing
meshRenderer.lightProbeUsage = UnityEngine.Rendering.LightProbeUsage.Off;
if (!shouldUseGPUInstancedMaterial)
{
m_CustomMaterial = Config.Instance.NewMaterialTransient(ShaderMode.SD, gpuInstanced:false);
ApplyMaterial();
}
if (SortingLayer.IsValid(m_Master.sortingLayerID))
sortingLayerID = m_Master.sortingLayerID;
else
Debug.LogError(string.Format("Beam '{0}' has an invalid sortingLayerID ({1}). Please fix it by setting a valid layer.", Utils.GetPath(m_Master.transform), m_Master.sortingLayerID));
sortingOrder = m_Master.sortingOrder;
meshFilter = gameObject.GetOrAddComponent<MeshFilter>();
meshFilter.hideFlags = customHideFlags;
gameObject.hideFlags = customHideFlags;
#if UNITY_EDITOR
UnityEditor.GameObjectUtility.SetStaticEditorFlags(gameObject, master.GetStaticEditorFlagsForSubObjects());
gameObject.SetSameSceneVisibilityStatesThan(master.gameObject);
#endif
RestartFadeOutCoroutine();
}
/// <summary>
/// Generate the cone mesh and calls UpdateMaterialAndBounds.
/// Since this process involves recreating a new mesh, make sure to not call it at every frame during playtime.
/// </summary>
public void RegenerateMesh(bool masterEnabled)
{
Debug.Assert(m_Master);
if (Config.Instance.geometryOverrideLayer)
gameObject.layer = Config.Instance.geometryLayerID;
else
gameObject.layer = m_Master.gameObject.layer;
gameObject.tag = Config.Instance.geometryTag;
if (coneMesh && m_CurrentMeshType == MeshType.Custom)
{
DestroyImmediate(coneMesh);
}
m_CurrentMeshType = m_Master.geomMeshType;
switch (m_Master.geomMeshType)
{
case MeshType.Custom:
{
coneMesh = MeshGenerator.GenerateConeZ_Radii(1f, 1f, 1f, m_Master.geomCustomSides, m_Master.geomCustomSegments, m_Master.geomCap, Config.Instance.SD_requiresDoubleSidedMesh);
coneMesh.hideFlags = Consts.Internal.ProceduralObjectsHideFlags;
meshFilter.mesh = coneMesh;
break;
}
case MeshType.Shared:
{
coneMesh = GlobalMeshSD.Get();
meshFilter.sharedMesh = coneMesh;
break;
}
default:
{
Debug.LogError("Unsupported MeshType");
break;
}
}
UpdateMaterialAndBounds();
visible = masterEnabled;
}
Vector3 ComputeLocalMatrix()
{
// In the VS, we compute the vertices so the whole beam fits into a fixed 2x2x1 box.
// We have to apply some scaling to get the proper beam size.
// This way we have the proper bounds without having to recompute specific bounds foreach beam.
var maxRadius = Mathf.Max(m_Master.coneRadiusStart, m_Master.coneRadiusEnd);
transform.localScale = new Vector3(maxRadius, maxRadius, m_Master.maxGeometryDistance);
transform.localRotation = m_Master.beamInternalLocalRotation;
return transform.localScale;
}
bool isNoiseEnabled { get { return m_Master.isNoiseEnabled && m_Master.noiseIntensity > 0f && Noise3D.isSupported; } } // test Noise3D.isSupported the last
#pragma warning disable 0162
bool isDepthBlendEnabled { get { return BatchingHelper.forceEnableDepthBlend || m_Master.depthBlendDistance > 0f; } }
#pragma warning restore 0162
MaterialManager.StaticPropertiesSD ComputeMaterialStaticProperties()
{
var colorGradient = MaterialManager.ColorGradient.Off;
if (m_Master.colorMode == ColorMode.Gradient)
{
var precision = Utils.GetFloatPackingPrecision();
colorGradient = precision == Utils.FloatPackingPrecision.High ? MaterialManager.ColorGradient.MatrixHigh : MaterialManager.ColorGradient.MatrixLow;
}
Debug.Assert((int)BlendingMode.Additive == (int)MaterialManager.BlendingMode.Additive);
Debug.Assert((int)BlendingMode.SoftAdditive == (int)MaterialManager.BlendingMode.SoftAdditive);
Debug.Assert((int)BlendingMode.TraditionalTransparency == (int)MaterialManager.BlendingMode.TraditionalTransparency);
return new MaterialManager.StaticPropertiesSD
{
blendingMode = (MaterialManager.BlendingMode)m_Master.blendingMode,
noise3D = isNoiseEnabled ? MaterialManager.Noise3D.On : MaterialManager.Noise3D.Off,
depthBlend = isDepthBlendEnabled ? MaterialManager.SD.DepthBlend.On : MaterialManager.SD.DepthBlend.Off,
colorGradient = colorGradient,
dynamicOcclusion = m_Master._INTERNAL_DynamicOcclusionMode_Runtime,
meshSkewing = m_Master.hasMeshSkewing ? MaterialManager.SD.MeshSkewing.On : MaterialManager.SD.MeshSkewing.Off,
shaderAccuracy = (m_Master.shaderAccuracy == ShaderAccuracy.Fast) ? MaterialManager.SD.ShaderAccuracy.Fast : MaterialManager.SD.ShaderAccuracy.High
};
}
bool ApplyMaterial()
{
var staticProps = ComputeMaterialStaticProperties();
Material mat = null;
if (!shouldUseGPUInstancedMaterial)
{
mat = m_CustomMaterial;
if(mat)
staticProps.ApplyToMaterial(mat);
}
else
{
mat = MaterialManager.GetInstancedMaterial(m_Master._INTERNAL_InstancedMaterialGroupID, ref staticProps);
}
meshRenderer.material = mat;
return mat != null;
}
public void SetMaterialProp(int nameID, float value)
{
if (m_CustomMaterial)
m_CustomMaterial.SetFloat(nameID, value);
else
MaterialManager.materialPropertyBlock.SetFloat(nameID, value);
}
public void SetMaterialProp(int nameID, Vector4 value)
{
if (m_CustomMaterial)
m_CustomMaterial.SetVector(nameID, value);
else
MaterialManager.materialPropertyBlock.SetVector(nameID, value);
}
public void SetMaterialProp(int nameID, Color value)
{
if (m_CustomMaterial)
m_CustomMaterial.SetColor(nameID, value);
else
MaterialManager.materialPropertyBlock.SetColor(nameID, value);
}
public void SetMaterialProp(int nameID, Matrix4x4 value)
{
if (m_CustomMaterial)
m_CustomMaterial.SetMatrix(nameID, value);
else
MaterialManager.materialPropertyBlock.SetMatrix(nameID, value);
}
public void SetMaterialProp(int nameID, Texture value)
{
if (m_CustomMaterial)
m_CustomMaterial.SetTexture(nameID, value);
else
Debug.LogError("Setting a Texture property to a GPU instanced material is not supported");
}
void MaterialChangeStart()
{
if (m_CustomMaterial == null)
meshRenderer.GetPropertyBlock(MaterialManager.materialPropertyBlock);
}
void MaterialChangeStop()
{
if (m_CustomMaterial == null)
meshRenderer.SetPropertyBlock(MaterialManager.materialPropertyBlock);
}
public void SetDynamicOcclusionCallback(string shaderKeyword, MaterialModifier.Callback cb)
{
m_MaterialModifierCallback = cb;
if (m_CustomMaterial)
{
m_CustomMaterial.SetKeywordEnabled(shaderKeyword, cb != null);
if (cb != null)
cb(this);
}
else
UpdateMaterialAndBounds();
}
public void UpdateMaterialAndBounds()
{
Debug.Assert(m_Master);
if (ApplyMaterial() == false)
{
return;
}
MaterialChangeStart();
{
if (m_CustomMaterial == null)
{
if(m_MaterialModifierCallback != null)
m_MaterialModifierCallback(this);
}
float slopeRad = (m_Master.coneAngle * Mathf.Deg2Rad) / 2; // use coneAngle (instead of spotAngle) which is more correct with the geometry
SetMaterialProp(ShaderProperties.SD.ConeSlopeCosSin, new Vector2(Mathf.Cos(slopeRad), Mathf.Sin(slopeRad)));
// kMinRadius and kMinApexOffset prevents artifacts when fresnel computation is done in the vertex shader
const float kMinRadius = 0.0001f;
var coneRadius = new Vector2(Mathf.Max(m_Master.coneRadiusStart, kMinRadius), Mathf.Max(m_Master.coneRadiusEnd, kMinRadius));
SetMaterialProp(ShaderProperties.ConeRadius, coneRadius);
const float kMinApexOffset = 0.0001f;
float nonNullApex = Mathf.Sign(m_Master.coneApexOffsetZ) * Mathf.Max(Mathf.Abs(m_Master.coneApexOffsetZ), kMinApexOffset);
SetMaterialProp(ShaderProperties.ConeGeomProps, new Vector2(nonNullApex, m_Master.geomSides));
if (m_Master.usedColorMode == ColorMode.Flat)
{
SetMaterialProp(ShaderProperties.ColorFlat, m_Master.color);
}
else
{
var precision = Utils.GetFloatPackingPrecision();
m_ColorGradientMatrix = m_Master.colorGradient.SampleInMatrix((int)precision);
// pass the gradient matrix in OnWillRenderObject()
}
float intensityInside, intensityOutside;
m_Master.GetInsideAndOutsideIntensity(out intensityInside, out intensityOutside);
SetMaterialProp(ShaderProperties.SD.AlphaInside, intensityInside);
SetMaterialProp(ShaderProperties.SD.AlphaOutside, intensityOutside);
SetMaterialProp(ShaderProperties.SD.AttenuationLerpLinearQuad, m_Master.attenuationLerpLinearQuad);
SetMaterialProp(ShaderProperties.DistanceFallOff, new Vector3(m_Master.fallOffStart, m_Master.fallOffEnd, m_Master.maxGeometryDistance));
SetMaterialProp(ShaderProperties.SD.DistanceCamClipping, m_Master.cameraClippingDistance);
SetMaterialProp(ShaderProperties.SD.FresnelPow, Mathf.Max(0.001f, m_Master.fresnelPow)); // no pow 0, otherwise will generate inf fresnel and issues on iOS
SetMaterialProp(ShaderProperties.SD.GlareBehind, m_Master.glareBehind);
SetMaterialProp(ShaderProperties.SD.GlareFrontal, m_Master.glareFrontal);
SetMaterialProp(ShaderProperties.SD.DrawCap, m_Master.geomCap ? 1 : 0);
SetMaterialProp(ShaderProperties.SD.TiltVector, m_Master.tiltFactor);
SetMaterialProp(ShaderProperties.SD.AdditionalClippingPlaneWS, m_Master.additionalClippingPlane);
if (Config.Instance.isHDRPExposureWeightSupported)
{
SetMaterialProp(ShaderProperties.HDRPExposureWeight, m_Master.hdrpExposureWeight);
}
if (isDepthBlendEnabled)
{
SetMaterialProp(ShaderProperties.SD.DepthBlendDistance, m_Master.depthBlendDistance);
}
if (isNoiseEnabled)
{
Noise3D.LoadIfNeeded();
var noiseVelocity = m_Master.noiseVelocityUseGlobal ? Config.Instance.globalNoiseVelocity : m_Master.noiseVelocityLocal;
var noiseScale = m_Master.noiseScaleUseGlobal ? Config.Instance.globalNoiseScale : m_Master.noiseScaleLocal;
SetMaterialProp(ShaderProperties.NoiseVelocityAndScale, new Vector4(
noiseVelocity.x,
noiseVelocity.y,
noiseVelocity.z,
noiseScale));
SetMaterialProp(ShaderProperties.NoiseParam, new Vector2(
m_Master.noiseIntensity,
m_Master.noiseMode == NoiseMode.WorldSpace ? 0f : 1f));
}
var localScale = ComputeLocalMatrix(); // compute matrix before sending it to the shader
if (m_Master.hasMeshSkewing)
{
var localForwardDirectionNormalized = m_Master.skewingLocalForwardDirectionNormalized;
SetMaterialProp(ShaderProperties.SD.LocalForwardDirection, localForwardDirectionNormalized);
if (coneMesh != null) // coneMesh can be null few frames with Dynamic Occlusion & GPU Instancing
{
var localForwardDirectionN = localForwardDirectionNormalized;
localForwardDirectionN /= localForwardDirectionN.z;
localForwardDirectionN *= m_Master.fallOffEnd;
localForwardDirectionN.x /= localScale.x;
localForwardDirectionN.y /= localScale.y;
var bounds = MeshGenerator.ComputeBounds(1f, 1f, 1f);
var min = bounds.min;
var max = bounds.max;
if (localForwardDirectionN.x > 0.0f) max.x += localForwardDirectionN.x;
else min.x += localForwardDirectionN.x;
if (localForwardDirectionN.y > 0.0f) max.y += localForwardDirectionN.y;
else min.y += localForwardDirectionN.y;
bounds.min = min;
bounds.max = max;
coneMesh.bounds = bounds;
}
}
#if VLB_SRP_SUPPORT
// This update is to make QA test 'ReflectionObliqueProjection' pass
UpdateMatricesPropertiesForGPUInstancingSRP();
#endif
}
MaterialChangeStop();
#if DEBUG_SHOW_MESH_NORMALS
for (int vertexInd = 0; vertexInd < coneMesh.vertexCount; vertexInd++)
{
var vertex = coneMesh.vertices[vertexInd];
// apply modification done inside VS
vertex.x *= Mathf.Lerp(coneRadius.x, coneRadius.y, vertex.z);
vertex.y *= Mathf.Lerp(coneRadius.x, coneRadius.y, vertex.z);
vertex.z *= m_Master.fallOffEnd;
var cosSinFlat = new Vector2(vertex.x, vertex.y).normalized;
var normal = new Vector3(cosSinFlat.x * Mathf.Cos(slopeRad), cosSinFlat.y * Mathf.Cos(slopeRad), -Mathf.Sin(slopeRad)).normalized;
vertex = transform.TransformPoint(vertex);
normal = transform.TransformDirection(normal);
Debug.DrawRay(vertex, normal * 0.25f);
}
#endif
}
#if VLB_SRP_SUPPORT
void UpdateMatricesPropertiesForGPUInstancingSRP()
{
if (SRPHelper.IsUsingCustomRenderPipeline() && Config.Instance.GetActualRenderingMode(ShaderMode.SD) == RenderingMode.GPUInstancing)
{
SetMaterialProp(ShaderProperties.LocalToWorldMatrix, transform.localToWorldMatrix);
SetMaterialProp(ShaderProperties.WorldToLocalMatrix, transform.worldToLocalMatrix);
}
}
#if UNITY_2019_1_OR_NEWER
void OnBeginCameraRenderingSRP(UnityEngine.Rendering.ScriptableRenderContext context, Camera cam)
#else
void OnBeginCameraRenderingSRP(Camera cam)
#endif
{
m_CurrentCameraRenderingSRP = cam;
}
#endif
void OnWillRenderObject()
{
Camera currentCam = null;
#if VLB_SRP_SUPPORT
if (SRPHelper.IsUsingCustomRenderPipeline())
{
currentCam = m_CurrentCameraRenderingSRP;
}
else
#endif
{
currentCam = Camera.current;
}
OnWillCameraRenderThisBeam(currentCam);
}
void OnWillCameraRenderThisBeam(Camera cam)
{
if (m_Master && cam)
{
if (
#if UNITY_EDITOR
Utils.IsEditorCamera(cam) || // make sure to call UpdateCameraRelatedProperties for editor scene camera
#endif
cam.enabled) // prevent from doing stuff when we render from a previous DynamicOcclusionDepthBuffer's DepthCamera, because the DepthCamera are disabled
{
UpdateCameraRelatedProperties(cam);
m_Master._INTERNAL_OnWillCameraRenderThisBeam(cam);
}
}
}
void UpdateCameraRelatedProperties(Camera cam)
{
if (cam && m_Master)
{
MaterialChangeStart();
{
var camPosOS = m_Master.transform.InverseTransformPoint(cam.transform.position);
var camForwardVectorOSN = transform.InverseTransformDirection(cam.transform.forward).normalized;
float camIsInsideBeamFactor = cam.orthographic ? -1f : m_Master.GetInsideBeamFactorFromObjectSpacePos(camPosOS);
SetMaterialProp(ShaderProperties.SD.CameraParams, new Vector4(camForwardVectorOSN.x, camForwardVectorOSN.y, camForwardVectorOSN.z, camIsInsideBeamFactor));
#if VLB_SRP_SUPPORT
// This update is to be able to move beams without trackChangesDuringPlaytime enabled with SRP & GPU Instancing
UpdateMatricesPropertiesForGPUInstancingSRP();
#endif
if (m_Master.usedColorMode == ColorMode.Gradient)
{
// Send the gradient matrix every frame since it's not a shader's property
SetMaterialProp(ShaderProperties.ColorGradientMatrix, m_ColorGradientMatrix);
}
}
MaterialChangeStop();
#if FORCE_CURRENT_CAMERA_DEPTH_TEXTURE_MODE
if (m_Master.depthBlendDistance > 0f)
cam.depthTextureMode |= DepthTextureMode.Depth;
#endif
}
}
#if UNITY_EDITOR
public int _EDITOR_InstancedMaterialID { get { return ComputeMaterialStaticProperties().GetMaterialID(); } }
#endif
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 50a48a2b69575db4c8b5bf5aa8186d89
timeCreated: 1504793414
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,185 @@
using UnityEngine;
using UnityEngine.Serialization;
namespace VLB
{
[AddComponentMenu("")] // hide it from Component search
[DisallowMultipleComponent]
[RequireComponent(typeof(VolumetricLightBeamSD))]
public abstract class DynamicOcclusionAbstractBase : MonoBehaviour
{
public const string ClassName = "DynamicOcclusionAbstractBase";
/// <summary>
/// How often will the occlusion be processed?
/// Try to update the occlusion as rarely as possible to keep good performance.
/// </summary>
public DynamicOcclusionUpdateRate updateRate = Consts.DynOcclusion.UpdateRateDefault;
/// <summary>
/// How many frames we wait between 2 occlusion tests?
/// If you want your beam to be super responsive to the changes of your environment, update it every frame by setting 1.
/// If you want to save on performance, we recommend to wait few frames between each update by setting a higher value.
/// </summary>
[FormerlySerializedAs("waitFrameCount")]
public int waitXFrames = Consts.DynOcclusion.WaitFramesCountDefault;
/// <summary>
/// Manually process the occlusion.
/// You have to call this function in order to update the occlusion when using DynamicOcclusionUpdateRate.Never.
/// </summary>
public void ProcessOcclusionManually() { ProcessOcclusion(ProcessOcclusionSource.User); }
public event System.Action onOcclusionProcessed;
public static bool _INTERNAL_ApplyRandomFrameOffset = true;
protected enum ProcessOcclusionSource
{
RenderLoop,
OnEnable,
EditorUpdate,
User,
}
protected void ProcessOcclusion(ProcessOcclusionSource source)
{
if (!Config.Instance.featureEnabledDynamicOcclusion)
return;
if (m_LastFrameRendered == Time.frameCount && Application.isPlaying && source == ProcessOcclusionSource.OnEnable)
return; // allow to call ProcessOcclusion from OnEnable (when disabling/enabling multiple a beam on the same frame) without generating an error
Debug.Assert(!Application.isPlaying || m_LastFrameRendered != Time.frameCount, "ProcessOcclusion has been called twice on the same frame, which is forbidden");
Debug.Assert(m_Master);
bool occlusionSuccess = OnProcessOcclusion(source);
if(onOcclusionProcessed != null)
onOcclusionProcessed();
if (m_Master)
{
Debug.Assert(m_MaterialModifierCallbackCached != null);
m_Master._INTERNAL_SetDynamicOcclusionCallback(GetShaderKeyword(), occlusionSuccess ? m_MaterialModifierCallbackCached : (MaterialModifier.Callback)(null));
}
if (updateRate.HasFlag(DynamicOcclusionUpdateRate.OnBeamMove))
m_TransformPacked = transform.GetWorldPacked();
bool firstTime = m_LastFrameRendered < 0;
m_LastFrameRendered = Time.frameCount;
if (firstTime && _INTERNAL_ApplyRandomFrameOffset)
{
m_LastFrameRendered += Random.Range(0, waitXFrames); // add a random offset to prevent from updating texture for all beams having the same wait value
}
}
TransformUtils.Packed m_TransformPacked;
int m_LastFrameRendered = int.MinValue;
public int _INTERNAL_LastFrameRendered { get { return m_LastFrameRendered; } } // for unit tests
protected VolumetricLightBeamSD m_Master = null;
protected MaterialModifier.Callback m_MaterialModifierCallbackCached = null;
protected abstract string GetShaderKeyword();
protected abstract MaterialManager.SD.DynamicOcclusion GetDynamicOcclusionMode();
protected abstract bool OnProcessOcclusion(ProcessOcclusionSource source);
protected abstract void OnModifyMaterialCallback(MaterialModifier.Interface owner);
protected abstract void OnEnablePostValidate();
protected virtual void OnValidateProperties()
{
waitXFrames = Mathf.Clamp(waitXFrames, 1, 60);
}
protected virtual void Awake()
{
m_Master = GetComponent<VolumetricLightBeamSD>();
Debug.Assert(m_Master);
m_Master._INTERNAL_DynamicOcclusionMode = GetDynamicOcclusionMode();
}
protected virtual void OnDestroy()
{
m_Master._INTERNAL_DynamicOcclusionMode = MaterialManager.SD.DynamicOcclusion.Off;
DisableOcclusion();
}
protected virtual void OnEnable()
{
// cache the delegate to prevent from being inlined as '() => OnModifyMaterialCallback' when calling _INTERNAL_SetDynamicOcclusionCallback and from generating GC garbage
m_MaterialModifierCallbackCached = OnModifyMaterialCallback;
OnValidateProperties();
OnEnablePostValidate();
#if UNITY_EDITOR
if (Application.isPlaying)
#endif
{
m_Master.onWillCameraRenderThisBeam += OnWillCameraRender;
if (!updateRate.HasFlag(DynamicOcclusionUpdateRate.Never))
m_Master.RegisterOnBeamGeometryInitializedCallback(() => ProcessOcclusion(ProcessOcclusionSource.OnEnable));
}
}
protected virtual void OnDisable()
{
#if UNITY_EDITOR
if (Application.isPlaying)
#endif
{
m_Master.onWillCameraRenderThisBeam -= OnWillCameraRender;
}
DisableOcclusion();
}
#if UNITY_EDITOR
protected virtual void OnValidate()
{
OnValidateProperties();
}
#endif
void OnWillCameraRender(Camera cam)
{
Debug.Assert(Application.isPlaying);
if (cam != null && cam.enabled
&& Time.frameCount != m_LastFrameRendered) // prevent from updating multiple times if there are more than 1 camera
{
bool shouldUpdate = false;
if (!shouldUpdate && updateRate.HasFlag(DynamicOcclusionUpdateRate.OnBeamMove))
{
if (!m_TransformPacked.IsSame(transform))
shouldUpdate = true;
}
if (!shouldUpdate && updateRate.HasFlag(DynamicOcclusionUpdateRate.EveryXFrames))
{
if (Time.frameCount >= m_LastFrameRendered + waitXFrames)
shouldUpdate = true;
}
if (shouldUpdate)
ProcessOcclusion(ProcessOcclusionSource.RenderLoop);
}
}
void DisableOcclusion()
{
m_Master._INTERNAL_SetDynamicOcclusionCallback(GetShaderKeyword(), null);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: c87e171f8942d184e958eba76fd39108
timeCreated: 1510650372
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,231 @@
using UnityEngine;
using System.Collections;
namespace VLB
{
[ExecuteInEditMode]
[HelpURL(Consts.Help.SD.UrlDynamicOcclusionDepthBuffer)]
[AddComponentMenu(Consts.Help.SD.AddComponentMenuDynamicOcclusionDepthBuffer)]
public class DynamicOcclusionDepthBuffer : DynamicOcclusionAbstractBase
{
public new const string ClassName = "DynamicOcclusionDepthBuffer";
/// <summary>
/// The beam can only be occluded by objects located on the layers matching this mask.
/// It's very important to set it as restrictive as possible (checking only the layers which are necessary)
/// to perform a more efficient process in order to increase the performance.
/// It should NOT include the layer on which the beams are generated.
/// </summary>
public LayerMask layerMask = Consts.DynOcclusion.LayerMaskDefault;
/// <summary>
/// Whether or not the virtual camera will use occlusion culling during rendering from the beam's POV.
/// </summary>
public bool useOcclusionCulling = Consts.DynOcclusion.DepthBufferOcclusionCullingDefault;
/// <summary>
/// Controls how large the depth texture captured by the virtual camera is.
/// The lower the resolution, the better the performance, but the less accurate the rendering.
/// </summary>
public int depthMapResolution = Consts.DynOcclusion.DepthBufferDepthMapResolutionDefault;
/// <summary>
/// Fade out the beam before the occlusion surface in order to soften the transition.
/// </summary>
public float fadeDistanceToSurface = Consts.DynOcclusion.DepthBufferFadeDistanceToSurfaceDefault;
protected override string GetShaderKeyword() { return ShaderKeywords.SD.OcclusionDepthTexture; }
protected override MaterialManager.SD.DynamicOcclusion GetDynamicOcclusionMode() { return MaterialManager.SD.DynamicOcclusion.DepthTexture; }
Camera m_DepthCamera = null;
bool m_NeedToUpdateOcclusionNextFrame = false;
void ProcessOcclusionInternal()
{
UpdateDepthCameraPropertiesAccordingToBeam();
m_DepthCamera.Render();
}
protected override bool OnProcessOcclusion(ProcessOcclusionSource source)
{
Debug.Assert(m_Master && m_DepthCamera);
if (SRPHelper.IsUsingCustomRenderPipeline()) // Recursive rendering is not supported on SRP
m_NeedToUpdateOcclusionNextFrame = true;
else
ProcessOcclusionInternal();
return true;
}
void Update()
{
if (m_NeedToUpdateOcclusionNextFrame && m_Master && m_DepthCamera
&& Time.frameCount > 1) // fix NullReferenceException in UnityEngine.Rendering.Universal.Internal.CopyDepthPass.Execute when using SRP
{
ProcessOcclusionInternal();
m_NeedToUpdateOcclusionNextFrame = false;
}
}
void UpdateDepthCameraPropertiesAccordingToBeam()
{
Debug.Assert(m_Master);
Utils.SetupDepthCamera(m_DepthCamera
, m_Master.coneApexOffsetZ, m_Master.maxGeometryDistance, m_Master.coneRadiusStart, m_Master.coneRadiusEnd
, m_Master.beamLocalForward, m_Master.GetLossyScale(), m_Master.IsScalable(), m_Master.beamInternalLocalRotation
, true);
}
public bool HasLayerMaskIssues()
{
if(Config.Instance.geometryOverrideLayer)
{
int layerBit = 1 << Config.Instance.geometryLayerID;
return ((layerMask.value & layerBit) == layerBit);
}
return false;
}
protected override void OnValidateProperties()
{
base.OnValidateProperties();
depthMapResolution = Mathf.Clamp(Mathf.NextPowerOfTwo(depthMapResolution), 8, 2048);
fadeDistanceToSurface = Mathf.Max(fadeDistanceToSurface, 0f);
}
void InstantiateOrActivateDepthCamera()
{
if (m_DepthCamera != null)
{
m_DepthCamera.gameObject.SetActive(true); // active it in case it has been disabled by OnDisable()
}
else
{
// delete old depth cameras when duplicating the GAO
gameObject.ForeachComponentsInDirectChildrenOnly<Camera>(cam => DestroyImmediate(cam.gameObject), true);
m_DepthCamera = Utils.NewWithComponent<Camera>("Depth Camera");
if (m_DepthCamera && m_Master)
{
m_DepthCamera.enabled = false;
m_DepthCamera.cullingMask = layerMask;
m_DepthCamera.clearFlags = CameraClearFlags.Depth;
m_DepthCamera.depthTextureMode = DepthTextureMode.Depth;
m_DepthCamera.renderingPath = RenderingPath.VertexLit; // faster
m_DepthCamera.useOcclusionCulling = useOcclusionCulling;
m_DepthCamera.gameObject.hideFlags = Consts.Internal.ProceduralObjectsHideFlags;
m_DepthCamera.transform.SetParent(transform, false);
Config.Instance.SetURPScriptableRendererIndexToDepthCamera(m_DepthCamera);
var rt = new RenderTexture(depthMapResolution, depthMapResolution, 16, RenderTextureFormat.Depth);
m_DepthCamera.targetTexture = rt;
UpdateDepthCameraPropertiesAccordingToBeam();
#if UNITY_EDITOR
UnityEditor.GameObjectUtility.SetStaticEditorFlags(m_DepthCamera.gameObject, m_Master.GetStaticEditorFlagsForSubObjects());
m_DepthCamera.gameObject.SetSameSceneVisibilityStatesThan(m_Master.gameObject);
#endif
}
}
}
protected override void OnEnablePostValidate()
{
InstantiateOrActivateDepthCamera();
}
protected override void OnDisable()
{
base.OnDisable();
if (m_DepthCamera) m_DepthCamera.gameObject.SetActive(false);
}
protected override void Awake()
{
base.Awake();
#if UNITY_EDITOR
MarkMaterialAsDirty();
#endif
}
protected override void OnDestroy()
{
base.OnDestroy();
DestroyDepthCamera();
#if UNITY_EDITOR
MarkMaterialAsDirty();
#endif
}
void DestroyDepthCamera()
{
if (m_DepthCamera)
{
if (m_DepthCamera.targetTexture)
{
m_DepthCamera.targetTexture.Release();
DestroyImmediate(m_DepthCamera.targetTexture);
m_DepthCamera.targetTexture = null;
}
DestroyImmediate(m_DepthCamera.gameObject); // Make sure to delete the GAO
m_DepthCamera = null;
}
}
protected override void OnModifyMaterialCallback(MaterialModifier.Interface owner)
{
Debug.Assert(owner != null);
owner.SetMaterialProp(ShaderProperties.SD.DynamicOcclusionDepthTexture, m_DepthCamera.targetTexture);
var scale = m_Master.GetLossyScale();
owner.SetMaterialProp(ShaderProperties.SD.DynamicOcclusionDepthProps, new Vector4(Mathf.Sign(scale.x) * Mathf.Sign(scale.z), Mathf.Sign(scale.y), fadeDistanceToSurface, m_DepthCamera.orthographic ? 0f : 1f));
}
#if UNITY_EDITOR
bool m_NeedToReinstantiateDepthCamera = false;
public void ForceReinstantiateDepthCamera()
{
m_NeedToReinstantiateDepthCamera = true;
}
void MarkMaterialAsDirty()
{
// when adding/removing this component in editor, we might need to switch from a GPU Instanced material to a custom one,
// since this feature doesn't support GPU Instancing
if (!Application.isPlaying)
m_Master._EditorSetBeamGeomDirty();
}
protected override void OnValidate()
{
base.OnValidate();
m_NeedToReinstantiateDepthCamera = true;
}
void LateUpdate()
{
if (!Application.isPlaying)
{
if (m_NeedToReinstantiateDepthCamera)
{
DestroyDepthCamera();
InstantiateOrActivateDepthCamera();
m_NeedToReinstantiateDepthCamera = false;
}
if(m_Master && m_Master.enabled)
ProcessOcclusion(ProcessOcclusionSource.EditorUpdate);
}
}
#endif // UNITY_EDITOR
}
}

View File

@@ -0,0 +1,28 @@
fileFormatVersion: 2
guid: fdb43fff075aa0b4b995dcfaed06dc44
labels:
- volumetric
- light
- lighting
- ray
- shaft
- beam
- density
- vr
- dynamic
- spot
- spotlight
- fog
- noise
- occlusion
- procedural
timeCreated: 1577531941
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: f4140fedf3f72d7448a4e55ea9db44ab, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,473 @@
#if DEBUG
//#define DEBUG_SHOW_RAYCAST_LINES
#endif
using UnityEngine;
using UnityEngine.Serialization;
namespace VLB
{
[ExecuteInEditMode]
[HelpURL(Consts.Help.SD.UrlDynamicOcclusionRaycasting)]
[AddComponentMenu(Consts.Help.SD.AddComponentMenuDynamicOcclusionRaycasting)]
public class DynamicOcclusionRaycasting : DynamicOcclusionAbstractBase
{
public new const string ClassName = "DynamicOcclusionRaycasting";
/// <summary>
/// Should it interact with 2D or 3D occluders?
/// </summary>
public Dimensions dimensions = Consts.DynOcclusion.RaycastingDimensionsDefault;
/// <summary>
/// The beam can only be occluded by objects located on the layers matching this mask.
/// It's very important to set it as restrictive as possible (checking only the layers which are necessary)
/// to perform a more efficient process in order to increase the performance.
/// </summary>
public LayerMask layerMask = Consts.DynOcclusion.LayerMaskDefault;
/// <summary>
/// Should this beam be occluded by triggers or not?
/// </summary>
public bool considerTriggers = Consts.DynOcclusion.RaycastingConsiderTriggersDefault;
/// <summary>
/// Minimum 'area' of the collider to become an occluder.
/// Colliders smaller than this value will not block the beam.
/// </summary>
public float minOccluderArea = Consts.DynOcclusion.RaycastingMinOccluderAreaDefault;
/// <summary>
/// Approximated percentage of the beam to collide with the surface in order to be considered as occluder
/// </summary>
public float minSurfaceRatio = Consts.DynOcclusion.RaycastingMinSurfaceRatioDefault;
/// <summary>
/// Max angle (in degrees) between the beam and the surface in order to be considered as occluder
/// </summary>
public float maxSurfaceDot = Consts.DynOcclusion.RaycastingMaxSurfaceDotDefault;
/// <summary>
/// Alignment of the computed clipping plane:
/// </summary>
public PlaneAlignment planeAlignment = Consts.DynOcclusion.RaycastingPlaneAlignmentDefault;
/// <summary>
/// Translate the plane. We recommend to set a small positive offset in order to handle non-flat surface better.
/// </summary>
public float planeOffset = Consts.DynOcclusion.RaycastingPlaneOffsetDefault;
/// <summary>
/// Fade out the beam before the computed clipping plane in order to soften the transition.
/// </summary>
[FormerlySerializedAs("fadeDistanceToPlane")]
public float fadeDistanceToSurface = Consts.DynOcclusion.RaycastingFadeDistanceToSurfaceDefault;
[System.Obsolete("Use 'fadeDistanceToSurface' instead")]
public float fadeDistanceToPlane { get { return fadeDistanceToSurface; } set { fadeDistanceToSurface = value; } }
public bool IsColliderHiddenByDynamicOccluder(Collider collider)
{
Debug.Assert(collider, "You should pass a valid Collider to VLB.DynamicOcclusion.IsColliderHiddenByDynamicOccluder");
if (!planeEquationWS.IsValid())
return false;
var isInside = GeometryUtility.TestPlanesAABB(new Plane[] { planeEquationWS }, collider.bounds);
return !isInside;
}
public struct HitResult
{
public HitResult(ref RaycastHit hit3D)
{
point = hit3D.point;
normal = hit3D.normal;
distance = hit3D.distance;
collider3D = hit3D.collider;
collider2D = null;
}
public HitResult(ref RaycastHit2D hit2D)
{
point = hit2D.point;
normal = hit2D.normal;
distance = hit2D.distance;
collider2D = hit2D.collider;
collider3D = null;
}
public Vector3 point;
public Vector3 normal;
public float distance;
Collider2D collider2D;
Collider collider3D;
public bool hasCollider { get { return collider2D || collider3D; } }
public string name
{
get
{
if (collider3D) return collider3D.name;
else if (collider2D) return collider2D.name;
else return "null collider";
}
}
public Bounds bounds
{
get
{
if (collider3D) return collider3D.bounds;
else if (collider2D) return collider2D.bounds;
else return new Bounds();
}
}
public void SetNull() { collider2D = null; collider3D = null; }
}
/// <summary>
/// Get information about the current occluder hit by the beam.
/// Can be null if the beam is not occluded.
/// </summary>
HitResult m_CurrentHit;
protected override string GetShaderKeyword() { return ShaderKeywords.SD.OcclusionClippingPlane; }
protected override MaterialManager.SD.DynamicOcclusion GetDynamicOcclusionMode() { return MaterialManager.SD.DynamicOcclusion.ClippingPlane; }
float m_RangeMultiplier = 1f;
public Plane planeEquationWS { get; private set; }
#if UNITY_EDITOR
public HitResult editorCurrentHitResult { get { return m_CurrentHit; } }
public struct EditorDebugData
{
public int lastFrameUpdate;
}
public EditorDebugData editorDebugData;
public static bool editorShowDebugPlane = true;
public static bool editorRaycastAtEachFrame = true;
private static bool editorPrefsLoaded = false;
public static void EditorLoadPrefs()
{
if (!editorPrefsLoaded)
{
editorShowDebugPlane = UnityEditor.EditorPrefs.GetBool(EditorPrefsStrings.DynOcclusion.PrefShowDebugPlane, true);
editorRaycastAtEachFrame = UnityEditor.EditorPrefs.GetBool(EditorPrefsStrings.DynOcclusion.PrefRaycastingEditor, true);
editorPrefsLoaded = true;
}
}
#endif
protected override void OnValidateProperties()
{
base.OnValidateProperties();
minOccluderArea = Mathf.Max(minOccluderArea, 0f);
fadeDistanceToSurface = Mathf.Max(fadeDistanceToSurface, 0f);
}
protected override void OnEnablePostValidate()
{
m_CurrentHit.SetNull();
#if UNITY_EDITOR
EditorLoadPrefs();
editorDebugData.lastFrameUpdate = 0;
#endif
}
protected override void OnDisable()
{
base.OnDisable();
SetHitNull();
}
void Start()
{
if (Application.isPlaying)
{
var triggerZone = GetComponent<TriggerZone>();
if (triggerZone)
{
m_RangeMultiplier = Mathf.Max(1f, triggerZone.rangeMultiplier);
}
}
}
Vector3 GetRandomVectorAround(Vector3 direction, float angleDiff)
{
var halfAngle = angleDiff * 0.5f;
return Quaternion.Euler(Random.Range(-halfAngle, halfAngle), Random.Range(-halfAngle, halfAngle), Random.Range(-halfAngle, halfAngle)) * direction;
}
QueryTriggerInteraction queryTriggerInteraction { get { return considerTriggers ? QueryTriggerInteraction.Collide : QueryTriggerInteraction.Ignore; } }
float raycastMaxDistance { get { return m_Master.raycastDistance * m_RangeMultiplier * m_Master.GetLossyScale().z; } }
HitResult GetBestHit(Vector3 rayPos, Vector3 rayDir)
{
return dimensions == Dimensions.Dim2D ? GetBestHit2D(rayPos, rayDir) : GetBestHit3D(rayPos, rayDir);
}
HitResult GetBestHit3D(Vector3 rayPos, Vector3 rayDir)
{
var hits = Physics.RaycastAll(rayPos, rayDir, raycastMaxDistance, layerMask.value, queryTriggerInteraction);
int bestHit = -1;
float bestLength = float.MaxValue;
for (int i = 0; i < hits.Length; ++i)
{
if (hits[i].collider.gameObject != m_Master.gameObject) // skip collider from TriggerZone
{
if (hits[i].collider.bounds.GetMaxArea2D() >= minOccluderArea)
{
if (hits[i].distance < bestLength)
{
bestLength = hits[i].distance;
bestHit = i;
}
}
}
}
#if DEBUG_SHOW_RAYCAST_LINES
Debug.DrawLine(rayPos, rayPos + rayDir * raycastMaxDistance, bestHit != -1 ? Color.green : Color.red);
#endif
if (bestHit != -1)
return new HitResult(ref hits[bestHit]);
else
return new HitResult();
}
HitResult GetBestHit2D(Vector3 rayPos, Vector3 rayDir)
{
var hits = Physics2D.RaycastAll(new Vector2(rayPos.x, rayPos.y), new Vector2(rayDir.x, rayDir.y), raycastMaxDistance, layerMask.value);
int bestHit = -1;
float bestLength = float.MaxValue;
for (int i = 0; i < hits.Length; ++i)
{
if (!considerTriggers && hits[i].collider.isTrigger) // do not query triggers if considerTriggers is disabled
continue;
if (hits[i].collider.gameObject != m_Master.gameObject) // skip collider from TriggerZone
{
if (hits[i].collider.bounds.GetMaxArea2D() >= minOccluderArea)
{
if (hits[i].distance < bestLength)
{
bestLength = hits[i].distance;
bestHit = i;
}
}
}
}
#if DEBUG_SHOW_RAYCAST_LINES
Debug.DrawLine(rayPos, rayPos + rayDir * raycastMaxDistance, bestHit != -1 ? Color.green : Color.red);
#endif
if (bestHit != -1)
return new HitResult(ref hits[bestHit]);
else
return new HitResult();
}
enum Direction {
Up,
Down,
Left,
Right,
Max2D = Down,
Max3D = Right,
};
uint m_PrevNonSubHitDirectionId = 0;
uint GetDirectionCount() { return dimensions == Dimensions.Dim2D ? ((uint)Direction.Max2D + 1) : ((uint)Direction.Max3D + 1); }
Vector3 GetDirection(uint dirInt)
{
dirInt = dirInt % GetDirectionCount();
switch (dirInt)
{
case (uint)Direction.Up: return m_Master.raycastGlobalUp;
case (uint)Direction.Right: return m_Master.raycastGlobalRight;
case (uint)Direction.Down: return -m_Master.raycastGlobalUp;
case (uint)Direction.Left: return -m_Master.raycastGlobalRight;
}
return Vector3.zero;
}
bool IsHitValid(ref HitResult hit, Vector3 forwardVec)
{
if (hit.hasCollider)
{
float dot = Vector3.Dot(hit.normal, -forwardVec);
return dot >= maxSurfaceDot;
}
return false;
}
protected override bool OnProcessOcclusion(ProcessOcclusionSource source)
{
#if UNITY_EDITOR
editorDebugData.lastFrameUpdate = Time.frameCount;
#endif
var raycastGlobalForward = m_Master.raycastGlobalForward;
var bestHit = GetBestHit(transform.position, raycastGlobalForward);
if (IsHitValid(ref bestHit, raycastGlobalForward))
{
if (minSurfaceRatio > 0.5f)
{
var raycastDistance = m_Master.raycastDistance;
for (uint i = 0; i < GetDirectionCount(); i++)
{
var dir3 = GetDirection(i + m_PrevNonSubHitDirectionId) * (minSurfaceRatio * 2 - 1);
dir3.Scale(transform.localScale);
var startPt = transform.position + dir3 * m_Master.coneRadiusStart;
var newPt = transform.position + dir3 * m_Master.coneRadiusEnd + raycastGlobalForward * raycastDistance;
var bestHitSub = GetBestHit(startPt, (newPt - startPt).normalized);
if (IsHitValid(ref bestHitSub, raycastGlobalForward))
{
if (bestHitSub.distance > bestHit.distance)
{
bestHit = bestHitSub;
}
}
else
{
m_PrevNonSubHitDirectionId = i;
bestHit.SetNull();
break;
}
}
}
}
else
{
bestHit.SetNull();
}
SetHit(ref bestHit);
return bestHit.hasCollider;
}
void SetHit(ref HitResult hit)
{
if (!hit.hasCollider)
{
SetHitNull();
}
else
{
switch (planeAlignment)
{
case PlaneAlignment.Beam:
SetClippingPlane(new Plane(-m_Master.raycastGlobalForward, hit.point));
break;
case PlaneAlignment.Surface:
default:
SetClippingPlane(new Plane(hit.normal, hit.point));
break;
}
m_CurrentHit = hit;
}
}
void SetHitNull()
{
SetClippingPlaneOff();
m_CurrentHit.SetNull();
}
protected override void OnModifyMaterialCallback(MaterialModifier.Interface owner)
{
Debug.Assert(owner != null);
var planeWS = planeEquationWS;
owner.SetMaterialProp(ShaderProperties.SD.DynamicOcclusionClippingPlaneWS, new Vector4(planeWS.normal.x, planeWS.normal.y, planeWS.normal.z, planeWS.distance));
owner.SetMaterialProp(ShaderProperties.SD.DynamicOcclusionClippingPlaneProps, fadeDistanceToSurface);
}
void SetClippingPlane(Plane planeWS)
{
planeWS = planeWS.TranslateCustom(planeWS.normal * planeOffset);
SetPlaneWS(planeWS);
Debug.Assert(m_MaterialModifierCallbackCached != null);
m_Master._INTERNAL_SetDynamicOcclusionCallback(GetShaderKeyword(), m_MaterialModifierCallbackCached);
}
void SetClippingPlaneOff()
{
SetPlaneWS(new Plane());
m_Master._INTERNAL_SetDynamicOcclusionCallback(GetShaderKeyword(), null);
}
void SetPlaneWS(Plane planeWS)
{
planeEquationWS = planeWS;
#if UNITY_EDITOR
m_DebugPlaneLocal = planeWS;
if (m_DebugPlaneLocal.IsValid())
{
float dist;
if (m_DebugPlaneLocal.Raycast(new Ray(transform.position, m_Master.raycastGlobalForward), out dist))
m_DebugPlaneLocal.distance = dist; // compute local distance
}
#endif
}
#if UNITY_EDITOR
void LateUpdate()
{
if (!Application.isPlaying)
{
// In Editor, process raycasts at each frame update
if (!editorRaycastAtEachFrame)
SetHitNull();
else
ProcessOcclusion(ProcessOcclusionSource.EditorUpdate);
}
}
Plane m_DebugPlaneLocal;
void OnDrawGizmos()
{
if (!editorShowDebugPlane)
return;
if (m_DebugPlaneLocal.IsValid())
{
var planePos = transform.position + m_DebugPlaneLocal.distance * m_Master.raycastGlobalForward;
float planeDistNormalized = Mathf.Clamp01(Mathf.InverseLerp(0f, m_Master.raycastDistance, m_DebugPlaneLocal.distance));
float planeSize = Mathf.Lerp(m_Master.coneRadiusStart, m_Master.coneRadiusEnd, planeDistNormalized);
var color = m_Master.ComputeColorAtDepth(planeDistNormalized).ComputeComplementaryColor(false);
Utils.GizmosDrawPlane(
m_DebugPlaneLocal.normal,
planePos,
color,
Matrix4x4.identity,
planeSize,
planeSize * 0.5f);
UnityEditor.Handles.color = color;
UnityEditor.Handles.DrawWireDisc(planePos,
m_DebugPlaneLocal.normal,
planeSize * (minSurfaceRatio * 2 - 1));
}
}
#endif
}
}

View File

@@ -0,0 +1,28 @@
fileFormatVersion: 2
guid: 558dd6d156642974780bc97cd2ab1bd2
labels:
- volumetric
- light
- lighting
- ray
- shaft
- beam
- density
- vr
- dynamic
- spot
- spotlight
- fog
- noise
- occlusion
- procedural
timeCreated: 1513615359
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: f4140fedf3f72d7448a4e55ea9db44ab, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,45 @@
using UnityEngine;
using System.Collections;
namespace VLB
{
public static class GlobalMeshSD
{
public static Mesh Get()
{
var needDoubleSided = Config.Instance.SD_requiresDoubleSidedMesh;
if (ms_Mesh == null
|| ms_DoubleSided != needDoubleSided)
{
Destroy();
ms_Mesh = MeshGenerator.GenerateConeZ_Radii(
lengthZ: 1f,
radiusStart: 1f,
radiusEnd: 1f,
numSides: Config.Instance.sharedMeshSides,
numSegments: Config.Instance.sharedMeshSegments,
cap: true,
doubleSided: needDoubleSided);
ms_Mesh.hideFlags = Consts.Internal.ProceduralObjectsHideFlags;
ms_DoubleSided = needDoubleSided;
}
return ms_Mesh;
}
public static void Destroy()
{
if (ms_Mesh != null)
{
GameObject.DestroyImmediate(ms_Mesh);
ms_Mesh = null;
}
}
static Mesh ms_Mesh = null;
static bool ms_DoubleSided = false;
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 0e4bae9c762e9004296c04beb33798ed
timeCreated: 1529559345
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,59 @@
using UnityEngine;
using System.Collections;
namespace VLB
{
[ExecuteInEditMode]
[HelpURL(Consts.Help.SD.UrlSkewingHandle)]
public class SkewingHandleSD : MonoBehaviour
{
public const string ClassName = "SkewingHandleSD";
public VolumetricLightBeamSD volumetricLightBeam = null;
public bool shouldUpdateEachFrame = false;
#if UNITY_EDITOR
void Update()
{
if (!Application.isPlaying && CanSetSkewingVector())
SetSkewingVector();
}
#endif
public bool IsAttachedToSelf() { return volumetricLightBeam != null && volumetricLightBeam.gameObject == this.gameObject; }
public bool CanSetSkewingVector() { return volumetricLightBeam != null && volumetricLightBeam.canHaveMeshSkewing; }
public bool CanUpdateEachFrame() { return CanSetSkewingVector() && volumetricLightBeam.trackChangesDuringPlaytime; }
bool ShouldUpdateEachFrame() { return shouldUpdateEachFrame && CanUpdateEachFrame(); }
void OnEnable()
{
if(CanSetSkewingVector())
SetSkewingVector();
}
void Start()
{
if (Application.isPlaying && ShouldUpdateEachFrame())
{
StartCoroutine(CoUpdate());
}
}
IEnumerator CoUpdate()
{
while(ShouldUpdateEachFrame())
{
SetSkewingVector();
yield return null;
}
}
void SetSkewingVector()
{
Debug.Assert(CanSetSkewingVector());
var vec = volumetricLightBeam.transform.InverseTransformPoint(transform.position);
volumetricLightBeam.skewingLocalForwardDirection = vec;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 39d38d9261901ee459f4c704884f0ad3
timeCreated: 1617808264
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 96c382e4368041b4aad93aed0a833e2b, type: 3}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,29 @@
fileFormatVersion: 2
guid: 7b69c542c9a8f4f44a3123e3fa103d13
labels:
- volumetric
- light
- lighting
- ray
- shaft
- beam
- density
- vr
- dynamic
- spot
- spotlight
- fog
- noise
- occlusion
- procedural
timeCreated: 1507404056
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences:
- m_Shader: {fileID: 4800000, guid: 936bd00b0f168d949b0c27d2be40615a, type: 3}
executionOrder: 0
icon: {fileID: 2800000, guid: 837747a8b63291a48838c340da834873, type: 3}
userData:
assetBundleName:
assetBundleVariant: