7 days of WordPress themes, graphics & videos - for free!* Unlimited asset downloads! Start 7-Day Free Trial
Advertisement
  1. Game Development
  2. Aesthetics

Corrección gamma y por qué es importante

Scroll to top
Read Time: 17 mins

Spanish (Español) translation by steven (you can also view the original English article)

Si eres un desarrollador de juegos, probablemente hayas oído hablar de los términos gamma y corrección de gamma. Puede que sepas o no lo que significan, pero no deben descartarse a la ligera.

Los desarrolladores de juegos tienden a ignorar la gamma porque sus efectos son lo suficientemente sutiles como para corregirse aproximadamente ajustando las intensidades de la luz, las intensidades especulares y similares, pero para lograr una calidad de imagen real con una iluminación de apariencia realista, es importante comprender el valor de gamma y los pasos necesarios. Trabajar en torno a su presencia en la imagen digital, a fin de recibir la mejor calidad posible. Aplicar la corrección de gamma adecuada es una de las formas más sencillas de mejorar radicalmente el aspecto de tus gráficos 3D en tiempo real.

Introducción: Cómo funcionan los monitores

Los monitores CRT que se utilizaron originalmente para pantallas de computadora tienen una propiedad curiosa: la respuesta de color en sus pantallas no es lineal con respecto a los valores sin procesar que se transmiten desde la tarjeta gráfica.

No lineal, en este sentido, significa que los aumentos en uno de tus componentes de color en una proporción constante (por ejemplo, si un componente rojo de un color se vuelve dos veces más alto) no dará como resultado un aumento de la intensidad de la luz emitida por el monitor por esa misma proporción (es decir, la luz roja emitida por la pantalla no será el doble de alta).

La respuesta de color de un monitor CRT es en realidad una función exponencial. (Como en toda la física, esto es mucho más complejo de lo que estamos describiendo, pero en aras de la simplicidad, nos ceñiremos a esta suposición). Es decir, la función EmittedLight (C), donde C es un valor de componente de color (rojo , verde o azul) que van de 0 (sin luz) a 1 (intensidad de luz completa), C se eleva a cierta potencia γ.

Este número, γ, se llama exponente gamma o simplemente gamma. Los valores típicos de gamma oscilan entre 2.0 y 2.4, y cuando se trata de gamma en el sentido general, se acuerda que el valor es 2.2 como un compromiso, y muchos de los monitores más nuevos están diseñados para tener el valor gamma de exactamente 2.2.

En un escenario común de gamma = 2.2, así es como el monitor realmente muestra las intensidades de color de tu juego (curva verde). La línea roja punteada muestra cómo un monitor lineal mostraría las mismas intensidades.

En la práctica, esto significa que el blanco y negro se mostrará sin distorsiones en la pantalla (porque cero elevado a cualquier potencia es cero, y uno elevado a cualquier potencia es uno), pero todos los valores intermedios estarán sesgados sin una forma confiable de percibir esto sucede con solo mirar.

Por ejemplo, si está mostrando un color que supuestamente es dos veces más oscuro que el negro, es decir, RGB(0.5, 0.5, 0.5), en realidad se mostrará como menos de cuatro veces más oscuro, dado el valor de gamma común de 2.2, ya que 0.5 elevado a 2.2 es alrededor de 0.22. Claramente, esto no es lo que pretendes, y este no es el caso solo con los monitores CRT: las pantallas LCD, aunque no tienen esta propiedad sin querer, están diseñadas para ser compatibles con sus contrapartes más antiguas y, por lo tanto, mostrar sus valores de color extendidos de esta manera.

Además, como los componentes rojo, verde y azul se tratan de forma independiente, los tonos de color previstos de las imágenes se pueden alterar fácilmente ya que las intensidades de los tres componentes de color no se escalarán uniformemente. ¿Qué pasará cuando muestres el valor de color RGB (1, 0.5, 0.5)? El componente rojo permanecerá en 1, pero los demás bajarán a la mitad de sus valores, cambiando por completo el tono de tu color.

