Skip to content

Commit

Permalink
Improve vr haptics example (#23307)
Browse files Browse the repository at this point in the history
* Improve vr haptics example

- make audio more pleasant
  a) changing frequency to a pentatonic
  b) changing oscillator from square to sine type
- fix a bug so multiple boxes can simultaneously light up when
  more than 1 controllers is used

* Make vr haptics example compatible with WebXR emulator

* Make sure that we don't get array out of bounds for musical scale again
  • Loading branch information
zz85 authored Jan 26, 2022
1 parent 406da8c commit c77a176
Showing 1 changed file with 53 additions and 31 deletions.
84 changes: 53 additions & 31 deletions examples/webxr_vr_haptics.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js vr - dragging</title>
<title>three.js vr - haptics</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<link type="text/css" rel="stylesheet" href="main.css">
Expand Down Expand Up @@ -42,6 +42,9 @@
let controls, group;
let audioCtx = null;

// minor pentatonic scale, so whichever notes is striked would be more pleasant
const musicScale = [ 0, 3, 5, 7, 10, 12 ];

init();
animate();

Expand All @@ -56,14 +59,9 @@
audioCtx = new ( window.AudioContext || window.webkitAudioContext )();
function createOscillator() {

// creates oscillator
const oscillator = audioCtx.createOscillator();
const real = Array.from( { length: 8192 }, ( _, n ) => (
n === 0 ?
0 :
4 / ( n * Math.PI ) * Math.sin( Math.PI * n * 0.18 )
) );
const imag = real.map( () => 0 );
oscillator.setPeriodicWave( audioCtx.createPeriodicWave( Float32Array.from( real ), Float32Array.from( imag ) ) );
oscillator.type = 'sine'; // possible values: sine, triangle, square
oscillator.start();
return oscillator;

Expand Down Expand Up @@ -116,10 +114,11 @@
group = new THREE.Group();
group.position.z = - 0.5;
scene.add( group );
const BOXES = 10;

for ( let i = 0; i < 10; i ++ ) {
for ( let i = 0; i < BOXES; i ++ ) {

const intensity = ( i + 1 ) / 10;
const intensity = ( i + 1 ) / BOXES;
const w = 0.1;
const h = 0.1;
const minH = 1;
Expand Down Expand Up @@ -230,56 +229,66 @@

function handleCollisions() {

for ( let i = 0; i < group.children.length; i ++ ) {

group.children[ i ].collided = false;

}

for ( let g = 0; g < controllers.length; g ++ ) {

controllers[ g ].colliding = false;
const controller = controllers[ g ];
controller.colliding = false;

const { grip, gamepad } = controllers[ g ];
const { grip, gamepad } = controller;
const sphere = {
radius: 0.03,
center: grip.position
};

if ( 'hapticActuators' in gamepad && gamepad.hapticActuators != null && gamepad.hapticActuators.length > 0 ) {
const supportHaptic = 'hapticActuators' in gamepad && gamepad.hapticActuators != null && gamepad.hapticActuators.length > 0;

for ( let i = 0; i < group.children.length; i ++ ) {
for ( let i = 0; i < group.children.length; i ++ ) {

const child = group.children[ i ];
box.setFromObject( child );
if ( box.intersectsSphere( sphere ) ) {
const child = group.children[ i ];
box.setFromObject( child );
if ( box.intersectsSphere( sphere ) ) {

child.material.emissive.b = 1;
const intensity = child.userData.index / group.children.length;
child.scale.setScalar( 1 + Math.random() * 0.1 * intensity );
gamepad.hapticActuators[ 0 ].pulse( intensity, 100 );
oscillators[ g ].frequency.value = 100 + intensity * 60;
controllers[ g ].colliding = true;
child.material.emissive.b = 1;
const intensity = child.userData.index / group.children.length;
child.scale.setScalar( 1 + Math.random() * 0.1 * intensity );

} else {
if ( supportHaptic ) {

child.material.emissive.b = 0;
child.scale.setScalar( 1 );
gamepad.hapticActuators[ 0 ].pulse( intensity, 100 );

}

const musicInterval = musicScale[ child.userData.index % musicScale.length ] + 12 * Math.floor( child.userData.index / musicScale.length );
oscillators[ g ].frequency.value = 110 * Math.pow( 2, musicInterval / 12 );
controller.colliding = true;
group.children[ i ].collided = true;

}

}

if ( controllers[ g ].colliding ) {

if ( ! controllers[ g ].playing ) {

controllers[ g ].playing = true;
if ( controller.colliding ) {

if ( ! controller.playing ) {

controller.playing = true;
oscillators[ g ].connect( audioCtx.destination );

}

} else {

if ( controllers[ g ].playing ) {
if ( controller.playing ) {

controllers[ g ].playing = false;
controller.playing = false;
oscillators[ g ].disconnect( audioCtx.destination );

}
Expand All @@ -288,6 +297,19 @@

}

for ( let i = 0; i < group.children.length; i ++ ) {

let child = group.children[ i ];
if ( ! child.collided ) {

// reset uncollided boxes
child.material.emissive.b = 0;
child.scale.setScalar( 1 );

}

}

}

function render() {
Expand Down

0 comments on commit c77a176

Please sign in to comment.