Mapas de sombras clásicos en pocas palabras. Blog cuatro del desarrollador: Nuevas características gráficas de Combat Arms

La luz tiene tres características principales: brillo (Multiplicador), color (Color) y sombras proyectadas por los objetos que ilumina (Sombras).

Al disponer las fuentes de luz en una escena, asegúrese de prestar atención a su color. Las fuentes de luz natural tienen un tinte azul, pero para crear una fuente de luz artificial es necesario darle un color amarillento.

También hay que tener en cuenta que el color de la fuente que simula la luz de la calle depende de la hora del día. Por lo tanto, si la trama de la escena involucra el atardecer, la iluminación puede tener los tonos rojizos de una puesta de sol de verano.

Varios renderizadores ofrecen sus propios algoritmos de generación de sombras. La sombra proyectada por un objeto puede decir mucho: a qué altura está sobre el suelo, cuál es la estructura de la superficie sobre la que cae la sombra, qué fuente iluminó el objeto, etc.

Además, una sombra puede enfatizar el contraste entre el primer plano y el fondo, así como "revelar" un objeto que no está en el campo de visión de la lente de la cámara virtual.

Dependiendo de la forma de la sombra proyectada por el objeto, la escena puede parecer realista (Fig. 6.6) o no del todo creíble (Fig. 6.7).

Como decíamos anteriormente, un haz de luz real sufre una gran cantidad de reflexiones y refracciones, por lo que las sombras reales siempre tienen bordes borrosos. En los gráficos 3D, se utiliza un término especial para describir este tipo de sombras: sombras suaves.

Lograr sombras suaves es bastante difícil. Muchos renderizadores resuelven el problema de las sombras suaves agregando una fuente de luz no puntual que tiene una forma rectangular o de otro tipo a la interfaz de 3ds max 7. Una fuente de este tipo emite luz no desde un punto, sino desde todos los puntos de la superficie. Además, cuanto mayor sea el área de la fuente de luz, más suaves serán las sombras cuando se representen.

Existen diferentes enfoques para visualizar sombras: utilizando un mapa de sombras (Shadow Map), calco (Raytraced) e iluminación global (Global Illumination). Veámoslos en orden.

Arroz. 6.6. Sujeto con sombras suaves

Arroz. 6.7. Sujeto con sombras duras

Arroz. 6.8. Implementación de configuración de parámetros de mapa de sombras para fuente de luz

Usar un mapa de sombras te permite obtener sombras borrosas

con bordes borrosos. La configuración principal del Mapa de sombras es el tamaño del mapa de sombras (parámetro Tamaño) en el menú desplegable de configuración de Parámetros del mapa de sombras (Fig. 6.8). Si se reduce el tamaño del mapa, la claridad de las sombras resultantes también disminuirá.

El método de calco permite obtener sombras con formas ideales, que, sin embargo, no parecen naturales debido a su contorno nítido. El rastreo se refiere al seguimiento de las trayectorias de los rayos de luz individuales desde una fuente de luz hasta la lente de una cámara, teniendo en cuenta su reflejo en los objetos de la escena y su refracción en medios transparentes. El método de calco se utiliza a menudo para representar escenas que contienen reflejos especulares.

A partir de 3ds max 5, se utiliza el método Area Shadows para obtener sombras suaves, que se basa en un método de calco ligeramente modificado. Area Shadows (Distribución de sombras) le permite calcular las sombras de un objeto como si no hubiera una fuente de luz en la escena, sino un grupo de fuentes de luz puntuales distribuidas uniformemente en un área determinada.

Aunque el trazado de rayos reproduce con precisión los detalles finos de las sombras generadas, no es una solución de renderizado ideal debido a los contornos nítidos de las sombras resultantes.

El método de iluminación global (Radiosidad) le permite lograr sombras suaves en la imagen final. Este método es una alternativa al rastreo de iluminación. Si el método de rastreo visualiza solo aquellas áreas de la escena que están iluminadas por rayos de luz, entonces el método de iluminación global calcula la dispersión de la luz en áreas oscuras o no iluminadas de la escena basándose en un análisis de cada píxel de la imagen. Esto tiene en cuenta todos los reflejos de los rayos de luz en la escena.

La iluminación global le permite obtener una imagen realista, pero el proceso de renderizado supone una gran carga para la estación de trabajo y también requiere mucho tiempo. Por tanto, en algunos casos tiene sentido utilizar un sistema de iluminación que simule el efecto de la luz difusa. En este caso, las fuentes de luz deben colocarse de tal forma que su posición coincida con los lugares de exposición directa a la luz. Estas fuentes no deberían crear sombras y deberían tener un brillo bajo. Este método ciertamente no produce una imagen tan realista como la que se puede obtener utilizando un método de iluminación global real. Sin embargo, en escenas que tienen una geometría simple, puede resultar bastante útil.

Existen varios algoritmos para calcular la iluminación global; uno de los métodos para calcular la luz reflejada es el rastreo de fotones (Photon Mapping). Este método implica calcular la iluminación global basándose en la creación del llamado mapa de fotones. El mapa de fotones representa la información de iluminancia de la escena recopilada mediante el rastreo.

La ventaja del método de rastreo de fotones es que una vez guardados como un mapa de fotones, los resultados del rastreo de fotones se pueden utilizar posteriormente para crear efectos de iluminación globales en escenas de animación 3D. La calidad de la iluminación global calculada mediante el rastreo de fotones depende del número de fotones, así como de la profundidad del rastreo. Usando el rastreo de fotones, también puede calcular el efecto cáustico (lea más sobre el efecto cáustico en la sección “Información general sobre visualización en gráficos 3D”, Capítulo 7).

Entre las fuentes de luz estándar, tres fuentes (Spot, Direct y Omni) nos permiten elegir el tipo de sombras a calcular. Si utilizamos el estándar Default Scanline Renderer (DSR), entonces nos interesará lo siguiente: Sombras avanzadas con trazado de rayos, Sombras de área, Sombras con trazado de rayos, Mapas de sombras.

Cuando selecciona un tipo de sombra entre los desplazamientos de parámetros IS, aparece un desplazamiento de parámetros de sombra, cuyo nombre comienza con el nombre del tipo.

Mapa de sombras

El tipo de sombras más simple y poco exigente en términos de recursos computacionales.

  1. El tamaño del mapa en función del cual se calcula la sombra. Cuanto más grande sea el mapa, mejor será la calidad de la sombra calculada. Es mejor usar números de orden 2 n.
  2. Difuminando el borde de la sombra. Aumentar el parámetro le permite deshacerse del borde irregular cuando la resolución del mapa es baja
  3. Parámetro responsable de controlar el valor de Bias. Deshabilitado de forma predeterminada (mejor resultado en la mayoría de los casos). En el caso de la animación, habilitando la opción
  4. Si está desactivado, la luz atraviesa la superficie si incide en polígonos con normales de espaldas a él. Habilitar esta opción le permite obtener sombras correctas.

En la Fig. 1, la fila superior de imágenes muestra claramente el cambio en la calidad de la sombra a medida que aumenta el parámetro Tamaño. Incluso un aumento significativo en el tamaño del mapa no resuelve el problema de los bordes irregulares de la sombra, aunque el patrón de sombra ciertamente se vuelve más detallado.

En la segunda fila, en los tres casos, el tamaño del mapa sigue siendo el mismo, pero el parámetro Rango de muestra cambia. Al aumentarlo gradualmente, nos deshicimos de las irregularidades, difuminando el borde de la sombra.

Fig.1 Cambiar la calidad de la sombra del tipo Mapa de sombras con varios parámetros

Sombras con trazado de rayos

Este tipo de sombra se calcula en base a un algoritmo de trazado. Tienen bordes claros y son prácticamente imposibles de personalizar.

