Fotos 3D de Facebook en el interior: sombreadores de paralaje

imagen

En los últimos meses, Facebook ha inundado las fotos en 3D . Si no ha podido verlos, le explicaré: las fotos en 3D son imágenes dentro de la publicación que cambian suavemente el ángulo al desplazarse por la página o al mover el mouse sobre ellas.

Unos meses antes de que apareciera esta característica, Facebook probó una característica similar con los modelos 3D. Aunque puede comprender fácilmente cómo Facebook puede renderizar modelos en 3D y rotarlos de acuerdo con la posición del mouse, con las fotos en 3D la situación puede no ser tan intuitiva.

La técnica que usa Facebook para crear tridimensionalidad de imágenes bidimensionales a veces se denomina desplazamiento del mapa de elevación . Utiliza un fenómeno óptico llamado paralaje .

Ejemplo de una foto 3D de Facebook (GIF)

¿Qué es paralaje?


Si jugaste a Super Mario, entonces sabes exactamente qué es el paralaje. Aunque Mario corre a la misma velocidad, parece que los objetos distantes en el fondo se mueven más lentamente (ver más abajo).


Este efecto crea la ilusión de que algunos elementos, como montañas y nubes, se encuentran más lejos. Es efectivo porque nuestro cerebro usa paralaje (junto con otras señales visuales) para estimar la distancia a objetos distantes.

¿Cómo evalúa el cerebro la distancia?
Se supone que el cerebro humano usa varios mecanismos para estimar la distancia. A distancias cortas y medias, las distancias se calculan comparando las diferencias en la posición del objeto visible con el ojo derecho e izquierdo. Esto se llama visión estereoscópica y es de naturaleza generalizada.

Sin embargo, para objetos suficientemente distantes, una visión estereoscópica no es suficiente. Las montañas, las nubes y las estrellas difieren demasiado poco para que diferentes ojos noten una diferencia significativa. Por lo tanto, el paralaje relativo entra en juego. Los objetos en el fondo se mueven menos que los objetos en primer plano. Es su movimiento relativo lo que le permite establecer la distancia relativa.

En la percepción de la distancia, se utilizan muchos otros mecanismos. El más famoso de ellos es la bruma atmosférica, que le da a los objetos distantes un tinte azul. En otros mundos, la mayoría de estas pistas atmosféricas no existen, por lo que es muy difícil evaluar la escala de los objetos en otros planetas y en la luna. El usuario de YouTube Alex McCulgan explica esto en su canal Astrum , mostrando lo difícil que es determinar el tamaño de los objetos lunares que se muestran en el video.


Paralaje como un cambio


Si está familiarizado con el álgebra lineal, entonces probablemente sepa lo complicadas y no triviales que pueden ser las matemáticas de las rotaciones 3D. Por lo tanto, hay una forma mucho más simple de entender el paralaje, que no requiere nada más que cambios.

Imaginemos que estamos mirando un cubo (ver más abajo). Si estamos alineados con precisión con su centro, las caras frontal y posterior se verán como dos cuadrados de diferentes tamaños para nuestros ojos. Esta es la perspectiva .


Sin embargo, ¿qué sucede si bajamos la cámara o levantamos el cubo? Aplicando los mismos principios, podemos ver que las caras frontal y posterior han cambiado con respecto a su posición anterior. Aún más interesante es que se han movido entre sí. La cara posterior, que está más lejos de nosotros, como si se moviera menos.


Si queremos calcular las posiciones verdaderas de estos vértices del cubo en nuestro alcance proyectado, entonces tendremos que asumir seriamente la trigonometría. Sin embargo, esto no es realmente necesario. Si el movimiento de la cámara es lo suficientemente pequeño, entonces podemos aproximar el desplazamiento de los vértices, moviéndolos en proporción a su distancia.

Lo único que necesitamos determinar es la escala. Si movemos X metros hacia la derecha, entonces debería parecer que el objeto Y metros de distancia se ha movido Z metros. Si X sigue siendo pequeño, el paralaje se convierte en tarea de interpolación lineal en lugar de trigonometría. En esencia, esto significa que podemos simular pequeñas rotaciones 3D cambiando los píxeles dependiendo de su distancia de la cámara.

