prefacio
La sección anterior coloreó la superficie del agua, y esta sección resuelve la generación de ondas en la superficie del agua. Se divide en dos partes: normal y vértice:
los puntos de conocimiento involucrados capturan el algoritmo GerstnerWave
de captura de pantalla
1 normal
Dado que la iluminación no participa en el cálculo en este caso, las normales solo distorsionan el contenido submarino (implementado por captura de pantalla). Lo normal se muestrea dos veces aquí, y la velocidad de animación y el mosaico son diferentes para simular la irregularidad del movimiento ondulatorio.
1.1 Obtener tangente y binormal
o.tanW = normalize(TransformObjectToWorldDir(v.tangent.xyz));
o.biW = normalize(cross(v.normal.xyz, v.tangent.xyz)
* v.tangent.w * unity_WorldTransformParams.w);
1.2 Muestreo y mezcla normales
- Función de mezcla normal
_blendNormal
BlendedNormal = normalize( float3( A.xy + B.xy, A.z*B.z ).
- Normales en el espacio tangente
Esta sección solo usa información normal en el espacio tangente.
float3 _getNormalTS(float2 uv)
{
uv = uv / _NormalScale;
float speed = _Time.y * _NormalSpeed * 0.1;
real4 normalData1 = SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, uv+speed);
float3 normalT1 = UnpackNormalScale(normalData1, _NormalStr);
real4 normalData2 = SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap,
uv*0.2 + speed * (-0.35));
float3 normalT2 = UnpackNormalScale(normalData2, _NormalStr);
return _blendNormal(normalT1, normalT2);
}
1.3 Captura de pantalla
El uso de Grabpass en la canalización integrada es el siguiente
GrabPass {
"_GrabTex"}
Urp no tiene una función de captura de pantalla directa, por lo que el propósito de esta sección es lograr una función similar a grabpass . Hay varias formas de lograrlo. Aquí solo enumeramos el método más conveniente. Para otros métodos y detalles, consulte a mis notas de urp Yuque.
Vuelva a la configuración de canalización, verifíquelo, Opaque Texture
puede ver que esto se genera _CameraOpaqueTexture
antes de la representación translúcida, es decir, no habrá objetos translúcidos en estos datos, esta parte necesita atención
Ahora utilícelo _CameraOpaqueTexture
para lograr la captura de pantalla
float2 uvSS = screenPos.xy;
real4 grab_col = SAMPLE_TEXTURE2D(_CameraOpaqueTexture, sampler_CameraOpaqueTexture, uvSS);
Las coordenadas de muestra son coordenadas del espacio de la pantalla que se someten a una división homogénea para que se mapeen correctamente.
Luego usamos el espacio tangente anterior normal para hacer la distorsión.
uvSS += 0.01 * normalTS * _UWDistort;
1.4 Mezcla con color de superficie de agua
La distorsión bajo el agua está solo en la parte transparente de la malla en la superficie del agua, y luego agrega la espuma de la orilla, por lo que el código es el siguiente
// =========Mix Results=========== //
base_col = lerp(grab_col, base_col, base_col.a);
base_col = lerp(base_col, base_col+sinWave, sinWave.a);
Animación de 2 vértices
Use el plano subdividido para la animación de vértices
gerstnerola
Cree aquí la función GerstnerWave y llámela tres veces.
Las variables personalizadas waveA, waveB y waveC son tipos de datos vectoriales y los componentes representan:
SpeedXY, Steepness y longitud de onda.
float3 GerstnerWave( float3 position, inout float3 tangent, inout float3 binormal, float4 wave )
{
float steepness = wave.z * 0.01;
float wavelength = wave.w;
float k = 2 * 3.14159 / wavelength;
float c = sqrt(9.8 / k);
float2 d = normalize(wave.xy);
float f = k * (dot(d, position.xz) - c * _Time.y);
float a = steepness / k;
tangent += float3(
-d.x * d.x * (steepness * sin(f)),
d.x * (steepness * cos(f)),
-d.x * d.y * (steepness * sin(f))
);
binormal += float3(
-d.x * d.y * (steepness * sin(f)),
d.y * (steepness * cos(f)),
-d.y * d.y * (steepness * sin(f))
);
return float3(
d.x * (a * cos(f)),
a * sin(f),
d.y * (a * cos(f))
);
}
El plano horizontal usa la tangente y normal del mundo por defecto, usamos GerstnerWave
la función para modificar los vértices y la normal del espacio modelo
void _getVertexData(inout a2v v)
{
float3 tangent = float3( 1,0,0 );
float3 binormal = float3( 0,0,1 );
float3 posW = TransformObjectToWorld(v.vertex.xyz);
float3 wave1 = GerstnerWave(posW, tangent,binormal, _WaveA);
float3 wave2 = GerstnerWave(posW, tangent,binormal, _WaveB);
float3 wave3 = GerstnerWave(posW, tangent,binormal, _WaveC);
posW = posW + wave1 + wave2 + wave3;
v.vertex.xyz = TransformWorldToObject(posW.xyz);
v.vertex.w = 1;
float3 normalW = normalize(cross(binormal, tangent));
v.normal = mul( unity_WorldToObject, float4(normalW, 0 ) ).xyz;
}
resultado final del ajuste