Parte: 13 — VR, AR y experiencias inmersivas · Fuente: Documentación de audio 3D y XR en Godot 4 ⏱️ Duración estimada: 80 min · Nivel: Avanzado
La presencia en VR no es solo visual: el sonido y el tacto la refuerzan enormemente. El audio espacial hace que el jugador localice una fuente por el oído —arriba, detrás, a la derecha— tal como en la vida real, y el feedback háptico en los mandos convierte un agarre o un golpe en una sensación física. En esta clase colocarás sonido 3D con AudioStreamPlayer3D usando la cabeza del jugador (la XRCamera3D) como listener, añadirás reverb por espacio y dispararás pulsos hápticos con XRController3D.trigger_haptic_pulse().
El laboratorio integra ambos: objetos que suenan desde su posición en el mundo, atenuación con la distancia, y una vibración en el mando al agarrar o golpear con el gatillo. El resultado es una escena que se oye y se siente coherente con lo que se ve.
Al finalizar, el alumno podrá:
AudioStreamPlayer3D y explicar la atenuación por distancia.XRCamera3D para que el sonido siga la cabeza.trigger_haptic_pulse en los mandos.| # | Tema | Por qué importa |
|---|---|---|
| 1 | Audio 3D en VR | Localizar por el oído refuerza la presencia. |
| 2 | Listener en la cabeza | El sonido debe moverse con la XRCamera3D. |
| 3 | Atenuación y rango | Modela cómo el sonido baja con la distancia. |
| 4 | HRTF y paneo | Da la sensación de dirección y altura. |
| 5 | Reverb por espacio | Una sala suena distinta a un exterior. |
| 6 | Hápticos en los mandos | El tacto confirma acciones físicas. |
| 7 | Intensidad y duración del pulso | Calibra el feedback sin molestar. |
| 8 | Sincronizar audio y háptica | Juntos venden el impacto de una acción. |
AudioStreamPlayer3D: reproductor posicionado en el espacio 3D. Clave: su volumen y paneo dependen de dónde esté respecto al listener.XRCamera3D (la cabeza), no una cámara fija.unit_size y el modelo definen a qué ritmo baja.XRController3D: nodo del mando con pose y entradas. Clave: expone trigger_haptic_pulse para vibrar.trigger_haptic_pulse: dispara vibración con amplitud, frecuencia y duración. Clave: es el feedback táctil del mando.Continúa en tu proyecto VR con OpenXR y dos XRController3D (izquierdo y derecho) bajo el XROrigin3D. Necesitas auriculares para apreciar el audio espacial (el HRTF luce con cabeza/oídos). Ten algún archivo de sonido corto (un impacto, un zumbido) importado en res://audio/. Crea un bus de audio extra en el panel Audio para el reverb de la sala.
Referencias: AudioStreamPlayer3D en https://docs.godotengine.org/en/stable/classes/class_audiostreamplayer3d.html, buses de audio en https://docs.godotengine.org/en/stable/tutorials/audio/audio_buses.html y XRController3D en https://docs.godotengine.org/en/stable/classes/class_xrcontroller3d.html.
Añadiremos sonido 3D con el listener en la cabeza y háptica al interactuar.
AudioListener3D como hijo de la XRCamera3D y actívalo, para que el sonido se calcule desde donde mira el jugador:extends XRCamera3D
func _ready() -> void:
var listener := AudioListener3D.new()
add_child(listener)
listener.make_current() # el audio 3D se oye desde la cabeza
AudioStreamPlayer3D a un objeto (por ejemplo una máquina que zumba), asígnale el stream y configura la atenuación:extends AudioStreamPlayer3D
func _ready() -> void:
stream = preload("res://audio/zumbido.ogg")
unit_size = 2.0 # metros a los que se oye a volumen base
max_distance = 12.0 # mas alla no se oye
attenuation_model = ATTENUATION_INVERSE_DISTANCE
autoplay = true
Ejecuta con el visor y los auriculares: acércate y aléjate del objeto y gira la cabeza. El zumbido debe crecer al acercarte y sonar a un lado u otro según hacia dónde mires, porque el listener sigue la XRCamera3D.
Añade reverb por espacio. Crea un bus SalaReverb, añádele un efecto Reverb y enruta la fuente a ese bus dentro de la sala. Distintas salas pueden usar buses con reverb distinto para "sonar" diferente.
Dispara háptica al golpear con el gatillo. En el mando derecho, al pulsar el trigger, vibra el mando para confirmar la acción:
extends XRController3D # mando derecho
func _process(_delta: float) -> void:
if get_float("trigger") > 0.7:
# amplitud 0-1, frecuencia en Hz, duracion en segundos.
trigger_haptic_pulse("haptic", 0.0, 0.6, 0.1, 0.0)
AudioStreamPlayer3D de impacto y vibra el mando que lo sostiene, para que el golpe se oiga y se sienta a la vez:func golpear(mando: XRController3D, sonido_impacto: AudioStreamPlayer3D) -> void:
sonido_impacto.play() # se oye desde el punto de golpe
mando.trigger_haptic_pulse("haptic", 0.0, 0.8, 0.08, 0.0) # se siente en la mano
Con audio espacial y háptica, la escena gana cuerpo y credibilidad. En la próxima clase integramos todo en un capstone.
attenuation_model y compara cómo cae el volumen con la distancia.Area3D y quítalo al salir de la sala.Crea una escena VR con al menos dos fuentes de audio 3D posicionadas, el listener en la XRCamera3D, reverb por espacio y una interacción (agarrar y golpear) que dispare sonido de impacto desde la posición del golpe y un pulso háptico en el mando que sostiene el objeto.
Criterio de aceptación: con auriculares y visor, el jugador localiza cada fuente por el oído según su posición y orientación de cabeza, y al golpear un objeto agarrado oye el impacto desde el punto correcto mientras siente la vibración en el mando correspondiente.
| Síntoma / mensaje | Causa y cómo arreglar |
|---|---|
| El sonido no cambia al girar la cabeza | El listener no está en la XRCamera3D. Añade y activa un AudioListener3D como su hijo. |
| Todo suena centrado, sin dirección | Usaste AudioStreamPlayer (2D) en vez de AudioStreamPlayer3D. Cambia el nodo. |
| El mando no vibra | Nombre de acción háptica erróneo o mando sin soporte. Usa "haptic" y verifica el XRController3D. |
| El sonido se corta de golpe al alejarse | max_distance muy bajo. Súbelo o ajusta la atenuación. |
| La háptica es molesta o constante | Amplitud/duración altas o disparada cada frame. Reduce valores y condiciona el disparo. |
❓ ¿Necesito auriculares para el audio espacial? Para apreciar dirección y altura (HRTF), sí. Con altavoces se pierde gran parte de la localización.
❓ ¿Por qué el listener debe ser la cámara? Porque el jugador oye desde donde está su cabeza. Un listener fijo daría un sonido incoherente con lo que mira.
❓ ¿Los parámetros de trigger_haptic_pulse son universales? La firma es amplitud, frecuencia y duración, pero cada mando responde distinto. Calibra en el hardware real.
❓ ¿Cómo cambio el reverb entre salas? Enruta cada fuente a un bus con su propio efecto Reverb y conmuta según el Area3D en que esté el jugador.
Clase 239 - Capstone Parte 13: una experiencia VR o AR mínima