Boat Attack使用了Universal RP的许多新图形功能,可以用于探索 Universal RP 的使用方式和技巧。
您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 

345 行
12 KiB

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace WaterSystem
{
[ExecuteInEditMode]
public class Water : MonoBehaviour
{
// Singleton
private static Water _Instance = null;
public static Water Instance
{
get
{
if (_Instance == null)
_Instance = (Water)FindObjectOfType(typeof(Water));
return _Instance;
}
}
[SerializeField]
private RenderTexture _depthTex;
[SerializeField]
private Camera _depthCam;
[SerializeField]
private RenderTexture _fxTexture;
private Camera _fxCam;
public float _waterMaxDepth = 40f;
[SerializeField]
private Texture2D _colorRamp;
public Gradient _absorptionRampRaw;
public Gradient _scatterRampRaw;
[SerializeField]
private Texture2D _peakRamp;
public Gradient _peakRampRaw;
[SerializeField]
public List<Wave> _waves = new List<Wave>();
[SerializeField]
private Wave[] _backupWaves;
[SerializeField]
bool _customWaves = false;
[SerializeField]
public int randomSeed = 3234;
[SerializeField]
public BasicWaves _basicWaveSettings = new BasicWaves(1f, 45f, 4);
private float _maxWaveHeight;
[SerializeField]
DebugMode _debugMode;
void Start()
{
Init();
}
void OnDestroy()
{
if (_depthCam)
{
_depthCam.targetTexture = null;
DestroyImmediate(_depthCam.gameObject);
}
if(_depthTex)
DestroyImmediate(_depthTex);
if(_fxCam)
{
_fxCam.targetTexture = null;
DestroyImmediate(_fxCam.gameObject);
}
if(_fxTexture)
DestroyImmediate(_fxTexture);
}
public void Init()
{
SetWaves();
GenerateVertexColors();
GenerateColorRamp();
GeneratePeakRamp();
CaptureDepthMap();
CreateFXCam();
}
void CreateFXCam()
{
if(!_fxCam)
{
GameObject go = new GameObject("FXCam");
go.hideFlags = HideFlags.HideAndDontSave;
_fxCam = go.AddComponent<Camera>();
_fxCam.cullingMask = (1 << LayerMask.NameToLayer("WaterFX"));
_fxCam.clearFlags = CameraClearFlags.Color;
_fxCam.backgroundColor = Color.black;
_fxCam.transform.SetPositionAndRotation(Camera.main.transform.position, Camera.main.transform.rotation);
_fxCam.depthTextureMode = DepthTextureMode.None;
_fxCam.depth = -20;
}
if(!_fxTexture)
{
_fxTexture = new RenderTexture(Camera.main.pixelWidth, Camera.main.pixelHeight, 0, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear);
_fxTexture.name = "_WaterFX_Texture";
_fxCam.targetTexture = _fxTexture;
Debug.LogError(_fxTexture);
}
Shader.SetGlobalTexture("_WaterFXMap", _fxTexture);
}
void Update()
{
if(_fxCam)
{
_fxCam.transform.SetPositionAndRotation(Camera.main.transform.position, Camera.main.transform.rotation);
_fxCam.fieldOfView = Camera.main.fieldOfView;
if(_fxCam.activeTexture == null)
_fxCam.targetTexture =_fxTexture;
}
}
public void FragWaveNormals(bool toggle)
{
Material mat = GetComponent<Renderer>().sharedMaterial;
if (toggle)
mat.EnableKeyword("GERSTNER_WAVES");
else
mat.DisableKeyword("GERSTNER_WAVES");
}
[ContextMenu("UpdateShader")]
void SetWaves()
{
//if (_customWaves)
//_backupWaves = _waves.ToArray();
Vector4[] waveData = new Vector4[10];
Vector4[] waveData2 = new Vector4[10];
for (int i = 0; i < _waves.Count; i++)
{
waveData[i] = new Vector4(_waves[i].amplitude, _waves[i].direction, _waves[i].wavelength, 1);//1 is for omni testing only TODO
waveData2[i] = new Vector4(_waves[i].origin.x, _waves[i].origin.y, 0, 0);
}
foreach (Wave w in _waves)
{
_maxWaveHeight += w.amplitude;
}
_maxWaveHeight /= (float)_waves.Count;
Shader.SetGlobalFloat("_MaxWaveHeight", _maxWaveHeight);
Shader.SetGlobalFloat("_MaxDepth", _waterMaxDepth);
//GPU side
Shader.SetGlobalInt("_WaveCount", _waves.Count);
Shader.SetGlobalVectorArray("_WaveData", waveData);
Shader.SetGlobalVectorArray("_WaveData2", waveData2);
//CPU side
GerstnerWaves.GerstnerWaves._WaveCount = _waves.Count;
GerstnerWaves.GerstnerWaves._WaveData = waveData;
GerstnerWaves.GerstnerWaves._WaveData2 = waveData2;
CaptureDepthMap();
GenerateVertexColors();
}
public void ToggleBasicWaves(bool custom)
{
if(!custom)
{
//create basic waves based off basic wave settings
Random.State backupSeed = Random.state;
Random.InitState(randomSeed);
float a = _basicWaveSettings.amplitude;
float d = _basicWaveSettings.direction;
float l = _basicWaveSettings.wavelength;
_waves.Clear();
float r = 1f / _basicWaveSettings.numWaves;
for (int i = 0; i <= _basicWaveSettings.numWaves; i++)
{
float p = Mathf.Lerp(0.5f, 1.5f, (float)i * r);
float amp = a * p * Random.Range(0.8f, 1.2f);
float dir = d + Random.Range(-45f, 45f);
float len = l * p * Random.Range(0.8f, 1.2f);
Vector2 origin = new Vector2(Random.value * 2 - 1, Random.value * 2 - 1);
_waves.Add(new Wave(amp, dir, len, origin * 500f, true));//large wave
Random.InitState(randomSeed + i + 1);
}
Random.state = backupSeed;
}
else
{
//restore custom waves
_waves.Clear();
_waves.AddRange(_backupWaves);
}
}
void GenerateVertexColors()
{
Mesh mesh = GetComponent<MeshFilter>().sharedMesh;
Vector3[] vertices = mesh.vertices;
// create new colors array where the colors will be created.
Color[] colors = new Color[vertices.Length];
RaycastHit hit;
for (int i = 0; i < vertices.Length; i++)
{
colors[i] = Color.black;
//seafloor Depth
if (Physics.Raycast(vertices[i], -Vector3.up, out hit))
colors[i].r = hit.distance;
}
// assign the array of colors to the Mesh.
mesh.colors = colors;
}
public void GenerateColorRamp()
{
_colorRamp = new Texture2D(128, 2, TextureFormat.ARGB32, false, false);
_colorRamp.wrapMode = TextureWrapMode.Clamp;
Color[] cols = new Color[256];
for (int i = 0; i < 128; i++)
{
cols[i] = _absorptionRampRaw.Evaluate((float)i / 128f);
}
for (int i = 0; i < 128; i++)
{
cols[i + 128] = _scatterRampRaw.Evaluate((float)i / 128f);
}
_colorRamp.SetPixels(cols);
_colorRamp.Apply();
Shader.SetGlobalTexture("_AbsorptionScatteringRamp", _colorRamp);
}
[ContextMenu("Generate new peakmap")]
public void GeneratePeakRamp()
{
_peakRamp = new Texture2D(128, 1, TextureFormat.ARGB32, false, false);
_peakRamp.wrapMode = TextureWrapMode.Clamp;
Color[] cols = new Color[256];
for (int i = 0; i < 128; i++)
{
cols[i] = _peakRampRaw.Evaluate((float)i / 128f);
}
_peakRamp.SetPixels(cols);
_peakRamp.Apply();
Shader.SetGlobalTexture("_PeakMap", _peakRamp);
}
GerstnerWaves.WaveStruct tempWave = new GerstnerWaves.WaveStruct();
public float GetWaterHeight(Vector3 pos)
{
float waveHeight = 0;
tempWave = GerstnerWaves.GerstnerWaves.SampleWaves(pos, 1f);
waveHeight = (tempWave.position.y + transform.position.y) - pos.y;
return waveHeight;
}
[ContextMenu("Capture Depth")]
public void CaptureDepthMap()
{
//Generate the camera
if(_depthCam == null)
{
GameObject go = new GameObject("depthCamera");//create the cameraObject
go.hideFlags = HideFlags.HideAndDontSave;
_depthCam = go.AddComponent<Camera>();
}
_depthCam.transform.position = transform.position + Vector3.up * 4f;//center the camera on this water plane
_depthCam.transform.up = Vector3.forward;//face teh camera down
_depthCam.enabled = true;
_depthCam.orthographic = true;
_depthCam.orthographicSize = 500;//hardcoded - TODO
_depthCam.depthTextureMode = DepthTextureMode.Depth;
_depthCam.nearClipPlane =0.1f;
_depthCam.farClipPlane = _waterMaxDepth;
_depthCam.allowHDR = false;
//_depthCam.allowMSAA = false;
_depthCam.cullingMask = (1 << 10);
//Generate RT
if (!_depthTex)
_depthTex = new RenderTexture(1024, 1024, 24, RenderTextureFormat.Depth);
//do depth capture
_depthCam.targetTexture = _depthTex;
_depthCam.Render();
Shader.SetGlobalTexture("_WaterDepthMap", _depthTex);
// set depthbufferParams for depth cam(since it doesnt exist and only temporary)
float n = _depthCam.nearClipPlane;
float f = _depthCam.farClipPlane;
Vector4 zParams = new Vector4(n, f, f / (f-n), f * n / (n-f));
//Vector4 zParams = new Vector4(1-f/n, f/n, (1-f/n)/f, (f/n)/f);//2015
Shader.SetGlobalVector("_depthCamZParams", zParams);
_depthCam.enabled = false;
_depthCam.targetTexture = null;
}
[System.Serializable]
public class Wave
{
public float amplitude = 0.1f;//height of the wave in units
public float direction = 0f;//direction the wave travels in degrees from Z+
public float wavelength = 2f;//distance between crest>crest
public Vector2 origin = Vector2.zero;
public bool onmiDir;
public Wave(float amp, float dir, float length, Vector2 org, bool omni)
{
amplitude = amp;
direction = dir;
wavelength = length;
origin = org;
onmiDir = omni;
}
}
[System.Serializable]
public class BasicWaves
{
public int numWaves = 6;
public float amplitude;
public float direction;
public float wavelength;
public BasicWaves(float amp, float dir, float len)
{
numWaves = 6;
amplitude = amp;
direction = dir;
wavelength = len;
}
}
[System.Serializable]
public enum DebugMode { none, stationary, screen };
}
}