Generar mapas de profundidad


En principio, lo que hace Facebook no es muy diferente de lo que está sucediendo en Super Mario. Para una imagen determinada, ciertos píxeles se desplazan en la dirección del movimiento en función de la distancia a la cámara. Para crear una foto 3D de Facebook, solo necesita la foto en sí y un mapa que indique qué tan lejos está cada píxel de la cámara. Dicho mapa tiene el nombre esperado: "mapa de profundidad" . También se denomina mapa de altura, según el contexto.

Tomar una foto es bastante simple, pero generar el mapa de profundidad correcto es una tarea mucho más difícil. Los dispositivos modernos usan varias técnicas. La mayoría de las veces usa dos cámaras; cada uno toma una foto del mismo sujeto, pero con una perspectiva ligeramente diferente. El mismo principio se usa en la visión estereoscópica , que las personas usan para evaluar la profundidad a distancias cortas y medias. La imagen a continuación muestra cómo el iPhone 7 puede crear mapas de profundidad a partir de dos imágenes muy cercanas.


Los detalles de la implementación de dicha reconstrucción se describen en el artículo Instant 3D Photography , presentado por Peter Hedman y Johannes Kopf en SIGGRAPH2018.

Después de crear un mapa de profundidad de alta calidad, simular la tridimensionalidad se convierte en una tarea casi trivial. La verdadera limitación de esta técnica es que, incluso si puede recrear un modelo 3D aproximado, carece de información sobre cómo renderizar partes que son invisibles en la foto original. Por el momento, este problema no se puede resolver y, por lo tanto, todos los movimientos visibles en las fotografías en 3D son bastante insignificantes.

Nos familiarizamos con el concepto de fotografías en 3D y hablamos brevemente sobre cómo los teléfonos inteligentes modernos pueden crearlas. En la segunda parte, aprenderemos cómo se pueden usar las mismas técnicas para implementar fotos 3D en Unity usando sombreadores.


Parte 2. Sombreadores de paralaje y mapas de profundidad


Plantilla de sombreador


Si queremos recrear fotos 3D de Facebook usando un sombreador, primero debemos decidir qué haremos exactamente. Dado que este efecto funciona mejor con imágenes 2D, sería lógico implementar una solución compatible con los sprites de Unity. Crearemos un sombreador que se pueda usar con Sprite Renderer .

Aunque dicho sombreador se puede crear desde cero, a menudo es preferible comenzar con una plantilla preparada. Es mejor comenzar a avanzar copiando el sombreador difuso de sprites existente, que Unity usa de manera predeterminada para todos los sprites. Desafortunadamente, el motor no viene con un archivo de sombreador que puede editar usted mismo.

Para obtenerlo, debe ir al archivo de descarga de Unity y descargar el paquete de sombreadores integrados (consulte a continuación) para obtener la versión del motor que está utilizando.


Después de extraer el paquete, puede ver el código fuente de todos los sombreadores que vienen con Unity. Estamos interesados ​​en el archivo Sprites-Diffuse.shader , que se usa por defecto para todos los sprites creados.

Imágenes


El segundo aspecto que debe formalizarse son los datos que tenemos. Imagine que tenemos tanto la imagen que queremos animar como su mapa de profundidad. La última será una imagen en blanco y negro, en la que los píxeles en blanco y negro indican qué tan lejos o cerca están de la cámara.

Las imágenes utilizadas en este tutorial están tomadas del proyecto Pickle cat de Dennis Hotson , y este es sin duda lo mejor que verá hoy.


El mapa de altitud asociado con esta imagen refleja la distancia del hocico del gato desde la cámara.


Es fácil ver cómo se pueden lograr buenos resultados con un mapa de profundidad tan simple. Esto significa que es fácil crear sus propios mapas de profundidad para imágenes existentes.

Las propiedades


Ahora que tenemos todos los recursos, podemos comenzar a escribir el código del sombreador de paralaje. Si importamos la imagen principal como un sprite, Unity la pasará automáticamente al sombreador a través de la propiedad _MainTex . Sin embargo, debemos hacer que el mapa de profundidad esté disponible para el sombreador. Esto se puede implementar usando una nueva propiedad de sombreador llamada _HeightTex . Intencionalmente decidí no llamarlo _DepthTex para no confundirlo con la textura de profundidad (este es un concepto de Unidad similar utilizado para representar el mapa de profundidad de la escena).

