Caso práctico: creación de una galaxia en una realidad mixtaCase study - Creating a galaxy in mixed reality

Antes de que se enviara a Microsoft HoloLens, hemos preguntado a nuestra comunidad de desarrolladores qué tipo de aplicación les gustaría ver una compilación de equipo interna con experiencia para el nuevo dispositivo.Before Microsoft HoloLens shipped, we asked our developer community what kind of app they'd like to see an experienced internal team build for the new device. Se comparten más de 5000 ideas y, después de un sondeo de Twitter de 24 horas, el ganador era una idea denominada Galaxy Explorer.More than 5000 ideas were shared, and after a 24-hour Twitter poll, the winner was an idea called Galaxy Explorer.

Andy Zibits, el director de arte del proyecto y Karim Luccin, el ingeniero de gráficos del equipo, habla sobre el esfuerzo colaborativo entre arte e ingeniería que llevó a la creación de una representación precisa e interactiva de la forma láctea de Galaxy en el explorador de Galaxy.Andy Zibits, the art lead on the project, and Karim Luccin, the team's graphics engineer, talk about the collaborative effort between art and engineering that led to the creation of an accurate, interactive representation of the Milky Way galaxy in Galaxy Explorer.

La tecnologíaThe Tech

Nuestro equipo , compuesto por dos diseñadores, tres desarrolladores, cuatro artistas, un productor y un evaluador, tenía seis semanas para compilar una aplicación totalmente funcional que permitiría a los usuarios obtener información sobre la inmensaidad y la belleza de nuestra forma de ordeño.Our team - made up of two designers, three developers, four artists, a producer, and one tester — had six weeks to build a fully functional app which would allow people to learn about and explore the vastness and beauty of our Milky Way Galaxy.

Queríamos sacar el máximo partido de la capacidad de HoloLens para representar objetos 3D directamente en tu espacio de vida, por lo que decidimos que queríamos crear una galaxia de aspecto realista en la que los usuarios podrían hacer zoom para ampliar y ver los estrellas individuales, cada uno con sus propias trayectorias.We wanted to take full advantage of the ability of HoloLens to render 3D objects directly in your living space, so we decided we wanted to create a realistic looking galaxy where people would be able to zoom in close and see individual stars, each on their own trajectories.

En la primera semana de desarrollo, surgimos con unos pocos objetivos para nuestra representación de la forma láctea de Galaxy: era necesario tener una profundidad, un movimiento y un volumétrico (lleno de estrellas) que le ayuden a crear la forma de la galaxia.In the first week of development, we came up with a few goals for our representation of the Milky Way Galaxy: It needed to have depth, movement, and feel volumetric—full of stars that would help create the shape of the galaxy.

El problema con la creación de una galaxia animada que tenía miles de millones de estrellas era que el número de elementos únicos que es necesario actualizar sería demasiado grande por fotograma para que HoloLens se animase con la CPU.The problem with creating an animated galaxy that had billions of stars was that the sheer number of single elements that need updating would be too big per frame for HoloLens to animate using the CPU. Nuestra solución ha participado en una combinación compleja de arte y ciencia.Our solution involved a complex mix of art and science.

Entre bambalinasBehind the scenes

Para que los usuarios puedan explorar estrellas individuales, el primer paso era averiguar cuántas partículas se podían representar a la vez.To allow people to explore individual stars, our first step was to figure out how many particles we could render at once.

Representar objetosRendering particles

Las CPU actuales son ideales para procesar tareas en serie y hasta algunas tareas paralelas a la vez (en función de la cantidad de núcleos que tengan), pero las GPU son mucho más eficaces en el procesamiento de miles de operaciones en paralelo.Current CPUs are great for processing serial tasks and up to a few parallel tasks at once (depending on how many cores they have), but GPUs are much more effective at processing thousands of operations in parallel. Sin embargo, dado que normalmente no comparten la misma memoria que la CPU, el intercambio de datos entre la CPU<>GPU puede convertirse rápidamente en un cuello de botella.However, because they don’t usually share the same memory as the CPU, exchanging data between CPU<>GPU can quickly become a bottleneck. Nuestra solución era crear una galaxia en la GPU y debía vivir completamente en la GPU.Our solution was to make a galaxy on the GPU, and it had to live completely on the GPU.