El segundo color se obtuvo del primero aplicando la escala no lineal que emplean los monitores. Observa cómo no solo el brillo del color, sino también su saturación, se vieron afectados por esta transformación.

Ahora que hemos visto qué efectos tiene esta propiedad del monitor en los datos de color que se le dan al monitor, podemos ver qué pasos hay para combatirlos.

¿Qué es la corrección gamma?

La corrección gamma es el acto de deshacer el desafortunado trabajo del monitor. La corrección de gamma de una imagen consiste esencialmente en aumentar sus intensidades de color a 1/gamma, de modo que cuando el monitor a su vez aumenta el valor a gamma, estos se cancelan y el resultado es el color que originalmente pretendíamos mostrar.

(Recuerda que A elevado a B, y luego elevado a C, es lo mismo que A elevado a B × C, y es por eso que estas operaciones se cancelarán, ya que gamma × (1/gamma) es 1.)

Dado que el usuario medio no calibra su monitor para que tenga una respuesta lineal, muchas imágenes que encuentra se corrigen para que nunca sientan la diferencia. Como convención, la mayoría de los archivos de imágenes en Internet se distribuyen en lo que se denomina espacio de color sRGB; esto significa que los valores de color originales previstos se elevan aproximadamente a la potencia de 1/2.2 antes de colocarlos en archivos (aunque las ecuaciones más complejas requieren lugar en la realidad). Esto asegura que todos los usuarios con pantallas convencionales vean los colores reales. Los escáneres, las cámaras y muchos dispositivos de imágenes digitales tienen esto en cuenta y corrigen su salida cuando se guardan en formatos de imagen convencionales.

Esta imagen muestra el mapeo de las intensidades de color enviadas al monitor por la tarjeta gráfica y las intensidades que muestra el monitor.

Echa un vistazo a la imagen de arriba. Si no tenemos en cuenta la gamma, la curva será exponencial (curva verde inferior). Si realizamos la corrección gamma, la respuesta real será lineal, como debería ser. A modo de comparación, la imagen también muestra cómo se ve el gráfico cuando realizamos la corrección gamma, pero el monitor en realidad tiene una respuesta lineal. En este caso, las intensidades se distorsionarán de manera opuesta, y podemos ver que cuando un monitor no lineal las distorsiona a su vez, esto se anula y terminamos con una línea recta.

¿Cuándo debo preocuparme?

Hasta ahora, hemos explicado la teoría detrás de estos fenómenos; claro, los monitores no son lineales y la mayoría de las imágenes se corrigen para que se vean bien en estos monitores, pero ¿cuál parece ser el problema? ¿Por qué debería yo, un aspirante a desarrollador de juegos 3D, preocuparme por la corrección de gamma y hacer algo además de saberlo?

La respuesta es simple: siempre que las imágenes se creen solo para mostrarse, el problema ni siquiera existe. Sin embargo, tan pronto como desees que un programa haga algo con estas imágenes (escalarlas, usarlas como texturas, lo que sea), debes tener cuidado de que el programa sepa que los valores no son reales y simplemente se corrigen para que se vean reales en un monitor.

En particular, esto sucede en un renderizador cuando toma mapas de textura, como superficies difusas, como entrada. Realiza operaciones sobre ellos asumiendo que sus valores de color representan con precisión las intensidades de luz; es decir, asumiendo una correspondencia lineal con los fenómenos de la vida real que representan.

Pero este es un error fundamental: si deseas sumar valores de color y están corregidos por gamma (elevados a 1/gamma), obtiene los valores incorrectos. No hace falta ser un genio de las matemáticas para darse cuenta de que A elevado a 1/gamma más B elevado a 1/gamma no es igual a (A + B) elevado a 1/gamma. El problema también ocurre cuando un renderizador genera algunos valores, como cuando genera contribuciones de luz: si suma dos contribuciones de luz pero no sabe que el resultado se elevará a gamma cuando se muestre en la pantalla, ha producido valores incorrectos.

