Qué hay que aprender para convertirse en programador de gráficos
(blog.demofox.org)- Las habilidades que se buscan en contratación para gráficos en tiempo real exigen tanto APIs gráficas explícitas del lado de CPU como iluminación y shading del lado de GPU, y es difícil dominar ambas áreas en profundidad al mismo tiempo
- El lado de CPU abarca APIs modernas como DirectX12, Vulkan y Metal, además de carga de assets y trabajo de soporte de motor; el lado de GPU trata sombras, ambient occlusion, postprocesado y las características de rendimiento de la GPU
- El centro del aprendizaje en GPU es escribir un path tracer y entender PBR; Ray Tracing in One Weekend, LearnOpenGL PBR, la documentación de Filament y PBRT pueden ser buenos puntos de partida
- Un portafolio ideal muestra conocimiento con un renderizador en tiempo real basado en C++, un path tracer que genere imágenes fotorrealistas y código para comparar y validar ambos resultados de renderizado
- La matemática necesaria se centra en álgebra lineal, trigonometría básica y algo de cálculo; el lenguaje del lado de CPU en desarrollo de juegos es C++ y el lenguaje de shaders más común es HLSL
Los gráficos en tiempo real abarcan CPU y GPU a la vez
- El renderizado moderno, en la práctica, se parece a la combinación de dos trabajos
- Aprendizaje del lado de CPU: programación de motor para APIs explícitas modernas como DirectX12, Vulkan y Metal, además de carga de assets y otras tareas de soporte
- Aprendizaje del lado de GPU: matemáticas modernas de iluminación y shading, sombras, ambient occlusion, efectos de postprocesado y la diferencia entre tareas rápidas y lentas en la GPU
- Aprender ambas áreas al mismo tiempo es muy difícil
- Si quieres enfocarte en la parte de GPU, puedes usar herramientas con menor carga del lado de CPU, como OpenGL, WebGL, DirectX11 o motores ya existentes
- Si quieres enfocarte en la parte de CPU, puedes empezar mostrando un triángulo en pantalla y luego una malla, sin preocuparte demasiado por si el resultado se ve bonito
Path tracing y PBR
- El aprendizaje del lado de GPU incluye escribir un path tracer
- El path tracing es la técnica usada en renderizado para cine y es aquello que las técnicas modernas de renderizado en tiempo real intentan aproximar
- Como material inicial, el libro online gratuito Ray Tracing in One Weekend es adecuado, fácil de abordar y muestra el proceso de crear renderizados con aspecto fotográfico
- Physically Based Rendering (PBR) corresponde a la iluminación, en especial a cómo se aplica el specular
- PBR es un enfoque basado en principios que da buenos resultados si se siguen sus reglas
- Antes de PBR, se usaban muchas fórmulas arbitrarias, ajustes y hacks para la iluminación, así que un asset que se veía bien en un entorno de luz podía verse demasiado oscuro o demasiado brillante en otro
- Como resultado, había que crear distintas versiones del mismo asset para distintas condiciones de iluminación, lo que consumía mucho tiempo y esfuerzo
- PBR hace que los assets se vean más consistentes bajo varias condiciones de iluminación y reduce el tiempo y esfuerzo necesarios para producir versiones por entorno
- Aun así, el tiempo, costo y esfuerzo de producción de assets siguen siendo un gran cuello de botella en el desarrollo de juegos
Materiales de aprendizaje recomendados
- Para iniciarte en PBR, son adecuados la sección PBR Theory de LearnOpenGL y sus subsecciones
- Si quieres profundizar más, la documentación de Filament puede ser el siguiente paso
- Cuanto más a fondo estudias PBR, más aparecen el cálculo y la estadística
- Más adelante, está el libro online gratuito Physically Based Rendering: From Theory To Implementation
- Puede que el machine learning no logre lo que promete el hype actual, pero sí vale la pena aprender técnicas de fitting y optimización dentro de la caja de herramientas de ciencias de la computación
- Como material relacionado, puedes revisar el video Machine Learning For Game Developers
Código que vale la pena mostrar en un portafolio
- Para demostrar conocimientos ante reclutadores, lo ideal es tener código fuente compartible en un lugar como GitHub y enlazarlo desde el currículum
- Ejemplo de portafolio:
- Un renderizador tipo motor que cargue assets como modelos y texturas y los renderice en tiempo real en pantalla
- Con algunos efectos como iluminación y sombras, depth of field, area lights, tone mapping y ray traced shadows
- Si es posible, con iluminación basada en PBR, cámara controlable por el usuario, APIs como DX12 o Vulkan y uso de C++
- Un path tracer que genere imágenes con aspecto fotográfico
- Si es posible, mejor en C++, aunque también puede ser un programa sin ventana que solo exporte PNG
- No necesita ser en tiempo real
- Mejor aún si el path tracer es un modo separado dentro del renderizador tipo motor
- Así puedes comparar el resultado path traced con el renderizado PBR en tiempo real para validar la precisión
- Si puedes señalar en qué puntos no coinciden ambos renderizados, explicar por qué difieren y pensar cómo acercarlos más manteniendo el tiempo real, recibirás una evaluación más alta
- Un renderizador tipo motor que cargue assets como modelos y texturas y los renderice en tiempo real en pantalla
Matemáticas, algoritmos y elección de lenguaje
- Si haces tú mismo los puntos anteriores, te irás encontrando de forma natural con la matemática necesaria
- Lo básico que necesitas es álgebra lineal: multiplicación de matrices, cross product, dot product, trigonometría básica y algo de cálculo
- En gráficos y desarrollo de juegos, el mínimo de matemáticas requerido es relativamente pequeño, pero el rango de matemáticas que puedes aprovechar es prácticamente ilimitado
- Con los algoritmos pasa algo similar
- Hay que conocer tipos abstractos de datos y algoritmos básicos como linked list, hash table, ordenamiento y búsqueda
- Los algoritmos más rápidos suelen ser los simples, y los arreglos son mucho más rápidos que las linked lists
- Los conceptos más avanzados de algoritmos ayudan cuando de verdad necesitas algo nuevo y hecho a la medida
- El lenguaje que debes aprender para desarrollo de juegos es C++
- Hay gente que usa Rust y tiene cierta presencia, pero no es el lenguaje estándar que la mayoría espera
- WebGPU tiene muchas capacidades que WebGL no tenía y se está convirtiendo en una plataforma más seria, además de permitir hacer trabajo del lado de CPU con JavaScript
- Aun así, no se ven muchos empleos de WebGPU ni mucho contenido sobre WebGPU en la web
- El lenguaje de shaders más común es HLSL
- Algunos usan GLSL
- En juegos multiplataforma, a menudo los shaders se convierten a otros lenguajes de shaders
Alcance de uso de LLM y ML
- Considera que la tecnología actual de ML no está a la altura de la mayoría de los usos comerciales con los que se vende
- Claude sí sirve para hablar de matemáticas, papers y algoritmos poco familiares
- En esas situaciones es fácil verificar si está inventando cosas y también validar lo que dice con otras fuentes
- Para programar no resulta muy útil
- Aunque produzca código que funcione como quieres, igual necesitas invertir tiempo para entender ese código
- En ese caso, considera mejor escribirlo tú mismo
- Puede ser útil para usos pequeños
- Por ejemplo, si preguntas “¿ves un bug en este archivo?”, si la respuesta es yes puedes investigar, y si responde no, el costo de preguntar fue casi nulo
- Cree que algún día la humanidad construirá una inteligencia artificial de nivel humano y que irá más allá de eso, pero no sabe si ocurrirá durante su vida
- La era actual de los LLM se parece más a un ensayo general para cuando llegue lo “real”
1 comentarios
Opiniones de Hacker News
Primero hay que distinguir si quieres hacer juegos o dedicarte a la programación de motores 3D.
Si quieres hacer juegos, conviene usar un motor existente como Unreal Engine, Unity, Godot o Bevy; vas a aprender problemas de gráficos de más alto nivel, más que cómo empujar píxeles directamente. Lo realmente difícil es hacerlo divertido.
Si quieres crear un motor 3D, tienes que saber que ya hay demasiados motores de juego pésimos. Solo mirando el ecosistema de Rust, los proyectos principales son tres renderizadores fallidos, un renderizador incompleto y el renderizador dentro de Bevy, y hay muchísimos más proyectos que dicen “voy a hacer un motor de juego”. Llegar siquiera al nivel de “primer renderizador” toma unos 2 años, y llegar a escenas grandes, detalladas y dinámicas es una tarea mucho mayor.
Si el objetivo es conseguir empleo, la industria de los videojuegos no tiene buenos sueldos ni buenos horarios; cuando termina el proyecto, también se acaba el trabajo, y está llena de aspirantes que quieren entrar, como Hollywood. Además, por el colapso del Metaverse, ahora también hay exceso de gente con experiencia.
Mobile es un ejercicio de compresión donde faltan pantalla, potencia de cómputo, GPU y batería; por eso la mayoría de los juegos indie de hoy son 2D. Eso al menos es viable, y a menudo también se hacen con HTML/JavaScript.
Pero crear un renderizador básico y un game loop no es tan difícil, y probablemente ni siquiera sea la mayor parte del código del juego. Para un juego simple, puede bastar con llamar
drawObject()dentro de un buclefor, y preocupaciones como streaming de recursos, optimización de bindings o paralelismo pueden dejarse para después, cuando hagan falta.Me da curiosidad qué punto de partida y qué criterios de éxito se están suponiendo con lo de “2 años hasta el primer renderizador”. Hace más o menos un año hice, en un mes de tiempo libre —menos de una semana a tiempo completo—, un renderizador diferido con iluminación dinámica, shadow mapping y algunos postprocesados.
Tampoco hay razón para menospreciar el 2D. Mucho trabajo serio ocurre en interfaces 2D, y WebGL y el viejo 2D canvas hoy son bastante potentes. Entre los juegos indie exitosos también hay muchos 2D.
Es cierto que la industria de los videojuegos no es gran cosa, pero hoy casi todo usa GPU. Escribir y depurar tareas de machine learning, visualización de datos, HUD e interfaces de usuario en general también suelen requerir comprensión de gráficos.
Además de los juegos, hay muchos más campos que usan gráficos, como visualización y simulación, y los buenos programadores gráficos son extremadamente raros, así que sorprendentemente puede ser una buena carrera. Contrasta bastante con lo difícil que parece ser para desarrolladores de juegos o artistas conseguir buenos empleos. Eso sí, tanto la oferta como la demanda son pequeñas, así que cambiar de trabajo puede no ser fácil.
Si hablamos solo de estabilidad laboral, no recomendaría hacer carrera en desarrollo de juegos, pero la programación gráfica es otra cosa.
Entre los juegos que probé en los últimos años, Core Keeper (Unity), WORMHOLE (Unity, especialmente el lag del modo infinito) y Crab Champions (UE4, donde para mantener 60 fps a 1920x1200 hay que usar un upscaling que hace que la imagen se vea fea) tuvieron problemas graves de rendimiento.
En cambio Terraria, Necesse y Barony usan motores propios, corren de maravilla y parecen envejecer mejor.
Para ser justos, Tiny Rogues (Unity), según recuerdo, corría bastante bien en general, pero como el desarrollador está trabajando para salir de Unity en el futuro, parece que él mismo encontró el problema.
Entiendo la diferencia entre hacer un juego y hacer un motor, y la importancia de terminar y lanzar algo de verdad, pero si sacas basura es difícil dejar un buen legado. Creo que es mejor garantizar cierto nivel de calidad, aunque implique dar un rodeo más largo. Los juegos pueden jugarse durante décadas después de su lanzamiento, y si tienen bugs o lag, la gente seguirá sufriéndolos.
“Primero voy a hacer un motor para mi juego, así el próximo juego será más fácil” es una trampa sorprendentemente fuerte. Porque, de hecho, aprendes cosas importantes y obtienes pequeñas victorias todos los días. Haces un unroll más para que la escena se vea fluida, agregas otra capa lógica al formato de configuración para que sea más fácil crear escenas, lees otro paper de SIGGRAPH.
Siempre hay algo importante que mejorar, pero esas cosas no se juntan para convertirse en un juego terminado. Mirando atrás, usar un motor propio es una forma perfecta para que una persona técnica postergue la parte difícil pero necesaria del juego que soñaba: “hacerlo divertido”. Aprendes la técnica de programar videojuegos impresionantes, pero no aprendes a hacer juegos.
También hay subtrampas. Aprendes cien formas de crear efectos visuales hermosos que corren suavemente en tiempo real, pero no aprendes a usarlos como arte.
Esto se parece mucho a la trampa de “Enterprise Java”. Solo que es más sutil porque trata con términos concretos. Como en el Scene Graph no hay una Factory Factory Interface, crees que esquivaste esa bala, pero en realidad se te escapa que todo eso es innecesario para la tarea de poner un bitmap en pantalla y hacer que responda a teclas.
Esto es especialmente cierto en 2D. Por ejemplo, estoy haciendo un juego con un motor propio, enfocado en rendimiento, compresión y una arquitectura sin servidor ni base de datos.
Este motor tiene una estructura y supuestos muy específicos sobre la estructura del juego para lograr rendimiento y compresión extremos dentro de las restricciones que definí. Planeo publicar pronto un artículo relacionado en Hacker News, si es posible la próxima semana.
Antes intenté varias veces hacer juegos de navegador con Unity, Godot y React, pero aprender sus API era un suplicio, y los motores no cumplían con mis restricciones extremas. Por supuesto, quizá también era culpa mía por no saber manejarlos bien, pero aun mirando atrás creo que lo que logré internamente habría sido imposible sin un motor personalizado hecho desde cero.
Aprendí muchísimo haciendo mi propio motor y mi propio juego, y especialmente hoy, gracias a los LLM, creo que para un desarrollador con experiencia se volvió de pronto algo realista, al alcance de la mayoría de los desarrolladores, intentar crear un motor de juego a medida.
Hoy no le recomendaría a nadie meterse en programación gráfica
Empecé en 2001, cuando Nvidia presentó su primera GeForce 1, la llamada “Gigatexel shader card”, y desde entonces la velocidad de avance e innovación en este campo ha sido vertiginosa. Comparado con hace 25 años, la tecnología actual es realmente impresionante.
Pero todo este asombro tiene un gran “pero”. Este campo avanza a una velocidad aterradora. Nvidia incluso lanzó efectos basados en IA que afectan escenas y assets, algo que en ese entonces ni siquiera imaginábamos que pudiera ser posible en tiempo real.
Ya ni sé si es posible convertirse en un “buen experto” en este campo. Dicho de otra forma: “¿dónde está el John Carmack de hoy?”. Él se hizo famoso por exprimir el hardware al máximo y usar ideas que estaban escondidas en la comunidad, pero hoy no parece haber una ventaja competitiva para alguien así. El campo es demasiado amplio y cambia demasiado rápido como para que exista la oportunidad de convertirse en el próximo Carmack.
También hay otra perspectiva. Si hasta ahora solo has hecho apps web y Kubernetes, quizá precisamente te convenga probar la programación gráfica. El ciclo de retroalimentación es emocionante, y te hace sentir lo absurdamente rápida que puede ser una computadora común. Incluso si al final terminas optimizando cosas que no importan, vale la pena porque quizá nunca aprendiste lo rápido que pueden ser las cosas a bajo nivel.
También hay mucho material, y las matemáticas no son excesivamente difíciles. El modelado 3D podría convertirse en una salida creativa que no sabías que tenías. Aunque no lo apliques en absoluto en tu trabajo principal, te hará apreciar de nuevo el arte de la programación de computadoras, y puede que decidas no volver a tocar Kubernetes y dedicar cinco años de tu tiempo libre a escribir tu propio motor de juegos.
Hay muchos locos de esos, y la comunidad de desarrolladores aficionados que no se han quemado con el desarrollo profesional de juegos es más grande de lo que uno cree. El Discord de Graphics Programming también es un espacio acogedor que vale la pena revisar. Solo hay que intentarlo.
Para alguien a quien no le importa lo que realmente va a hacer y solo quiere cambiar de carrera, tal vez el consejo de evitarlo sea correcto. Pero vivir así no es una buena forma de vivir. Es mejor seguir aquello que te parece interesante y valioso, aprender cosas nuevas constantemente y desafiarte a ti mismo. Entonces se vuelve relativamente claro si debes aprender computación gráfica o no, y para la persona adecuada es una ganancia neta. Aunque no se convierta en tu trabajo, las habilidades se transfieren muy bien a muchas otras áreas.
No pasa nada si no eres tan famoso como una de las personas más conocidas de un campo; también puedes hacerlo simplemente porque lo disfrutas. Las matemáticas y el arte de la programación gráfica y de juegos son hermosos por sí mismos.
Mi razón para no meterse en programación gráfica es otra. ¿Seguirán existiendo dentro de unos años los motores 3D con vértices y texturas? ¿O todo será renderizado directamente por modelos de mundo de IA? ¿Cuánto código habrá en los juegos, o existirán más bien como una serie de prompts escritos con inteligencia?
Si necesitas un tutorial rápido de álgebra lineal, puedes ver este imprimible de 4 páginas que escribí: https://minireference.com/static/tutorials/linear_algebra_in...
También hay aquí un notebook con ejemplos de código en SymPy: https://github.com/minireference/noBSLAnotebooks
Gracias a las visualizaciones, cosas que no había entendido en la clase de Linear 101 por fin me hicieron clic.
Me sorprende un poco que no se hable de principios básicos de diseño ni de las características de la percepción humana.
Mi hermano fue artista de producción en videojuegos famosos de los 90 y 2000, y se quejaba constantemente de programadores y gerentes sin sensibilidad visual ni curiosidad por entender el lado de los artistas.
Los gráficos no son mi especialidad, pero como músico, diseñador de sonido y productor, los coders de DSP de audio más eficaces e influyentes que conozco entienden los fundamentos de la música, la física y la acústica del sonido, y las trampas entre el procesamiento digital discreto y la forma en que percibimos e interpretamos los estímulos.
Que un programador gráfico tenga mentalidad artística ayuda, pero normalmente trabaja a un nivel bastante bajo, así que no es imprescindible para tener éxito.
La IA cambió un poco el cálculo, o al menos tiene el potencial de hacerlo, pero creo que buena parte de la corriente de “aprende a programar” de mediados de los 2000 también venía de esto: tratar el desarrollo de software como “una capacidad, no un producto” de expertos de campos existentes, para que las personas que mejor conocen el dominio hicieran software directamente en vez de traducir requisitos para un equipo de desarrollo.
Sinceramente, la programación gráfica en general se parece más a un rol de servicio que hace posible lo que esas personas quieren hacer, o les ayuda a construir lo que imaginaron.
Inigo Quilez suele mencionarse como ejemplo de alguien que es programador gráfico y artista a la vez, y de verdad es una persona poderosísima, como un unicornio.
Personalmente, me gusta más tocar música y la programación de audio, y eso sirve como una buena base para aprender DSP. Por ejemplo, si empujas el ruido de renderizado hacia las frecuencias altas, a veces un filtro pasa-bajas es más efectivo para eliminarlo.
Si te da curiosidad y tienes tiempo, vale la pena aprenderlo. Es realmente divertido, se aprende mucho y te convierte en un mejor ingeniero en muchas otras áreas de las ciencias de la computación. Llegas a entender el hardware, la programación de sistemas, el modelo de máquina del programador, etc.
Pero si tu objetivo final es el dinero, mejor no lo aprendas. En estos tiempos, la recompensa es efímera, temporal y no está garantizada.
Desde hace tiempo me interesaba la programación gráfica y hace unos años empecé a aprender Vulkan por mi cuenta. No sé cuánto tiempo le dediqué en total, pero creo que fueron unos 6 meses de tiempo libre por las noches, quizá un poco menos. Llegué a hacer algo parecido a un framework de renderizado.
Pero es de esas cosas en las que, cuanto más avanzas, más te das cuenta de todo lo que no sabes. Justo cuando sientes que la estructura está bien, descubres que no es la arquitectura correcta.
Al final, lo que haces es básicamente matemáticas aplicadas de iluminación, y el resto es plomería. Te preguntas “¿por qué el spotlight atraviesa el cubo como si nada?”, y resulta que tienes que calcular sombras, y entonces pasas semanas investigando cómo meter eso en el pipeline de renderizado. Aun así, si te gusta este tipo de cosas, es bastante “divertido”.
Por ejemplo, incluso para hacer sombras, tienes que escribir 10 veces más código del que la técnica en sí requeriría por naturaleza.
Para aprender programación gráfica, creo que es mucho más disfrutable escribir un renderizador por software. Hay menos código, y el código que escribes toca lo esencial en vez de ser boilerplate. La desventaja es que pierdes aceleración por hardware y se vuelve lento.
Si solo quieres crear juegos, puedes usar un motor de juegos como Unity, Godot o Unreal.
Si quieres trabajar con gráficos como motores, simulaciones o renderizadores, tienes que aprender un lenguaje de bajo nivel y una API gráfica. Como lenguaje recomiendo C++; también puedes usar C o Rust, pero C es un poco difícil, y como las APIs gráficas ya son difíciles de por sí, no vas a querer pelearte también con el lenguaje. Rust también podría ser una buena opción, pero personalmente siento que los tiempos de compilación son muy lentos y que la sintaxis es fea.
Como API recomiendo OpenGL. Es multiplataforma y antigua; eso es tanto una ventaja como una desventaja, y es la más fácil de todas.
learnopengl.com es, por mucho, el mejor tutorial de OpenGL, así que recomiendo seguirlo.
Después de usar OpenGL por un tiempo, puedes expandirte a Vulkan o a bibliotecas gráficas que implementen varias APIs, o si te va bien, puedes seguir usando OpenGL.
Sin duda no es fácil, pero creo que es una de las áreas más fascinantes de las ciencias de la computación.
Me da algo de pena decirlo yo mismo, pero la comunidad también es genial. La web es una gran forma de compartir lo que haces mientras aprendes, reunir feedback y ganar visibilidad. Dentro de la comunidad también ha habido muchos casos de gente que terminó dedicándose profesionalmente a los gráficos 3D.
A veces reviso el repositorio y me da vergüenza lo desastroso que era mi código de aquella época, pero creo que sin ese proyecto no estaría donde estoy ahora.
Puedes empezar con etiquetas simples, agregar animaciones y, si te falta algo, sumar componentes de la comunidad. Si aun así no alcanza, puedes modificarlo con ThreeJS e incluso llegar hasta shaders. A-Frame es excelente.
Además, también puedes hacer AR y VR.
En vez de “convertirse en programador gráfico”, ¿qué tal simplemente hacer programación gráfica? Puedes empezar con cosas simples, ir agarrándole la mano y, cuando finalmente ves que todo consiste en enviar logística a la GPU, puedes construir encima todo tipo de conceptos complejos.
Es como subir una montañita y de repente todo encaja y dices “wow…”. Empiezas a ver las posibilidades y las cosas con las que puedes experimentar.
Frases como “soy escalador”, “soy gamer”, “soy artista”, “soy madre”, “soy padre”, “soy fanático del gimnasio” o “soy programador gráfico” no necesariamente hablan de un trabajo, pero sí sugieren algo más profundo que una participación ligera y pasajera.
Hoy aprendí el formato de imagen PPM, y para este tipo de uso es muy accesible. Escribir bitmaps no es ninguna ciencia espacial, pero PPM es todavía más fácil.