Utiliza el micrófono de Android en Realidad Aumentada

Como utilizar el micrófono con MindAR 

Hagamos una aplicación de Realidad Aumentada WebAR en Android que utilice comandos de voz

micrófono de Android en Realidad Aumentada
Micrófono de Android en Realidad Aumentada

¡Aumentados! En este tutorial haremos una aplicación de realidad aumentada que utiliza el micrófono de nuestros teléfonos Android para hacer llamados a modelos 3D.

El control de voz puede fusionarse en las apps para crear experiencias inmersivas y accesibles.

Vamos a crear esta WebAR usando A-Frame, MindAR.js y Web Speech API.

Es importante tener varios puntos en cuenta:

  • La app de realidad aumentada funciona en desktops (Computadores de mesa y portátiles) (El reconocimiento de voz no se detiene a menos que se presione el botón de detener reconocimiento).
  • El rendimiento en dispositivos Android es óptimo utilizando el navegador Google Chrome. (El reconocimiento de voz se detiene con cada comando reconocido -Motivos de seguridad de Android).
  • En dispositivos iOS la historia es diferente (El rendimiento es muy pobre y no funciona como debería funcionar – En el futuro hare una app que permita el correcto funcionamiento del micrófono y el Web Speech API). Te recomiendo este tutorial que te puede ayudar a entender cómo funciona Web Speech API: Tutorial gratis para crear Realidad Aumentada

Estructura Fundamental del HTML


<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MindAR Voz 3D</title>

<script src="https://aframe.io/releases/1.5.0/aframe.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/mind-ar@1.2.2/dist/mindar-image-aframe.prod.js"></script>
</head>
<body>

<a-scene
mindar-image="imageTargetSrc: ./targets.mind; autoStart: true; videoSettings: { facingMode: 'environment', width: { ideal: 3840 }, height: { ideal: 2160 } }"
color-space="sRGB"
renderer="colorManagement: true, physicallyCorrectLights: true, antialias: true, alpha: true"
vr-mode-ui="enabled: false"
device-orientation-permission-ui="enabled: false"
id="ar-scene">

<a-assets>
<a-asset-item id="customGlbModel" src="scene.glb"></a-asset-item>
</a-assets>

<a-camera position="0 0 0" look-controls="enabled: false"></a-camera>

<a-entity mindar-image-target="targetIndex: 0">

<a-text id="markerRecognizedText" value="Marcador reconocido!" position="0 0.5 0" color="#FFFFFF" align="center" visible="false"
width="2" height="2" wrap-count="20"></a-text>

<a-sphere id="sphereModel" radius="0.5" color="#FFC107" position="0 0 0.1" visible="false"
material="shader: standard; metalness: 0.5; roughness: 0.5;"></a-sphere>

<a-box id="cubeModel" width="1" height="1" depth="1" color="#2196F3" position="0 0 0.1" visible="false"
material="shader: standard; metalness: 0.5; roughness: 0.5;"></a-box>

<a-cone id="coneModel" radius-bottom="0.6" radius-top="0" height="1" color="#4CAF50" position="0 0 0.1" visible="false"
material="shader: standard; metalness: 0.5; roughness: 0.5;"></a-cone>

<a-gltf-model id="customModel" src="#customGlbModel" position="0 0 0.1" scale="0.5 0.5 0.5" rotation="90 0 0"visible="false"></a-gltf-model>
</a-entity>
</a-scene>
<div class="overlay">
<div id="messageBox" class="message-box">
Presiona "Iniciar Reconocimiento" y di "esfera", "cubo", "triángulo" o "modelo".
</div>
<div class="button-container">
<button id="startButton">Iniciar Reconocimiento</button>
<button id="stopButton" disabled>Detener Reconocimiento</button>
</div>
</div>
</body>
</html>

<!DOCTYPE html> y <html>: Declaran el tipo de documento y el elemento raíz de la página.

<head>: Contiene metadatos, el título de la página (<title>MindAR Voz 3D</title>), la codificación de caracteres (<meta charset=»UTF-8″>) y la configuración del viewport para asegurar la correcta visualización en dispositivos móviles (<meta name=»viewport» content=»width=device-width, initial-scale=1.0″>).

<script> tags: Incluyen las librerías necesarias para la Realidad Aumentada:

  • A-Frame: Un framework web para construir experiencias de realidad virtual en el navegador.
  • MindAR: Una librería de realidad aumentada para la web, que se integra con A-Frame para el seguimiento de imágenes.