Ray-Traced Shadow es más preciso en relación con Shadow Map. Además, puede tener en cuenta la transparencia del objeto, pero al mismo tiempo es “seco” y claro, lo que en la mayoría de los casos no parece muy natural. Ray-Traced Shadow exige más recursos informáticos que Shadow Map.

  1. Distancia del objeto desde la sombra proyectada
  2. La profundidad del trazado es un parámetro responsable del desarrollo de la sombra. Aumentar este valor puede aumentar significativamente el tiempo de renderizado.

Las sombras con trazado de rayos con un IC tipo Omni tardarán más en renderizarse que una combinación de sombras con trazado de rayos + puntual (o direccional)

Fig.2 Sombras con trazado de rayos de objetos opacos y transparentes

Sombras avanzadas con trazado de rayos

Las sombras de este tipo son muy similares a las Sombras Ray-Traced, pero como su nombre indica, tienen configuraciones más avanzadas que permiten cálculos más naturales y correctos.

  1. Método de generación de sombras
    Simple – un solo haz emerge del IC. La sombra no admite ninguna configuración de suavizado o calidad.
    Antialias de 1 pasada – se simula la emisión de un haz de rayos. Además, la misma cantidad de rayos se refleja en cada superficie iluminada (la cantidad de rayos se ajusta mediante la Calidad de la sombra).
    Antialias de 2 pasadas – Similar, pero se emiten dos haces de rayos.
  2. Si se apaga, la luz atraviesa la superficie si incide en polígonos con normales de espaldas a ella. Habilitar esta opción le permite obtener sombras correctas.
  3. Número de rayos emitidos por una superficie iluminada.
  4. El número de rayos secundarios emitidos por la superficie iluminada.
  5. El radio (en píxeles) del desenfoque del borde de la sombra. Aumentar el parámetro mejora la calidad del desenfoque. Si se pierden pequeños detalles al difuminar el borde, corríjalo aumentando la integridad de las sombras.
  6. Distancia del objeto desde la sombra proyectada
  7. Un parámetro que controla la aleatoriedad de los rayos. Inicialmente, los rayos se dirigen a lo largo de una estricta rejilla, lo que puede provocar artefactos desagradables. Introducir caos hará que la sombra luzca más natural.
    Los valores recomendados son 0,5-1,0. Pero las sombras más borrosas requerirán una mayor cantidad de fluctuación.

Sombras del área

Este tipo de sombra te permite tener en cuenta las dimensiones de la fuente de luz, por lo que puedes obtener sombras extendidas naturales que se “dividen” y se difuminan a medida que te alejas del objeto. 3dsMax produce estas sombras mezclando varias "muestras" de sombras. Cuantas más “muestras” y mejor sea la mezcla, mejor será la sombra calculada.

  1. La forma de una fuente de luz imaginaria que permite determinar la naturaleza de la sombra.
    Simple – un solo haz emerge del IC. La sombra no admite ninguna configuración de suavizado ni de calidad.
    Luz rectangular t – se simula la emisión de luz desde un área rectangular.
    Luz de disco – El CI se comporta como si hubiera adquirido la forma de un disco.
    Caja de luz – imitación de IC cúbico.
    Luz esférica t – imitación de un IC esférico.
  2. Si está desactivado, la luz atraviesa la superficie si incide en polígonos con normales de espaldas a él. Habilitar esta opción le permite obtener sombras correctas.
  3. Controla el número de rayos emitidos (no lineal). Cuanto mayor sea el número, más rayos, mayor será la calidad de la sombra.
  4. Un parámetro responsable de la calidad de la sombra. Para un cálculo racional, establezca siempre un número superior a Shadow Integrity.
  5. El radio (en píxeles) del desenfoque del borde de la sombra. Aumentar el parámetro mejora la calidad del desenfoque. Si se pierden pequeños detalles al difuminar el borde, corríjalo aumentando la Integridad de las sombras.
  6. La distancia del objeto a la sombra proyectada.
  7. Un parámetro que controla la aleatoriedad de los rayos. Inicialmente, los rayos se dirigen a lo largo de una estricta rejilla, lo que puede provocar artefactos desagradables. Introducir caos hará que la sombra luzca más natural.
  8. Dimensiones de la fuente imaginaria. Largo - largo, Ancho - ancho, Alto (activo solo para Box Light y Sphere Light) - alto.

Echemos un vistazo a la Fig.3. Sobre el primer fragmento. Varias "muestras" de sombras se superponen entre sí sin mezclarse. En el segundo fragmento ya están mezclados (la cantidad de jitter cambió de 0,0 a 6,0). Las "muestras" mixtas se perciben como una sombra más natural, pero su calidad deja mucho que desear. El tercer fragmento muestra una sombra con excelente calidad (Shadow Integrity y Shadow Quality cambiaron de valores únicos a 8 y 10, respectivamente).

Segunda fila en la Fig. 3. Ilustra cómo cambia el carácter de la sombra si aumentamos el tamaño de la fuente imaginaria. En este caso tenemos una fuente imaginaria del tipo Luz Rectángulo (rectangular plana). A medida que aumenta el área de origen, aumenta el desenfoque de la sombra.

Fig.3 Cambiar la calidad de la sombra del tipo Área de sombra con diferentes parámetros

Algunos valores de parámetros son de naturaleza consultiva, pero todo está limitado únicamente por su imaginación. La mejor manera de descubrirlo es mediante la experimentación. No tengas miedo de experimentar con la luz. Capte el estado de ánimo de la imagen futura y déjese llevar por la configuración.

En la figura 4. Caballero de ajedrez con un material basado en una textura de madera procesal simple. Tres fuentes de luz teñidas de diferentes colores. Configuración simple, pero la figura se ve bien de todos modos.

Fig.4 Pieza de ajedrez “Caballero”. Visualización del sujeto

Resumen

La iluminación es una de las etapas más importantes al trabajar en una escena tridimensional. A primera vista, puede parecer que la árida información de la lección no se puede aplicar al trabajo creativo. Sin embargo, con el ingenio y el trabajo duro adecuados, se pueden lograr resultados increíbles. Después de todo, todas las imágenes digitales son sólo colecciones de unos y ceros, y 3dsMax es sólo otra herramienta para ti, como un lápiz o un pincel.

