其他
Unity博主营地 | 如何在Unity中实现水体交互?
「Unity博主营地第一期」于2019年11月开启,现已收到数百篇原创投稿。每周根据Unity Connect社区反馈,帮助大家发现最优质、最干货、最受欢迎的博文作品。
制作可交互的水体大致分为以下三步:
1.标记水体碰撞的位置
2.计算水波的传递 通过波动公式,3D或者2D 波动公式都行
3.水面顶点采样波动传递结果计算结果做顶点Y轴偏移
本文由Unity Connect博主从自身实践经验出发,为大家分享在Unity中如何实现水体交互?
m_waterWaveMarkTexture = new RenderTexture(WaveTextureResolution, WaveTextureResolution, 0, RenderTextureFormat.Default);
m_waterWaveMarkTexture.name = "m_waterWaveMarkTexture";
m_waveTransmitTexture = new RenderTexture(WaveTextureResolution, WaveTextureResolution, 0, RenderTextureFormat.Default);
m_waveTransmitTexture.name = "m_waveTransmitTexture";
m_prevWaveMarkTexture = new RenderTexture(WaveTextureResolution, WaveTextureResolution, 0, RenderTextureFormat.Default);
m_prevWaveMarkTexture.name = "m_prevWaveMarkTexture";
void WaterPlaneCollider()
{
hasHit = false;
if (Input.GetMouseButton(0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hitInfo = new RaycastHit();
bool ret = Physics.Raycast(ray.origin, ray.direction, out hitInfo);
if (ret)
{
Vector3 waterPlaneSpacePos = WaterPlane.transform.worldToLocalMatrix * new Vector4(hitInfo.point.x, hitInfo.point.y, hitInfo.point.z, 1);
float dx = (waterPlaneSpacePos.x / WaterPlaneWidth) + 0.5f;
float dy = (waterPlaneSpacePos.z / WaterPlaneLength) + 0.5f;
hitPos.Set(dx, dy);
m_waveMarkParams.Set(dx, dy, WaveRadius * WaveRadius, WaveHeight);
hasHit = true;
}
}
}
float dx = i.uv.x - _WaveMarkParams.x;
float dy = i.uv.y - _WaveMarkParams.y;
float disSqr = dx * dx + dy * dy;
int hasCol = step(0, _WaveMarkParams.z - disSqr);
float waveValue = DecodeHeight(tex2D(_MainTex, i.uv));
if (hasCol == 1) {
waveValue = _WaveMarkParams.w;
}
static const float2 WAVE_DIR[4] = { float2(1, 0), float2(0, 1), float2(-1, 0), float2(0, -1) };
float dx = _WaveTransmitParams.w;
float avgWaveHeight = 0;
for (int s = 0; s < 4; s++)
{
avgWaveHeight += DecodeHeight(tex2D(_MainTex, i.uv + WAVE_DIR[s] * dx));
}
//(2 * c^2 * t^2 / d ^2) / (u * t + 2)*(z(x + dx, y, t) + z(x - dx, y, t) + z(x, y + dy, t) + z(x, y - dy, t);
float agWave = _WaveTransmitParams.z * avgWaveHeight;
// (4 - 8 * c^2 * t^2 / d^2) / (u * t + 2)
float curWave = _WaveTransmitParams.x * DecodeHeight(tex2D(_MainTex, i.uv));
// (u * t - 2) / (u * t + 2) * z(x,y,z, t - dt) 上一次波浪值 t - dt
float prevWave = _WaveTransmitParams.y * DecodeHeight(tex2D(_PrevWaveMarkTex, i.uv));
//波衰减
float waveValue = (curWave + prevWave + agWave) * _WaveAtten;
v2f vert (appdata v)
{
v2f o;
float4 localPos = v.vertex;
float4 waveTransmit = tex2Dlod(_WaveResult, float4(v.uv, 0, 0));
float waveHeight = DecodeFloatRGBA(waveTransmit);
localPos.y += waveHeight * _WaveScale;
float3 worldPos = mul(unity_ObjectToWorld, localPos);
float3 worldSpaceNormal = mul(unity_ObjectToWorld, v.normal);
float3 worldSpaceViewDir = UnityWorldSpaceViewDir(worldPos);
o.vertex = mul(UNITY_MATRIX_VP, float4(worldPos, 1));
o.uv = v.uv;
o.worldSpaceReflect = reflect(-worldSpaceViewDir, worldSpaceNormal);
return o;
点击“阅读原文”github地址
↓↓↓