Iniciamos pruebas de esfuerzo con miles de objetos de punto en distintos patrones.We started stress tests with thousands of point particles in various patterns. Esto nos permitió obtener la galaxia en HoloLens para ver lo que funcionó y lo que no.This allowed us to get the galaxy on HoloLens to see what worked and what didn’t.

Crear la posición de las estrellasCreating the position of the stars

Uno de nuestros miembros del equipo ya ha escrito el código de C# que generaría estrellas en su posición inicial.One of our team members had already written the C# code that would generate stars at their initial position. Las estrellas se encuentran en una elipse y su posición puede describirse mediante (curveOffset, ellipseSize, elevation), donde curveOffset es el ángulo de la estrella a lo largo de la elipse, ellipseSize es la dimensión de la elipse a lo largo de X y Z, y eleva la elevación adecuada de la estrella dentro de la galaxia.The stars are on an ellipse and their position can be described by (curveOffset, ellipseSize, elevation) where curveOffset is the angle of the star along the ellipse, ellipseSize is the dimension of the ellipse along X and Z, and elevation the proper elevation of the star within the galaxy. Por lo tanto, podemos crear un búfer (ComputeBuffer de Unity) que se inicializaría con cada atributo de estrella y lo enviaría en la GPU donde residiría para el resto de la experiencia.Thus, we can create a buffer (Unity’s ComputeBuffer) that would be initialized with each star attribute and send it on the GPU where it would live for the rest of the experience. Para dibujar este búfer, usamos DrawProcedural de Unity , que permite ejecutar un sombreador (código en una GPU) en un conjunto arbitrario de puntos sin tener una malla real que represente la galaxia:To draw this buffer, we use Unity’s DrawProcedural which allows running a shader (code on a GPU) on an arbitrary set of points without having an actual mesh that represents the galaxy:

CPUCPU:

GraphicsDrawProcedural(MeshTopology.Points, starCount, 1);

GPUGPU:

v2g vert (uint index : SV_VertexID)
{

 // _Stars is the buffer we created that contains the initial state of the system
 StarDescriptor star = _Stars[index];
 …

}

Comenzamos con patrones circulares sin procesar con miles de partículas.We started with raw circular patterns with thousands of particles. Esto nos dio la prueba de que necesitábamos que podamos administrar muchas partículas y ejecutarla a velocidades de rendimiento, pero no estamos satisfecho con la forma general de Galaxy.This gave us the proof we needed that we could manage many particles AND run it at performant speeds, but we weren’t satisfied with the overall shape of the galaxy. Para mejorar la forma, se intentaron varios patrones y sistemas de partículas con rotación.To improve the shape, we attempted various patterns and particle systems with rotation. Estarían en primer lugar, ya que el número de partículas y el rendimiento se han mantenido coherentes, pero la forma se ha interrumpido cerca del centro y las estrellas no eran realistas.These were initially promising because the number of particles and performance stayed consistent, but the shape broke down near the center and the stars were emitting outwardly which wasn't realistic. Necesitábamos una emisión que nos permitiera manipular el tiempo y hacer que las partículas se muevan de forma realista, lo que se repite cada vez más cerca del centro de la galaxia.We needed an emission that would allow us to manipulate time and have the particles move realistically, looping ever closer to the center of the galaxy.

Se han intentado varios patrones y sistemas de partículas que se han girado, como estos.

Se han intentado varios patrones y sistemas de partículas que se han girado, como estos.We attempted various patterns and particle systems that rotated, like these.

Nuestro equipo realizó una investigación sobre la manera en que galaxiesó la función y creamos un sistema de partículas personalizado específicamente para la galaxia, de modo que podríamos trasladar las partículas a las elipses en función de "teoría de ola de densidad", que theorizes que los brazos de una galaxia son áreas de mayor densidad pero en flujo constante, como un atasco de tráfico.Our team did some research about the way galaxies function and we made a custom particle system specifically for the galaxy so that we could move the particles on ellipses based on "density wave theory," which theorizes that the arms of a galaxy are areas of higher density but in constant flux, like a traffic jam. Parece estable y sólido, pero en realidad las estrellas están pasando y salen de los brazos a medida que se mueven a lo largo de sus puntos suspensivos respectivos.It appears stable and solid, but the stars are actually moving in and out of the arms as they move along their respective ellipses. En nuestro sistema, los objetos nunca existen en la CPU, por lo que se generan las tarjetas y se orientan todas en la GPU, por lo que todo el sistema es simplemente el estado inicial + hora.In our system, the particles never exist on the CPU—we generate the cards and orient them all on the GPU, so the whole system is simply initial state + time. Progresaría de la siguiente manera:It progressed like this:

Progresión del sistema de partículas con representación de GPU

Progresión del sistema de partículas con representación de GPUProgression of particle system with GPU rendering

Una vez que se agregan las elipses suficientes y se establecen para rotar, el Galaxies comenzó a formar "armas" donde converge el movimiento de estrellas.Once enough ellipses are added and are set to rotate, the galaxies began to form “arms” where the movement of stars converge. El espaciado de las estrellas a lo largo de cada trazado elíptico se proporcionó cierta aleatoriedad y cada estrella tenía un bit de aleatoriedad posicional agregado.The spacing of the stars along each elliptical path was given some randomness, and each star got a bit of positional randomness added. Esto creó una distribución mucho más natural del movimiento de estrella y la forma de ARM.This created a much more natural looking distribution of star movement and arm shape. Por último, se ha agregado la capacidad de controlar el color en función de la distancia desde el centro.Finally, we added the ability to drive color based on distance from center.

Crear el movimiento de las estrellasCreating the motion of the stars

Para animar el movimiento de estrella general, era necesario agregar un ángulo constante para cada fotograma y hacer que las estrellas se muevan a lo largo de sus puntos suspensivos en una velocidad radial constante.To animate the general star motion, we needed to add a constant angle for each frame and to get stars moving along their ellipses at a constant radial velocity. Esta es la razón principal para usar curveOffset.This is the primary reason for using curveOffset. Esto no es técnicamente correcto, ya que las estrellas se moverán más rápido a lo largo de los extremos largos de las elipses, pero el movimiento general se considera adecuado.This isn’t technically correct as stars will move faster along the long sides of the ellipses, but the general motion felt good.

Las estrellas se mueven más rápido en el arco largo, más lentamente en los bordes.

Las estrellas se mueven más rápido en el arco largo, más lentamente en los bordes.Stars move faster on the long arc, slower on the edges.

Con eso, cada estrella se describe por completo (curveOffset, ellipseSize, elevación, Age), donde Age es una acumulación del tiempo total transcurrido desde que se cargó la escena.With that, each star is fully described by (curveOffset, ellipseSize, elevation, Age) where Age is an accumulation of the total time that has passed since the scene was loaded.

float3 ComputeStarPosition(StarDescriptor star)
{

  float curveOffset = star.curveOffset + Age;
  
  // this will be coded as a “sincos” on the hardware which will compute both sides
  float x = cos(curveOffset) * star.xRadii;
  float z = sin(curveOffset) * star.zRadii;
   
  return float3(x, star.elevation, z);
  
}

Esto nos permitió generar decenas de miles de estrellas una vez al principio de la aplicación y, a continuación, animamos un conjunto único de estrellas a lo largo de las curvas establecidas.This allowed us to generate tens of thousands of stars once at the start of the application, then we animated a singled set of stars along the established curves. Dado que todo está en la GPU, el sistema puede animar todas las estrellas en paralelo sin costo alguno en la CPU.Since everything is on the GPU, the system can animate all the stars in parallel at no cost to the CPU.

Este es su aspecto cuando se dibujan cuatros blancos.

Este es su aspecto cuando se dibujan cuatros blancos.Here’s what it looks like when drawing white quads.

Para que cada cuatro se enfrente a la cámara, usamos un sombreador de geometría para transformar cada posición en estrella en un rectángulo 2D de la pantalla que contendrá la textura en estrella.To make each quad face the camera, we used a geometry shader to transform each star position to a 2D rectangle on the screen that will contain our star texture.

Diamantes en lugar de cuádruples.

Diamantes en lugar de cuádruples.Diamonds instead of quads.

Como queríamos limitar el exceso (el número de veces que se procesará un píxel) en la medida de lo posible, giramos nuestras cuádruples para que tuvieran menos superposición.Because we wanted to limit the overdraw (number of times a pixel will be processed) as much as possible, we rotated our quads so that they would have less overlap.