<style>: Contiene todo el código CSS para estilizar la página y sus elementos (hablaremos más adelante sobre esto).

<body>: Contiene el contenido visible de la página web.

<a-scene>: El elemento central de A-Frame que representa la escena 3D.

mindar-image: Un componente de MindAR que configura el seguimiento de imágenes. Se le especifica la ruta al archivo de los marcadores (targets.mind) y se habilita el inicio automático y la configuración de la cámara.

color-space y renderer: Configuración para un renderizado de color más preciso y mejoras visuales.

vr-mode-ui y device-orientation-permission-ui: Deshabilitan la interfaz de usuario de VR y la solicitud de permiso de orientación del dispositivo, ya que la aplicación se enfoca en AR con seguimiento de imagen.

<a-assets>: Un contenedor para cargar activos como modelos 3D (<a-asset-item id=»customGlbModel» src=»scene.glb»></a-asset-item>).

El modelo 3D fue descargado de la comunidad de sketchfab: Newsfeed – Sketchfab

<a-camera>: La cámara virtual de la escena. look-controls=»enabled: false» deshabilita los controles de mirada manuales, ya que la cámara es controlada por MindAR.

<a-entity mindar-image-target=»targetIndex: 0″>: Un contenedor para los objetos 3D que aparecerán cuando se detecte el primer marcador de imagen (targetIndex: 0).

<a-text>: Un elemento de texto que se hará visible cuando el marcador sea reconocido.

<a-sphere>, <a-box>, <a-cone>: Primitivas 3D de A-Frame, inicialmente invisibles, que se mostrarán según los comandos de voz.

<a-gltf-model>: Un elemento para cargar el modelo 3D GLB personalizado (scene.glb), también inicialmente invisible.

<div class=»overlay»>: Un contenedor para superponer elementos de la interfaz de usuario sobre la escena AR.

<div id=»messageBox» class=»message-box»>: Un cuadro de texto para mostrar mensajes al usuario.

<div class=»button-container»>: Contiene los botones para controlar el reconocimiento de voz.

<button id=»startButton»>: Botón para iniciar el reconocimiento de voz.

<button id=»stopButton» disabled>: Botón para detener el reconocimiento de voz, inicialmente deshabilitado.

Estilos CSS


<style>

