Z-búfer
Un búfer de profundidad, también conocido como z-buffer, es un tipo de búfer de datos utilizado en gráficos por computadora para representar información de profundidad de objetos en el espacio 3D desde un perspectiva particular. Los búferes de profundidad son una ayuda para renderizar una escena para garantizar que los polígonos correctos ocluyan correctamente otros polígonos. El búfer Z fue descrito por primera vez en 1974 por Wolfgang Straßer en su tesis doctoral sobre algoritmos rápidos para renderizar objetos ocluidos. Una solución similar para determinar polígonos superpuestos es el algoritmo del pintor, que es capaz de manejar elementos de escena no opacos, aunque a costa de la eficiencia y de resultados incorrectos.
En una canalización de representación 3D, cuando se proyecta un objeto en la pantalla, la profundidad (valor z) de un fragmento generado en la imagen de pantalla proyectada se compara con el valor ya almacenado en el búfer (profundidad test), y lo reemplaza si el nuevo valor es más cercano. Funciona junto con el rasterizador, que calcula los valores coloreados. El fragmento generado por el rasterizador se guarda si no se superpone con otro fragmento.
Al ver una imagen que contiene superficies o objetos opacos parcial o totalmente superpuestos, no es posible ver completamente los objetos que están más alejados del espectador y detrás de otros objetos (es decir, algunas superficies están ocultas detrás de otras). Si no hubiera un mecanismo para administrar superficies superpuestas, las superficies se renderizarían una encima de la otra, sin importar si están destinadas a estar detrás de otros objetos. La identificación y eliminación de estas superficies se denomina problema de la superficie oculta. Para verificar la superposición, la computadora calcula el valor z de un píxel correspondiente al primer objeto y lo compara con el valor z en la misma ubicación de píxel en el búfer z. Si el valor z calculado es más pequeño que el valor z que ya está en el búfer z (es decir, el nuevo píxel está más cerca), entonces el valor z actual en el búfer z se reemplaza con el valor calculado. Esto se repite para todos los objetos y superficies de la escena (a menudo en paralelo). Al final, el z-buffer permitirá la reproducción correcta de la percepción de profundidad habitual: un objeto cercano oculta otro más lejano. Esto se llama eliminación de z.
El búfer z tiene la misma estructura de datos interna que una imagen, es decir, una matriz 2D, con la única diferencia de que almacena un solo valor para cada píxel de la pantalla en lugar de imágenes en color que usan 3 valores para crear color. Esto hace que el búfer z aparezca en blanco y negro porque no almacena información de color. El búfer tiene las mismas dimensiones que el búfer de pantalla para mantener la coherencia.
Las pruebas de visibilidad primarias (como la selección de la cara posterior) y las pruebas de visibilidad secundarias (como las comprobaciones de superposición y el recorte de pantalla) generalmente se realizan en objetos' polígonos para omitir polígonos específicos que no son necesarios para renderizar. El búfer Z, en comparación, es comparativamente caro, por lo que realizar pruebas de visibilidad primaria y secundaria libera al búfer z de algunas tareas.
La granularidad de un z-buffer tiene una gran influencia en la calidad de la escena: el z-buffer tradicional de 16 bits puede generar artefactos (llamados "z-fighting" o stitching) cuando dos objetos están muy cerca uno del otro. Un z-buffer más moderno de 24 o 32 bits se comporta mucho mejor, aunque el problema no se puede eliminar sin algoritmos adicionales. Un z-buffer de 8 bits casi nunca se usa porque tiene muy poca precisión.
Usos
Z-buffer es una tecnología utilizada en casi todas las computadoras, laptops y teléfonos móviles actuales para realizar gráficos de computadora en 3D. El uso principal ahora es para videojuegos, que requieren un procesamiento rápido y preciso de escenas 3D. El búfer Z se implementa en hardware dentro de las tarjetas gráficas de consumo. El búfer Z también se utiliza (implementado como software en lugar de hardware) para producir efectos especiales generados por computadora para películas.
Además, los datos de Z-buffer obtenidos al renderizar una superficie desde el punto de vista de una luz permiten la creación de sombras mediante la técnica de mapeo de sombras.
Desarrollos
Incluso con una granularidad lo suficientemente pequeña, pueden surgir problemas de calidad cuando la precisión en los valores de distancia del búfer z no se distribuye uniformemente a lo largo de la distancia. Los valores más cercanos son mucho más precisos (y, por lo tanto, pueden mostrar mejor los objetos más cercanos) que los valores que están más lejos. Generalmente, esto es deseable, pero a veces hará que aparezcan artefactos a medida que los objetos se vuelven más distantes. Una variación del z-buffering que da como resultado una precisión distribuida más uniformemente se llama w-buffering (ver más abajo).
Al comienzo de una nueva escena, el búfer z debe borrarse a un valor definido, generalmente 1,0, porque este valor es el límite superior (en una escala de 0 a 1) de profundidad, lo que significa que ningún objeto es presente en este punto a través del tronco de visualización.
La invención del concepto de búfer z se suele atribuir a Edwin Catmull, aunque Wolfgang Straßer describió esta idea en su doctorado de 1974. tesis meses antes de la invención de Catmull.
En las tarjetas gráficas de PC más recientes (1999–2005), la administración de z-buffer utiliza una parte significativa del ancho de banda de la memoria disponible. Se han empleado varios métodos para reducir el costo de rendimiento del z-buffering, como la compresión sin pérdidas (los recursos informáticos para comprimir/descomprimir son más baratos que el ancho de banda) y el hardware ultrarrápido z-clear que hace obsoleto el "one frame positive, un fotograma negativo" truco (saltar el claro entre fotogramas por completo usando números firmados para verificar inteligentemente las profundidades).
Z-sacrificio
En el renderizado, z-culling es la eliminación temprana de píxeles basada en la profundidad, un método que proporciona un aumento en el rendimiento cuando el renderizado de superficies ocultas es costoso. Es una consecuencia directa del búfer z, donde la profundidad de cada píxel candidato se compara con la profundidad de la geometría existente detrás de la cual podría estar oculto.
Cuando se usa un búfer z, un píxel se puede seleccionar (descartar) tan pronto como se conoce su profundidad, lo que permite omitir todo el proceso de iluminación y texturización de un píxel que de todos modos no sería visible. Además, los sombreadores de píxeles que consumen mucho tiempo generalmente no se ejecutarán para los píxeles eliminados. Esto hace que z-culling sea un buen candidato para la optimización en situaciones en las que la tasa de relleno, la iluminación, las texturas o los sombreadores de píxeles son los principales cuellos de botella.
Mientras que el búfer z permite ordenar la geometría, ordenar los polígonos aumentando la profundidad (usando así un algoritmo de pintor inverso) permite que cada píxel de la pantalla se represente menos veces. Esto puede aumentar el rendimiento en escenas con tasa de relleno limitada con grandes cantidades de overdraw, pero si no se combina con z-buffering, sufre problemas graves como:
- polígonos pueden ocluirse uno al otro en un ciclo (por ejemplo: triángulo A occludes B, B occludes C, C occludes A), y
- no hay un punto canónico "clásico" en un triángulo (por ejemplo: no importa si se clasifican los triángulos por su punto centralide o punto más cercano o punto más lejano, uno siempre puede encontrar dos triángulos A y B tales que A es "cliente" pero en realidad B debe ser dibujado primero).
Como tal, el algoritmo de pintor inverso no se puede utilizar como una alternativa a la selección Z (sin una reingeniería extenuante), excepto como una optimización de la selección Z. Por ejemplo, una optimización podría ser mantener los polígonos ordenados según la ubicación x/y y la profundidad z para proporcionar límites, en un esfuerzo por determinar rápidamente si es posible que dos polígonos tengan una interacción de oclusión.
Matemáticas
La gama de valores de profundidad en el espacio de cámara que se va a hacer se define a menudo entre un cerca{displaystyle {textit {near}} y lejos{displaystyle {textit {far}} valor z{displaystyle z}.
Después de una transformación de perspectiva, el nuevo valor z{displaystyle z}, o z.{displaystyle z}, se define por:
- z.=lejos+cercalejos− − cerca+1z()− − 2⋅ ⋅ lejos⋅ ⋅ cercalejos− − cerca){displaystyle {fnh} {fnh} {fnh}} {fnh}} {fnh}} {fnh}}}} {fn}}fn}fnh}fn}fnh} {fnfnh} {fnfnfnhnh}}} {f}f}f}f}}}f}}}}fnfnfnfnfnf}}}f}}}}}}}}}f}f}fnfnfnfnf}}}}}fnfnfnfnfnfnhnfnfnh}fnfnfnfnfnfnh}}}}}}}}}}fnfnhnfnfnfnfnfnh}}}fnh
Después de una proyección ortográfica, el nuevo valor z{displaystyle z}, o z.{displaystyle z}, se define por:
- z.=2⋅ ⋅ z− − cercalejos− − cerca− − 1{fnMicroc} {{}-{textit {near}}{textit {far}-{textit {f} {f} {f}} {f}} {f}} {f}}}} {fn}}}- {fnf} {near}}}}-1}
Donde z{displaystyle z} es el antiguo valor de z{displaystyle z} en el espacio de la cámara, y a veces se llama w{displaystyle w} o w.{displaystyle w'}.
Los valores resultantes de z.{displaystyle z} se normalizan entre los valores de -1 y 1, donde los cerca{displaystyle {textit {near}} el avión está en -1 y el far{displaystyle {Mathit {far}} El avión está en 1. Los valores fuera de esta gama corresponden a puntos que no están en el frustum visual, y no deben ser renderizados.
Representación de punto fijo
Por lo general, estos valores se almacenan en el t-buffer del acelerador gráfico de hardware en formato de punto fijo. Primero se normalizan a un rango más común que es [0, 1] sustituyendo la conversión apropiada z2.=12()z1.+1){displaystyle z'_{2}={2}left(z'_{1}+1right)} en la fórmula anterior:
- z.=lejos+cerca2⋅ ⋅ ()lejos− − cerca)+12+1z()− − lejos⋅ ⋅ cercalejos− − cerca){displaystyle z'={frac {{textit {far}textit {near}}{2cdot left({textit {far}}-{textit {near}right)}}+{frac {1}{2}}+{frac {1}{z}left({frac {-{textit {far}cdot {textit {near}}}{textit {far}-{textit {near}right)}}}}}}} {f}}} {f}}}}} {f}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} {m}}}}}} {m}} {m}}}}}}}}}}}}}}}}}}} {f}}}}}}}}} {f}}}}}}}}}}}}}}}}}}}}}}}}}}}} {m}}}}}}}}}}}}}}} {m}}}}}}}}}}}}}}}}}}}} {
Simplificando:
- z.=lejos()lejos− − cerca)+1z()− − lejos⋅ ⋅ cercalejos− − cerca){fnK} {fnh}fnh} {fnhfnh}}fnh} {fnh} {fnh} {fnh}fnh} {fnfnhfnh}fnh} {fnfn}fnfnh}} {fnfnhnhnhnhnhnhnhnhnhnhnhnhnhnh}}}}}}}}f}f}fnhf}fnhnfnhnhnfnhnhnhnhnhf}fnhfnhnhnhnhnh}fnhnh}fnhnfnhnhfnhnhnh}fnh}fnhnh}fnhnh}fnhnh}fnhnh}}}fnh
Segundo, la fórmula anterior se multiplica por S=2d− − 1{displaystyle S=2^{d}-1} donde d es la profundidad del t-buffer (normalmente 16, 24 o 32 bits) y redondeando el resultado a un entero:
- z.=f()z)=⌊()2d− − 1)⋅ ⋅ ()lejos()lejos− − cerca)+1z()− − lejos⋅ ⋅ cercalejos− − cerca))⌋{fnMicrosoft} {f} {f}f} {f}}} {f}} {f} {f}}} {f}} {f}f}} {f}}} {f}f} {f} {f}f} {f}}}}}f} {f} {f}f}}}}}f}}}}}}}f}} {f}f}}}}f} {f} {f}f}}}}}}}}}f} {f} {f}f} {f}}}}}}}}}}}}f} {f} {f}}}}}}}}}f}f} {f} {f}f}f}}}}f}}}}}}}}}f}}}}}}}}}}}}}}}}}}}}}}}
Esta fórmula puede ser invertida y derivada para calcular la resolución del t-buffer (la 'granularidad' mencionada anteriormente). El inverso de lo anterior f()z){displaystyle f(z),}:
- z=− − lejos⋅ ⋅ cercaz.S()lejos− − cerca)− − lejos=− − S⋅ ⋅ lejos⋅ ⋅ cercaz.()lejos− − cerca)− − lejos⋅ ⋅ S{displaystyle z={frac {textit {far}cdot {textit {fnear}{frac}{frac} {f} {f}} {f}}} {f}}} {fnf}}} {fnf} {fnK}left({textit {far}-{textit {near}right)-{textit {far}}={frac} {-Scdot {textit {cdot} {textit {fn}{z'left({textit {far}}-{textit {near}}right)-{textit {far}cdot}cdot} S}
Donde S=2d− − 1{displaystyle S=2^{d}-1}
La resolución z-buffer en términos de espacio de cámara sería el valor incremental resultante del cambio más pequeño en el entero almacenado en el t-buffer z, que es +1 o -1. Por lo tanto, esta resolución se puede calcular a partir del derivado de z{displaystyle z} como función de z.{displaystyle z}:
- dzdz.=− − 1⋅ ⋅ − − 1⋅ ⋅ S⋅ ⋅ lejos⋅ ⋅ cerca()z.()lejos− − cerca)− − lejos⋅ ⋅ S)2⋅ ⋅ ()lejos− − cerca){displaystyle {frac {}{dz}={frac} {-1cdot -1cdot ¿Por qué?
Expresándolo en términos de espacio de cámara, sustituyendo z.{displaystyle z} por lo anterior f()z){displaystyle f(z),}:
- dzdz.=− − 1⋅ ⋅ − − 1⋅ ⋅ S⋅ ⋅ lejos⋅ ⋅ cerca⋅ ⋅ ()lejos− − cerca)()S⋅ ⋅ ()− − lejos⋅ ⋅ cercaz+lejos)− − lejos⋅ ⋅ S)2=()lejos− − cerca)⋅ ⋅ z2S⋅ ⋅ lejos⋅ ⋅ cerca=z2S⋅ ⋅ cerca− − z2S⋅ ⋅ lejos.. z2S⋅ ⋅ cerca{displaystyle {begin{aligned}{frac {dz} {begin{aligned}{frac {f} {f}} {f}}} {f}}} {fnfnfnfnf}}}} {fnfnfnKfnKf}}}}}}} {f}}}}}} {fnfnfnfnfnfnfnfnfnKfnfnfnfnfnfnfnfnfnKfnKfnfnfnKfnKfnKfnKfnfnKfnKfnKfnfnKfnKfnfnKfnfnKfnfnfnKfnKfnK}}}}}}} {-1cdot -1cdot Scdot {textit {far}cdot {textit {near}cdot left({textit {far}}-{textit {near}}right)}{cdot left({frac {textit {textit {-{textit}cdot}cdot {cdot}cdot {cdot}}}}}cdot {cdot {cdot {cdot {cdot {cdotcdot {cdot {cdot {cdot {cdotcdot {cdot {cdot {cdot {cdot {cdot {cdot {cdot {cdot {cdot {cdot {cdot {cdot {cdot {cdot {cdot {cdot {cdot { {far}}cdot {textit {near}}{z}} {textit {far}right)-{textit {far}}cdot Sright)}\cdot}cdot {fn}cdot}cdot={cdot} {cdot} {cdot} {cdot} {cdot} {cdot}}}}} {cdot}} {cdot} {cdot {cdot {cdot}}}} {cdot {cdot {f}}}}}}}}}} {cdot {cdot {cdot {cdot {f} {cdot {f} {f} {cdot {f}}}}}}}}}}}}}} {f}}}}}}}}}}}}} {cdot {cdot { Scdot {textit {far}cdot {textit {near}\\\fn}\\fn}\fnfn}\fn}\fn}\\\fn\fnfnh}cdot {fnh}cdot}cdot}cdot {cdot}cdot}\cdot}cdot}cdotcdot {cdot {cdot}}cdot}cdot {cdot {cdot}}\\cdot {cdot {cdot {cdot {cdot {cdot {cdot {cdot {\cdot}}}}}}}}}\cdot {cdot}\\\\\\cdot}}\cdot {fnMicrosoft} {fnMicrosoft Sans Serif} {fnMicrosoft} {fnMicrosoft} {f}} {fnMicrosoft} {fnMicrosoft} {fnMicrosoft}}} {cdot {fnMicrosoft} {fnMicrosoft}}}} {cdot} {f} {f}}}} {cdot {cdot {f} {f}f}f}}}f}f}f}}}f} {cdot {cdot {f} {f}}}cdot {f} {f} {cdot {cdot {f}} {f}f} {f}f}f}f}f}f}}f}f}f}f}f}f}f}f}f}f}f}} {near}}-{frac} {fnK} {fnMicrosoft}fnK}fnK}}cdot {fnh} {fn}}fnK}}} {fnK}} {fnK}}}} {fnK}}}}} {cdot {f}fnK}}}} {f}}f}}}}cdot}cdot}}}}}}}cdot}}}cdot}}}cdot}}}}}cdot}cdot}cdot}}cdot}}}}}}cdot}cdot}cdot {f} {f} {cdot {f}}f}f}f}cdot}f}f}}}}f}f}}f}f}f}cdot}}cdot}}}cdot} {fnMicroc {fn} {fnh}} {fnh}} {fnh}} {fn}} {fn}}} {fn}}}fn}} {fn} {fn}} {fn}}}} {f}}}}}}}} {fn}}}}}}}}}}}f}}}}}}}f}}}}f}f}f}}}}}}}f}}f}}}}f}}}}}}f}}}}}f}f}}}f}}}}}}}}}f}f}}}}}}}f}}}}}}f}f}}f}}}f}f} {f}f}}fn}f}f}f}}f}}}}}}f}}}}}}}}}
Esto demuestra que los valores z.{displaystyle z} se agrupan mucho más densamente cerca de cerca{displaystyle {textit {near}} plano, y mucho más escasamente lejos, lo que resulta en una mejor precisión más cerca de la cámara. Cuanto menor near{displaystyle near} es, la menor precisión que hay lejos - tener la near{displaystyle near} plano demasiado cerca es una causa común de artefactos de renderización indeseables en objetos más distantes.
Para implementar un z-buffer, los valores de z.{displaystyle z} se interpolan linealmente a través del espacio de pantalla entre los vértices del polígono actual, y estos valores intermedios se almacenan generalmente en el t-buffer z en formato de punto fijo.
Búfer W
Para implementar un w-buffer, los viejos valores de z{displaystyle z} en espacio de cámara, o w{displaystyle w}, se almacenan en el búfer, generalmente en el formato de punto flotante. Sin embargo, estos valores no pueden ser interpolados linealmente a través del espacio de pantalla desde los vértices, por lo general tienen que ser invertidos, interpolados y luego invertidos de nuevo. Los valores resultantes de w{displaystyle w}, en lugar de z.{displaystyle z}, son espacio uniformemente entre cerca{displaystyle {textit {near}} y lejos{displaystyle {textit {far}}. Hay implementaciones del w-buffer que evitan las inversiones por completo.
El hecho de que un búfer z o un búfer w produzca una mejor imagen depende de la aplicación.
Algoritmos
El siguiente pseudocódigo demuestra el proceso de z-buffering:
// En primer lugar, inicializar la profundidad de cada pixel. d(i, j) = infinite // Longitud máxima // Iniciar el valor de color para cada pixel al color de fondo c(i, j) = color de fondo // Para cada polígono, haga los siguientes pasos: para (cada pixel en proyección de polígono) {} // Encontrar profundidad i.e, z de polígono // en (x, y) correspondiente a pixel (i, j) si {} d(i, j) = z; c(i, j) = color; } }
Contenido relacionado
Unidad de control
Red de desarrolladores de Microsoft
Wikipedia: espacio de nombres