Y aquí es precisamente donde ocurre el problema: siempre que un renderizador asume que los colores que obtiene corresponden linealmente a fenómenos de la vida real cuando no lo hacen, o asume que los colores que genera corresponderán linealmente a las intensidades de luz en la pantalla cuando no lo harán, se ha cometido un error bastante grave que puede afectar la apariencia de las imágenes que produce.

Si no corriges ninguno de los errores, no te asegures de que los colores de textura de entrada introducidos en el renderizador sean lineales, y no te asegures de que la imagen de salida del renderizador sea lineal con respecto a la pantalla, estas imágenes cancelarán cada una otros hasta cierto punto, al igual que cancelan cada uno cuando muestran archivos JPEG precorregidos en un navegador web. Sin embargo, tan pronto como incluyas algunos cálculos intermedios que asuman correspondencias lineales, tus matemáticas serán incorrectas.

(a) No corregir texturas y no corregir la imagen final, (b) no corregir texturas sino corregir la imagen final, (c) corregir texturas pero no corregir la imagen final, (d) corregir tanto las texturas como la imagen final.

Recuerda lo que dijimos antes sobre el cambio de tonos de color; ese hecho puede (a veces) ayudarte a detectar la no linealidad. Una regla general es: si, cuando aplicas ajustes lineales a los parámetros (como duplicar el brillo de las luces en la escena), la imagen resultante cambia no solo en brillo sino también en tonos de color (por ejemplo, un área que va de un tono naranja rojizo hacia amarillo), esto significa que es muy probable que se esté produciendo algún proceso intermedio no lineal.

Esto puede suceder con mapas de textura que se recuperaron de varias fuentes: Internet, una cámara digital que guarda en sRGB JPEG, un escáner o si la textura se pintó en un monitor que no se calibró explícitamente para tener una respuesta lineal o no se corrigió explícitamente después. Cualquier cálculo matemático realizado en estos mapas de textura será incorrecto y se desviará ligeramente de los valores teóricamente correctos. Esto es visible con el filtrado de texturas y los mapas MIP: dado que el filtrado asume respuestas lineales al promediar los valores de color, verás errores pronunciados: las texturas más pequeñas (distantes) aparecerán notablemente más oscuras que las más grandes (es decir, cuando estén más cerca de ti): esto se debe a que cuando están distantes, el algoritmo de filtrado promedia más muestras y su no linealidad afecta más el resultado.

La iluminación también sufrirá una gamma incorrecta: las contribuciones de luz a las superficies se suman en el mundo real y, en consecuencia, en un renderizador, pero la suma no es una operación fiel si el resultado no está sesgado linealmente. Si tienes sombreadores de fragmentos complejos que realizan una iluminación sofisticada, como la dispersión del subsuelo o HDR, los errores se vuelven cada vez más pronunciados, hasta el punto de que uno se pregunta qué está mal con la imagen, en lugar de tener una sensación incómoda de "tal vez una iluminación algo incorrecta, pero probablemente soy solo yo", lo que también puede suceder a menudo. Oscurecer las texturas o aclarar las imágenes finales con un factor constante o lineal no mata el efecto, porque también son operaciones lineales, y necesitas una no lineal para combatir la curva de respuesta exponencial inherente que ocurre en el monitor.

¿Cómo lo soluciono?

Ahora, con suerte, eres plenamente consciente de qué es gamma y lo que son las correcciones gamma, y por qué esto es tan importante cuando se hacen gráficos 3D en tiempo real. Pero, por supuesto, ¿debe haber alguna forma de solucionar estos problemas?

La respuesta es sí, y corregir la gamma es una operación bastante simple que no requiere que cambies nada más que agregar algunas líneas de código, sin contar los ajustes adicionales de parámetros, intensidad y color que deberás realizar para obtener la iluminación correcta si has estado configurando tus escenas para que se vean bien en monitores no lineales sin corregirlas.

