304 lines
9.8 KiB
C#
304 lines
9.8 KiB
C#
using System;
|
|
using System.Linq;
|
|
using UnityEngine;
|
|
using UnityEngine.Serialization;
|
|
|
|
namespace UltimateWater
|
|
{
|
|
public sealed class WettableSurface : MonoBehaviour
|
|
{
|
|
public enum Mode
|
|
{
|
|
TextureSpace = 0,
|
|
NearCamera = 1
|
|
}
|
|
|
|
[FormerlySerializedAs("wettableUtilShader")]
|
|
[SerializeField]
|
|
[HideInInspector]
|
|
private Shader _WettableUtilShader;
|
|
|
|
[HideInInspector]
|
|
[SerializeField]
|
|
[FormerlySerializedAs("wettableUtilNearShader")]
|
|
private Shader _WettableUtilNearShader;
|
|
|
|
[FormerlySerializedAs("water")]
|
|
[SerializeField]
|
|
private Water _Water;
|
|
|
|
[FormerlySerializedAs("mainCamera")]
|
|
[SerializeField]
|
|
[Tooltip("Surface wetting near this camera will be more precise.")]
|
|
private WaterCamera _MainCamera;
|
|
|
|
[FormerlySerializedAs("mode")]
|
|
[SerializeField]
|
|
[Tooltip("Texture space is good for small objects, especially convex ones.\nNear camera mode is better for terrains and big meshes that are static and don't have geometry at the bottom.")]
|
|
private Mode _Mode;
|
|
|
|
[FormerlySerializedAs("resolution")]
|
|
[SerializeField]
|
|
private int _Resolution = 512;
|
|
|
|
[FormerlySerializedAs("meshRenderers")]
|
|
[SerializeField]
|
|
[Header("Direct references (Optional)")]
|
|
private MeshRenderer[] _MeshRenderers;
|
|
|
|
[FormerlySerializedAs("terrains")]
|
|
[SerializeField]
|
|
private Terrain[] _Terrains;
|
|
|
|
private MeshFilter[] _MeshFilters;
|
|
|
|
private Material _WettableUtilMaterial;
|
|
|
|
private RenderTexture _WetnessMapA;
|
|
|
|
private RenderTexture _WetnessMapB;
|
|
|
|
private Camera _WettingCamera;
|
|
|
|
private Material[] _Materials;
|
|
|
|
private bool[] _TerrainDrawTrees;
|
|
|
|
private int[] _TerrainLayers;
|
|
|
|
public WaterCamera MainCamera
|
|
{
|
|
get
|
|
{
|
|
return _MainCamera;
|
|
}
|
|
set
|
|
{
|
|
_MainCamera = value;
|
|
}
|
|
}
|
|
|
|
private void LateUpdate()
|
|
{
|
|
if (!_MainCamera.enabled)
|
|
{
|
|
return;
|
|
}
|
|
switch (_Mode)
|
|
{
|
|
case Mode.TextureSpace:
|
|
{
|
|
Graphics.SetRenderTarget(_WetnessMapA);
|
|
_WettableUtilMaterial.SetPass(0);
|
|
_WettableUtilMaterial.SetTexture("_TotalDisplacementMap", _Water.DynamicWater.GetCameraOverlaysData(_MainCamera.GetComponent<Camera>()).GetTotalDisplacementMap());
|
|
_WettableUtilMaterial.SetVector("_LocalMapsCoords", _MainCamera.LocalMapsShaderCoords);
|
|
for (int m = 0; m < _MeshFilters.Length; m++)
|
|
{
|
|
Graphics.DrawMeshNow(_MeshFilters[m].sharedMesh, _MeshFilters[m].transform.localToWorldMatrix);
|
|
}
|
|
if (_Terrains.Length != 0)
|
|
{
|
|
int waterTempLayer2 = WaterProjectSettings.Instance.WaterTempLayer;
|
|
for (int n = 0; n < _Terrains.Length; n++)
|
|
{
|
|
GameObject gameObject2 = _Terrains[n].gameObject;
|
|
_TerrainLayers[n] = gameObject2.layer;
|
|
gameObject2.layer = waterTempLayer2;
|
|
}
|
|
Shader.SetGlobalTexture("_TotalDisplacementMap", _Water.DynamicWater.GetCameraOverlaysData(_MainCamera.GetComponent<Camera>()).GetTotalDisplacementMap());
|
|
Shader.SetGlobalVector("_LocalMapsCoords", _MainCamera.LocalMapsShaderCoords);
|
|
Camera wettingCamera2 = GetWettingCamera();
|
|
wettingCamera2.transform.position = _Terrains[0].transform.position + _Terrains[0].terrainData.size * 0.5f;
|
|
wettingCamera2.RenderWithShader(_WettableUtilShader, "CustomType");
|
|
for (int num = 0; num < _Terrains.Length; num++)
|
|
{
|
|
_Terrains[num].gameObject.layer = _TerrainLayers[num];
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case Mode.NearCamera:
|
|
{
|
|
int waterTempLayer = WaterProjectSettings.Instance.WaterTempLayer;
|
|
for (int i = 0; i < _Terrains.Length; i++)
|
|
{
|
|
_TerrainDrawTrees[i] = _Terrains[i].drawTreesAndFoliage;
|
|
_Terrains[i].drawTreesAndFoliage = false;
|
|
GameObject gameObject = _Terrains[i].gameObject;
|
|
_TerrainLayers[i] = gameObject.layer;
|
|
gameObject.layer = waterTempLayer;
|
|
}
|
|
Shader.SetGlobalTexture("_WetnessMapPrevious", _WetnessMapB);
|
|
Shader.SetGlobalTexture("_TotalDisplacementMap", _Water.DynamicWater.GetCameraOverlaysData(_MainCamera.GetComponent<Camera>()).GetTotalDisplacementMap());
|
|
Shader.SetGlobalVector("_LocalMapsCoords", _MainCamera.LocalMapsShaderCoords);
|
|
Rect localMapsRectPrevious = _MainCamera.LocalMapsRectPrevious;
|
|
Shader.SetGlobalVector("_LocalMapsCoordsPrevious", new Vector4((0f - localMapsRectPrevious.xMin) / localMapsRectPrevious.width, (0f - localMapsRectPrevious.yMin) / localMapsRectPrevious.width, 1f / localMapsRectPrevious.width, localMapsRectPrevious.width));
|
|
Rect localMapsRect = _MainCamera.LocalMapsRect;
|
|
Camera wettingCamera = GetWettingCamera();
|
|
wettingCamera.transform.position = new Vector3(localMapsRect.center.x, _Terrains[0].transform.position.y + _Terrains[0].terrainData.size.y + 1f, localMapsRect.center.y);
|
|
wettingCamera.orthographicSize = localMapsRect.width * 0.5f;
|
|
wettingCamera.nearClipPlane = 1f;
|
|
wettingCamera.farClipPlane = _Terrains[0].terrainData.size.y * 2f;
|
|
wettingCamera.targetTexture = _WetnessMapA;
|
|
wettingCamera.clearFlags = CameraClearFlags.Color;
|
|
wettingCamera.backgroundColor = new Color(0f, 0f, 0f, 0f);
|
|
wettingCamera.RenderWithShader(_WettableUtilNearShader, "CustomType");
|
|
for (int j = 0; j < _Materials.Length; j++)
|
|
{
|
|
_Materials[j].SetTexture("_WetnessMap", _WetnessMapA);
|
|
}
|
|
for (int k = 0; k < _Terrains.Length; k++)
|
|
{
|
|
_Terrains[k].drawTreesAndFoliage = _TerrainDrawTrees[k];
|
|
_Terrains[k].gameObject.layer = _TerrainLayers[k];
|
|
}
|
|
RenderTexture wetnessMapB = _WetnessMapB;
|
|
_WetnessMapB = _WetnessMapA;
|
|
_WetnessMapA = wetnessMapB;
|
|
for (int l = 0; l < _Materials.Length; l++)
|
|
{
|
|
_Materials[l].SetVector("_LocalMapsCoords", _MainCamera.LocalMapsShaderCoords);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void OnValidate()
|
|
{
|
|
if (_WettableUtilShader == null)
|
|
{
|
|
_WettableUtilShader = Shader.Find("UltimateWater/Utility/Wetness Update");
|
|
}
|
|
if (_WettableUtilNearShader == null)
|
|
{
|
|
_WettableUtilNearShader = Shader.Find("UltimateWater/Utility/Wetness Update (Near Camera)");
|
|
}
|
|
if (_MeshRenderers == null || _MeshRenderers.Length == 0)
|
|
{
|
|
_MeshRenderers = GetComponentsInChildren<MeshRenderer>(true);
|
|
}
|
|
if (_Terrains == null || _Terrains.Length == 0)
|
|
{
|
|
_Terrains = GetComponentsInChildren<Terrain>(true);
|
|
}
|
|
Material[] array = _Materials;
|
|
if (Application.isPlaying)
|
|
{
|
|
return;
|
|
}
|
|
if (array == null)
|
|
{
|
|
array = _MeshRenderers.SelectMany((MeshRenderer mr) => mr.sharedMaterials).Concat(_Terrains.Select((Terrain t) => t.materialTemplate)).ToArray();
|
|
}
|
|
if (_Mode == Mode.NearCamera)
|
|
{
|
|
for (int num = 0; num < array.Length; num++)
|
|
{
|
|
array[num].EnableKeyword("_WET_NEAR_CAMERA");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int num2 = 0; num2 < array.Length; num2++)
|
|
{
|
|
array[num2].DisableKeyword("_WET_NEAR_CAMERA");
|
|
}
|
|
}
|
|
}
|
|
|
|
private void Awake()
|
|
{
|
|
if (_Water == null || _Water.DynamicWater == null)
|
|
{
|
|
base.enabled = false;
|
|
return;
|
|
}
|
|
OnValidate();
|
|
_TerrainLayers = new int[_Terrains.Length];
|
|
_TerrainDrawTrees = new bool[_Terrains.Length];
|
|
_MeshFilters = new MeshFilter[_MeshRenderers.Length];
|
|
for (int i = 0; i < _MeshFilters.Length; i++)
|
|
{
|
|
_MeshFilters[i] = _MeshRenderers[i].GetComponent<MeshFilter>();
|
|
}
|
|
_WetnessMapA = new RenderTexture(_Resolution, _Resolution, 0, RenderTextureFormat.RHalf, RenderTextureReadWrite.Linear)
|
|
{
|
|
name = "[UWS] WettableSurface - Wetness Map",
|
|
hideFlags = HideFlags.DontSave,
|
|
filterMode = FilterMode.Bilinear
|
|
};
|
|
if (_Mode == Mode.NearCamera)
|
|
{
|
|
_WetnessMapB = new RenderTexture(_Resolution, _Resolution, 0, RenderTextureFormat.RHalf, RenderTextureReadWrite.Linear)
|
|
{
|
|
name = "[UWS] WettableSurface - Wetness Map",
|
|
hideFlags = HideFlags.DontSave,
|
|
filterMode = FilterMode.Bilinear
|
|
};
|
|
}
|
|
Material[] materials = Enumerable.Distinct(_MeshRenderers.SelectMany((MeshRenderer mr) => mr.sharedMaterials).Concat(_Terrains.Select((Terrain t) => t.materialTemplate))).ToArray();
|
|
_Materials = InstantiateMaterials(materials);
|
|
OnValidate();
|
|
_WettableUtilMaterial = new Material((_Mode != Mode.TextureSpace) ? _WettableUtilNearShader : _WettableUtilShader)
|
|
{
|
|
hideFlags = HideFlags.DontSave
|
|
};
|
|
}
|
|
|
|
private Material[] InstantiateMaterials(Material[] materials)
|
|
{
|
|
Material[] array = new Material[materials.Length];
|
|
for (int i = 0; i < array.Length; i++)
|
|
{
|
|
array[i] = UnityEngine.Object.Instantiate(materials[i]);
|
|
}
|
|
for (int j = 0; j < _MeshRenderers.Length; j++)
|
|
{
|
|
MeshRenderer meshRenderer = _MeshRenderers[j];
|
|
Material[] sharedMaterials = meshRenderer.sharedMaterials;
|
|
for (int k = 0; k < sharedMaterials.Length; k++)
|
|
{
|
|
int num = Array.IndexOf(materials, sharedMaterials[k]);
|
|
sharedMaterials[k] = array[num];
|
|
}
|
|
meshRenderer.sharedMaterials = sharedMaterials;
|
|
}
|
|
for (int l = 0; l < _Terrains.Length; l++)
|
|
{
|
|
Terrain terrain = _Terrains[l];
|
|
int num2 = Array.IndexOf(materials, terrain.materialTemplate);
|
|
terrain.materialTemplate = array[num2];
|
|
}
|
|
for (int m = 0; m < array.Length; m++)
|
|
{
|
|
array[m].SetTexture("_WetnessMap", _WetnessMapA);
|
|
}
|
|
return array;
|
|
}
|
|
|
|
private Camera GetWettingCamera()
|
|
{
|
|
if (_WettingCamera == null)
|
|
{
|
|
GameObject gameObject = new GameObject("Wetting Camera");
|
|
gameObject.hideFlags = HideFlags.DontSave;
|
|
GameObject gameObject2 = gameObject;
|
|
gameObject2.transform.position = new Vector3(0f, 100000f, 0f);
|
|
gameObject2.transform.eulerAngles = new Vector3(90f, 0f, 0f);
|
|
_WettingCamera = gameObject2.AddComponent<Camera>();
|
|
_WettingCamera.enabled = false;
|
|
_WettingCamera.orthographic = true;
|
|
_WettingCamera.orthographicSize = 1000000f;
|
|
_WettingCamera.nearClipPlane = 10f;
|
|
_WettingCamera.farClipPlane = 1000000f;
|
|
_WettingCamera.cullingMask = 1 << WaterProjectSettings.Instance.WaterTempLayer;
|
|
_WettingCamera.renderingPath = RenderingPath.VertexLit;
|
|
_WettingCamera.clearFlags = CameraClearFlags.Nothing;
|
|
_WettingCamera.targetTexture = _WetnessMapA;
|
|
}
|
|
return _WettingCamera;
|
|
}
|
|
}
|
|
}
|