Para cambiar la intensidad del efecto, también agregaremos la propiedad _Scale .

 Properties { ... _HeightTex ("Heightmap (R)", 2D) = "gray" {} _Scale ("Scale", Vector) = (0,0,0,0) } 

Estas dos nuevas propiedades también deben corresponder a dos variables con el mismo nombre que deben agregarse a la ENDCG CGPROGRAM / ENDCG :

 sampler2D _HeightTex; fixed2 _Scale; 

Ahora todo está listo, y podemos comenzar a escribir el código que realizará el desplazamiento.

El primer paso es muestrear el valor del mapa de profundidad, que se puede hacer usando la función tex2D . Dado que _HeightTex es una textura en blanco y negro, podemos tomar su canal rojo y descartar el resto. El valor resultante mide la distancia en algunas unidades arbitrarias desde el píxel actual a la cámara.

El valor de profundidad está entre antes pero lo extenderemos al intervalo de antes . Esto le permite proporcionar paralaje positivo (color blanco) y negativo (color negro).

Teoría


Para simular el efecto de paralaje en esta etapa, necesitamos usar la información de profundidad para cambiar los píxeles de la imagen. Cuanto más se acerca el píxel, más fuerte necesita ser desplazado. Este proceso se explica en el siguiente diagrama. El píxel rojo de la imagen original, de acuerdo con la información del mapa de profundidad, debe desplazarse dos píxeles hacia la izquierda. Del mismo modo, el píxel azul debería desplazar dos píxeles hacia la derecha.


Aunque en teoría esto debería funcionar, no hay formas fáciles de implementar esto en el sombreador. La cuestión es que un sombreador por su principio solo puede cambiar el color del píxel actual . Al ejecutar el código del sombreador, debe dibujar un píxel específico en la pantalla; no podemos simplemente mover este píxel a otro lugar o cambiar el color del vecino. Esta restricción de localidad proporciona una operación paralela muy eficiente de sombreadores, pero no nos permite implementar todo tipo de efectos que serían triviales siempre que haya acceso aleatorio para grabar en cada píxel de la imagen.

Si queremos ser precisos, entonces necesitamos muestrear el mapa de profundidad de todos los píxeles vecinos para averiguar cuál debería (si debería) moverse a la posición actual. Si varios píxeles deben estar en el mismo lugar, entonces podemos promediar su influencia. Aunque tal sistema funciona y proporciona el mejor resultado posible, es extremadamente ineficiente y potencialmente cientos de veces más lento que el sombreador difuso original con el que comenzamos.

La mejor alternativa sería la siguiente solución: obtenemos la profundidad del píxel actual del mapa de profundidad; luego, si necesitamos desplazarlo hacia la derecha , reemplace el color actual con el píxel a la izquierda (vea la imagen a continuación). Aquí asumimos que si desea mover el píxel a la derecha, entonces los píxeles vecinos a la izquierda también deberían moverse de la misma manera.


Es fácil ver que esto es solo una aproximación de bajo costo de lo que realmente queríamos lograr. Sin embargo, es muy efectivo porque los mapas de profundidad generalmente resultan ser suaves.

Código


Siguiendo el algoritmo descrito en la sección anterior, podemos implementar el sombreador de paralaje con un desplazamiento simple de las coordenadas UV .

Esto lleva al siguiente código:

 void surf (Input IN, inout SurfaceOutput o) { // Displacement fixed height = tex2D(_HeightTex, IN.uv_MainTex).r; fixed2 displacement = _Scale * ((height - 0.5) * 2); fixed4 c = SampleSpriteTexture (IN.uv_MainTex - displacement) * IN.color; ... } 

Esta técnica funciona bien con objetos casi planos, como se ve en la animación a continuación.


Pero realmente funciona muy bien con modelos 3D, porque es muy fácil renderizar la textura de profundidad para una escena 3D. A continuación se muestra una imagen renderizada en 3D y su mapa de profundidad.


Los resultados finales se muestran aquí:

Source: https://habr.com/ru/post/444706/


All Articles