Parte: 4 — Gráficos, shaders y rendering moderno · Fuente: Akenine-Möller et al., "Real-Time Rendering" (4ª ed.) + Documentación de rendering de Godot 4 ⏱️ Duración estimada: 50 min · Nivel: Avanzado
Entender, de principio a fin, qué le pasa a un triángulo desde que existe en memoria hasta que se convierte en píxeles de color en la pantalla. Al terminar sabrás nombrar cada etapa del pipeline de rasterización, distinguir qué partes son programables (vertex y fragment) de las que son fijas, ubicar los espacios de coordenadas por los que viaja cada vértice y explicar por qué las draw calls y la elección entre forward y deferred afectan al rendimiento en Godot 4 sobre Vulkan.
Al finalizar, el alumno podrá:
| # | Tema | Por qué importa |
|---|---|---|
| 1 | Etapas del pipeline | Es el mapa mental sobre el que se apoya todo lo demás del curso |
| 2 | Etapas programables vs fijas | Define exactamente dónde puedes escribir código de shader |
| 3 | Espacios de coordenadas | Sin ellos no entiendes qué contiene VERTEX en cada función |
| 4 | Matrices de transformación | Convierten un vértice de un espacio al siguiente |
| 5 | Draw calls y batching | Principal cuello de botella de CPU→GPU en juegos reales |
| 6 | Forward vs deferred | Determina cómo se calcula la iluminación de la escena |
| 7 | Vulkan en Godot 4 | Es el backend que ejecuta este pipeline en tu máquina |
ALBEDO/COLOR).Necesitas Godot 4.x con el Forward+ renderer activo (es el predeterminado y usa Vulkan). Trabajaremos en una escena 3D vacía, así que crea un proyecto nuevo o abre uno de práctica. Ten a mano el Inspector y el menú Project → Project Settings → Rendering para observar las opciones del backend. Para profundizar, consulta el capítulo de arquitectura de rendering en la documentación oficial de Godot y el resumen del pipeline en Real-Time Rendering. No hace falta escribir shaders complejos aún: el objetivo es ver dónde encaja cada pieza.
Vamos a crear el shader más pequeño posible que produce algo visible y a ubicar cada línea dentro del pipeline.
Paso 1 — Escena base. Crea una escena 3D con un nodo Node3D como raíz. Añade un MeshInstance3D, y en su propiedad Mesh elige un BoxMesh. Añade también una Camera3D apuntando al cubo y una DirectionalLight3D. Guarda como pipeline_demo.tscn.
Paso 2 — Crear el material y el shader. Selecciona el MeshInstance3D. En el Inspector, en Material Override → [empty], elige New ShaderMaterial. Haz clic en el ShaderMaterial recién creado y, en su propiedad Shader, elige New Shader. Ponle nombre minimo.gdshader y tipo spatial.
Paso 3 — Shader mínimo. Abre el editor de shaders y escribe:
shader_type spatial;
// vertex() se ejecuta UNA vez por cada vértice del cubo (8 en un BoxMesh).
// Aquí no tocamos nada: Godot proyecta VERTEX al espacio de clip por nosotros.
void vertex() {
// VERTEX está en espacio de objeto; el motor lo lleva a clip con las matrices.
}
// fragment() se ejecuta UNA vez por cada fragmento que cubre el cubo en pantalla.
void fragment() {
ALBEDO = vec3(0.1, 0.6, 1.0); // color base: azul claro
}
Al guardar, el cubo se vuelve azul. Acabas de intervenir la etapa fragment.
Paso 4 — Ubicar cada cosa. Razona en voz alta con esta correspondencia:
| Etapa del pipeline | Qué pasa aquí en tu demo |
|---|---|
| Aplicación (CPU) | Godot recorre la escena y emite la draw call del cubo |
| Vertex | Se ejecuta vertex() por cada vértice; VERTEX pasa de objeto a clip |
| Rasterización (fija) | La GPU decide qué píxeles cubre el cubo e interpola datos |
| Fragment | Se ejecuta fragment(); asignas ALBEDO |
| Salida (fija) | Depth test + blending escriben el píxel final |
Paso 5 — Ver la draw call. Ejecuta la escena y abre el panel inferior Depurar → Monitores (o el overlay de depuración). Observa el contador de Draw calls. Duplica el MeshInstance3D cinco veces (Ctrl+D) y comprueba cómo sube el número: cada cubo con su material es, típicamente, una draw call más.
Resultado visible: un cubo azul cuyo color viene de tu código de fragment, y un contador de draw calls que reacciona cuando añades geometría.
ALBEDO para que el cubo sea rojo y explica por qué el cambio ocurre en la etapa fragment y no en la vertex.SphereMesh con el mismo shader y anota cuántas draw calls hay ahora.VERTEX en vertex() y qué contendría después de la proyección.Construye una escena con tres mallas distintas (cubo, esfera y cilindro) que compartan un único ShaderMaterial con el shader mínimo azul. Muestra el contador de draw calls antes y después de compartir el material.
Criterio de aceptación: las tres mallas se ven azules con el mismo shader, y demuestras (captura o descripción del monitor) que compartir un mismo material no multiplica innecesariamente el trabajo de configuración, explicando en qué etapa del pipeline actúa tu ALBEDO.
| Síntoma | Causa y arreglo |
|---|---|
| El shader no compila: "Expected ';'" | Falta ; al final de una sentencia; revisa cada línea de asignación |
| El cubo se ve negro | No hay luz o pusiste ALBEDO sin iluminación; añade una DirectionalLight3D |
| "ALBEDO no está disponible" | Escribiste ALBEDO dentro de vertex(); solo existe en fragment() |
| El material no aplica | Olvidaste asignar el ShaderMaterial en Material Override de la malla |
| Muchísimas draw calls y caídas de FPS | Cada objeto con material único genera una draw call; reutiliza materiales |
| No aparece nada en pantalla | La Camera3D no apunta a la geometría; reposiciónala |
¿El vertex shader se ejecuta antes que el fragment shader? Sí. Primero se procesan todos los vértices del triángulo, luego se rasteriza y recién ahí corre el fragment por cada píxel cubierto.
¿Puedo programar la etapa de rasterización?
No. La rasterización es de función fija: la GPU decide qué píxeles cubre el triángulo. Tú programas vertex y fragment (y light()).
¿Godot 4 usa forward o deferred? El renderer Forward+ es el predeterminado y, pese al nombre, usa un enfoque clustered forward que escala bien con muchas luces sobre Vulkan.
¿Menos draw calls siempre es mejor? Generalmente reduce la carga de CPU, pero el equilibrio depende de tu escena. Lo importante es medir con los monitores, no adivinar.
Clase 085 - Capstone Parte 3: un mini-juego de física