html, body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
* {
box-sizing: border-box; /* Asegura que padding y border se incluyan en el ancho/alto */
}
body {
font-family: 'Inter', sans-serif;
overflow: hidden; /* Hide scrollbars */
}
#ar-scene {
width: 100vw;
height: 100vh;
position: fixed; /* Fija la posición en la ventana */
top: 0;
left: 0;
z-index: 0; /* Asegura que esté en la capa de fondo */
}
/* Asegura que el canvas generado por A-Frame también ocupe todo el espacio */
canvas {
display: block;
width: 100% !important;
height: 100% !important;
}
.overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: flex-end;
align-items: center;
padding: 20px;
box-sizing: border-box;
pointer-events: none;
z-index: 1; /* Asegura que el overlay esté por encima de la escena AR */
}
.message-box {
background-color: rgba(0, 0, 0, 0.7);
color: white;
padding: 15px 25px;
border-radius: 12px;
text-align: center;
font-size: 1.1em;
margin-bottom: 20px;
pointer-events: auto; /* Allow interaction with the message box */
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
max-width: 90%;
}
.button-container {
pointer-events: auto; /* Allow interaction with buttons */
margin-bottom: 20px;
}
button {
background-color: #4CAF50;
color: white;
padding: 12px 24px;
border: none;
border-radius: 8px;
font-size: 1.1em;
cursor: pointer;
transition: background-color 0.3s ease, transform 0.2s ease;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
button:hover {
background-color: #45a049;
transform: translateY(-2px);
}
button:active {
transform: translateY(0);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
button:disabled {
background-color: #cccccc;
cursor: not-allowed;
box-shadow: none;
transform: none;
}
</style>

El CSS es responsable de la apariencia y el diseño de la página, asegurando que la escena de Realidad Aumentada ocupe toda la pantalla y que los elementos de la interfaz de usuario sean visualmente atractivos y funcionales.

html, body: Resetea los márgenes y paddings por defecto y asegura que el html y body ocupen el 100% del ancho y alto de la ventana.

*: Aplica box-sizing: border-box; globalmente para un modelo de caja más intuitivo.

body: Define la fuente, oculta las barras de desplazamiento (overflow: hidden;) y establece un estilo general.

#ar-scene: Posiciona la escena de A-Frame de forma fija en la ventana, ocupando todo el espacio (100vw, 100vh) y con un z-index bajo para que otros elementos puedan superponerse.

canvas: Asegura que el canvas generado por A-Frame también se extienda por toda la pantalla.

.overlay: Crea una capa superpuesta que cubre toda la ventana. Utiliza flexbox para posicionar su contenido en la parte inferior de la pantalla. pointer-events: none; inicialmente desactiva la interacción del overlay con el ratón, permitiendo que la cámara AR funcione sin interrupciones, pero los elementos interactivos dentro de él sobrescriben esta propiedad.

.message-box: Estiliza el cuadro de mensajes con un fondo semitransparente, texto blanco, bordes redondeados, y una sombra. pointer-events: auto; lo hace interactivo.

.button-container: Contenedor para los botones, también pointer-events: auto; para permitir la interacción.

button: Estilos generales para los botones, incluyendo color de fondo, texto, padding, bordes redondeados, tamaño de fuente y un efecto de transición suave.

button:hover: Efecto de cambio de color y ligero levantamiento al pasar el ratón por encima.

button:active: Efecto de hundimiento al hacer clic.

button:disabled: Estilos para cuando el botón está deshabilitado, indicando que no se puede interactuar con él.

Logica Javascript


<script>

const sphereModel = document.getElementById('sphereModel');
const cubeModel = document.getElementById('cubeModel');
const coneModel = document.getElementById('coneModel');
const customModel = document.getElementById('customModel'); // New: Reference to the custom GLB model
const markerRecognizedText = document.getElementById('markerRecognizedText'); // New: Reference to the marker recognized text

const messageBox = document.getElementById('messageBox');
const startButton = document.getElementById('startButton');
const stopButton = document.getElementById('stopButton');

const arScene = document.getElementById('ar-scene');

let recognition;
let isRecognizing = false;

function hideAllModels() {
sphereModel.setAttribute('visible', 'false');
cubeModel.setAttribute('visible', 'false');
coneModel.setAttribute('visible', 'false');
customModel.setAttribute('visible', 'false');
}

function showModel(modelName) {
hideAllModels();
markerRecognizedText.setAttribute('visible', 'false');
switch (modelName) {
case 'esfera':
sphereModel.setAttribute('visible', 'true');
messageBox.textContent = 'Mostrando: Esfera';
break;
case 'cubo':
cubeModel.setAttribute('visible', 'true');
messageBox.textContent = 'Mostrando: Cubo';
break;
case 'triángulo':
coneModel.setAttribute('visible', 'true');
messageBox.textContent = 'Mostrando: Triángulo';
break;
case 'modelo':
customModel.setAttribute('visible', 'true');
messageBox.textContent = 'Mostrando: Modelo 3D';
break;
default:
messageBox.textContent = 'Comando no reconocido. Intenta de nuevo.';
break;
}
}

if ('webkitSpeechRecognition' in window || 'SpeechRecognition' in window) {
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
recognition = new SpeechRecognition();

recognition.continuous = true;
recognition.interimResults = false;
recognition.lang = 'es-ES';

recognition.onstart = function() {
isRecognizing = true;
messageBox.textContent = 'Escuchando... Di "esfera", "cubo", "triángulo" o "modelo".';
startButton.disabled = true;
stopButton.disabled = false;
};

recognition.onresult = function(event) {
const transcript = event.results[event.results.length - 1][0].transcript.toLowerCase().trim();
console.log('Comando reconocido:', transcript);

if (transcript.includes('esfera')) {
showModel('esfera');
} else if (transcript.includes('cubo')) {
showModel('cubo');
} else if (transcript.includes('triángulo')) {
showModel('triángulo');
} else if (transcript.includes('modelo')) {
showModel('modelo');
} else {
messageBox.textContent = 'Comando no reconocido: "' + transcript + '". Intenta de nuevo.';
}
};

recognition.onerror = function(event) {
isRecognizing = false;
console.error('Error de reconocimiento de voz:', event.error);
messageBox.textContent = 'Error en el reconocimiento de voz: ' + event.error + '. Intenta reiniciar.';
startButton.disabled = false;
stopButton.disabled = true;
};

recognition.onend = function() {
isRecognizing = false;
messageBox.textContent = 'Reconocimiento detenido. Presiona "Iniciar Reconocimiento" para continuar.';
startButton.disabled = false;
stopButton.disabled = true;
};

startButton.addEventListener('click', () => {
if (!isRecognizing) {
recognition.start();
}
});

stopButton.addEventListener('click', () => {
if (isRecognizing) {
recognition.stop();
}
});

} else {
messageBox.textContent = 'Tu navegador no soporta la API de reconocimiento de voz.';
startButton.disabled = true;
stopButton.disabled = true;
}

arScene.addEventListener('targetFound', function (event) {
console.log('Marcador encontrado!');
markerRecognizedText.setAttribute('visible', 'true');
});

arScene.addEventListener('targetLost', function (event) {
console.log('Marcador perdido!');
markerRecognizedText.setAttribute('visible', 'false');
});

hideAllModels();
markerRecognizedText.setAttribute('visible', 'false');
</script>

El JavaScript es el cerebro de la aplicación, manejando la interacción con el reconocimiento de voz y la visibilidad de los modelos 3D en la escena de Realidad Aumentada.

Referencias a Elementos del DOM: Se obtienen referencias a los elementos HTML clave mediante su id, como los modelos 3D, el cuadro de mensajes y los botones.

Variables de Estado: recognition almacenará la instancia de SpeechRecognition y isRecognizing indicará si el reconocimiento de voz está activo.

hideAllModels(): Esta función oculta todos los modelos 3D configurando su atributo visible a ‘false’. Esto asegura que solo se muestre el modelo deseado en un momento dado.

showModel(modelName): Esta función es central para la interactividad. Primero llama a hideAllModels() para limpiar la escena, luego, basándose en el modelName recibido, establece el atributo visible del modelo correspondiente a ‘true’ y actualiza el messageBox.

Inicialización de SpeechRecognition:

Verifica si la API de reconocimiento de voz está disponible en el navegador.

Crea una nueva instancia de SpeechRecognition.

recognition.continuous = true;: Permite que el reconocimiento continúe escuchando comandos sin necesidad de reiniciar después de cada comando.

recognition.interimResults = false;: Solo se entregarán resultados finales y estables, no transcripciones parciales.

recognition.lang = ‘es-ES’;: Establece el idioma del reconocimiento a español.

Eventos de SpeechRecognition:

onstart: Se activa cuando el reconocimiento comienza. Actualiza el mensaje, deshabilita el botón de inicio y habilita el de detener.

onresult: Es el evento más importante. Se dispara cuando el reconocimiento detecta un comando de voz.

Obtiene la transcripción del último resultado, la convierte a minúsculas y elimina espacios en blanco.

Utiliza una serie de if/else if para verificar si la transcripción incluye las palabras clave («esfera», «cubo», «triángulo», «modelo») y llama a showModel() con el nombre apropiado.

Si el comando no es reconocido, actualiza el cuadro de mensajes.

onerror: Maneja los errores que puedan ocurrir durante el reconocimiento de voz, mostrando un mensaje de error al usuario y ajustando el estado de los botones.

onend: Se activa cuando el reconocimiento finaliza, ya sea por una llamada a stop() o por alguna otra razón. Restablece el estado de la interfaz.

Event Listeners para Botones:

El botón «Iniciar Reconocimiento» (startButton) inicia el reconocimiento de voz si no está ya activo.

El botón «Detener Reconocimiento» (stopButton) detiene el reconocimiento si está activo.

Manejo de Navegadores sin Soporte: Si el navegador del usuario no soporta la API de reconocimiento de voz, se muestra un mensaje informativo y los botones se deshabilitan.

Eventos de MindAR (targetFound, targetLost):

targetFound: Se activa cuando MindAR detecta el marcador de imagen. En este caso, muestra el texto «Marcador reconocido!».

targetLost: Se activa cuando el marcador de imagen se pierde de vista, ocultando el texto.

Inicialización al Cargar: Al final del script, se llama a hideAllModels() y se oculta el texto del marcador para asegurar que la escena comience en un estado limpio.

Aquí te dejo un short de Youtube de cómo funciona la aplicación en un teléfono Android.

Si quieres todo el código en un solo archivo te invito a que te agregues a la sección de la comunidad Tutoriales y Videotutoriales.

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Scroll al inicio
0
Would love your thoughts, please comment.x
()
x