Hola a todos. Mis artículos anteriores fueron y Programación reactiva en el desarrollo de juegos: aspectos específicos de Unity . Desarrollo de juegos en Unity: examen de enfoques para organizar la arquitectura Hoy me gustaría tocar un tema como el renderizado y los shaders en Unity. Los sombreadores (en palabras simples) son instrucciones para tarjetas de video que les dicen cómo renderizar y transformar objetos en el juego. Entonces, bienvenido al club, amigo. ¡Precaución! Este artículo tenía un kilómetro de largo, ¡así que lo dividí en dos partes! ¿Cómo funciona el renderizado en Unity? En la versión actual de , tenemos tres canales de representación diferentes: integrado, HDRP y URP. Antes de abordar el renderizado, debemos comprender el concepto de canalización de renderizado que nos ofrece Unity. Unity Cada canalización de representación realiza algunos pasos que realizan una operación más significativa y forman un proceso de representación completo. Y cuando cargamos un modelo (por ejemplo, .fbx) en el escenario, antes de que llegue a nuestros monitores, recorre un largo camino, como si viajara de Washington a Los Ángeles por caminos diferentes. Cada tubería de representación tiene sus propiedades con las que trabajaremos. Las propiedades de los materiales, las fuentes de luz, las texturas y todas las funciones dentro del shader afectarán la apariencia y optimización de los objetos en la pantalla. Entonces, ¿cómo ocurre este proceso? Para eso, necesitamos discutir la arquitectura básica de las canalizaciones de renderizado. Unity divide todo en cuatro etapas: funciones de aplicación, trabajo con geometría, rasterización y procesamiento de píxeles. Funciones de la aplicación El procesamiento de las funciones comienza en la CPU y tiene lugar dentro de nuestra escena. Esto puede incluir: Procesamiento físico y error de cálculo de colisión Animaciones de textura Entrada de teclado y mouse Nuestros guiones Aquí es donde nuestra aplicación lee los datos almacenados en la memoria para generar aún más nuestras primitivas (triángulos, vértices, etc.). Al final de la etapa de aplicación, todo esto se envía a la etapa de procesamiento de geometría para trabajar en transformaciones de vértices utilizando transformaciones de matrices. Procesamiento de geometría Cuando el ordenador solicita a través de la CPU las imágenes que vemos en pantalla, esto se hace en 2 etapas: de nuestra GPU Cuando se configura el estado de procesamiento y se han pasado los pasos desde el procesamiento de geometría hasta el procesamiento de píxeles Cuando el objeto se representa en la pantalla La fase de procesamiento de la geometría tiene lugar en la GPU y es responsable de procesar la vértices de nuestro objeto. Esta fase se divide en cuatro subprocesos: sombreado de vértices, proyección, recorte y visualización en pantalla. Cuando nuestras primitivas se han cargado y ensamblado con éxito en la primera etapa de aplicación, se envían a la etapa de sombreado de vértices. Tiene dos tareas: Calcular la posición de los vértices en el objeto. Convierta la posición a otras coordenadas espaciales (de coordenadas locales a mundiales, por ejemplo) para que puedan representarse en la pantalla Además, durante este paso, podemos seleccionar adicionalmente las propiedades que serán necesarias para los próximos pasos de dibujar los gráficos. Estos incluyen normales, tangentes, así como coordenadas UV y otros parámetros. La proyección y el recorte funcionan como pasos adicionales y dependen de la configuración de la cámara en nuestra escena. Tenga en cuenta que todo el proceso de renderizado se realiza en relación con Camera Frustum. La proyección se encargará de la perspectiva o el mapeado ortográfico, mientras que el recorte nos permite recortar el exceso de geometría fuera de Camera Frustum. Rasterización y trabajo con píxeles La es la rasterización. Consiste en encontrar píxeles en nuestra proyección que se correspondan con nuestras coordenadas 2D en la pantalla. El proceso de encontrar todos los píxeles que están ocupados por el objeto de la pantalla se denomina rasterización. Este proceso puede considerarse un paso de sincronización entre los objetos de nuestra escena y los píxeles de la pantalla. siguiente etapa del trabajo de renderizado Los siguientes pasos se realizan para cada objeto en la pantalla: Triangle Setup es responsable de generar datos sobre nuestros objetos y transmitirlos para su recorrido. Triangle Traversal enumera todos los píxeles que forman parte del grupo de polígonos; en este caso, este grupo de píxeles se denomina fragmento. El último paso sigue cuando hemos recopilado todos los datos y estamos listos para mostrar los píxeles en la pantalla. En este punto, se lanza el fragment shader, que es el responsable de la visibilidad de cada píxel. Es responsable del color de cada píxel que se representará en la pantalla. Sombreado directo y diferido Como ya sabemos, Unity tiene tres tipos de canalizaciones de renderizado: integradas, URP y HDRP. Por un lado, tenemos Built-In (el tipo de renderizado más antiguo que cumple con todos los criterios de Unity). Por el contrario, tenemos los HDRP y URP más modernos, optimizados y flexibles (llamados RP Scriptable). Cada tubería de representación tiene sus rutas para el procesamiento de gráficos, que corresponden al conjunto de operaciones requeridas para ir desde la carga de la geometría hasta su representación en la pantalla. Esto nos permite procesar gráficamente una escena iluminada (por ejemplo, una escena con luz direccional y paisaje). Entre los ejemplos de rutas de representación se incluyen la ruta de avance, la ruta diferida y el vértice heredado diferido y heredado iluminado. Cada uno admite ciertas características y limitaciones, teniendo su rendimiento. En Unity, la ruta de avance es la predeterminada para el renderizado. Esto se debe a que la mayor cantidad de tarjetas de video lo admiten. Pero el camino hacia adelante tiene sus limitaciones en la iluminación y otras características. Tenga en cuenta que URP solo admite la ruta directa, mientras que HDRP tiene más opciones y puede combinar rutas directas y diferidas. Para comprender mejor este concepto, debemos considerar un ejemplo donde tenemos un objeto y una luz direccional. La forma en que interactúan estos objetos determinará nuestra ruta de representación (modelo de iluminación). Además, el resultado estará influenciado por: Características materiales Características de las fuentes de iluminación. El modelo básico de iluminación corresponde a la suma de 3 propiedades diferentes: color ambiental, reflexión difusa y reflexión especular. El cálculo de la iluminación se realiza en el shader. Se puede hacer por vértice o fragmento. Cuando la iluminación se calcula por vértice, se denomina iluminación por vértice y se realiza en la etapa de sombreado de vértices. De manera similar, si la iluminación se calcula por fragmento, se denomina sombreado por fragmento o por píxel y se realiza en la etapa de sombreado de fragmento (píxel). La iluminación de vértices es mucho más rápida que la iluminación de píxeles, pero debes considerar que tus modelos deben tener muchos polígonos para lograr un resultado hermoso. Matrices en la Unidad Entonces, volvamos a nuestras etapas de renderizado, más precisamente a la etapa de trabajar con vértices. Se utilizan matrices para su transformación. Una matriz es una lista de elementos numéricos que obedecen ciertas reglas aritméticas y se usan a menudo en gráficos por computadora. En Unity, las matrices representan transformaciones espaciales. Entre ellos, podemos encontrar: UNITY_MATRIX_MVP UNITY_MATRIX_MV UNITY_MATRIX_V UNITY_MATRIX_P UNITY_MATRIX_VP UNITY_MATRIX_T_MV UNITY_MATRIX_IT_MV unity_ObjectToWorld unity_WorldToObject Todos corresponden a matrices de cuatro por cuatro (4x4). Cada matriz tiene cuatro filas y cuatro columnas de valores numéricos. Un ejemplo de matriz puede ser la siguiente opción: Como se dijo antes, nuestros objetos tienen dos nodos (en algunos editores gráficos, se llaman transformación y forma), y ambos son responsables de la posición de nuestros vértices en el espacio del objeto. El espacio del objeto define la posición de los nodos en relación con el centro del objeto. Y cada vez que cambiamos la posición, rotación o escala de los vértices del objeto, multiplicamos cada vértice por la matriz modelo (en el caso de Unity - UNITY_MATRIX_M). Para trasladar coordenadas de un espacio a otro y trabajar dentro de él, trabajaremos constantemente con distintas matrices. Propiedades de los objetos poligonales Continuando con el tema de trabajar con objetos poligonales, puedo decir que en el mundo de los gráficos 3D, cada objeto se compone de una malla poligonal. Los objetos de nuestra escena tienen propiedades; cada uno siempre contiene vértices, tangentes, normales, coordenadas UV y color. Todos juntos forman una malla. Todo esto es . administrado por sombreadores Con los shaders podemos acceder y modificar cada uno de estos parámetros. Usualmente usaremos vectores (float4) cuando trabajemos con estos parámetros. A continuación, analicemos cada uno de los parámetros de nuestro objeto. vértices Los vértices de un objeto corresponden a un conjunto de puntos que definen el área de la superficie en el espacio 2D o 3D. En los editores 3D, los vértices suelen representarse como puntos de intersección entre la malla y el objeto. Los vértices se caracterizan, por regla general, por 2 puntos: Son componentes secundarios del componente de transformación. Tienen una determinada posición según el centro del objeto común en el espacio local. Esto significa que cada vértice tiene su componente de transformación responsable de su tamaño, rotación y posición, así como atributos que indican dónde están estos vértices en relación con el centro de nuestro objeto. Normales Las normales nos ayudan inherentemente a determinar dónde se ubica la cara de nuestros segmentos de objetos. Una normal corresponde a un vector perpendicular sobre la superficie de un polígono, que se utiliza para determinar la dirección u orientación de una cara o vértice. tangentes Haciendo referencia a la documentación de Unity, obtenemos la siguiente descripción: Una tangente es . Las tangentes en Unity se representan como Vector4, con componentes x, y, z que definen el vector, y w se usa para voltear el binormal si es necesario - Manual de Unity un vector de longitud unitaria que sigue a la superficie de malla a lo largo de la dirección de textura horizontal (U) ¿Qué diablos acabo de leer? En un lenguaje sencillo, las tangentes siguen las coordenadas U en UV para cada forma geométrica. coordenadas UV Muchos muchachos han mirado las máscaras en y tal vez, como yo, incluso intentaron dibujar algo propio. Y las coordenadas UV están exactamente relacionadas con esto. Podemos usarlos para colocar una textura 2D en un objeto 3D. GTA Vice City Estas coordenadas actúan como puntos de referencia que controlan qué elementos de textura del mapa de textura corresponden a cada vértice de la malla. El área de las coordenadas UV equivale a un rango entre 0,0 (flotante) y 1,0 (flotante), donde "0" representa el punto inicial y "1" representa el punto final. Colores de vértice Además de la posición, la rotación y el tamaño, los vértices también tienen sus colores. Cuando exportamos un objeto desde un software 3D, asigna un color al objeto que necesita ser afectado por la iluminación o copiando otro color. El color de vértice predeterminado es blanco (1,1,1,1,1,1) y los colores están codificados en RGBA. Con la ayuda de los colores de vértice, puede, por ejemplo, trabajar con la combinación de texturas, como se muestra en la imagen de arriba. Pequeña conclusión Este es el final de la 1 parte. En la 2 parte, discutiré: que es un sombreador lenguajes de sombreado Tipos básicos de shaders en Unity Estructura de sombreador ShaderLab Mezcla Z-Buffer (Búfer de profundidad) sacrificio Cg/HLSL Gráfico de sombreado Si tienes alguna pregunta, ¡déjala en los comentarios!