Heroes_of_Hiis/Assets/Polaris - Low Poly Ecosystem/Poseidon - Low Poly Water S.../Runtime/Scripts/Effects/PWaterFX.cs

418 lines
12 KiB
C#

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.Rendering;
using UnityEngine.Events;
#if UNITY_POST_PROCESSING_STACK_V2
using Pinwheel.Poseidon.FX.PostProcessing;
using UnityEngine.Rendering.PostProcessing;
#endif
#if POSEIDON_URP
using Pinwheel.Poseidon.FX.Universal;
#endif
namespace Pinwheel.Poseidon.FX
{
[ExecuteInEditMode]
[RequireComponent(typeof(PWater))]
public class PWaterFX : MonoBehaviour
{
[SerializeField]
private PWater water;
public PWater Water
{
get
{
return water;
}
set
{
water = value;
}
}
[SerializeField]
private PWaterFXProfile profile;
public PWaterFXProfile Profile
{
get
{
return profile;
}
set
{
PWaterFXProfile oldProfile = profile;
PWaterFXProfile newProfile = value;
profile = newProfile;
if (oldProfile != newProfile && newProfile != null)
{
UpdatePostProcessOrVolumeProfile();
}
}
}
#if UNITY_POST_PROCESSING_STACK_V2
public PostProcessProfile PostProcessProfile { get; private set; }
public PostProcessVolume PostProcessVolume { get; private set; }
#endif
#if POSEIDON_URP
public VolumeProfile VolumeProfile { get; private set; }
public Volume Volume { get; private set; }
#endif
[SerializeField]
private Vector3 volumeExtent;
public Vector3 VolumeExtent
{
get
{
return volumeExtent;
}
set
{
Vector3 v = value;
//v.x = Mathf.Max(0, v.x);
//v.y = Mathf.Max(0, v.y);
//v.z = Mathf.Max(0, v.z);
volumeExtent = v;
}
}
[SerializeField]
private LayerMask volumeLayer;
public LayerMask VolumeLayer
{
get
{
return volumeLayer;
}
set
{
volumeLayer = value;
}
}
private float lastDistanceToSurface;
private float wetLensTime;
[SerializeField]
private UnityEvent onEnterWater;
public UnityEvent OnEnterWater
{
get
{
return onEnterWater;
}
set
{
onEnterWater = value;
}
}
[SerializeField]
private UnityEvent onExitWater;
public UnityEvent OnExitWater
{
get
{
return onExitWater;
}
set
{
onExitWater = value;
}
}
private void Reset()
{
Water = GetComponent<PWater>();
#if UNITY_POST_PROCESSING_STACK_V2
VolumeExtent = new Vector3(0, 100, 0);
#endif
}
private void OnEnable()
{
Camera.onPreCull += OnCameraPreCull;
RenderPipelineManager.beginCameraRendering += OnBeginCameraRendering;
if (Camera.main != null)
{
float waterHeight = GetWaterHeight(Camera.main.transform.position);
lastDistanceToSurface = Camera.main.transform.position.y - waterHeight;
}
wetLensTime = Mathf.Infinity;
if (PUtilities.IsPlaying)
{
SetupQuickVolume();
}
}
private void OnDisable()
{
Camera.onPreCull -= OnCameraPreCull;
RenderPipelineManager.beginCameraRendering -= OnBeginCameraRendering;
CleanupQuickVolume();
}
private void OnBeginCameraRendering(ScriptableRenderContext context, Camera cam)
{
OnCameraPreCull(cam);
}
private void OnCameraPreCull(Camera cam)
{
UpdateEffects(cam);
if (cam == Camera.main && Water != null)
{
Vector3 cameraPos = cam.transform.position;
float waterHeight = GetWaterHeight(cam.transform.position);
float distanceToSuface = cam.transform.position.y - waterHeight;
if (distanceToSuface <= 0 && lastDistanceToSurface > 0)
{
if (Water.CheckTilesContainPoint(cameraPos))
{
OnEnterWater.Invoke();
}
}
if (distanceToSuface > 0 && lastDistanceToSurface <= 0)
{
if (Water.CheckTilesContainPoint(cameraPos))
{
OnExitWater.Invoke();
}
}
lastDistanceToSurface = cameraPos.y - waterHeight;
}
}
private void SetupQuickVolume()
{
if (Water == null || Profile == null)
return;
Water.ReCalculateBounds();
Bounds bounds = Water.Bounds;
GameObject volumeGO = null;
#if UNITY_POST_PROCESSING_STACK_V2
if (PCommon.CurrentRenderPipeline == PRenderPipelineType.Builtin)
{
PostProcessEffectSettings[] settings = new PostProcessEffectSettings[0];
PostProcessVolume volume = PostProcessManager.instance.QuickVolume(VolumeLayer, 0, settings);
volume.isGlobal = false;
volumeGO = volume.gameObject;
PostProcessVolume = volume;
PostProcessProfile = volume.profile;
PostProcessProfile.name = "~TemporaryEffectProfile";
Profile.UpdatePostProcessingProfile(PostProcessProfile);
}
#endif
#if POSEIDON_URP
if (PCommon.CurrentRenderPipeline == PRenderPipelineType.Universal)
{
volumeGO = new GameObject();
volumeGO.layer = VolumeLayer;
Volume volume = volumeGO.AddComponent<Volume>();
volume.isGlobal = false;
VolumeProfile profile = ScriptableObject.CreateInstance<VolumeProfile>();
volume.profile = profile;
this.Volume = volume;
this.VolumeProfile = profile;
this.VolumeProfile.name = "~TemporaryEffectProfile";
Profile.UpdateVolumeProfile(VolumeProfile);
}
#endif
volumeGO.hideFlags = HideFlags.DontSave;
volumeGO.transform.parent = transform;
volumeGO.transform.localPosition = bounds.center;
volumeGO.transform.localRotation = Quaternion.identity;
volumeGO.transform.localScale = Vector3.one;
volumeGO.name = "~WaterPostFXVolume";
BoxCollider b = volumeGO.AddComponent<BoxCollider>();
b.center = new Vector3(0, 0, 0);
b.size = bounds.size + VolumeExtent;
b.isTrigger = true;
}
private void CleanupQuickVolume()
{
#if UNITY_POST_PROCESSING_STACK_V2
if (PostProcessProfile != null)
{
PUtilities.DestroyObject(PostProcessProfile);
}
if (PostProcessVolume != null)
{
PUtilities.DestroyGameobject(PostProcessVolume.gameObject);
}
#endif
#if POSEIDON_URP
if (VolumeProfile != null)
{
PUtilities.DestroyObject(VolumeProfile);
}
if (Volume != null)
{
PUtilities.DestroyGameobject(Volume.gameObject);
}
#endif
}
private void UpdateEffects(Camera cam)
{
if (cam == null)
return;
if (cam != Camera.main)
return;
if (Profile == null)
return;
float waterHeight = GetWaterHeight(cam.transform.position);
if (Profile.EnableUnderwater)
{
float intensity = cam.transform.position.y < waterHeight ? 1 : 0;
UpdateUnderwaterIntensityAndWaterLevel(intensity, waterHeight);
}
float distanceToSurface = Camera.main.transform.position.y - waterHeight;
if (Profile.EnableWetLens)
{
if (distanceToSurface > 0 && lastDistanceToSurface <= 0)
{
wetLensTime = 0;
}
float intensity;
if (distanceToSurface <= 0)
{
intensity = 0;
}
else if (wetLensTime > Profile.WetLensDuration)
{
intensity = 0;
}
else
{
float f = Mathf.InverseLerp(0, Profile.WetLensDuration, wetLensTime);
intensity = Profile.WetLensFadeCurve.Evaluate(f);
}
UpdateWetLensIntensity(intensity);
}
wetLensTime += PUtilities.DeltaTime;
}
private void UpdateUnderwaterIntensityAndWaterLevel(float intensity, float waterLevel)
{
#if UNITY_POST_PROCESSING_STACK_V2
if (PCommon.CurrentRenderPipeline == PRenderPipelineType.Builtin)
{
if (PostProcessProfile == null)
return;
PUnderwater underwaterSettings;
if (PostProcessProfile.TryGetSettings<PUnderwater>(out underwaterSettings))
{
underwaterSettings.intensity.Override(intensity);
underwaterSettings.waterLevel.Override(waterLevel);
}
}
#endif
#if POSEIDON_URP
if (PCommon.CurrentRenderPipeline == PRenderPipelineType.Universal)
{
if (VolumeProfile == null)
return;
PUnderwaterOverride underwaterSettigns;
if (VolumeProfile.TryGet<PUnderwaterOverride>(out underwaterSettigns))
{
underwaterSettigns.intensity.Override(intensity);
underwaterSettigns.waterLevel.Override(waterLevel);
}
}
#endif
}
private void UpdateWetLensIntensity(float intensity)
{
#if UNITY_POST_PROCESSING_STACK_V2
if (PCommon.CurrentRenderPipeline == PRenderPipelineType.Builtin)
{
if (PostProcessProfile == null)
return;
PWetLens wetlensSettings;
if (PostProcessProfile.TryGetSettings<PWetLens>(out wetlensSettings))
{
wetlensSettings.intensity.Override(intensity);
}
}
#endif
#if POSEIDON_URP
if (PCommon.CurrentRenderPipeline == PRenderPipelineType.Universal)
{
if (VolumeProfile == null)
return;
PWetLensOverride wetlensSettings;
if (VolumeProfile.TryGet<PWetLensOverride>(out wetlensSettings))
{
wetlensSettings.intensity.Override(intensity);
}
}
#endif
}
public void UpdatePostProcessOrVolumeProfile()
{
if (profile == null)
return;
#if UNITY_POST_PROCESSING_STACK_V2
if (PCommon.CurrentRenderPipeline == PRenderPipelineType.Builtin)
{
if (PostProcessProfile != null)
{
profile.UpdatePostProcessingProfile(PostProcessProfile);
}
}
#endif
#if POSEIDON_URP
if (PCommon.CurrentRenderPipeline == PRenderPipelineType.Universal)
{
if (VolumeProfile != null)
{
profile.UpdateVolumeProfile(VolumeProfile);
}
}
#endif
}
private float GetWaterHeight(Vector3 worldPos)
{
if (water == null)
return 0;
if (water.Profile.EnableWave)
{
Vector3 localPos = water.transform.InverseTransformPoint(worldPos);
localPos.y = 0;
localPos = water.GetLocalVertexPosition(localPos, false);
worldPos = water.transform.TransformPoint(localPos);
return worldPos.y;
}
else
{
return water.transform.position.y;
}
}
}
}