Tengo un código para cargar archivos de imagen DDS en texturas OpenGL, y me gustaría extenderlo para admitir los formatos comprimidos BC6 y BC7 introducidos en D3D11. Dado que DirectX y OpenGL no están de acuerdo sobre si el origen de una textura está en la esquina superior izquierda o inferior izquierda, mi cargador DDS voltea los píxeles de cada imagen a lo largo del eje Y antes de pasar los píxeles a OpenGL.
Voltear las texturas comprimidas presenta una arruga adicional: además de voltear cada fila de bloques de 4x4 píxeles, también debe voltear los píxeles dentro de cada bloque. Encontré el código aquí para voltear los bloques BC1 / BC2 / BC3, y desde los diagramas de bloques en MSDN fue fácil adaptar el código de volteo BC3 para manejar BC4 y BC5. Los FC6 y BC7 formatos ven significativamente más intimidante, sin embargo. ¿Existe un truco similar de giro de bits para voltear estos formatos, o tendría que descomprimir y recomprimir completamente cada bloque?
ACTUALIZACIÓN: Resulta que el cambio de textura solo era necesario porque mis coordenadas de textura se invertían incorrectamente en el momento de la exportación. La eliminación de ambos flips hizo que el código fuera más simple y rápido (¡gracias Humus!). Voltear bloques BC6 / BC7 aún puede ser un desafío interesante, pero ya no es relevante para mi escenario original.
Respuestas:
Sospecho que es posible voltear bloques BC6-7 con mucho menos trabajo que una descompresión completa y volver a comprimir, pero todavía no es un picnic y es mucho más complejo que voltear bloques BC1-5.
En primer lugar, BC6-7 tiene una variedad de modos que se pueden seleccionar por bloque. Los modos tienen diseños binarios completamente diferentes, por lo que tendrías que escribir una rutina de volteo diferente para cada modo (hay ~ 20 en total, IIRC).
Otra dificultad son los modos particionados, donde los píxeles del bloque se dividen en 2 o 3 subconjuntos, cada uno con su propio segmento de línea RGB. La partición debe elegirse de un conjunto predefinido; los de BC6 se pueden ver aquí . El problema es que este conjunto de particiones no es simétrico bajo volteos verticales. Sin embargo, sospecho que es simétrico bajo alguna combinación de volteos verticales e intercambiando los dos subconjuntos. Por ejemplo, mirando la partición # 22 (6ta fila, 3ra columna) en ese enlace, no hay una versión volteada verticalmente en la tabla, pero si voltea verticalmente yintercambia 0s y 1s, terminas con la partición # 9 (3ra fila, 2da columna). No he verificado que todas las particiones se puedan voltear de esta manera, ni he verificado las de BC7 (que también incluye particiones con 3 subconjuntos).
Incluso si eso funciona, todavía no estás libre en casa. En BC1-5, el orden de los dos puntos finales del segmento de línea RGB se utilizó para cambiar de modo, pero en BC6-7 se elige el orden de los puntos finales para fijar un bit de los índices por píxel en cada subconjunto de particiones. Por lo tanto, si cambia la partición, es posible que también deba cambiar el orden de los puntos finales.
Y por último, pero no menos importante, en BC6-7 los puntos finales a menudo están comprimidos en delta (es decir, un punto final se almacena con total precisión y los otros se almacenan como deltas de menor precisión). El intercambio de subconjuntos de partición y orden de punto final cambiará qué punto final es el de alta precisión, por lo que tendrá que barajar los bits de baja precisión y negar algunos deltas.
En general, no parece que haya un showtopper fundamental (aunque en realidad no he escrito el código), pero seguramente sería mucho trabajo voltear o rotar estos formatos. Si es posible, recomendaría voltear las imágenes en su canalización de arte antes de que se compriman.
(Por cierto, la especificación más completa de BC6-7 que he encontrado es la especificación ARB_texture_compression_bptc ; también escribí una publicación de blog sobre los formatos BCn hace un tiempo).
fuente
El volteo es solo una cuestión de forma predeterminada en los dos formatos. Puedes ir en contra de lo predeterminado.
Probablemente sea mejor hacerlo en el lado de OpenGL, porque OpenGL tiene un nivel más bajo y, por lo tanto, es menos probable que pierda la optimización al hacer cosas como esta.
fuente