Hay tres pasos básicos para garantizar que te mantengas lineal el mayor tiempo posible y se realice la corrección en el punto correcto:

1.Asegúrate de que los colores de tus texturas sean correctos

Normalmente, no debes alterar las imágenes de origen para que contengan colores lineales; tener colores con corrección de gamma para el monitor típico en campos de color de ocho bits te brinda la resolución adicional necesaria en áreas más oscuras donde el ojo humano es más sensible a las variaciones de intensidad. Sin embargo, puedes asegurarte de que los valores de color sean lineales antes de que lleguen a tus sombreadores.

Normalmente, en OpenGL, puedes hacer esto pasando GL_SRGB8 en lugar de GL_RGB8, y GL_SRGB8_ALPHA8 en lugar de GL_RGBA8, a glTexImage2D(), al especificar una textura. Esto asegurará que todos los valores leídos de esta textura a través de un muestreador de sombreado se corregirán desde el espacio de color sRGB a uno lineal, que es precisamente lo que necesitamos. Si estás utilizando un motor de renderizado o de juego que realiza la carga de texturas por ti, puedes tener esto en cuenta o es posible que debas especificarlo manualmente; consulta la documentación de la biblioteca o pide ayuda a alguien si no estás seguro.

Sin embargo, asegúrate de no hacer esto erróneamente con imágenes que, por definición, no representan información de color y que fueron pintadas explícitamente con esto en mente. Los ejemplos incluyen mapas normales, mapas de relieve o mapas de altura, que codifican algunos datos distintos del color en los canales de color de una textura y, por lo tanto, no es probable que necesiten este tipo de precorrección.

De la demostración incluida en este artículo (algunos parámetros intercambiados con sus valores reales para mayor claridad):

Esto cargará la textura en un espacio de color sin corregir. Sin embargo, si los datos en el archivo de textura están en el espacio de color sRGB, deberíamos cambiar el tercer parámetro a GL_SRGB8, dando como resultado:

Esto asegurará que OpenGL corrija los datos de textura cuando los busquemos.

2.Asegúrate de que los colores de la imagen de salida sean correctos

Ahora debes aplicar la corrección de color a las imágenes de salida finales de tu renderizador. Asegúrate de no aplicar la corrección a nada que no sea el búfer de fotogramas final que se mostrará en la pantalla. (No toques los búferes intermedios que se ingresan a otros sombreadores de posprocesamiento, ya que aún esperarán funcionar con valores lineales).

Esto se puede hacer en OpenGL especificando el renderbuffer (el framebuffer final, no muestreable) para tener una codificación de color sRGB pasando GL_SRGB en lugar de GL_RGB como parámetro a glRenderbufferStorage(). Después de eso, debes activar la bandera GL_FRAMEBUFFER_SRGB llamando a glEnable. De esta manera, las escrituras de sombreado en búferes sRGB se corregirán para que se muestren directamente en un monitor típico.

Si estás utilizando un motor o un framework, probablemente incluyas algún tipo de opción para crear un búfer de framework sRGB para ti y configurarlo correctamente. Nuevamente, puedes consultar la documentación de la biblioteca o pedirle a alguien que te aclare esto.

En la demostración, usamos la biblioteca GLFW, que nos ofrece una forma sencilla de solicitar un framebuffer sRGB. En particular, establecemos una sugerencia de ventana y luego, más tarde, le decimos a OpenGL que habilite las operaciones de framebuffer para que estén en el espacio sRGB:

3. Corrige tus intensidades de luz y parámetros de color modificados

Si este no es el comienzo de un nuevo proyecto, es probable que la iluminación y el filtrado incorrectos en gamma hayan pasado factura. Tal vez hayas ajustado tus colores de reflectancia difusa, intensidades de luz y otras cosas en un intento de compensar las sutiles molestias que te ha traído el descuido de la gamma.

