Files
Northbound/Assets/FlatKit/[Render Pipeline] URP/Water/Scripts/Buoyancy.cs
2026-01-25 11:27:33 +09:00

112 lines
3.9 KiB
C#

using UnityEngine;
namespace FlatKit {
public class Buoyancy : MonoBehaviour {
[Tooltip("The object that contains a Water material.")]
public Transform water;
[Space]
[Tooltip("Range of probing wave height for buoyancy rotation.")]
public float size = 1f;
[Tooltip("Max height of buoyancy going up and down.")]
public float amplitude = 1f;
[Space, Tooltip("Optionally provide a separate material to get the wave parameters.")]
public Material overrideWaterMaterial;
private Material _material;
private float _speed;
private float _amplitude;
private float _frequency;
private float _direction;
private Vector3 _originalPosition;
private Quaternion _originalRotation;
private void Start() {
var r = water.GetComponent<Renderer>();
Debug.Assert(r);
_material = overrideWaterMaterial != null ? overrideWaterMaterial : r.sharedMaterial;
Debug.Assert(_material);
Debug.Assert(_material.HasProperty("_WaveSpeed"));
_speed = _material.GetFloat("_WaveSpeed");
_amplitude = _material.GetFloat("_WaveAmplitude");
_frequency = _material.GetFloat("_WaveFrequency");
_direction = _material.GetFloat("_WaveDirection");
var t = transform;
_originalPosition = t.position;
_originalRotation = t.rotation;
}
private void Update() {
var positionWS = transform.position;
var positionOS = water.InverseTransformPoint(positionWS);
positionWS.y = GetHeightOS(positionOS) + _originalPosition.y;
transform.position = positionWS;
var normal = GetNormalWS(positionOS);
transform.rotation = Quaternion.FromToRotation(Vector3.up, normal) * _originalRotation;
}
Vector2 GradientNoiseDir(Vector2 p) {
p = new Vector2(p.x % 289, p.y % 289);
float x = (34 * p.x + 1) * p.x % 289 + p.y;
x = (34 * x + 1) * x % 289;
x = ((x / 41) % 1) * 2 - 1;
return (new Vector2(x - Mathf.Floor(x + 0.5f), Mathf.Abs(x) - 0.5f)).normalized;
}
float GradientNoise(Vector2 p) {
Vector2 ip = new Vector2(Mathf.Floor(p.x), Mathf.Floor(p.y));
Vector2 fp = new Vector2(p.x % 1, p.y % 1);
float d00 = Vector3.Dot(GradientNoiseDir(ip), fp);
float d01 = Vector3.Dot(GradientNoiseDir(ip + Vector2.up), fp - Vector2.up);
float d10 = Vector3.Dot(GradientNoiseDir(ip + Vector2.right), fp - Vector2.right);
float d11 = Vector3.Dot(GradientNoiseDir(ip + Vector2.one), fp - Vector2.one);
fp = fp * fp * fp * (fp * (fp * 6f - Vector2.one * 15f) + Vector2.one * 10f);
return Mathf.Lerp(Mathf.Lerp(d00, d01, fp.y), Mathf.Lerp(d10, d11, fp.y), fp.x);
}
private Vector3 GetNormalWS(Vector3 positionOS) {
Vector3 b = positionOS + Vector3.forward * size;
b.y = GetHeightOS(b);
Vector3 c = positionOS + Vector3.right * size;
c.y = GetHeightOS(b);
Vector3 n = Vector3.Cross(b - positionOS, c - positionOS).normalized;
return water.TransformDirection(n);
}
private float SineWave(Vector3 positionOS, float offset) {
// Shader:
// sin(offset + _Time.z * _WaveSpeed + (pos.x * sin(offset + _WaveDirection) + pos.z *
// cos(offset + _WaveDirection)) * _WaveFrequency);
float timez = Time.timeSinceLevelLoad * 2f;
float s = Mathf.Sin(offset + timez * _speed +
(positionOS.x * Mathf.Sin(offset + _direction) + positionOS.z *
Mathf.Cos(offset + _direction)) * _frequency);
if (_material.IsKeywordEnabled("_WAVEMODE_POINTY")) {
s = 1.0f - Mathf.Abs(s);
}
return s * _amplitude;
}
private float GetHeightOS(Vector3 positionOS) {
float y = SineWave(positionOS, 0.0f);
if (_material.IsKeywordEnabled("_WAVEMODE_GRID")) {
y *= SineWave(positionOS, 1.57f);
}
y *= amplitude;
return y;
}
}
}