El algoritmo de mapeo de sombras original se inventó hace bastante tiempo. Su principio de funcionamiento es el siguiente:
  1. Dibujamos la escena en una textura (mapa de sombras) desde la posición de la fuente de luz. Es importante señalar aquí que las cosas suceden de manera un poco diferente para los diferentes tipos de fuentes de luz.
    Las fuentes de luz direccionales (en cierta medida esto incluye la luz solar) no tienen una posición en el espacio, pero para formar un mapa de sombras se debe elegir esta posición. Por lo general, está vinculado a la posición del observador, de modo que el mapa de sombras incluye objetos ubicados directamente en el campo de visión del observador. El renderizado utiliza una proyección ortográfica.
    Las fuentes de luz de proyección (lámparas con pantalla opaca, focos) tienen una posición determinada en el espacio y limitan la propagación de la luz en determinadas direcciones. Al representar el mapa de sombras en este caso, se utiliza una matriz de proyección en perspectiva convencional.
    Las fuentes de luz omnidireccionales (una lámpara incandescente, por ejemplo), aunque tienen una determinada posición en el espacio, distribuyen la luz en todas direcciones. Para construir correctamente sombras a partir de dicha fuente de luz, es necesario utilizar mapas de cubos, lo que normalmente significa dibujar la escena en un mapa de sombras 6 veces. No todos los juegos pueden permitirse sombras dinámicas provenientes de este tipo de fuentes de luz, y no todos los juegos las necesitan. Si está interesado en cómo funciona este enfoque, hay un hilo sobre ese tema.
    Además, existe una subclase de algoritmos de mapeo de sombras (LiSPSM, TSM, PSM, etc.), que utilizan matrices de proyección de vistas no estándar para mejorar la calidad de las sombras y eliminar las deficiencias del enfoque original.
    No importa cómo se forme el mapa de sombras, invariablemente contiene la distancia desde la fuente de luz al punto visible más cercano (desde la posición de la fuente de luz) o una función de esta distancia en versiones más complejas del algoritmo.
  2. Dibujamos la escena desde la cámara principal. Para saber si un punto de un objeto está en la sombra, basta con traducir las coordenadas de este punto al espacio del mapa de sombras y hacer una comparación. El espacio del mapa de sombras está determinado por la matriz de vista-proyección que se utilizó para generar este mapa. Traduciendo las coordenadas del punto del objeto a este espacio y transformando las coordenadas del rango [-1;-1] V , obtenemos coordenadas de textura. Si las coordenadas recibidas están fuera del rango , entonces este punto no está incluido en el mapa de sombras y puede considerarse sin sombras. Haciendo una selección del mapa de sombras utilizando las coordenadas de textura resultantes, obtendremos la distancia entre la fuente de luz y el punto más cercano de cualquier objeto a ella. Si comparamos esta distancia con la distancia entre el punto actual y la fuente de luz, el punto aparece en la sombra si el valor en el mapa de sombras es menor. Esto es bastante simple desde un punto de vista lógico, si el valor del mapa de sombras es menor, significa que en este punto hay algún objeto que está más cerca de la fuente de luz y estamos en su sombra.
El mapeo de sombras es probablemente el algoritmo más común para representar sombras dinámicas en la actualidad. La implementación de una u otra modificación del algoritmo se puede encontrar en casi cualquier motor gráfico. La principal ventaja de este algoritmo es que proporciona una rápida formación de sombras a partir de objetos arbitrariamente geométricamente complejos. Al mismo tiempo, la existencia de una amplia gama de variaciones del algoritmo se debe en gran medida a sus deficiencias, que pueden dar lugar a artefactos gráficos muy desagradables. A continuación se analizarán los problemas específicos del PPSM y las formas de superarlos.

Mapeo de sombras divididas en paralelo

Considere el siguiente problema: es necesario dibujar sombras dinámicas de objetos ubicados a una distancia considerable del jugador sin comprometer las sombras de objetos ubicados cerca. Limitémonos a la luz solar dirigida.
Este tipo de problema puede ser especialmente relevante en juegos al aire libre, donde en algunas situaciones el jugador puede ver el paisaje a cientos de metros frente a él. Al mismo tiempo, cuanto más queramos ver la sombra, más espacio debería quedar en el mapa de sombras. Para mantener la resolución adecuada de los objetos en el mapa de sombras, nos vemos obligados a aumentar la resolución del mapa en sí, lo que primero conduce a una disminución en el rendimiento y luego nos encontramos con una limitación en el tamaño máximo del objetivo de renderizado. Como resultado, al equilibrar el rendimiento y la calidad de las sombras, obtenemos sombras con un efecto de alias claramente visible, que no se enmascara bien incluso con el desenfoque. Está claro que una solución así no puede satisfacernos.
Para resolver este problema, podemos crear una matriz de proyección tal que los objetos ubicados cerca del jugador reciban un área más grande en el mapa de sombras que los objetos que están ubicados lejos. Esta es la idea principal del algoritmo Perspective Shadow Mapping (PSM) y de varios otros algoritmos. La principal ventaja de este enfoque es el hecho de que prácticamente no hemos cambiado el proceso de renderizado de la escena, solo ha cambiado el método de cálculo de la matriz de proyección de vista. Este enfoque se puede integrar fácilmente en un juego o motor existente sin necesidad de realizar modificaciones importantes en este último. La principal desventaja de este tipo de enfoque son las condiciones de contorno. Imaginemos una situación en la que dibujamos sombras del Sol al atardecer. A medida que el Sol se acerca al horizonte, los objetos en el mapa de sombras comienzan a superponerse mucho entre sí. En este caso, una matriz de proyección atípica puede agravar la situación. En otras palabras, los algoritmos de clase PSM funcionan bien en determinadas situaciones, por ejemplo, cuando el juego dibuja sombras del "Sol fijo" cerca del cenit.
En el algoritmo PSSM se propone un enfoque fundamentalmente diferente. Algunos pueden conocer este algoritmo como Mapeo de sombras en cascada (CSM). Formalmente, estos son algoritmos diferentes; incluso diría que PSSM es un caso especial de CSM. Este algoritmo propone dividir la pirámide de visibilidad (frustum) de la cámara principal en segmentos. En el caso del PSSM, con límites paralelos a los planos de corte cercano y lejano, en el caso del CSM, el tipo de división no está estrictamente regulado. Para cada segmento ( dividir en la terminología del algoritmo) se construye su propio mapa de sombras. En la siguiente figura se muestra un ejemplo de división.


En la figura puedes ver la división de la pirámide de visibilidad en 3 segmentos. Cada uno de los segmentos está resaltado con un rectángulo delimitador (en el espacio tridimensional habrá un cuadro delimitador paralelepípedo). Para cada una de estas partes limitadas del espacio, se construirá su propio mapa de sombras. El lector atento notará que aquí utilicé paralelepípedos delimitadores alineados axialmente. También puede usar no alineados; esto agregará complejidad adicional al algoritmo de recorte de objetos y cambiará un poco la forma en que se genera la matriz de vista a partir de la posición de la fuente de luz. A medida que la pirámide de visibilidad se expande, el área de los segmentos más cercanos a la cámara puede ser significativamente menor que el área de los más alejados. Dada la misma resolución de los mapas de sombras, esto significa una mayor resolución para las sombras de los objetos cercanos. El artículo mencionado anteriormente en GPU Gems 3 propone el siguiente esquema para calcular las distancias divididas de la pirámide de visibilidad:



Dónde i– índice de partición, metro– número de particiones, norte– distancia al plano de recorte más cercano, F– distancia al plano de corte lejano, λ – coeficiente que determina la interpolación entre las escalas de partición logarítmica y uniforme.

General en implementación
El algoritmo PSSM implementado en Direct3D 11 y OpenGL tiene mucho en común. Para implementar el algoritmo, es necesario preparar lo siguiente:
  1. Varios mapas de sombras (según el número de particiones). A primera vista, parece que para obtener múltiples mapas de sombras es necesario dibujar los objetos varias veces. De hecho, no es necesario hacer esto explícitamente; usaremos el mecanismo de creación de instancias de hardware. Para hacer esto, necesitamos la llamada matriz de textura de renderizado y un sombreador de geometría simple.
  2. Mecanismo para cortar objetos. Los objetos en el mundo del juego pueden tener diferentes formas geométricas y tener diferentes posiciones en el espacio. Los objetos extendidos pueden ser visibles en varios mapas de sombras, los objetos pequeños, solo en uno. Un objeto puede aparecer directamente en el borde de segmentos adyacentes y debe dibujarse con al menos 2 mapas de sombras. Por lo tanto, se necesita un mecanismo para determinar en qué subconjunto de mapas de sombras cae un objeto en particular.
  3. Un mecanismo para determinar el número óptimo de particiones. Representar mapas de sombras para cada segmento por cuadro puede ser un desperdicio de recursos computacionales. En muchas situaciones, el jugador ve solo una pequeña parte del mundo del juego frente a él (por ejemplo, se mira los pies o su mirada se posa en la pared frente a él). Está claro que esto depende en gran medida del tipo de revisión del juego, pero sería bueno tener dicha optimización.
