Quería ver si podía lograr esto sin regenerar dinámicamente la malla para la cascada en cada cuadro. Resulta que hay un camino. :RE
Cada objeto que puede bloquear la cascada (objetos que llevan un WaterCatcher
guión en mi prototipo) tiene una malla de contorno que rodea su perímetro. (Esto se puede generar automáticamente por adelantado utilizando la forma del colisionador)
Esta malla de contorno hace que el agua fluya a lo largo del objeto. Uso un sombreador para clip
sacar la parte que está debajo del objeto. También sigo un punto de "captura" izquierdo y derecho donde una cascada cae sobre el objeto y fluye hacia la izquierda o hacia la derecha, respectivamente, para poder clip
ver la parte que está a la izquierda de la cascada derecha y a la derecha de la cascada izquierda.
Entonces las caídas verticales son solo primitivas cuádruples básicas, estiradas a la longitud adecuada. Utilizo otro sombreador para desplazar la textura de la cascada sobre las cataratas y desvanecerla en los extremos superior e inferior. Luego coloco un sistema de partículas de espuma en el punto de impacto para ayudar a cubrir la mezcla.
Aquí hay un primer plano para que pueda ver las partes componentes.
En la parte superior tengo una cascada "raíz" para comenzar. Cada cuadro, después de que todas las Update()
secuencias de comandos se han ejecutado para mover las cosas, dispara CircleCast
hacia abajo, para ver si el agua golpea algo. Si golpea a WaterCatcher
, le dice que muestre su capa de agua aguas abajo del punto de golpe.
Determino "aguas abajo" usando el golpe normal: si está muy cerca de la vertical, o si la cascada entrante abarca bordes que se inclinan en ambas direcciones, entonces derramamos tanto a la izquierda como a la derecha.
Cada uno WaterCatcher
tiene su propia cascada a la izquierda y a la derecha, que habilita y coloca en su extremo más alejado si se derrama en esa dirección; de lo contrario, permanecen ocultos. Estas cascadas a su vez disparan CircleCast
hacia abajo para encontrar en qué se derraman, y así sucesivamente ...
El prototipo todavía tiene algunas fallas visuales que podrían mejorarse: el flujo de agua a lo largo de un objeto aparece de una vez en lugar de animarse, y las reglas de flujo podrían usar un poco de tolerancia o histéresis adicionales para que no se corte tan fácilmente. objetos rotativos Sin embargo, creo que estos deberían ser problemas bastante solucionables.
Fondo, rocas y texturas de plataforma giratoria a través de Kenney
Estos son los trucos que uso en mi sombreador de fragmentos de colector de agua:
// My wraparound geometry is build so the "x+" UV direction
// points "outward" from the object.
// Using derivatives, I can turn this into a vector in screen space.
// We'll use this below to clip out water hanging off the bottom.
float2 outward = float2(ddx(i.uv.x), ddy(i.uv.x));
// i.worldX is the worldspace x position of this fragment
// (interpolated from the vertex shader)
// _LeftX is a material property representing the worldspace x coordinate
// of the rightmost water flow that's spilling left,
// and _RightX the wold x of the leftmost water flow that's spilling right.
float left = _LeftX - i.worldX; // +ve if we're to the left of a left spill.
float right = i.worldX - _RightX; // +ve if we're to the right of a right spill.
float limit = max(left, right); // +ve if we're in the path of either flow.
// If the "outward" vector is pointing down, make this negative.
limit = min(limit, outward.y + 0.001f);
// If any of the conditions above make limit <= 0, abort this fragment.
clip(limit);
// Otherwise, scroll the water texture!
// Counter-clockwise if we're in the left flow, clockwise otherwise.
i.uv.y -= sign(left) * _Time.y;