Funciones de modelado
La lógica del shader es especial, es diferente de lo que estamos acostumbrados en JavaScript u otros lenguajes de programación. Aunque la sintaxis es similar, la forma en que implementamos la lógica es distinta. Es un poco como una caja negra, pones algunos datos y obtienes algunos colores para el fragment shader, o algunas posiciones para el vertex shader.
Pero, ¿cómo se controla la salida? ¿Cómo haces que se vea como quieres? Aquí es donde entran las funciones de modelado.
Nos enfocaremos en el fragment shader para esta lección, pero los mismos principios se aplican al vertex shader.
Zona de práctica
Para dominar el arte del modelado, necesitarás practicar y experimentar. Te llevará tiempo acostumbrarte a la forma en que funciona el shader, pero una vez que lo domines, podrás crear efectos increíbles.
Porque quiero ponerte en la mejor posición para tener éxito, he preparado esta escena de Galería de Arte 3D para que visualices tus shaders en tiempo real en un ambiente agradable.
¿Puedes sentir fluir tu creatividad? ¡Todos esos marcos vacíos están esperando tus obras maestras!
El modelo 3D usado es VR Gallery de Maxim Mavrichev y está licenciado bajo Creative Commons Attribution.
Usé <CameraControls />
para crear una cámara en primera persona para navegar dentro de la galería y Squoosh para reducir el tamaño de las texturas.
SimpleShaderMaterial
Todos los marcos de la galería son copias de SimpleShaderMaterial
, es un shader personalizado básico que preparé para ti con:
uColor
: un coloruTime
: el tiempo transcurrido desde el comienzo de la aplicaciónvUv
: las coordenadas UV del fragment (0 a 1 en ambos ejes)
Todos se extienden en el <App.jsx />
para poder usarlos de forma declarativa en nuestra escena.
Se nombran en función de su posición en la galería, pero siéntete libre de renombrarlos a algo más significativo una vez que hayas creado obras maestras con ellos.
Funciones
Para cada fragmento de nuestro shader, nuestro mismo código se ejecutará con diferentes entradas.
Si queremos dibujar una línea, podríamos usar if statements para verificar si el píxel está dentro de la línea o no. Pero hacer formas más complejas sería muy difícil e ineficiente.
En su lugar, usamos funciones para dar forma a nuestra salida. No te preocupes, no necesitas ser un experto en matemáticas para usarlas. Solo necesitas entender qué funciones están a tu disposición y qué hacen.
Piensa en una función como una máquina que toma una entrada y te da una salida. Por ejemplo, la función
f(x) = x * 2
toma un númerox
y te dax * 2
como resultado.
Para visualizar el efecto de las diferentes funciones, utilizaremos Graphtoy, es una herramienta simple para escribir funciones y ver su salida. Ayuda a validar nuestra comprensión de las funciones cuando experimentamos con ellas en nuestros shaders.
Vamos a visualizar nuestra función f(x) = x * 2
en Graphtoy:
Graphtoy se convertirá rápidamente en tu mejor amigo cuando experimentes con shaders.
Es hora de experimentar con las diferentes funciones a nuestra disposición.
Step
La función step es una función simple que devuelve 0
si la entrada es menor que un umbral, y 1
si la entrada es mayor que el umbral.
Toma dos parámetros:
edge
: el umbralx
: el valor de entrada
Vamos a probarlo en el fragment shader del frame frontal ArtFront02Material.jsx
:
void main() { float pct = 1.0; pct = step(0.5, vUv.x); vec3 finalColor = pct * uColor; gl_FragColor = vec4(finalColor, 1.0); }
Declaramos una variable pct
para determinar el porcentaje del color que queremos mostrar. La configuramos a 1.0
por defecto, y luego usamos la función step
para configurarla a 0.0
si el vUv.x
es menor que 0.5
.
Podemos ver que la mitad izquierda del frame es negra, y la mitad derecha tiene el color establecido en el uniforme uColor
.
Vamos a aplicarlo al eje vertical con un umbral diferente:
void main() { float pct = 1.0; pct = step(0.2, vUv.y); vec3 finalColor = pct * uColor; gl_FragColor = vec4(finalColor, 1.0); }
Podemos ver que el 20% de la parte inferior del frame es negra, y el resto es púrpura.
Las coordenadas UV tienen el origen en la esquina inferior izquierda del frame, por lo que
[0, 0]
es la esquina inferior izquierda, y[1, 1]
es la esquina superior derecha.
Si quieres revertir el efecto, simplemente puedes intercambiar los parámetros de la función step
:
void main() { float pct = 1.0; pct = step(vUv.y, 0.2); vec3 finalColor = pct * uColor; gl_FragColor = vec4(finalColor, 1.0); }
Ahora tenemos el efecto opuesto.
Mix
La función mix es una función simple que devuelve una interpolación lineal entre dos valores.
Toma tres parámetros:
x
: el primer valory
: el segundo valora
: el valor a interpolar entrex
yy
Vamos a probarlo:
void main() { float pct = 1.0; pct = mix(0.0, 1.0, vUv.x); vec3 finalColor = pct * uColor; gl_FragColor = vec4(finalColor, 1.0); }
Podemos ver un bonito degradado de negro a púrpura.
Como muchas otras funciones, puedes usarla en otros tipos de datos, como los componentes vectoriales. Vamos a usarla para crear un degradado de blanco a púrpura en el eje vertical:
void main() { vec3 whiteColor = vec3(1.0); vec3 finalColor = mix(whiteColor, uColor, vUv.y); gl_FragColor = vec4(finalColor, 1.0); }
Podemos ver un bonito degradado de blanco a púrpura.
Vamos a cambiar el valor de interpolación llamando a la función mix
una primera vez para obtener el valor pct
, y luego usarlo para interpolar entre el whiteColor
y el uColor
:
void main() { vec3 whiteColor = vec3(1.0); float pct = mix(0.0, 0.3, vUv.y); vec3 finalColor = mix(whiteColor, uColor, pct); gl_FragColor = vec4(finalColor, 1.0); }
El púrpura es muy claro ya que el valor máximo de pct
es 0.3
.
Utiliza Graphtoy para experimentar con la función mix
y entender cómo funciona.
3 interpolaciones diferentes con la función mix
dan resultados completamente diferentes.
Smoothstep
La función smoothstep es una función simple que devuelve una interpolación suave entre dos valores.
Toma tres parámetros:
edge0
: el borde inferioredge1
: el borde superiorx
: el valor a interpolar entreedge0
yedge1
Devuelve tres resultados diferentes:
0.0
six
es menor queedge0
1.0
six
es mayor queedge1
- una interpolación suave entre
0.0
y1.0
six
está entreedge0
yedge1
Vamos a usarlo para cambiar nuestro valor pct
:
void main() { vec3 whiteColor = vec3(1.0); float pct = smoothstep(0.4, 0.6, vUv.y); vec3 finalColor = mix(whiteColor, uColor, pct); gl_FragColor = vec4(finalColor, 1.0); }
La transición ahora es solo entre 0.4
y 0.6
. Todo lo que está por debajo es blanco, y todo lo que está por encima es púrpura.
Min & Max
min
y max
son funciones simples que devuelven el valor mínimo o máximo entre dos entradas. Funcionan exactamente como las funciones Math.min
y Math.max
en JavaScript.
Vamos a usarlas para ajustar nuestro valor pct
. Primero vamos a asegurarnos de que nunca sea inferior a 0.4
(lo que significa que nunca será totalmente blanco):
void main() { vec3 whiteColor = vec3(1.0); float pct = smoothstep(0.4, 0.6, vUv.y); pct = max(pct, 0.4); vec3 finalColor = mix(whiteColor, uColor, pct); gl_FragColor = vec4(finalColor, 1.0); }
Y nunca superior a 0.6
(lo que significa que nunca será totalmente púrpura):
void main() { vec3 whiteColor = vec3(1.0); float pct = smoothstep(0.4, 0.6, vUv.y); pct = max(pct, 0.4); pct = min(pct, 0.6); vec3 finalColor = mix(whiteColor, uColor, pct); gl_FragColor = vec4(finalColor, 1.0); }
Los colores están deslavados y la transición es muy suave.
Vamos a visualizarlo en Graphtoy:
Representación de max(x, 0.4)
Representación de min(x, 0.6)
Y si los combinamos:
Puedes ver que nuestros valores nunca bajan de 0.4
y nunca suben de 0.6
.
Nuestra combinación de las funciones
min
ymax
puede ser reemplazada por la función clamp, que es una abreviatura demin(max(x, min), max)
.
Operaciones y patrones
Antes de descubrir muchas otras funciones útiles, veamos cómo podemos usar operaciones para crear patrones.
React Three Fiber: The Ultimate Guide to 3D Web Development
✨ You have reached the end of the preview ✨
Go to the next level with Three.js and React Three Fiber!
Get full access to this lesson and the complete course when you enroll:
- 🔓 Full lesson videos with no limits
- 💻 Access to the final source code
- 🎓 Course progress tracking & completion
- 💬 Invite to our private Discord community
One-time payment. Lifetime updates included.