Agregar nubesAdding clouds

Hay muchas maneras de obtener una sensación volumétrica con partículas: desde Ray, desde el interior de un volumen hasta el dibujo de tantas partículas como sea posible para simular una nube.There are many ways to get a volumetric feeling with particles—from ray marching inside of a volume to drawing as many particles as possible to simulate a cloud. El radio en tiempo real de marzo iba a ser demasiado caro y difícil de crear, por lo que primero hemos intentado crear un sistema impostor con un método para representar bosques en juegos, con una gran cantidad de imágenes 2D de árboles orientados a la cámara.Real-time ray marching was going to be too expensive and hard to author, so we first tried building an imposter system using a method for rendering forests in games—with a lot of 2D images of trees facing the camera. Cuando hacemos esto en un juego, podemos hacer que las texturas de los árboles se representen a partir de una cámara que gira, guardar todas esas imágenes y en tiempo de ejecución para cada tarjeta de la cartelera, seleccionar la imagen que coincida con la dirección de la vista.When we do this in a game, we can have textures of trees rendered from a camera that rotates around, save all those images, and at runtime for each billboard card, select the image that matches the view direction. Esto no funciona tan bien cuando las imágenes son hologramas.This doesn't work as well when the images are holograms. La diferencia entre el ojo izquierdo y el ojo derecho lo hace para que se necesite una resolución mucho más alta, o bien que se parezca plana, con alias o repetitivo.The difference between the left eye and the right eye make it so that we need a much higher resolution, or else it just looks flat, aliased, or repetitive.

En el segundo intento, intentamos tener tantas partículas como sea posible.On our second attempt, we tried having as many particles as possible. Los mejores objetos visuales se logran cuando se dibujan partículas y se desenfocaron antes de agregarlas a la escena.The best visuals were achieved when we additively drew particles and blurred them before adding them to the scene. Los problemas típicos de ese enfoque estaban relacionados con el número de objetos que se podían dibujar en un momento dado y el área de la pantalla que se encontraban mientras se sigue manteniendo 60fps.The typical problems with that approach were related to how many particles we could draw at a single time and how much screen area they covered while still maintaining 60fps. Desenfocar la imagen resultante para obtener esta nube suele ser una operación muy costosa.Blurring the resulting image to get this cloud feeling was usually a very costly operation.

Sin textura, este es el aspecto de las nubes con una opacidad del 2%.

Sin textura, este es el aspecto de las nubes con una opacidad del 2%.Without texture, this is what the clouds would look like with 2% opacity.

Ser aditivos y tener una gran cantidad de ellos significa que tendremos varias cuádruples en la parte superior entre sí, con un sombreado repetido del mismo píxel.Being additive and having a lot of them means that we would have several quads on top of each other, repeatedly shading the same pixel. En el centro de la galaxia, el mismo píxel tiene cientos de cuádruples unos de otros, y esto tenía un costo enorme cuando se realizaba una pantalla completa.In the center of the galaxy, the same pixel has hundreds of quads on top of each other and this had a huge cost when being done full screen.

Realizar nubes de pantalla completa e intentar desenfocarlos habría sido una mala idea, por lo que, en su lugar, decidimos dejar que el hardware hiciera el trabajo.Doing full screen clouds and trying to blur them would have been a bad idea, so instead we decided to let the hardware do the work for us.

Un bit de contexto primeroA bit of context first

Cuando se usan texturas en un juego, el tamaño de la textura rara vez coincidirá con el área en la que se desea utilizar, pero se puede usar un tipo diferente de filtrado de textura para que la tarjeta gráfica se interpole el color que se desea de los píxeles de la textura (filtrado de textura).When using textures in a game the texture size will rarely match the area we want to use it in, but we can use different kind of texture filtering to get the graphic card to interpolate the color we want from the pixels of the texture (Texture Filtering). El filtrado que nos interesa es bilineal Filtering , que calculará el valor de cualquier píxel usando los 4 vecinos más cercanos.The filtering that interests us is bilinear filtering which will compute the value of any pixel using the 4 nearest neighbors.

Original antes del filtrado

Resultado después del filtrado

Con esta propiedad, vemos que cada vez que se intenta dibujar una textura en un área dos veces como grande, se desenfoca el resultado.Using this property, we see that each time we try to draw a texture into an area twice as big, it blurs the result.

