[sombreador de unidad/representación de superficie de agua estilizada/notas básicas] versión de código urp 04-normal y animación de onda de vértice

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);

        }

inserte la descripción de la imagen aquí

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
inserte la descripción de la imagen aquí
puede ver que esto se genera _CameraOpaqueTextureantes de la representación translúcida, es decir, no habrá objetos translúcidos en estos datos, esta parte necesita atención
inserte la descripción de la imagen aquí
Ahora utilícelo _CameraOpaqueTexturepara lograr la captura de pantalla

float2 uvSS = screenPos.xy;
real4 grab_col = SAMPLE_TEXTURE2D(_CameraOpaqueTexture, sampler_CameraOpaqueTexture, uvSS);

inserte la descripción de la imagen aquí
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;

inserte la descripción de la imagen aquí

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);

inserte la descripción de la imagen aquí

Animación de 2 vértices


Use el plano subdividido para la animación de vértices
inserte la descripción de la imagen aquí

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 GerstnerWavela 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
inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/qq_43544518/article/details/128757913
Recomendado
Clasificación