259 lines
8.2 KiB
C#
259 lines
8.2 KiB
C#
// Stylized Water 3 by Staggart Creations (http://staggart.xyz)
|
|
// COPYRIGHT PROTECTED UNDER THE UNITY ASSET STORE EULA (https://unity.com/legal/as-terms)
|
|
// • Copying or referencing source code for the production of new asset store, or public, content is strictly prohibited!
|
|
// • Uploading this file to a public repository will subject it to an automated DMCA takedown request.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.Rendering;
|
|
|
|
namespace StylizedWater3
|
|
{
|
|
[ExecuteAlways]
|
|
[AddComponentMenu("")] //Hide, only to be used with the prefab
|
|
public class OceanFollowBehaviour : MonoBehaviour
|
|
{
|
|
public static OceanFollowBehaviour Instance;
|
|
|
|
const int LODCount = 7;
|
|
private static readonly float[] gridSizes = new[]
|
|
{
|
|
0.5f, //LOD0
|
|
01f, //LOD1
|
|
02f, //LOD2
|
|
04f, //LOD3
|
|
08f, //LOD4
|
|
16f, //LOD5
|
|
32f, //LOD6
|
|
32f //LOD7
|
|
};
|
|
|
|
private const float EXPECTED_MAX_WAVE_HEIGHT = 15f;
|
|
|
|
public Material material;
|
|
|
|
[Space]
|
|
|
|
[Tooltip("Enable to executing the camera following behaviour when outside of Play mode")]
|
|
public bool enableInEditMode = true;
|
|
[Tooltip("Assign a specific transform to follow on the XZ axis." +
|
|
"\n\nIf left empty, the camera currently rendering will be targeted.")]
|
|
public Transform followTarget;
|
|
|
|
[Space]
|
|
|
|
public static bool ShowWireFrame = true;
|
|
|
|
[Serializable]
|
|
public class LOD
|
|
{
|
|
public List<GameObject> gameObjects = new List<GameObject>();
|
|
public float gridSize = 1f;
|
|
}
|
|
[SerializeField]
|
|
//[HideInInspector]
|
|
private LOD[] lods;
|
|
|
|
//To ensure that each LOD renders behind the one before it, move each one down a tiny bit
|
|
private const float heightOffset = 0.01f;
|
|
|
|
private void Reset()
|
|
{
|
|
//BuildLODs();
|
|
}
|
|
|
|
#if SWS_DEV
|
|
[ContextMenu("Build LODs")]
|
|
#endif
|
|
//Populates the LOD list and sets the gridsize for each
|
|
void BuildLODs()
|
|
{
|
|
lods = new LOD[LODCount+1];
|
|
for (int i = 0; i < lods.Length; i++)
|
|
{
|
|
lods[i] = new LOD();
|
|
lods[i].gridSize = gridSizes[i];
|
|
}
|
|
|
|
MeshRenderer[] childs = this.gameObject.GetComponentsInChildren<MeshRenderer>(true);
|
|
for (int i = 0; i < childs.Length; i++)
|
|
{
|
|
childs[i].gameObject.layer = WaterObject.WaterLayer;
|
|
|
|
string objName = childs[i].name;
|
|
int lodIndex = 0;
|
|
|
|
if(objName.EndsWith("0")) lodIndex = 0;
|
|
if(objName.EndsWith("1")) lodIndex = 1;
|
|
if(objName.EndsWith("2")) lodIndex = 2;
|
|
if(objName.EndsWith("3")) lodIndex = 3;
|
|
if(objName.EndsWith("4")) lodIndex = 4;
|
|
if(objName.EndsWith("5")) lodIndex = 5;
|
|
if(objName.EndsWith("6")) lodIndex = 6;
|
|
if(objName.EndsWith("7")) lodIndex = 7;
|
|
|
|
#if UNITY_EDITOR
|
|
childs[i].scaleInLightmap = Mathf.Lerp(1, 0.01f, (float)lodIndex / LODCount);
|
|
#endif
|
|
|
|
lods[lodIndex].gameObjects.Add(childs[i].gameObject);
|
|
}
|
|
}
|
|
|
|
private Vector3 targetPosition;
|
|
private void SetPosition(Transform target)
|
|
{
|
|
float height = this.transform.position.y;
|
|
|
|
for (int i = 0; i < lods.Length; i++)
|
|
{
|
|
for (int j = 0; j < lods[i].gameObjects.Count; j++)
|
|
{
|
|
targetPosition = WaterGrid.SnapToGrid(target.position, this.transform.lossyScale.x * lods[i].gridSize);
|
|
//targetPosition = target.position; //No snapping
|
|
|
|
//Progressively lower the height of each LOD a small amount, this helps ensure transparency sorting will be correct.
|
|
targetPosition.y = height - (heightOffset * i);
|
|
|
|
#if UNITY_EDITOR || DEVELOPMENT_BUILD
|
|
if (lods[i].gameObjects[j] == false) throw new Exception("[Ocean] A child GameObject was deleted, these should not be touched!");
|
|
#endif
|
|
|
|
lods[i].gameObjects[j].transform.position = targetPosition;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void ApplyMaterial()
|
|
{
|
|
for (int i = 0; i < lods.Length; i++)
|
|
{
|
|
foreach (var lod in lods[i].gameObjects)
|
|
{
|
|
MeshRenderer r = lod.GetComponent<MeshRenderer>();
|
|
|
|
if (r)
|
|
{
|
|
r.sharedMaterial = material;
|
|
PadBounds(r);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//Pad the bounds so that meshes don't get unintentionally culled when using high waves
|
|
private void PadBounds()
|
|
{
|
|
for (int i = 0; i < lods.Length; i++)
|
|
{
|
|
foreach (var lod in lods[i].gameObjects)
|
|
{
|
|
MeshRenderer r = lod.GetComponent<MeshRenderer>();
|
|
|
|
if (r)
|
|
{
|
|
r.sharedMaterial = material;
|
|
|
|
PadBounds(r);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void PadBounds(MeshRenderer m_renderer)
|
|
{
|
|
Bounds bounds = m_renderer.localBounds;
|
|
bounds.Expand(Vector3.up * (EXPECTED_MAX_WAVE_HEIGHT * 0.5f));
|
|
|
|
m_renderer.localBounds = bounds;
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
Instance = this;
|
|
|
|
PadBounds();
|
|
|
|
#if URP
|
|
RenderPipelineManager.beginCameraRendering += OnCameraRender;
|
|
#endif
|
|
}
|
|
|
|
private void LateUpdate()
|
|
{
|
|
if (followTarget)
|
|
{
|
|
SetPosition(followTarget);
|
|
}
|
|
}
|
|
|
|
#if URP
|
|
private void OnCameraRender(ScriptableRenderContext context, Camera targetCamera)
|
|
{
|
|
if (targetCamera.cameraType == CameraType.Preview) return;
|
|
|
|
//Component set up to follow a specific target
|
|
if (followTarget != null) return;
|
|
|
|
#if UNITY_EDITOR
|
|
//Skip if disabled in scene-view
|
|
if (targetCamera.cameraType == CameraType.SceneView && (enableInEditMode == false || Application.isPlaying)) return;
|
|
#endif
|
|
|
|
SetPosition(targetCamera.transform);
|
|
}
|
|
#endif
|
|
|
|
private void OnDisable()
|
|
{
|
|
Instance = null;
|
|
|
|
#if URP
|
|
RenderPipelineManager.beginCameraRendering -= OnCameraRender;
|
|
#endif
|
|
}
|
|
|
|
private void OnDrawGizmosSelected()
|
|
{
|
|
if (!ShowWireFrame) return;
|
|
|
|
MeshFilter[] meshes = GetComponentsInChildren<MeshFilter>();
|
|
|
|
Gizmos.color = new Color(0,0,0,0.25f);
|
|
for (int i = 0; i < meshes.Length; i++)
|
|
{
|
|
Gizmos.matrix = meshes[i].transform.localToWorldMatrix;
|
|
Gizmos.DrawWireMesh(meshes[i].sharedMesh);
|
|
}
|
|
|
|
/*
|
|
Gizmos.color = new Color(1,1,0,0.25f);
|
|
Gizmos.matrix = Matrix4x4.identity;
|
|
for (int i = 0; i < lods.Length; i++)
|
|
{
|
|
foreach (var lod in lods[i].gameObjects)
|
|
{
|
|
MeshRenderer r = lod.GetComponent<MeshRenderer>();
|
|
Gizmos.DrawWireCube(r.bounds.center, r.bounds.size);
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
|
|
public bool InvalidSetup()
|
|
{
|
|
if(lods == null) return true;
|
|
if(lods.Length == 0) return true;
|
|
|
|
for (int i = 0; i < lods.Length; i++)
|
|
{
|
|
foreach (var lod in lods[i].gameObjects)
|
|
{
|
|
if(!lod.gameObject) return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
} |