En lugar de representarla en una pantalla completa y perder esos precioso milisegundos que podríamos gastar en algo más, representamos en una versión pequeña de la pantalla.Instead of rendering to a full screen and losing those precious milliseconds we could be spending on something else, we render to a tiny version of the screen. Después, copiando esta textura y ajustándola en un factor de 2 varias veces, volveremos a la pantalla completa al desenfocar el contenido del proceso.Then, by copying this texture and stretching it by a factor of 2 several times, we get back to full screen while blurring the content in the process.

X3 vuelve a escalar a la resolución completa.

X3 vuelve a escalar a la resolución completa.x3 upscale back to full resolution.

Esto nos permitió obtener la parte de la nube con solo una fracción del costo original.This allowed us to get the cloud part with only a fraction of the original cost. En lugar de agregar nubes en la resolución completa, solo dibujamos 1/64TH de los píxeles y simplemente ajustamos la textura a la resolución completa.Instead of adding clouds on the full resolution, we only paint 1/64th of the pixels and just stretch the texture back to full resolution.

Izquierda, con una escala de 1/8 a resolución completa; y a la derecha, con una capacidad de 3 escalado con potencia de 2.

Izquierda, con una escala de 1/8 a resolución completa; y a la derecha, con una capacidad de 3 escalado con potencia de 2.Left, with an upscale from 1/8th to full resolution; and right, with 3 upscale using power of 2.

Tenga en cuenta que el intento de pasar de 1/64TH del tamaño al tamaño completo en un solo aspecto sería completamente diferente, ya que la tarjeta gráfica seguiría usando 4 píxeles en nuestra configuración para sombrear un área más grande y los artefactos comenzarán a aparecer.Note that trying to go from 1/64th of the size to the full size in one go would look completely different, as the graphic card would still use 4 pixels in our setup to shade a bigger area and artifacts start to appear.

A continuación, si agregamos estrellas de resolución completa con tarjetas más pequeñas, obtenemos el completo Galaxy:Then, if we add full resolution stars with smaller cards, we get the full galaxy:

Resultado casi final de la representación de Galaxy con estrellas de resolución completa

Una vez que se encontraba el buen seguimiento con la forma, agregamos una capa de nubes, cambiaban los puntos temporales por los que dibujamos en Photoshop y agregamos un color adicional.Once we were on the right track with the shape, we added a layer of clouds, swapped out the temporary dots with ones we painted in Photoshop, and added some additional color. El resultado era una forma láctea de Galaxy que nuestros equipos de arte e ingeniería nos sentían bien y cumplían nuestros objetivos de tener profundidad, volumen y movimiento, todo ello sin agotar la CPU.The result was a Milky Way Galaxy our art and engineering teams both felt good about and it met our goals of having depth, volume, and motion—all without taxing the CPU.

La forma láctea final de Galaxy en 3D.

La forma láctea final de Galaxy en 3D.Our final Milky Way Galaxy in 3D.

Más información para explorarMore to explore

Hemos abierto el código para la aplicación Galaxy Explorer y lo hemos puesto a disposición de los desarrolladores en GitHub .We've open-sourced the code for the Galaxy Explorer app and made it available on GitHub for developers to build on.

¿Está interesado en encontrar más información sobre el proceso de desarrollo de Galaxy Explorer?Interested in finding out more about the development process for Galaxy Explorer? Eche un vistazo a las últimas actualizaciones del proyecto en el canal de YouTube de Microsoft HoloLens.Check out all our past project updates on the Microsoft HoloLens YouTube channel.

Acerca de los autoresAbout the authors

Picture of Karim Luccin at his desk Karim Luccin es un ingeniero de software y entusiasta de los objetos visuales.Karim Luccin is a Software Engineer and fancy visuals enthusiast. Fue el ingeniero de gráficos de Galaxy Explorer.He was the Graphics Engineer for Galaxy Explorer.
Photo of art lead Andy Zibits Andy Zibits es un líder de vanguardia y un entusiasta de espacio que administraba el equipo de modelado 3D para Galaxy Explorer y fought para incluso más partículas.Andy Zibits is an Art Lead and space enthusiast who managed the 3D modeling team for Galaxy Explorer and fought for even more particles.

Consulte tambiénSee also