Un plugin de navegador para Unity

Las herramientas y el motor de desarrollo de Unity son, de lejos, la forma más común de crear aplicaciones para RV y RA hoy en día. Anteriormente, hemos hecho posible exportar experiencias basadas en la web desde Unity. Hoy, estamos encantados de mostrar algunos de los primeros trabajos que abordan la otra forma en que los desarrolladores de Unity quieren utilizar la web: como un componente en sus entornos virtuales basados en Unity.

A partir de nuestro trabajo portando un motor de navegador a muchas plataformas y escenarios de incrustación, incluyendo como Firefox Reality AR para HoloLens 2, hemos construido un nuevo componente de Unity basado en Servo, un moderno motor web escrito en el lenguaje Rust.

El motor Unity tiene un sistema de plugins multiplataforma muy adaptable con un saludable ecosistema de plugins de terceros, tanto de código abierto como propietarios. El sistema de plugins nos permite ejecutar módulos nativos del sistema operativo y conectarlos directamente a componentes que se ejecutan en el entorno de scripting de Unity.

Los objetivos de los experimentos eran construir un plugin nativo de Unity y un conjunto de componentes de script de Unity C# que permitieran a terceros incorporar las ventanas del navegador Servo en las escenas de Unity y, opcionalmente, proporcionar soporte para el uso de la superficie del navegador en aplicaciones de RV y RA construidas en Unity.

Hoy, estamos lanzando un prototipo totalmente funcional del navegador web Servo que se ejecuta dentro de un plugin de Unity. Se trata de una primera fase de nuestro trabajo, pero sabemos que hay mucha expectación por este tipo de solución, así que esperamos que pruebes este prototipo, nos des tu opinión y te unas a nosotros para construir cosas con él. La versión publicada hoy está orientada a la plataforma macOS, pero muy pronto añadiremos algunas de las otras plataformas soportadas por Servo.

Cómo empezar

Hemos abierto el plugin, en https://github.com/MozillaReality/servo-unity. Dirígete a él, haz clic en la estrella y bifurca el código, compruébalo en tu máquina local y luego abre el proyecto dentro de Unity.

Las instrucciones para desarrolladores están en el archivo README del repositorio.

Qué hace

Puedes trabajar directamente con la ventana del navegador y los controles dentro del Editor de Unity. El nivel superior de configuración está en el objeto ServoUnityController. Otros objetos importantes en la escena incluyen el ServoUnityWindow, ServoUnityNavbarController, y ServoUnityMousePointer.

El ServoUnityWindow puede ser posicionado en cualquier lugar en una escena de Unity. Aquí, lo hemos dejado caer en la cueva de la seta de Mozilla (conocida por los usuarios de Firefox Reality, por la increíble artista Jasmin Habezai-Fekri), y hemos proporcionado un manipulador de cámara que nos permite movernos por la escena y ver que es una vista en 3D del contenido del navegador.

Servo tiene reproducción de medios de alta calidad a través del framework GStreamer, incluyendo soporte de audio. Aquí estamos viendo una muestra de vídeo MPEG4, que se ejecuta dentro de un reproductor Unity desplegado.

La búsqueda personalizable se incluye en el plugin. Una amplia variedad de contenido web se puede ver con la versión actual de Servo, con una mayor compatibilidad web en la que se está trabajando activamente (más adelante). El contenido WebGL también funciona.

Cómo funciona

Arquitectura

El desarrollo en Unity utiliza una arquitectura basada en componentes, donde Unity ejecuta el código del usuario adjunto a los GameObjects, organizados en escenas. Los usuarios personalizan los GameObjects adjuntando scripts que se ejecutan en un entorno C#, ya sea utilizando el tiempo de ejecución Mono o el compilador anticipado IL2CPP. El ciclo de vida de los eventos de Unity es accesible a los scripts de usuario que heredan de la clase MonoBehaviour de Unity C#. Los scripts de usuario pueden invocar código nativo en los plugins (que no son más que objetos dinámicos compartidos nativos del sistema operativo) a través del mecanismo P/Invoke del tiempo de ejecución de C#. De hecho, el núcleo de Unity está implementado en C++ y proporciona código nativo en los plugins con un segundo conjunto de interfaces accesibles en C/C++ para ayudar en algunas tareas de bajo nivel del plugin.

Servo es en sí mismo una pieza compleja de software. Por diseño, la mayor parte de su funcionalidad no orientada al usuario se compila en una biblioteca de Rust, libservo. Para esta primera fase del proyecto, hacemos uso de una interfaz simplificada compatible con C en otra biblioteca de Rust llamada libsimpleservo2. Esta biblioteca expone funciones llamables en C y ganchos de devolución de llamadas para controlar el navegador y ver su salida. Alrededor de libsimpleservo2, ponemos en su lugar abstracciones nativas de C++ que encapsulan el modelo de hilos y renderizado de Unity, y exponen un conjunto de interfaces invocables por Unity que a su vez son operadas por nuestros componentes de script de C#.