Como resultado, obtenemos el siguiente algoritmo para generar matrices de proyección de vista para representar mapas de sombras:
  1. Calculamos las distancias para dividir la pirámide de visibilidad en el peor de los casos. El peor caso aquí es que vemos sombras hasta el plano de recorte de la cámara lejana.

    Código

    void calcularMaxSplitDistances() ( float nearPlane = m_camera.getInternalCamera().GetNearPlane(); float farPlane = m_camera.getInternalCamera().GetFarPlane(); for (int i = 1; i< m_splitCount; i++) { float f = (float)i / (float)m_splitCount; float l = nearPlane * pow(farPlane / nearPlane, f); float u = nearPlane + (farPlane - nearPlane) * f; m_maxSplitDistances = l * m_splitLambda + u * (1.0f - m_splitLambda); } m_farPlane = farPlane + m_splitShift; }

  2. Determinamos la distancia entre la cámara y el punto visible más lejano del objeto que proyecta la sombra. Es importante tener en cuenta aquí que los objetos pueden o no proyectar sombras. Por ejemplo, se puede hacer que un paisaje llano y montañoso no proyecte sombras; en este caso, un algoritmo de iluminación puede ser responsable de las sombras. Sólo los objetos que proyecten sombras se dibujarán en el mapa de sombras.

    Código

    float calcularFurthestPointInCamera(const matrix44& cameraView) ( bbox3 scenebox; scenebox.begin_extend(); for (size_t i = 0; i< m_entitiesData.size(); i++) { if (m_entitiesData[i].isShadowCaster) { bbox3 b = m_entitiesData[i].geometry.lock()->getBoundingBox(); b.transform(m_entitiesData[i].modelo); cuadro de escena.extend(b); ) ) escenabox.end_extend(); float maxZ = m_camera.getInternalCamera().GetNearPlane(); para (int i = 0; i< 8; i++) { vector3 corner = scenebox.corner_point(i); float z = -cameraView.transform_coord(corner).z; if (z >máxZ) máxZ = z; ) devolver std::min(maxZ, m_farPlane); )

  3. En base a los valores obtenidos en los pasos 1 y 2, determinamos la cantidad de segmentos que realmente necesitamos y las distancias de partición para los mismos.

    Código

    void calcularSplitDistances() ( // calcula cuántos mapas de sombras realmente necesitamos m_currentSplitCount = 1; if (!m_maxSplitDistances.empty()) ( for (size_t i = 0; i< m_maxSplitDistances.size(); i++) { float d = m_maxSplitDistances[i] - m_splitShift; if (m_furthestPointInCamera >= d) m_currentSplitCount++; ) ) float nearPlane = m_camera.getInternalCamera().GetNearPlane(); para (int i = 0; i< m_currentSplitCount; i++) { float f = (float)i / (float)m_currentSplitCount; float l = nearPlane * pow(m_furthestPointInCamera / nearPlane, f); float u = nearPlane + (m_furthestPointInCamera - nearPlane) * f; m_splitDistances[i] = l * m_splitLambda + u * (1.0f - m_splitLambda); } m_splitDistances = nearPlane; m_splitDistances = m_furthestPointInCamera; }

  4. Para cada segmento (los límites del segmento están determinados por las distancias cercanas y lejanas), calculamos el paralelepípedo delimitador.

    Código

    bbox3 calcularFrustumBox(flotar plano cercano, flotar plano lejano) ( vector3 ojo = m_camera.getPosition(); vector3 vZ = m_camera.getOrientation().z_direction(); vector3 vX = m_camera.getOrientation().x_direction(); vector3 vY = m_camera. getOrientation().y_direction(); float fov = n_deg2rad(m_camera.getInternalCamera().GetAngleOfView()); float aspecto = m_camera.getInternalCamera().GetAspectRatio(); float nearPlaneHeight = n_tan(fov * 0.5f) * nearPlane; float nearPlaneWidth = nearPlaneHeight * aspecto; float farPlaneHeight = n_tan(fov * 0.5f) * farPlane; float farPlaneWidth = farPlaneHeight * aspecto; vector3 nearPlaneCenter = ojo + vZ * nearPlane; vector3 farPlaneCenter = ojo + vZ * farPlane; bbox3 caja; caja. comenzar_extend(); box.extend(vector3(nearPlaneCenter - vX * nearPlaneWidth - vY * nearPlaneHeight)); box.extend(vector3(nearPlaneCenter - vX * nearPlaneWidth + vY * nearPlaneHeight)); box.extend(vector3(nearPlaneCenter + vX * nearPlaneWidth + vY * nearPlaneHeight));box.extend(vector3(nearPlaneCenter + vX * nearPlaneWidth - vY * nearPlaneHeight)); box.extend(vector3(farPlaneCenter - vX * farPlaneWidth - vY * farPlaneHeight)); box.extend(vector3(farPlaneCenter - vX * farPlaneWidth + vY * farPlaneHeight)); box.extend(vector3(farPlaneCenter + vX * farPlaneWidth + vY * farPlaneHeight)); box.extend(vector3(farPlaneCenter + vX * farPlaneWidth - vY * farPlaneHeight)); cuadro.end_extend(); caja de devolución; )

  5. Calculamos la matriz de sombras de la vista de proyección para cada segmento.

    Código

    Matrix44 CalculaShadowViewProjection(const bbox3& frustumBox) ( const float LIGHT_SOURCE_HEIGHT = 500.0f; vector3 viewDir = m_camera.getOrientation().z_direction(); vector3 size = frustumBox.size(); vector3 center = frustumBox.center() - viewDir * m_splitShift; center.y = 0; auto lightSource = m_lightManager.getLightSource(0); vector3 lightDir = lightSource.orientation.z_direction(); Matrix44 ShadowView; ShadowView.pos_component() = centro - lightDir * LIGHT_SOURCE_HEIGHT; ShadowView.lookatRh(shadowView.pos_component( ) + lightDir, lightSource.orientation.y_direction()); ShadowView.invert_simple(); Matrix44 ShadowProj; float d = std::max(size.x, size.z); shadowProj.orthoRh(d, d, 0.1f, 2000.0f); devuelve ShadowView * ShadowProj; )

Implementamos el recorte de objetos utilizando una prueba simple para la intersección de dos paralelepípedos delimitadores (un objeto y un segmento de la pirámide de visibilidad). Hay una característica aquí que es importante tener en cuenta. Puede que no veamos el objeto, pero podemos ver su sombra. No es difícil adivinar que con el enfoque descrito anteriormente, cortaremos todos los objetos que no son visibles en la cámara principal y no habrá sombras en ellos. Para evitar que esto suceda, utilicé una técnica bastante común: extendí el cuadro delimitador del objeto a lo largo de la dirección de propagación de la luz, lo que dio una aproximación aproximada de la región del espacio en la que la sombra del objeto es visible. Como resultado, para cada objeto se generó una matriz de índices de mapas de sombras en los que se debe dibujar este objeto.

Código

actualización nulaShadowVisibilityMask(const bbox3& frustumBox, const std::shared_ptr & entidad, EntityData& entidadData, int splitIndex) ( bbox3 b = entidad->getBoundingBox(); b.transform(entityData.model); // cálculo del cuadro de sombra auto lightSource = m_lightManager.getLightSource(0); vector3 lightDir = lightSource.orientation .z_direction(); float shadowBoxL = fabs(lightDir.z)< 1e-5 ? 1000.0f: (b.size().y / -lightDir.z); bbox3 shadowBox; shadowBox.begin_extend(); for (int i = 0; i < 8; i++) { shadowBox.extend(b.corner_point(i)); shadowBox.extend(b.corner_point(i) + lightDir * shadowBoxL); } shadowBox.end_extend(); if (frustumBox.clipstatus(shadowBox) != bbox3::Outside) { int i = entityData.shadowInstancesCount; entityData.shadowIndices[i] = splitIndex; entityData.shadowInstancesCount++; } }


Ahora veamos el proceso de renderizado y las partes específicas de Direct3D 11 y OpenGL 4.3.
Implementación en Direct3D 11
Para implementar el algoritmo en Direct3D 11 necesitaremos:
  1. Una variedad de texturas para representar mapas de sombras. Para crear este tipo de objetos, existe un campo ArraySize en la estructura D3D11_TEXTURE2D_DESC. Entonces, en el código C++ no tendremos nada como ID3D11Texture2D* array[N] . Desde el punto de vista de la API de Direct3D, una serie de texturas difiere poco de una sola textura. Una característica importante al usar una matriz de este tipo en un sombreador es que podemos determinar en qué textura de la matriz dibujaremos este o aquel objeto (semántica SV_RenderTargetArrayIndex en HLSL). Ésta es la principal diferencia entre este enfoque y MRT (múltiples objetivos de renderizado), en el que un objeto se dibuja en todas las texturas especificadas a la vez. Para los objetos que deben dibujarse en varios mapas de sombras a la vez, usaremos instancias de hardware, que nos permiten clonar objetos a nivel de GPU. En este caso, el objeto se puede dibujar en una textura de la matriz y sus clones en otras. Solo almacenaremos el valor de profundidad en los mapas de sombras, por lo que usaremos el formato de textura DXGI_FORMAT_R32_FLOAT.
  2. Muestrario de textura especial. En la API de Direct3D, puede establecer parámetros especiales para el muestreo de una textura, lo que le permitirá comparar el valor de la textura con un número determinado. El resultado en este caso será 0 o 1, y la transición entre estos valores se puede suavizar mediante un filtro lineal o anisotrópico. Para crear una muestra en la estructura D3D11_SAMPLER_DESC, establezca los siguientes parámetros:

    SamplerDesc.Filter = D3D11_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT; samplerDesc.ComparisonFunc = D3D11_COMPARISON_LESS; samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_BORDER; samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_BORDER; samplerDesc.BorderColor = 1.0f; samplerDesc.BorderColor = 1.0f; samplerDesc.BorderColor = 1.0f; samplerDesc.BorderColor = 1.0f;
    Así, tendremos filtrado bilineal, comparación con la función “menor que” y muestreo de la textura en coordenadas fuera de rango. devolverá 1 (es decir, sin sombra).

Realizaremos el renderizado de acuerdo con el siguiente esquema:

Implementación en OpenGL 4.3
Para implementar el algoritmo en OpenGL 4.3, necesitamos todo lo mismo que para Direct3D 11, pero hay sutilezas. En OpenGL, solo podemos realizar búsquedas comparables para texturas que contienen un valor de profundidad (por ejemplo, en el formato GL_DEPTH_COMPONENT32F). En consecuencia, renderizaremos solo en el búfer de profundidad y eliminaremos la grabación en color (más precisamente, vincularemos solo una serie de texturas al búfer de fotogramas para almacenar el búfer de profundidad). Esto, por un lado, nos ahorrará un poco de memoria de vídeo y facilitará el proceso de gráficos, por otro lado, nos obligará a trabajar con valores de profundidad normalizados.
Los parámetros de muestreo en OpenGL se pueden vincular directamente a la textura. Serán idénticos a los comentados anteriormente para Direct3D 11.

Flotador constante BORDER_COLOR = (1.0f, 1.0f, 1.0f, 1.0f); glBindTexture(m_shadowMap->getTargetType(), m_shadowMap->getDepthBuffer()); glTexParameteri(m_shadowMap->getTargetType(), GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(m_shadowMap->getTargetType(), GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(m_shadowMap->getTargetType(), GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); glTexParameteri(m_shadowMap->getTargetType(), GL_TEXTURE_COMPARE_FUNC, GL_LESS); glTexParameteri(m_shadowMap->getTargetType(), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameteri(m_shadowMap->getTargetType(), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); glTexParameterfv(m_shadowMap->getTargetType(), GL_TEXTURE_BORDER_COLOR, BORDER_COLOR); glBindTexture(m_shadowMap->getTargetType(), 0);
Es interesante el proceso de creación de una serie de texturas, que está representada por una textura tridimensional dentro de OpenGL. No se creó ninguna función especial para crearlo, ambos se crean usando glTexStorage3D. El equivalente GLSL de SV_RenderTargetArrayIndex es la variable gl_Layer incorporada.
El esquema de renderizado también sigue siendo el mismo:

Problemas

El algoritmo de mapeo de sombras y sus modificaciones tienen muchos problemas. A menudo, el algoritmo debe ajustarse cuidadosamente para un juego específico o incluso para una escena específica. Puede encontrar una lista de los problemas más comunes y las formas de resolverlos. Al implementar PSSM encontré lo siguiente:

Actuación

Las mediciones de rendimiento se realizaron en una computadora con la siguiente configuración: AMD Phenom II X4 970 3,79 GHz, 16 Gb de RAM, AMD Radeon HD 7700 Series, con Windows 8.1.

Tiempo medio de fotograma. Direct3D 11 / 1920x1080 / MSAA 8x / pantalla completa / escena pequeña (~12k polígonos por fotograma, ~20 objetos)

Tiempo medio de fotograma. OpenGL 4.3 / 1920x1080 / MSAA 8x / pantalla completa / escena pequeña (~12k polígonos por fotograma, ~20 objetos)

Tiempo medio de fotograma. 4 divisiones / 1920x1080 / MSAA 8x / pantalla completa / escena grande (~1000k polígonos por fotograma, ~1000 objetos, ~500 instancias de objetos)

Los resultados mostraron que en escenas grandes y pequeñas la implementación de OpenGL 4.3 es generalmente más rápida. A medida que aumenta la carga en la canalización de gráficos (aumentando la cantidad de objetos y sus instancias, aumentando el tamaño de los mapas de sombras), la diferencia en la velocidad operativa entre implementaciones disminuye. Asocio la ventaja de la implementación de OpenGL con un método diferente para generar mapas de sombras de Direct3D 11 (usamos solo un búfer de profundidad sin escribir en color). Nada nos impide hacer lo mismo en Direct3D 11, resignándonos a utilizar valores de profundidad normalizados. Sin embargo, este enfoque solo funcionará hasta que queramos almacenar algunos datos adicionales o una función del valor de profundidad en el mapa de sombras en lugar del valor de profundidad. Y algunas mejoras en el algoritmo (por ejemplo, Variance Shadow Mapping) nos resultarán difíciles de implementar.

conclusiones

El algoritmo PSSM es uno de los métodos más exitosos para crear sombras en grandes espacios abiertos. Se basa en un principio de partición simple y claro, que se puede escalar fácilmente aumentando o disminuyendo la calidad de las sombras. Este algoritmo se puede combinar con otros algoritmos de mapeo de sombras para obtener sombras suaves más hermosas o más correctas físicamente. Al mismo tiempo, los algoritmos de la clase de mapeo de sombras a menudo conducen a la aparición de artefactos gráficos desagradables que deben eliminarse ajustando el algoritmo para un juego específico.

Etiquetas:

  • Mapeo de sombras
  • PSSM
  • Direct3D 11
  • OpenGL 4
Agregar etiquetas

Blog cuatro del desarrollador: Nuevas funciones gráficas

En el primer diario de actualización del motor gráfico, hablamos brevemente sobre algunas de las nuevas mejoras gráficas que pronto se agregarán al juego. Además, hemos dicho que la mayoría de estas mejoras estarán a la par de los motores de juegos modernos como Unity 5, Unreal 4 o CryEngine 3. Pero, ¿qué significa esto realmente?

En primer lugar, queremos que comprendas que el proceso de actualización se realizará de forma gradual y que no todos los mapas, personajes, texturas de armas y objetos se actualizarán de inmediato. La mayoría de ellos seguirán funcionando con los recursos actuales del juego, pero los actualizaremos con el tiempo para darle a Combat Arms una apariencia verdaderamente actualizada.

Vale la pena señalar que lograr que muchas de estas capacidades gráficas funcionen en un motor tan antiguo, y al mismo tiempo mantener la compatibilidad con el modo y los recursos gráficos antiguos, requirió que hiciéramos muchas soluciones alternativas interesantes y a veces locas, limitadas a la capacidades de DirectX 9. ¡Fue muy divertido!

Iluminación y sombras dinámicas.

El motor Lithitech Jupiter original tenía soporte limitado para iluminación y sombras dinámicas, aunque lo que ofrecía el motor era bastante avanzado para la época en la que se desarrolló. Básicamente, en el motor gráfico original de Lithtech Jupiter, la iluminación y el sombreado eran completamente estáticos, lo que significa que se calculaban previamente y se almacenaban como una textura que se usaba al representar la geometría del mapa. Sin embargo, incluso la iluminación estática en algunos puntos les permitió crear escenas iluminadas dinámicamente en ciertos objetos, como modelos de personajes y armas. Dado que la iluminación dinámica se utilizaba por vértice en los objetos, también fue necesario calcular previamente varios detalles y protuberancias adicionales y aplicarlos directamente sobre las texturas difusas. Y debido a que están horneados, no pueden interactuar dinámicamente con diferentes fuentes de luz y, a menudo, no se adaptan a las condiciones de iluminación. Esto hace que la imagen parezca muy plana y anticuada para 2017.

La mejora más importante que pudimos implementar fue combinar tanto la geometría estática del mapa como los objetos que reciben iluminación y sombras completamente dinámicas. La iluminación dinámica realmente le permite renderizar una escena con iluminación, reflejos, luces, sombras dinámicas y mapas de relieve píxel a píxel.

Si bien la introducción de una única fuente de luz dinámica inicialmente no fue tan difícil, surgieron desafíos debido a la necesidad de admitir simultáneamente múltiples fuentes de luz dinámicas de manera eficiente. La compatibilidad con múltiples fuentes de luz dinámicas se ha convertido en una característica central de casi todos los motores de juegos modernos. La única forma en que el motor Lithtech permitía renderizar múltiples luces dinámicas era esencialmente volver a dibujar toda la escena varias veces, una para cada luz en el mapa. Esto es algo exagerado, ya que Lithtech es capaz de agrupar la geometría del mapa en bloques que se pueden hacer mediante una esfera de luz delimitadora, y solo será necesario volver a dibujar esos bloques del mapa. Pero esto todavía requiere una alta carga de CPU para renderizar la escena varias veces y impone aún más restricciones sobre cuán compleja es la geometría del mapa y cuántos objetos se pueden mostrar en la pantalla a la vez.

Al principio, comenzamos teniendo solo la luz solar direccional principal como única fuente de luz dinámica. Todas las demás fuentes de luz internas omnidireccionales y puntuales se dejaron estáticas. Pero muchas de las ubicaciones del juego en Combat Arms están total o parcialmente ubicadas en edificios, por lo que la diferencia entre la iluminación estática interior y la iluminación dinámica exterior era demasiado notable.

Por lo tanto, para la iluminación dinámica que utiliza múltiples fuentes de luz, era necesario realizar grandes cambios en la forma en que el motor representa la escena y maneja la luz en sí. Para ello, utilizamos una técnica de renderizado conocida como sombreado diferido. El tema de la iluminación y las sombras diferidas puede ser bastante amplio y lo mencionamos brevemente en la primera publicación del blog de desarrollo. Básicamente, permite que toda la iluminación dinámica pase al ámbito del renderizado posterior al proceso, que es completamente independiente de la complejidad de la escena y puede ser manejado casi en su totalidad por la GPU con muy poca sobrecarga de CPU.

Con todas estas optimizaciones en mente, pudimos implementar un sombreador de iluminación de física compleja. Luego probamos exhaustivamente este modelo de iluminación, comparándolo con cómo se representarían escenas similares en otros motores de juegos modernos como Unity 5 y Unreal 4, así como con escenas completamente renderizadas con rayos creadas utilizando renderizado profesional fuera de línea. Nos limitamos únicamente a lo que podíamos implementar en tiempo real con hardware gráfico moderno, utilizando sombreadores de iluminación modernos. Los resultados son bastante comparables a los de la representación de rayos, siendo las principales diferencias la precisión de la reflexión y la atenuación de la iluminación.

Nuevos sombreadores de iluminación dinámica en Combat Arms:

Versión con trazado de rayos de la escena:

tarjeta de sombra

Al implementar sombras dinámicas, nos enfrentamos a una serie de desafíos para lograr un sombreado totalmente dinámico y de última generación en Combat Arms. En el motor Lithtech original, la mayoría de las sombras se integran en texturas de iluminación estáticas que se utilizan al representar la geometría del mapa. Por eso no todos los objetos proyectan sombras, especialmente los objetos dinámicos, porque la sombra es fija y no puede cambiar. Si bien Lithtech tiene una función que te permite crear sombras dinámicas en ciertos objetos, no se ha utilizado mucho en Combat Arms. Además, esta característica tiene un alcance demasiado limitado y los objetos dinámicos en sí no pueden recibir sombras.

Al final, decidimos utilizar un mapa de sombras en cascada (CSM) totalmente dinámico para la principal fuente de luz direccional del sol, y una solución parcialmente dinámica para luces omnidireccionales y fuentes de luz utilizando un mapa de sombras omnidireccional precalculado que se puede aplicar. tanto a la geometría mundial como a los objetos dinámicos. Esto es similar a cómo otros motores de juegos modernos proporcionan sombreado dinámico.

En general, ¿qué es una Carta Sombra? Es esencialmente un truco muy inteligente que utilizan los juegos y los programas de renderizado para simular el sombreado dinámico acelerado por la GPU. https://en.wikipedia.org/wiki/Shadow_mapping.

El algoritmo de representación de sombras básicamente se ocupa de la necesidad de representar la escena en términos de una fuente de luz en una textura, usándola como punto de entrada para el sombreador de iluminación de píxeles y luego usando esa textura para que la GPU calcule si el píxel está en sombra o no.

En el juego, la textura del mapa de sombras se ve así:

Tenga en cuenta que esta textura no tiene 1, sino 4 mapas de sombras. Cada uno de estos mapas de sombras se denomina cascada de mapas de sombras. A medida que aumenta la distancia a la superficie observada, se utiliza una cascada más grande, pero con una resolución más baja. Esto permite que las sombras se extiendan mucho pero aún encajen en una textura de tamaño fijo. En este caso, las sombras cercanas al observador tendrán una resolución mayor. La resolución del mapa de sombras está directamente relacionada con la nitidez y precisión de las sombras.

Dado que el mapa de sombras es solo otra cámara en la escena, se puede renderizar dinámicamente en tiempo real. La configuración de calidad de las sombras afectará la resolución de la textura del mapa de sombras.

Así es como se ve la solución del mapa de sombras cuando se filtra.

Filtrado de mapas de sombras

Usar solo un mapa de sombras puede resultar en sombras muy marcadas. Y aunque a veces puedan parecer buenos, esto no es la realidad.

En el mundo real, las sombras no siempre son duras o suaves, cambian según el tamaño de la fuente de luz y la distancia al objeto iluminado. Puedes ver ejemplos en la foto:

Observa cómo en estas fotos las sombras se vuelven más suaves a medida que se alejan de los objetos que las proyectan. La mayoría de los demás juegos modernos todavía utilizan un método de filtrado de sombreado simple llamado Filtrado porcentual más cercano o PCF, que aplica un valor fijo de dureza o suavidad a todas las sombras.

Estas capturas de pantalla de los juegos muy modernos Doom y Overwatch muestran cómo la mayoría de los juegos realizan un filtrado de sombras simple usando PCF.

Sin embargo, en Combat Arms decidimos implementar una tecnología de filtrado de sombras más avanzada que se acercará más a lo que vemos en la vida real. En el juego simulamos esto usando una tecnología desarrollada por NVidia llamada Closer Soft Shadows (PCSS).

Aunque esta tecnología se introdujo en 2005, sólo ahora el hardware gráfico se ha vuelto lo suficientemente potente como para utilizar este método, y los juegos modernos recién han comenzado a hacer un uso intensivo de ella para el filtrado de mapas de sombras en los últimos años. Al momento de escribir este blog, esta tecnología aún no está disponible en Unreal 4 o Unity 5. Aunque técnicamente hablando, Unreal 4 proporciona una solución alternativa llamada trazado de rayos a distancia, pero se limita a resolver solo geometría estática para proyectar sombras.

PCSS deshabilitado:

PCSS habilitado:

Se aplicará un filtrado fino con PCSS cuando la configuración de calidad de las sombras esté configurada en alta. Además, actualmente el PCSS solo se utiliza para luz solar direccional básica en todos los niveles de calidad. Desafortunadamente, PCSS no es compatible con el filtrado de sombras acelerado por hardware. Shader Model 3 DirectX 9 no es compatible con las instrucciones de sombreado Gather4 que se usan comúnmente en los sombreadores de píxeles DirectX 10+/Shader Model 4+ para el filtrado de mapas de sombras. Debido a la carga operativa de PCSS que utiliza el sombreador de píxeles Shader Model 3, se utiliza filtrado antialias para reducir la carga de GPU.

Mapeo de sombras omnidireccional

Con las fuentes de luz omnidireccionales, las cosas son un poco más complicadas. Dado que proyectan sombras en todas direcciones, hacer mapas de sombras para ellos no es tan fácil ya que la escena debe representarse usando algún tipo de cámara de 360°. Por lo general, esto implica renderizar la escena en múltiples direcciones desde la posición de la fuente de luz. Sin embargo, es difícil escalar una escena cuando hay muchas fuentes de luz de este tipo. Entonces, para esto utilizamos un mapa de sombras precalculado donde solo se calcula una vez cuando se carga el mapa en lugar de cada cuadro. Un mapa de sombras precalculado puede proyectar sombras sobre objetos dinámicos en la escena, pero los objetos dinámicos dentro de la escena no proyectarán sombras. Para sortear esta limitación, se utiliza la función de sombra de objetos nativa del motor Lithtech para proporcionar sombras de objetos a partir de mapas de sombras omnidireccionales precalculados. También combinamos esto con el rastreo de Sombras en el espacio de pantalla para dar a los objetos sombras nativas detalladas y sombras de contacto.

Un ejemplo interesante de cómo se utiliza un mapa de sombras para proyectar un mapa de sombras omnidireccional en una sola textura:

Esto utiliza un método de proyección de 360° conocido como parametrización de octaedro esférico, o a veces llamado "mapeo octaédrico", donde la esfera se asigna a una textura única en función de su proyección sobre la cara del octaedro.

Los mapas de sombras omnidireccionales tradicionales utilizan un mapa cúbico, que requiere al menos 6 texturas diferentes para representar un mapa de sombras omnidireccional completo de 360°, pero con esta proyección de mapa, solo se utiliza 1 textura. Este método también produce menos distorsión que la mayoría de los otros métodos de diseño 2D esféricos y, a diferencia de un mapa cúbico sin envolver, encaja perfectamente en una única textura cuadrada. Muchos mapas existentes en el juego utilizan una gran cantidad de luces omnidireccionales como fuente de luz principal, y esto permite que muchos de ellos también admitan sombreado dinámico en tiempo real.

resumámoslo

Creemos que esta combinación de tecnologías de iluminación y sombreado le dará al juego un aspecto muy moderno para 2017 y que nuestras soluciones son bastante competitivas con lo que ofrecen otros motores de juegos en la actualidad. Si bien estos cambios por sí solos no son suficientes para "modernizar" el juego, todavía tenemos mucho trabajo por hacer para mejorar las texturas y los recursos que aprovecharán al máximo las nuevas funciones.

Por supuesto, estos no son todos los cambios, esto fue solo una mirada en profundidad a los detalles técnicos de la implementación de iluminación y sombreado dinámicos en la próxima actualización de Combat Arms. Además, es importante tener en cuenta que las capturas de pantalla que se muestran se tomaron utilizando una compilación con los activos actuales para demostrar las características gráficas. Es posible que no reflejen con precisión el nivel de gráficos final una vez que se publique la actualización.

También debo recordarte que la configuración de gráficos actualizada es opcional y podrás cambiar entre versiones del motor una vez que se publique la actualización. Estamos desarrollando estas mejoras gráficas basándonos en las capacidades de los dispositivos gráficos modernos de gama media y alta que son relevantes para 2016. Queremos que el motor del juego pueda aprovechar al máximo las GPU modernas para ofrecer la mejor calidad visual posible. Seguimos evaluando y optimizando constantemente nuevas funciones gráficas, pero tenga en cuenta que es posible que el hardware un poco más antiguo o más barato solo pueda ejecutar nuevas opciones gráficas en configuraciones o resoluciones más bajas. Continuaremos admitiendo el motor gráfico heredado, para que los jugadores con hardware más antiguo o menos potente, o aquellos que simplemente prefieran el estilo clásico de Combat Arms, puedan seguir disfrutando del juego como antes.

¡Saludos cordiales, equipo de Combat Arms!

El mapeo de sombras es probablemente la parte más difícil de crear una representación visual de un objeto. Los usamos para obtener luces y sombras horneadas.
Deben desenvolverse de manera única para que cada parte del modelo tenga su propio lugar en el espacio ultravioleta para terminar con la información correcta de luces y sombras.
Es importante recordar que la resolución del mapa de sombras es pequeña en comparación con el tamaño del espacio ultravioleta.
También es importante comprender que cuanto más se necesita optimizar un nivel, menor debe ser el diseñador de niveles para usar la resolución en los mapas de luz, a veces llegando a 8 por 8 o 16 por 16 en el caso de objetos más pequeños.
Esta tendencia requiere que dejemos mucho espacio adicional alrededor de cada sección del barrido del objeto para que las áreas oscuras
no afectó las luces y no destruyó la ilusión de corrección visual de las sombras en el juego.

Hay 3 formas principales de crear dicho barrido:

DESENVOLVER LA CAJA

Este suele ser el método más confiable para crear un diseño de objeto, ya que la mayoría de los modelos ambientales tienen una forma similar a bloques que se combinan en algún tipo de estructura.
Una malla continua (una malla en la que no hay partes separadas de la parte principal) suele ser una solución muy útil a la hora de construir una red,
Esta solución ayudará a proporcionar una distribución más eficiente de la geometría de la malla en el espacio UV.
Esto también funcionará bien incluso con un mapa de sombras de baja resolución, ya que entonces formará un gradiente único de oscuro a claro.
Esto contrasta con un escaneo fragmentado donde el resultado parecerá más ambiguo y es posible que sea necesario aumentar la resolución del mapa de sombras para contrarrestar el efecto de las transiciones bruscas.
Deberíamos intentar evitar esto en la medida de lo posible. Desafortunadamente, a veces no es posible utilizar una resolución más baja o un escaneo de geometría única.

DESENVOLVER PLANO

Este método es especialmente útil para estructuras planas, como paredes con varios chaflanes o extrusiones. También es muy útil para grandes partes de fachadas de edificios, como edificios de apartamentos.
plano se desarrollará mucho mejor si utiliza una geometría continua, porque aquí la cuestión sólo será "relajar" la cuadrícula de escaneo.
A veces también es una buena regla general asegurarse de que haya más espacio horizontal en un escaneo como este que espacio vertical, ya que la proyección de sombras tiende a ser desde un lado en un ángulo ligeramente más alto.
en lugar de hacia abajo. Por lo tanto, un espacio horizontal más grande brinda mayores oportunidades para crear sombras más nítidas, debido a la tendencia de los diseñadores a elegir la iluminación en ángulo.
para crear sombras más interesantes que la iluminación de arriba hacia abajo.

DESENVOLVER CILÍNDRICO

La mayoría de las otras formas pueden considerarse variaciones de la forma cilíndrica, a menos, por supuesto, que estén cerca de paralelepípedos o planos.
El desarrollo cilíndrico es bueno para muchas estructuras que tienen un frente y lados, pero no detrás; de lo contrario, usaríamos el método DESENVOLVER LA CAJA.

Ejemplos

Era una malla continua por lo que era fácil de expandir con DESENVOLVER LA CAJA y simplemente colóquelo horizontalmente para utilizar la mayor cantidad posible de espacio del mapa de sombras.
Las superficies inferiores que serían visibles en la imagen del medio se han eliminado, ya que casi siempre serán negras.
y si estuvieran conectados con el resto del escaneo, las sombras de ellos simplemente se filtrarían en puntos oscuros de las paredes donde no debería estar. Lo mismo ocurre con las caras superiores.
Excepto que siempre serían ligeros.


Este método de desenvolvimiento nos permite tener un mapa de sombras casi perfecto en el juego con una resolución de 32 por 32. La geometría no tiene costuras. Donde debería haber sombra, vemos finas líneas negras, y donde no debería haberla, no la hay.


Aquí vemos que es necesario utilizar la mayor cantidad de espacio posible, ya que el mapa de sombras cubrirá todo el escaneo en cualquier caso.
Por lo tanto, verá una diferencia significativa entre la relación de aspecto de un objeto de 1 a 1 y de 1 a 7. También puede ver que algunas partes del escaneo están separadas aquí y alejadas de la malla principal.
Esto se hace porque estas partes siempre permanecerán en la sombra. No deberían afectar al resto del mapa de sombras.


Incluso en grandes fachadas como ésta, plano muestra buenos resultados. Esta malla es continua, lo que ayuda a nuestro trabajo,
pero en este caso todo funcionaría igual incluso si el escaneo se dividiera en varias franjas verticales u horizontales, aunque era necesario hacer pequeñas hendiduras entre ellas.


Puede ver aquí que la geometría ajustada facilitó la colocación de los rayos UV. También puedes ver que hay hendiduras entre las partes del escaneo para que las áreas oscuras no afecten a las claras.
Cuanto menor sea la resolución del mapa, más sangría deberá realizar.


Se puede ver una distorsión bastante agresiva en las piezas verticales que se cruzan y que mantienen unida la barandilla.
Podéis ver que el soporte central está dividido en dos partes en lugar de tres, como si lo recortáramos por los bordes de la parte central. Esto se hace para reducir la cantidad de costuras y proporcionar una iluminación suave en un área más grande.


Algunos proyectos no siguen estas sencillas reglas, como se muestra en la siguiente captura de pantalla.


Cuando hay tantos elementos individuales no tenemos más remedio que aumentar la resolución de las texturas, de lo contrario estaríamos desperdiciando mucho espacio en el relleno entre los elementos de escaneo, se vería terrible en el juego.
Entonces, la resolución de los mapas de sombras se elevó a 128 por 128, pero aún no se ve perfecto, pero tampoco tanto como para destruir por completo la imagen visual del objeto en el juego.


A veces es fácil expandir un objeto; basta con dividirlo en varias partes razonables. Y luego simplemente "relajar" el barrido. Un gran ejemplo es el objeto siguiente.


Este diseño es esencialmente un cilindro con una base plana, por lo que se utilizan estos dos métodos básicos para desenvolver un objeto.
plano rota partes de la geometría hacia abajo en el eje Z, y luego aplica un modificador de "relajación" y ajusta un poco las posiciones de los vértices para asegurarse de que nada tenga muy poca cobertura.
En el medio hay un caso similar a la base, aquí se divide y usa la parte central. plano en lugar de Cilíndrico para proporcionar un área de cobertura más grande.
Como siempre, nos preocupa más la cobertura que la relación de aspecto 1: 1. Es una gran ventaja colocar las costuras en sus ubicaciones reales, esto permitirá que las sombras se vean más naturales.
Si su objeto tiene cortes profundos, juntas geométricas extremadamente afiladas, entonces este es un excelente lugar para colocar una costura aquí, si, por supuesto, es necesario.

Índice de coordenadas de Lightmap

De forma predeterminada, el primer conjunto de UV (índice 0) de la malla estática se utilizará al crear el mapa de sombras para la iluminación estática.
Esto significa que el mismo conjunto de coordenadas que se utilizan para aplicar materiales a la malla también se utilizará para la iluminación estática.
Este método muchas veces no es el ideal. Una razón para esto es que los UV utilizados para generar el mapa de sombras deben ser únicos.
lo que significa que cada cara de la malla no debe superponerse a ninguna otra superficie en el espacio UV. La razón de esto es bastante obvia: si las caras se superponen en el mapa UV,
la porción del mapa de sombras correspondiente a este espacio se aplicará a ambas caras. Esto provocará una iluminación incorrecta y la aparición de sombras donde en principio no deberían existir.
Las mallas estáticas tienen la propiedad Índice de coordenadas de mapa de luz, que le permite utilizar un escaneo UV determinado para un mapa de sombras. Establezca esta propiedad para que apunte a un conjunto de UV que estén configurados correctamente para la iluminación.

Gráficos UV y relleno.

Los grupos de triángulos aislados con UV adyacentes se denominan gráficos UV.

Debe dividir el escaneo en gráficos y colocarlos por separado si desea excluir la influencia de las sombras de un gráfico sobre otro. Además, al aplicar sangría, debes recordar una regla simple:
El tamaño de la sangría debe ser mayor que 4x4 texels, ya que la compresión DXT funciona con bloques exactamente de este tamaño.

  1. Sangría desperdiciada
  2. Sangría requerida

Esto significa que para un mapa de sombras con resolución 32, el relleno entre partes del mapa UV debe ser del 12,5% del espacio UV total.
Sin embargo, tenga en cuenta que usar demasiado relleno entre partes del UV dará como resultado que la memoria del mapa de sombras se desperdicie en resoluciones más altas.
Cuanto más se acerque a los gráficos UV, mejor. Esto reducirá la cantidad de memoria desperdiciada.


Esto está lejos de ser un despliegue perfecto.

Un ejemplo de un problema de implementación es la fragmentación excesiva. Ves cómo las sombras que deberían quedar en las partes internas del objeto dan sombra a los bordes externos.
Otro problema potencial es confiar en el desenvolvimiento automático, ya que esto también puede provocar los mismos problemas.


La mejor manera de crear un mapa de red para un mapa de sombras es modelar toda la malla como un elemento continuo o crear la red a mano.


Esto producirá un barrido único que casi no tiene costuras y es mucho más eficiente.

El resultado final es una malla que se ilumina correctamente sin ningún artefacto.


Un beneficio adicional de este método es que generalmente también reduce la cantidad de vértices y triángulos necesarios para un modelo determinado.


CATEGORÍAS

ARTICULOS POPULARES

2023 “kingad.ru” - examen por ultrasonido de órganos humanos