527 lines
17 KiB
C#
527 lines
17 KiB
C#
using UnityEngine;
|
|
|
|
namespace AQUAS
|
|
{
|
|
public class AQUAS_UnderWaterEffect : MonoBehaviour
|
|
{
|
|
public enum QUALITY
|
|
{
|
|
low = 0,
|
|
medium = 1,
|
|
high = 2
|
|
}
|
|
|
|
[Header("Underwater Settings")]
|
|
public LayerMask cullingMask = -1;
|
|
|
|
public QUALITY backFaceQuality = QUALITY.medium;
|
|
|
|
[Range(0.1f, 1f)]
|
|
public float fogFade = 1f;
|
|
|
|
[Range(0f, 0.1f)]
|
|
public float distortionStrength = 0.025f;
|
|
|
|
[Range(0f, 0.002f)]
|
|
public float blurSize = 0.001f;
|
|
|
|
[Range(0f, 10f)]
|
|
public int blurSmoothness = 5;
|
|
|
|
public bool enableWetLensEffect = true;
|
|
|
|
[Range(0.5f, 3f)]
|
|
public float wetLensDuration = 1f;
|
|
|
|
[Space(10f)]
|
|
[Header("Underwater Audio Settings")]
|
|
public AudioClip underwaterAmbientSound;
|
|
|
|
[Range(0f, 1f)]
|
|
public float underwaterAmbientVolume = 0.5f;
|
|
|
|
public AudioClip diveSplashSound;
|
|
|
|
[Range(0f, 1f)]
|
|
public float diveSplashVolume = 1f;
|
|
|
|
public AudioClip surfaceSplashSound;
|
|
|
|
[Range(0f, 1f)]
|
|
public float surfaceSplashVolume = 0.2f;
|
|
|
|
[Space(10f)]
|
|
[Header("Bubble Spawn Settings")]
|
|
[Range(5f, 50f)]
|
|
public int maximumBubbleCount = 10;
|
|
|
|
public bool spawnBubbles;
|
|
|
|
private float fogDensity = 1f;
|
|
|
|
private float deepFogDensity = 1.5f;
|
|
|
|
private float maxFogDepth = 10f;
|
|
|
|
private float adjustedFogDensity;
|
|
|
|
private Color fogColor;
|
|
|
|
private Color deepFogColor;
|
|
|
|
private Color adjustedFogColor;
|
|
|
|
private GameObject container;
|
|
|
|
private GameObject boundaryMask;
|
|
|
|
private GameObject volumeMask;
|
|
|
|
private GameObject frontFaceMask;
|
|
|
|
private GameObject background;
|
|
|
|
private GameObject waterPlane;
|
|
|
|
private GameObject[] waterObjects;
|
|
|
|
private GameObject[] staticBoundaries;
|
|
|
|
[HideInInspector]
|
|
public GameObject dynamicBoundary;
|
|
|
|
private Material fogMat;
|
|
|
|
private Material blurMat;
|
|
|
|
private Material dropletMaskMat;
|
|
|
|
[HideInInspector]
|
|
public RenderTexture mask;
|
|
|
|
private RenderTexture buffer1;
|
|
|
|
private RenderTexture buffer2;
|
|
|
|
private RenderTexture fogBuffer;
|
|
|
|
private RenderTexture dropletBuffer;
|
|
|
|
private RenderTexture dropletMask;
|
|
|
|
[HideInInspector]
|
|
public bool underwater;
|
|
|
|
private GameObject audioObject;
|
|
|
|
private AudioSource underwaterAmbient;
|
|
|
|
private AudioSource diveSplash;
|
|
|
|
private AudioSource surfaceSplash;
|
|
|
|
private bool diveSplashPlayed = true;
|
|
|
|
private bool surfaceSplashPlayed = true;
|
|
|
|
private GameObject bubbleContainer;
|
|
|
|
private GameObject bubble;
|
|
|
|
private AQUAS_BubbleBehaviour bubbleBehaviour;
|
|
|
|
private float t2;
|
|
|
|
private float bubbleSpawnTimer;
|
|
|
|
private int maxBubbleCount;
|
|
|
|
private int bubbleCount;
|
|
|
|
[HideInInspector]
|
|
public float waterLevel;
|
|
|
|
private void Start()
|
|
{
|
|
container = GameObject.Find("AQUAS Container");
|
|
if (container == null)
|
|
{
|
|
base.enabled = false;
|
|
return;
|
|
}
|
|
waterObjects = new GameObject[container.transform.childCount];
|
|
staticBoundaries = new GameObject[container.transform.childCount];
|
|
for (int i = 0; i < container.transform.childCount; i++)
|
|
{
|
|
waterObjects[i] = container.transform.GetChild(i).gameObject;
|
|
if (waterObjects[i].transform.Find("Static Boundary") != null)
|
|
{
|
|
staticBoundaries[i] = waterObjects[i].transform.Find("Static Boundary").gameObject;
|
|
}
|
|
else
|
|
{
|
|
staticBoundaries[i] = dynamicBoundary;
|
|
}
|
|
}
|
|
boundaryMask = new GameObject("Boundary Mask");
|
|
volumeMask = new GameObject("Volume Mask");
|
|
frontFaceMask = new GameObject("Front Face Mask");
|
|
background = new GameObject("Background");
|
|
boundaryMask.hideFlags = HideFlags.HideAndDontSave;
|
|
volumeMask.hideFlags = HideFlags.HideAndDontSave;
|
|
frontFaceMask.hideFlags = HideFlags.HideAndDontSave;
|
|
background.hideFlags = HideFlags.HideAndDontSave;
|
|
boundaryMask.transform.SetParent(base.transform);
|
|
boundaryMask.AddComponent<Camera>().CopyFrom(GetComponent<Camera>());
|
|
boundaryMask.GetComponent<Camera>().cullingMask &= -2 << LayerMask.NameToLayer("Everything");
|
|
boundaryMask.GetComponent<Camera>().cullingMask ^= 1 << LayerMask.NameToLayer("Water");
|
|
boundaryMask.GetComponent<Camera>().depth = GetComponent<Camera>().depth - 4f;
|
|
boundaryMask.AddComponent<AQUAS_BoundaryMask>();
|
|
boundaryMask.GetComponent<AQUAS_BoundaryMask>().nextCam = volumeMask;
|
|
boundaryMask.AddComponent<AQUAS_ReflectNot>();
|
|
volumeMask.transform.SetParent(base.transform);
|
|
volumeMask.AddComponent<Camera>().CopyFrom(GetComponent<Camera>());
|
|
volumeMask.GetComponent<Camera>().cullingMask &= -2 << LayerMask.NameToLayer("Everything");
|
|
volumeMask.GetComponent<Camera>().cullingMask ^= 1 << LayerMask.NameToLayer("Water");
|
|
volumeMask.GetComponent<Camera>().depth = GetComponent<Camera>().depth - 3f;
|
|
volumeMask.AddComponent<AQUAS_VolumeMask>();
|
|
volumeMask.GetComponent<AQUAS_VolumeMask>().nextCam = frontFaceMask;
|
|
volumeMask.AddComponent<AQUAS_ReflectNot>();
|
|
frontFaceMask.transform.SetParent(base.transform);
|
|
frontFaceMask.AddComponent<Camera>().CopyFrom(GetComponent<Camera>());
|
|
frontFaceMask.GetComponent<Camera>().cullingMask &= -2 << LayerMask.NameToLayer("Everything");
|
|
frontFaceMask.GetComponent<Camera>().cullingMask ^= 1 << LayerMask.NameToLayer("Water");
|
|
frontFaceMask.GetComponent<Camera>().depth = GetComponent<Camera>().depth - 2f;
|
|
frontFaceMask.AddComponent<AQUAS_FrontFaceMask>();
|
|
frontFaceMask.GetComponent<AQUAS_FrontFaceMask>().nextCam = base.gameObject;
|
|
frontFaceMask.AddComponent<AQUAS_ReflectNot>();
|
|
background.transform.SetParent(base.transform);
|
|
background.AddComponent<Camera>().CopyFrom(GetComponent<Camera>());
|
|
background.GetComponent<Camera>().cullingMask = cullingMask;
|
|
background.GetComponent<Camera>().cullingMask &= ~(1 << LayerMask.NameToLayer("Water"));
|
|
background.GetComponent<Camera>().depth = GetComponent<Camera>().depth - 1f;
|
|
background.AddComponent<AQUAS_CaptureBackground>();
|
|
background.AddComponent<AQUAS_ReflectNot>();
|
|
switch (backFaceQuality)
|
|
{
|
|
case QUALITY.low:
|
|
background.GetComponent<AQUAS_CaptureBackground>().quality = 3;
|
|
break;
|
|
case QUALITY.medium:
|
|
background.GetComponent<AQUAS_CaptureBackground>().quality = 2;
|
|
break;
|
|
case QUALITY.high:
|
|
background.GetComponent<AQUAS_CaptureBackground>().quality = 0;
|
|
break;
|
|
}
|
|
fogMat = new Material(Shader.Find("Hidden/AQUAS/Underwater/Fog"));
|
|
blurMat = new Material(Shader.Find("Hidden/AQUAS/Underwater/Blur"));
|
|
dropletMaskMat = new Material(Shader.Find("Hidden/AQUAS/Underwater/Droplet Mask"));
|
|
float x = (float)Screen.width / (float)Screen.height;
|
|
fogMat.SetTexture("_DistortionLens", (Texture2D)Resources.Load("distortion_ellipse", typeof(Texture2D)));
|
|
fogMat.SetTexture("_DropletNormals", (Texture2D)Resources.Load("wet_lens_normal", typeof(Texture2D)));
|
|
fogMat.SetTextureScale("_DropletNormals", new Vector2(x, 1f));
|
|
fogMat.SetTexture("_DropletCutout", (Texture2D)Resources.Load("wet_lens_cutout", typeof(Texture2D)));
|
|
fogMat.SetTextureScale("_DropletCutout", new Vector2(x, 1f));
|
|
mask = new RenderTexture(Screen.height, Screen.width, 8, RenderTextureFormat.ARGB32);
|
|
buffer1 = new RenderTexture(Screen.width, Screen.height, 32, RenderTextureFormat.ARGB32);
|
|
buffer2 = new RenderTexture(Screen.width, Screen.height, 32, RenderTextureFormat.ARGB32);
|
|
fogBuffer = new RenderTexture(Screen.width, Screen.height, 32, RenderTextureFormat.ARGB32);
|
|
dropletBuffer = new RenderTexture(Screen.width, Screen.height, 32, RenderTextureFormat.ARGB32);
|
|
dropletMask = new RenderTexture(Screen.width, Screen.height, 32, RenderTextureFormat.ARGB32);
|
|
audioObject = new GameObject("Underwater Audio");
|
|
audioObject.transform.parent = base.transform;
|
|
audioObject.hideFlags = HideFlags.HideAndDontSave;
|
|
if (underwaterAmbientSound == null)
|
|
{
|
|
underwaterAmbientSound = (AudioClip)Resources.Load("underwater");
|
|
}
|
|
if (diveSplashSound == null)
|
|
{
|
|
diveSplashSound = (AudioClip)Resources.Load("dive-splash");
|
|
}
|
|
if (surfaceSplashSound == null)
|
|
{
|
|
surfaceSplashSound = (AudioClip)Resources.Load("surfacing-splash");
|
|
}
|
|
underwaterAmbient = audioObject.AddComponent<AudioSource>();
|
|
diveSplash = audioObject.AddComponent<AudioSource>();
|
|
surfaceSplash = audioObject.AddComponent<AudioSource>();
|
|
underwaterAmbient.clip = underwaterAmbientSound;
|
|
diveSplash.clip = diveSplashSound;
|
|
surfaceSplash.clip = surfaceSplashSound;
|
|
diveSplash.loop = false;
|
|
surfaceSplash.loop = false;
|
|
bubble = (GameObject)Resources.Load("Bubble", typeof(GameObject));
|
|
bubbleBehaviour = bubble.GetComponent<AQUAS_BubbleBehaviour>();
|
|
if (spawnBubbles)
|
|
{
|
|
bubbleContainer = new GameObject("Bubble Container");
|
|
bubbleContainer.hideFlags = HideFlags.HideAndDontSave;
|
|
}
|
|
}
|
|
|
|
private void OnTriggerEnter(Collider other)
|
|
{
|
|
if (other.gameObject.name == "Static Boundary")
|
|
{
|
|
if (other.transform.parent == null)
|
|
{
|
|
waterPlane = GetComponent<AQUAS_ProjectedGrid>().waterplane;
|
|
}
|
|
else
|
|
{
|
|
waterPlane = other.transform.parent.gameObject;
|
|
}
|
|
other.GetComponent<MeshRenderer>().enabled = true;
|
|
fogColor = waterPlane.GetComponent<AQUAS_UnderwaterParameters>().mainFogColor;
|
|
deepFogColor = waterPlane.GetComponent<AQUAS_UnderwaterParameters>().deepFogColor;
|
|
fogDensity = waterPlane.GetComponent<AQUAS_UnderwaterParameters>().mainFogDensity;
|
|
deepFogDensity = waterPlane.GetComponent<AQUAS_UnderwaterParameters>().deepFogDensity;
|
|
maxFogDepth = waterPlane.GetComponent<AQUAS_UnderwaterParameters>().maxFogDepth;
|
|
for (int i = 0; i < waterObjects.Length; i++)
|
|
{
|
|
waterObjects[i].layer = LayerMask.NameToLayer("Default");
|
|
staticBoundaries[i].layer = LayerMask.NameToLayer("Default");
|
|
}
|
|
boundaryMask.GetComponent<AQUAS_BoundaryMask>().boundaryObj = other.gameObject;
|
|
volumeMask.GetComponent<AQUAS_VolumeMask>().waterObj = waterPlane;
|
|
volumeMask.GetComponent<AQUAS_VolumeMask>().rend = waterPlane.GetComponent<Renderer>();
|
|
volumeMask.GetComponent<AQUAS_VolumeMask>().waterShaders[0] = waterPlane.GetComponent<Renderer>().sharedMaterials[0].shader;
|
|
volumeMask.GetComponent<AQUAS_VolumeMask>().waterShaders[1] = waterPlane.GetComponent<Renderer>().sharedMaterials[1].shader;
|
|
frontFaceMask.GetComponent<AQUAS_FrontFaceMask>().waterObj = waterPlane;
|
|
frontFaceMask.GetComponent<AQUAS_FrontFaceMask>().rend = waterPlane.GetComponent<Renderer>();
|
|
frontFaceMask.GetComponent<AQUAS_FrontFaceMask>().waterShaders[0] = waterPlane.GetComponent<Renderer>().sharedMaterials[0].shader;
|
|
frontFaceMask.GetComponent<AQUAS_FrontFaceMask>().waterShaders[1] = waterPlane.GetComponent<Renderer>().sharedMaterials[1].shader;
|
|
background.GetComponent<AQUAS_CaptureBackground>().waterObj = waterPlane;
|
|
background.GetComponent<AQUAS_CaptureBackground>().layerMask = cullingMask;
|
|
}
|
|
}
|
|
|
|
private void OnTriggerExit(Collider other)
|
|
{
|
|
if (other.gameObject.name == "Static Boundary")
|
|
{
|
|
other.GetComponent<MeshRenderer>().enabled = false;
|
|
waterPlane = null;
|
|
for (int i = 0; i < waterObjects.Length; i++)
|
|
{
|
|
waterObjects[i].layer = LayerMask.NameToLayer("Water");
|
|
staticBoundaries[i].layer = LayerMask.NameToLayer("Water");
|
|
}
|
|
boundaryMask.GetComponent<AQUAS_BoundaryMask>().boundaryObj = null;
|
|
volumeMask.GetComponent<AQUAS_VolumeMask>().waterObj = null;
|
|
frontFaceMask.GetComponent<AQUAS_FrontFaceMask>().waterObj = null;
|
|
background.GetComponent<AQUAS_CaptureBackground>().waterObj = null;
|
|
}
|
|
}
|
|
|
|
private void OnRenderImage(RenderTexture source, RenderTexture destination)
|
|
{
|
|
dropletMaskMat.SetTexture("_DropletMask", dropletMask);
|
|
dropletMaskMat.SetFloat("_Duration", wetLensDuration);
|
|
Graphics.Blit(mask, dropletBuffer, dropletMaskMat);
|
|
Graphics.Blit(dropletBuffer, dropletMask);
|
|
fogMat.SetTexture("_DropletMask", dropletMask);
|
|
if (blurSmoothness > 0)
|
|
{
|
|
fogMat.SetTexture("_DepthMask", mask);
|
|
fogMat.SetFloat("_Density", adjustedFogDensity);
|
|
fogMat.SetColor("_FogColor", adjustedFogColor);
|
|
fogMat.SetFloat("_Distortion", distortionStrength);
|
|
fogMat.SetFloat("_Fade", fogFade);
|
|
if (enableWetLensEffect)
|
|
{
|
|
fogMat.SetFloat("_EnableWetLens", 1f);
|
|
}
|
|
else
|
|
{
|
|
fogMat.SetFloat("_EnableWetLens", 0f);
|
|
}
|
|
Graphics.Blit(source, fogBuffer, fogMat);
|
|
blurMat.SetTexture("_DepthMask", mask);
|
|
blurMat.SetFloat("_BlurSize", blurSize);
|
|
if (blurSmoothness == 1)
|
|
{
|
|
Graphics.Blit(fogBuffer, destination, blurMat);
|
|
}
|
|
else if (blurSmoothness == 2)
|
|
{
|
|
Graphics.Blit(fogBuffer, buffer1, blurMat);
|
|
Graphics.Blit(buffer1, destination, blurMat);
|
|
buffer1.Release();
|
|
}
|
|
else
|
|
{
|
|
if (blurSmoothness <= 2)
|
|
{
|
|
return;
|
|
}
|
|
for (int i = 0; i < blurSmoothness; i++)
|
|
{
|
|
if (i == 0)
|
|
{
|
|
Graphics.Blit(fogBuffer, buffer1, blurMat);
|
|
}
|
|
if (i == blurSmoothness - 1)
|
|
{
|
|
if (i % 2 == 1)
|
|
{
|
|
Graphics.Blit(buffer1, destination, blurMat);
|
|
buffer1.Release();
|
|
}
|
|
else
|
|
{
|
|
Graphics.Blit(buffer2, destination, blurMat);
|
|
buffer2.Release();
|
|
}
|
|
}
|
|
if (i > 0 && i < blurSmoothness - 1)
|
|
{
|
|
if (i % 2 == 1)
|
|
{
|
|
Graphics.Blit(buffer1, buffer2, blurMat);
|
|
buffer1.Release();
|
|
}
|
|
else
|
|
{
|
|
Graphics.Blit(buffer2, buffer1, blurMat);
|
|
buffer2.Release();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fogMat.SetTexture("_DepthMask", mask);
|
|
fogMat.SetFloat("_Density", adjustedFogDensity);
|
|
fogMat.SetColor("_FogColor", adjustedFogColor);
|
|
fogMat.SetFloat("_Distortion", distortionStrength);
|
|
fogMat.SetFloat("_Fade", fogFade);
|
|
Graphics.Blit(source, destination, fogMat);
|
|
}
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (waterPlane != null)
|
|
{
|
|
if (waterPlane.GetComponent<AQUAS_CamLock>() != null && waterPlane.GetComponent<AQUAS_CamLock>().useDynamicMesh)
|
|
{
|
|
if (base.transform.position.y < waterLevel)
|
|
{
|
|
underwater = true;
|
|
}
|
|
else
|
|
{
|
|
underwater = false;
|
|
}
|
|
}
|
|
else if (base.transform.position.y < waterPlane.transform.position.y)
|
|
{
|
|
underwater = true;
|
|
}
|
|
else
|
|
{
|
|
underwater = false;
|
|
}
|
|
adjustedFogColor = Color.Lerp(fogColor, deepFogColor, (waterPlane.transform.position.y - base.transform.position.y) / maxFogDepth);
|
|
}
|
|
else
|
|
{
|
|
underwater = false;
|
|
}
|
|
underwaterAmbient.volume = underwaterAmbientVolume;
|
|
diveSplash.volume = diveSplashVolume;
|
|
surfaceSplash.volume = surfaceSplashVolume;
|
|
if (underwater)
|
|
{
|
|
surfaceSplashPlayed = false;
|
|
if (!underwaterAmbient.isPlaying)
|
|
{
|
|
underwaterAmbient.Play();
|
|
}
|
|
if (!diveSplashPlayed)
|
|
{
|
|
diveSplash.Play();
|
|
diveSplashPlayed = true;
|
|
}
|
|
if (spawnBubbles)
|
|
{
|
|
if (bubbleContainer == null)
|
|
{
|
|
bubbleContainer = new GameObject("Bubble Container");
|
|
bubbleContainer.hideFlags = HideFlags.HideAndDontSave;
|
|
}
|
|
t2 += Time.deltaTime;
|
|
BubbleSpawner();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
diveSplashPlayed = false;
|
|
if (underwaterAmbient.isPlaying)
|
|
{
|
|
underwaterAmbient.Stop();
|
|
}
|
|
if (!surfaceSplashPlayed)
|
|
{
|
|
surfaceSplash.Play();
|
|
surfaceSplashPlayed = true;
|
|
}
|
|
t2 = 0f;
|
|
bubbleSpawnTimer = 0f;
|
|
maxBubbleCount = Random.Range(maximumBubbleCount / 2, maximumBubbleCount);
|
|
bubbleCount = 0;
|
|
}
|
|
if (waterPlane != null)
|
|
{
|
|
adjustedFogDensity = Mathf.Lerp(fogDensity, deepFogDensity, (waterPlane.transform.position.y - base.transform.position.y) / maxFogDepth) * GetComponent<Camera>().farClipPlane / 10f;
|
|
adjustedFogColor = Color.Lerp(fogColor, deepFogColor, (waterPlane.transform.position.y - base.transform.position.y) / maxFogDepth);
|
|
}
|
|
}
|
|
|
|
private void BubbleSpawner()
|
|
{
|
|
if (t2 > bubbleSpawnTimer && maxBubbleCount > bubbleCount)
|
|
{
|
|
float num = Random.Range(0f, 0.06f);
|
|
bubbleBehaviour.mainCamera = base.gameObject;
|
|
if (waterPlane.GetComponent<AQUAS_CamLock>() != null && waterPlane.GetComponent<AQUAS_CamLock>().useDynamicMesh)
|
|
{
|
|
bubbleBehaviour.waterLevel = waterLevel;
|
|
}
|
|
else
|
|
{
|
|
bubbleBehaviour.waterLevel = waterPlane.transform.position.y;
|
|
}
|
|
bubbleBehaviour.averageUpdrift = 1f + Random.Range(-0.3f, 0.3f);
|
|
bubble.transform.localScale += new Vector3(num, num, num);
|
|
Object.Instantiate(bubble, new Vector3(base.transform.position.x + Random.Range(-3f, 3f), base.transform.position.y - 0.4f, base.transform.position.z + Random.Range(-3f, 3f)), Quaternion.identity).transform.SetParent(bubbleContainer.transform);
|
|
bubbleSpawnTimer += Random.Range(0.02f, 0.1f);
|
|
bubbleCount++;
|
|
bubble.transform.localScale = new Vector3(0.06f, 0.06f, 0.06f);
|
|
}
|
|
else if (t2 > bubbleSpawnTimer && maxBubbleCount <= bubbleCount)
|
|
{
|
|
float num2 = Random.Range(0f, 0.06f);
|
|
bubbleBehaviour.mainCamera = base.gameObject;
|
|
if (waterPlane.GetComponent<AQUAS_CamLock>() != null && waterPlane.GetComponent<AQUAS_CamLock>().useDynamicMesh)
|
|
{
|
|
bubbleBehaviour.waterLevel = waterLevel;
|
|
}
|
|
else
|
|
{
|
|
bubbleBehaviour.waterLevel = waterPlane.transform.position.y;
|
|
}
|
|
bubbleBehaviour.averageUpdrift = 1f + Random.Range(-0.3f, 0.3f);
|
|
bubble.transform.localScale += new Vector3(num2, num2, num2);
|
|
Object.Instantiate(bubble, new Vector3(base.transform.position.x + Random.Range(-0.5f, 0.5f), base.transform.position.y - 0.4f, base.transform.position.z + Random.Range(-0.5f, 0.5f)), Quaternion.identity).transform.SetParent(bubbleContainer.transform);
|
|
bubbleSpawnTimer += Random.Range(0.02f, 0.2f);
|
|
bubble.transform.localScale = new Vector3(0.06f, 0.06f, 0.06f);
|
|
}
|
|
}
|
|
}
|
|
}
|