Consiguiendo el contenido del navegador en Unity

Creamos un objeto en Unity, una instancia de ServoUnityWindow, para envolver una instancia de la clase Texture2D de Unity y tratarla como un panel de contenido del navegador. Cuando se utiliza el renderizador OpenGL de Unity, la clase Texture2D está respaldada por una textura OpenGL nativa, y pasamos el «nombre» de la textura OpenGL (es decir, un ID) al plugin, que vincula la textura a un objeto framebuffer que recibe la textura final compuesta de Servo.

Como no tenemos control sobre la unión de la textura y el contexto de Unity, el diseño actual para la actualización de esta textura utiliza un blit (copia) a través de la API surfman-chains de Servo. Esencialmente, el WebRender de Servo escribe en un búfer de superficie específico del sistema operativo en un hilo, y luego este búfer de superficie se vincula de sólo lectura al hilo de renderizado de Unity y se hace una copia de la textura utilizando las API de OpenGL. En la implementación inicial de macOS, por ejemplo, el búfer de superficie es un IOSurface que puede moverse a coste cero entre hilos, lo que permite una implementación eficiente en la que el compositor del navegador puede escribir en un hilo diferente al hilo que muestra la textura en Unity.

Los metadatos de control y de la página se comunican por separado, a través de un conjunto de APIs que permiten la búsqueda y la navegación a las URLs, la actualización de los títulos de las páginas, y el conjunto habitual de botones de retroceso/adelanto/parada/inicio.

Debido a que el contenido y los controles del navegador son todos, en última instancia, objetos de Unity, la aplicación de Unity que está construyendo puede posicionar, estilizar o controlar programáticamente estos de la manera que desee.

Desafíos

Llevar el proyecto a esta etapa no ha estado exento de desafíos, algunos de los cuales todavía estamos abordando. El entorno de scripting de Unity se ejecuta en gran medida en un solo hilo, con la excepción de las operaciones de renderizado que tienen lugar en un hilo separado en una cadencia diferente. Servo, sin embargo, genera potencialmente docenas de hilos ligeros para una variedad de tareas. Hemos tenido cuidado de marshal devolver los elementos de trabajo de Servo a los hilos correctos en Unity. Hay algunas optimizaciones restantes para decidir cuándo actualizar la textura de Unity. Actualmente, sólo se actualiza cada fotograma, pero estamos añadiendo una API a la interfaz de incrustación para permitir un control más preciso.

Como incubadora de tecnología de navegación, Servo se centra en el desarrollo de nuevas tecnologías. Entre las tecnologías más destacadas que han pasado de Servo al motor Gecko de Firefox se encuentran el motor de renderizado basado en la GPU, WebRender, y el motor CSS Stylo. Dejando a un lado estos éxitos, la compatibilidad total con la web sigue siendo un área en la que Servo tiene un hueco importante, ya que nos hemos centrado principalmente en grandes mejoras para el usuario y en experiencias específicas en la larga cola de la web. Un esfuerzo reciente de la comunidad Servo ha visto grandes avances en la compatibilidad web de Servo, por lo que esperamos que el subconjunto de la web navegable por Servo siga creciendo rápidamente.

Planes de desarrollo

La compatibilidad con toda la gama de plataformas actualmente soportadas por Servo es nuestra primera prioridad de desarrollo de seguimiento, con la compatibilidad con Windows Win32 y Windows UWP a la cabeza de la lista. Muchos de ustedes han visto nuestra aplicación Firefox Reality AR para HoloLens 2, y la compatibilidad con UWP les permitirá incorporar Servo a sus propias aplicaciones AR para la plataforma HoloLens utilizando el mismo motor de navegación subyacente.

También nos gustaría dar soporte a un mayor subconjunto de la capacidad completa del navegador. Lo primero en la lista es el soporte de múltiples ventanas. Actualmente estamos trabajando en la graduación del plugin de la interfaz libsimpleservo2 a una nueva interfaz que permitirá a las aplicaciones instanciar múltiples ventanas, pestañas, e implementar características como el historial, los marcadores y más.

Esta primera versión se centra en la web navegable a través de páginas web 2D. Servo también soporta la web inmersiva a través de la API WebXR, y estamos explorando la conexión de WebXR con el soporte de hardware XR de Unity a través de la interfaz del plugin. Empezaremos con la compatibilidad con la visualización de vídeos de 360°, que sabemos por nuestra base de usuarios de Firefox Reality que es un caso de uso primordial para el navegador.

Por último…

Ya sea un reproductor multimedia, una interfaz en el juego para la web abierta, el navegador como interfaz de usuario, la incorporación de experiencias web específicas, o la miríada de otras posibilidades, no podemos esperar a ver algunas de las formas imaginativas en que los desarrolladores explotarán la potencia y el rendimiento de Servo dentro de las aplicaciones construidas en Unity.