- Se implementa desde cero un renderizador de software sin bibliotecas gráficas externas para entender cómo funcionan internamente OpenGL, Vulkan, Metal y DirectX
- Convierte un modelo 3D en una imagen a partir de una malla de triángulos y texturas, sin abordar la implementación de una GUI ni de una aplicación para GPU
- El código final tiene alrededor de 500 líneas, y los estudiantes suelen dedicar entre 10 y 20 horas para empezar a crear un renderizador funcional
- Solo se proporciona una clase para manejar TGA compatible con RGB, RGBA y escala de grises, además de una función para establecer un píxel individual; el dibujo de segmentos de línea y triángulos debe implementarse directamente
- Para entender los conceptos de renderizado y también cómo funcionan internamente las bibliotecas 3D, conviene escribir el código uno mismo en lugar de copiar el código final
Proceso para construir directamente el pipeline de renderizado
- Se aprende cómo funciona el pipeline de renderizado siguiendo de forma aproximada la estructura de las bibliotecas modernas de gráficos 3D
- En lugar de aprender a escribir aplicaciones para GPU, se reproducen sus mecanismos internos con un renderizador de software
- La entrada es un modelo 3D compuesto por una malla de triángulos y texturas, y la salida es una imagen renderizada
- Sin una interfaz gráfica, el programa genera un archivo de imagen
- Para reducir dependencias externas, se usa TGA, un formato de imagen sencillo
- Las únicas funciones iniciales proporcionadas son cargar y guardar imágenes, y establecer el color de un solo píxel
- No hay funciones integradas para dibujar segmentos de línea ni triángulos, así que todo debe escribirse directamente
- El ejemplo inicial crea un framebuffer RGB de
64x64, establece en blanco los píxeles de tres coordenadas y luego lo guarda como framebuffer.tga
- Los valores de color se especifican en orden BGRA
Compilación y ejecución del código
git clone https://github.com/ssloy/tinyrenderer.git &&
cd tinyrenderer &&
cmake -Bbuild &&
cmake --build build -j &&
build/tinyrenderer obj/diablo3_pose/diablo3_pose.obj obj/floor.obj
- El resultado de la ejecución se guarda en
framebuffer.tga
- Aunque el código final tiene unas 500 líneas, el proceso de implementarlo directamente es esencial para entender los conceptos, por lo que no se recomienda usar el código proporcionado tal cual
1 comentarios
Opiniones en Hacker News
https://github.com/kshitijl/tinyrenderer-rs
El repositorio tiene muchas capturas del proceso de desarrollo y de bugs visuales graciosos. Aprendí mucho no solo sobre los principios del renderizado, sino también que las CPU modernas son muy rápidas y que incluso con un renderizador de CPU de un solo hilo se puede ejecutar un juego 3D interactivo con efectos especiales vistosos
Fue antes de los LLM, así que me tomó al menos dos meses, y la mayor parte del tiempo la pasé entendiendo las matemáticas de gráficos por computadora y rastreando errores de segmentación en C
Estas notas de clase en GitHub me sirvieron más para repasar conceptos. No me gusta el estilo de código del repositorio y el rasterizador antiguo también es demasiado simple e ineficiente, pero aun así me parece más fácil de leer que el libro de Foley
Con los cambios de edición, el lenguaje usado evolucionó de Pascal a C, y de C a C++, y la edición más reciente también incluye un poco de C#. Faltan varios conceptos nuevos, pero creo que todavía tiene mucho contenido valioso
El recorte del frustum puede resolverse seleccionando puntos de mosaicos locales, y para la composición de primitivas es más fácil tratar el rectángulo de recorte transformado inversamente en coordenadas baricéntricas. Los errores de redondeo se pueden controlar con doble precisión o punto fijo, y la dificultad clave es regenerar los valores Z y 1/Z de los nuevos vértices. En un rasterizador con composición diferida de atributos, el resto pasa naturalmente por el pipeline, y se pueden ver ejemplos en la implementación de código abierto de OpenSWR.org
La mayor barrera psicológica es lo poco familiar que resultan el espacio proyectivo y las coordenadas homogéneas. Los seis planos del espacio de recorte son simplemente
x = ±w,y = ±w,z = ±w; basta con recorrer cada arista del polígono, determinar si sus extremos están dentro o fuera, y luego interpolar linealmente la posición del cruce con el borde y los atributos del vértice. Si aplicas este proceso a cada plano en orden, el triángulo se convierte en un polígono convexo de hasta 9 vértices que se puede triangular de nuevo con facilidad. Si calculas de antemano los outcodes puedes saltarte el recorte de los triángulos completamente internos o externosArtículo: https://dl.acm.org/doi/10.1145/360767.360802
Si mantienes una forma de pipeline fijo, se puede procesar una cantidad sorprendente de triángulos incluso con funciones de dibujo bastante simples