Debes revisar estos valores una vez más y modificarlos para que se vean bien nuevamente; sin embargo, esta vez, tus escenas se verán más naturales debido a la iluminación que representa con mayor precisión las circunstancias del mundo real. Las esquinas no se verán demasiado oscuras, por lo que no necesitarás agregar más intensidad a las luces (arruinando así la iluminación de los objetos más brillantes que luego se verán artificialmente brillantes para esa cantidad de luz en la escena).

Esto dará sus frutos: volver a visitar tus parámetros para crear un ambiente natural con corrección de gamma contribuirá en gran medida a brindar a tus usuarios una experiencia y una distribución del brillo que se vean bien a sus ojos, tan acostumbrados y sensibles a cómo funciona la luz en la vida real.

Demo

Con este artículo se incluye una pequeña demostración de OpenGL 3.3 que muestra una escena simple con algunas texturas iluminadas por dos fuentes de luz en movimiento. Te permite alternar entre varios escenarios: no corrigiendo texturas sino corrigiendo la imagen final; corrigiendo texturas pero descuidando corregir la imagen final; corregir ambos (es decir, hacer todo bien); y no corregir ninguno de los dos (cometiendo efectivamente un doble error).

La demostración está escrita en C++ (con dos sombreadores GLSL) y utiliza bibliotecas portátiles GLFW y GLEW, por lo que debería ejecutarse en una amplia variedad de plataformas. El código fuente está lleno de comentarios para que puedas explorar todos los aspectos de esta breve aplicación.

La demo en acción.

Usa la tecla 1 en tu teclado para alternar entre corregir texturas y no corregir texturas, y la tecla 2 para alternar entre corregir el framebuffer y no corregir el framebuffer. Para alternar ambos al mismo tiempo, presiona 3 — útil para ver la diferencia entre descuidar la gamma por completo (dos errores que se cancelan entre sí en su mayor parte) y hacer todo bien. Cuando comienza la demostración, no se está realizando ninguna de estas correcciones, así que presiona 3 para ver los beneficios de la corrección de gamma adecuada.

He incluido un proyecto de Microsoft Visual C++ 2013, versiones compatibles de 64 bits de las bibliotecas GLFW y GLEW y un ejecutable de Windows de 64 bits. Sin embargo, puedes compilar esto con bastante facilidad en cualquier plataforma con soporte GLFW y GLEW: simplemente compila main.cpp y loader.cpp juntos y vincúlalos con esas dos bibliotecas. En Linux, instalar estas bibliotecas a través de tu administrador de paquetes y pasar -lglew -lglfw a g++ debería ser suficiente. (Ten en cuenta que esto no se probó en sistemas operativos que no sean Windows, pero se supone que funciona; si encuentras algún problema, hazme saber en los comentarios y lo solucionaré lo antes posible).

Como puedes ver al ejecutar la demostración, los efectos son bastante notables incluso con un modelo simple y una escena simple como esta. Por supuesto, en este caso simple, tal vez podrías salirte con la tuya ajustando los parámetros del sombreador para que la imagen se vea bien cuando no se corrija. Sin embargo, tan pronto como empieces a acumular complejidad en tus escenas, la diferencia simplemente será demasiado visible para compensarla de esta manera.

Conclusión

En este artículo hemos cubierto términos como gamma, corrección de gamma, entradas y salidas no lineales y matemáticas no lineales. Con suerte, he logrado convencerte de que deberías comenzar a preocuparte por la corrección de gamma ahora mismo si lo has descuidado hasta ahora, y si has tenido cuidado con gamma antes de encontrar este artículo, solo espero que te haya dado alguna nueva pequeña información para abordar el problema.

Lo más importante es que hemos aprendido a solucionar los problemas que surgen cuando se manipula incorrectamente los valores de color, asumiendo que son lineales, y hemos revisado los errores y síntomas comunes que ocurren cuando se descuida este importante aspecto de los gráficos por computadora.

Espero que te hayas divertido y hayas aprendido algo nuevo mientras leíste este artículo. ¡Hasta la próxima vez!

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Game Development tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.