[Xamarin.Forms] Aplicaciones con contenido 3D utilizando Wave Engine

Introducción

A la hora de desarrollar aplicaciones móviles, nos encontramos con una enorme variedad de requisitos a nivel visual y de contenido. En Xamarin.Forms gracias al avance en novedades (pestañas en la parte inferior, bordes redondeados, etc.) junto a SkiaSharp, estilos, efectos y Custom Renderers otorgan grandes opciones para desarrollar aplicaciones visualmente atractivas.

En determinadas ocasiones, la visualización e interacción con elementos 3D o cámaras en 360 grados por ejemplo, otorga una mejor experiencia en nuestras aplicaciones. Por ejemplo, la visualización de edificios y diferentes plantas o la previsulización de un coche que deseamos comprar. Para conseguir la visualización e integración con elementos 3D tenemos diferentes opciones como Urho o Wave Engine.

En este artículo, vamos a ver como integrar elementos 3D en una aplicación Xamarin.Forms utilizando Wave Engine.

Wave Engine

Wave Engine es un motor de videojuegos 2D y 3D multiplataforma, basado en componentes y totalmente gratuito (no hay licencias ni tampoco ningún tipo de royalty). Nos ofrece una API para trabajar con físicas, animaciones, sonido, etc. utilizando C# sin tener que profundizar a más bajo nivel y tener que trabajar con DirectX directamente.

Podemos desarrollar para Android, iOS, Linux, macOS, Windows, etc..

Creando la escena 3D

Vamos a realizar un ejemplo sencillo pero suficientemente interesante para conocer:

  • La creación de una escena 3D.
  • Integrar una escena 3D en Xamarin.Forms.
  • Interactuar desde una vista XAML de Xamarin.Forms con la escena 3D.

Crearemos una escena con un coche y podremos modificar el color del mismo desde un ListView de Xamarin.Forms.

¿Y de dónde obtenemos el modelo 3D?

Para este ejemplo, vamos a utilizar un modelo 3D totalmente gratuito de Sketchfab gracias a Karol Miklas.

Sketchfab

Tras descargar el modelo 3D, arrancamos el editor de Wave Engine.

Editor Wave Engine

NOTA: Puedes descargar Wave Engine desde este enlace.

Creamos nuevo proyecto, y arrastramos el modelo descargado a la carpeta Assets en el apartado Assets Details. Podemos hacer doble clic en el archivo fbx para asegurar que todo es correcto.

Cargar el modelo

Comenzamos a montar nuestra escena arrastrando el modelo que acabamos de previsualizar desde Assets Details a la Scene:

Creando la escena

Llegados a este punto, tenemos suficiente. Podemos mejorar la escena con pequeños cambios como:

  • Añadir entidad plano 3D para ele suelo.
  • Añadir una esfera en forma de cúpula, para añadir «límites» al escenario.
  • Añadir más luces a la añadida por defecto.
  • Etc.

Integrando la escena con proyecto Xamarin.Forms

De momento, tenemos un proyecto Windows (proyecto creado por defecto) con nuestra escena. Podemos lanzar y probar nuestro proyecto.

Ejemplo en Windows

Pero…¿y cómo llegamos a integrarlo todo en Xamarin.Forms?. Wave Engine es un motor multiplataforma. Se pueden crear proyectos para plataformas como Android, iOS, UWP, Linux o macOS. Entre las diferentes opciones, para Android, iOS y UWP hay proyectos con integración con Xamarin.Forms.

Desde el editor de Wave Engine, Edit > Project Properties…

Nuevo perfil

Podemos elegir entre diferentes plataformas, y en cada plataforma diferentes Launchers. En Android, iOS y UWP contamos con Launcher Xamarin.Forms.

Xamarin.Forms

Esto nos crea automáticamente un nuevo proyecto utilizando Xamarin.Forms.

Estructura del proyecto

Tenemos una proyecto Shared con toda la lógica compartida de Wave Engine (escenas, behaviors, componentes, etc.) y otro proyecto de igual tipo donde tenemos la aplicación Xamarin.Forms con las vistas, etc.

Al final, trabajamos con una aplicación Xamarin.Forms habitual donde la carga de la escena 3D se realiza vía Custom Renderer. Contamos con el siguiente control:

public class WaveEngineSurface : View, IViewController
{
     public static readonly BindableProperty GameProperty = BindableProperty.Create(
     propertyName: "Game",
     returnType: typeof(IGame),
     declaringType: typeof(WaveEngineSurface),
     defaultValue: null);

     public IGame Game
     {
          get { return (IGame)GetValue(GameProperty); }
          set { SetValue(GameProperty, value); }
     }
}

Desde una vista XAML:

<AbsoluteLayout>
     <controls:WaveEngineSurface x:Name="WaveEngineSurface"
          AbsoluteLayout.LayoutFlags="All"
          AbsoluteLayout.LayoutBounds="0, 0, 1, 1" />
</AbsoluteLayout>

Interacción con la escena 3D

En este ejemplo, vamos a utilizar SlideOverKit para añadir un menu lateral deslizante, donde mostrar un listado de colores. La idea es permitir cambiar el color de coche en 3D. Pero para conseguirlo, necesitaremos interaccionar con la escena 3D desde nuestra aplicación Xamarin.Forms, ¿cómo lo hacemos?.

Al seleccionar cualquir color, lanzamos un comando en la ViewModel:

public ICommand ColorTappedCommand => new Command<CustomColor>(ChooseColor);

private void ChooseColor(CustomColor color)
{
     // TODO:
}

Al crear el proyecto Xamarin.Forms desde el editor visual tenemos una clase llamada WaveEngineFacade. Desde esta clase tenemos la opción de acceder a la escena. Creamos un método llamado UpdateColor. En el método debemos acceder a la entidad del coche, en concreto a su material, y modificar el color.

¿Cómo sabemos cual es esa entidad?.

Desde el editor, vemos el desglose de entidades (piezas) que componen al coche. Seleccionamos la carrocería y elegimos la opción Copy EntityPath:

Copy EntityPath

public static void UpdateColor(CustomColor color)
{
     var entity = _scene.EntityManager.Find("car.Plane_036.Plane_041");
     var materialComponent = entity.FindComponent<MaterialComponent>();
     var hex = color.Hex;
     ((StandardMaterial)materialComponent.Material).DiffuseColor = FromHex(hex);
}

NOTA: En la variable _scene tenemos acceso a cualquier elemento de la escena (cámara, luces, entidades, etc.). Utilizamos un método Initialize lanzado en el arranque de la aplicación para establecer el valor de la variable.

Desde el comando sencillamente lanzamos nuestro método:

WaveEngineFacade.UpdateColor(color);

El resultado final:

El resultado

Puedes encontrar el ejemplo realizado en GitHub:

Ver GitHub

Más información

Un pensamiento en “[Xamarin.Forms] Aplicaciones con contenido 3D utilizando Wave Engine

Deja un comentario