Skip to content

Commit 1859806

Browse files
committed
Examples: Refactored webxr_vr_haptics.
1 parent 5988c7a commit 1859806

File tree

1 file changed

+68
-90
lines changed

1 file changed

+68
-90
lines changed

examples/webxr_xr_haptics.html

Lines changed: 68 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -30,45 +30,17 @@
3030

3131
let container;
3232
let camera, scene, renderer;
33+
34+
let listener;
3335
let controller1, controller2;
3436
let controllerGrip1, controllerGrip2;
37+
3538
const box = new THREE.Box3();
3639

37-
const controllers = [];
38-
const oscillators = [];
3940
let controls, group;
40-
let audioCtx = null;
41-
42-
// minor pentatonic scale, so whichever notes is stricken would be more pleasant
43-
const musicScale = [ 0, 3, 5, 7, 10 ];
4441

4542
init();
4643

47-
function initAudio() {
48-
49-
if ( audioCtx !== null ) {
50-
51-
return;
52-
53-
}
54-
55-
audioCtx = new ( window.AudioContext || window.webkitAudioContext )();
56-
function createOscillator() {
57-
58-
// creates oscillator
59-
const oscillator = audioCtx.createOscillator();
60-
oscillator.type = 'sine'; // possible values: sine, triangle, square
61-
oscillator.start();
62-
return oscillator;
63-
64-
}
65-
66-
oscillators.push( createOscillator() );
67-
oscillators.push( createOscillator() );
68-
window.oscillators = oscillators;
69-
70-
}
71-
7244
function init() {
7345

7446
container = document.createElement( 'div' );
@@ -80,6 +52,9 @@
8052
camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 0.1, 10 );
8153
camera.position.set( 0, 1.6, 3 );
8254

55+
listener = new THREE.AudioListener();
56+
camera.add( listener );
57+
8358
controls = new OrbitControls( camera, container );
8459
controls.target.set( 0, 1.6, 0 );
8560
controls.update();
@@ -140,7 +115,6 @@
140115
renderer.setPixelRatio( window.devicePixelRatio );
141116
renderer.setSize( window.innerWidth, window.innerHeight );
142117
renderer.setAnimationLoop( animate );
143-
renderer.xr.addEventListener( 'sessionstart', () => initAudio() );
144118
renderer.shadowMap.enabled = true;
145119
renderer.xr.enabled = true;
146120
container.appendChild( renderer.domElement );
@@ -175,25 +149,31 @@
175149

176150
}
177151

178-
function controllerConnected( evt ) {
152+
function controllerConnected( event ) {
179153

180-
controllers.push( {
181-
gamepad: evt.data.gamepad,
182-
grip: evt.target,
183-
colliding: false,
184-
playing: false
185-
} );
154+
const oscillator = listener.context.createOscillator();
155+
oscillator.type = 'sine';
156+
oscillator.start()
186157

187-
}
158+
const audio = new THREE.PositionalAudio( listener );
159+
audio.setNodeSource( oscillator );
160+
audio.setRefDistance( 20 );
161+
audio.setVolume( 0 );
188162

189-
function controllerDisconnected( evt ) {
163+
this.userData.gamepad = event.data.gamepad;
164+
this.userData.colliding = false;
165+
this.userData.audio = audio;
190166

191-
const index = controllers.findIndex( o => o.controller === evt.target );
192-
if ( index !== - 1 ) {
167+
this.add( audio );
193168

194-
controllers.splice( index, 1 );
169+
}
195170

196-
}
171+
function controllerDisconnected( event ) {
172+
173+
const audio = this.userData.audio;
174+
audio.source.stop();
175+
176+
this.remove( audio );
197177

198178
}
199179

@@ -206,88 +186,86 @@
206186

207187
}
208188

209-
//
210189

211-
function handleCollisions() {
190+
function handleCollisions( controller ) {
212191

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

215194
group.children[ i ].collided = false;
216195

217196
}
218197

219-
for ( let g = 0; g < controllers.length; g ++ ) {
220-
221-
const controller = controllers[ g ];
222-
controller.colliding = false;
223-
224-
const { grip, gamepad } = controller;
225-
const sphere = {
226-
radius: 0.03,
227-
center: grip.position
228-
};
198+
handleController( controllerGrip1 );
199+
handleController( controllerGrip2 );
229200

230-
const supportHaptic = 'hapticActuators' in gamepad && gamepad.hapticActuators != null && gamepad.hapticActuators.length > 0;
201+
for ( let i = 0; i < group.children.length; i ++ ) {
231202

232-
for ( let i = 0; i < group.children.length; i ++ ) {
203+
const child = group.children[ i ];
204+
if ( ! child.collided ) {
233205

234-
const child = group.children[ i ];
235-
box.setFromObject( child );
236-
if ( box.intersectsSphere( sphere ) ) {
206+
// reset uncollided boxes
207+
child.material.emissive.b = 0;
208+
child.scale.setScalar( 1 );
237209

238-
child.material.emissive.b = 1;
239-
const intensity = child.userData.index / group.children.length;
240-
child.scale.setScalar( 1 + Math.random() * 0.1 * intensity );
210+
}
241211

242-
if ( supportHaptic ) {
212+
}
243213

244-
gamepad.hapticActuators[ 0 ].pulse( intensity, 100 );
214+
}
245215

246-
}
216+
// minor pentatonic scale, so whichever notes is stricken would be more pleasant
217+
const musicScale = [ 0, 3, 5, 7, 10 ];
247218

248-
const musicInterval = musicScale[ child.userData.index % musicScale.length ] + 12 * Math.floor( child.userData.index / musicScale.length );
249-
oscillators[ g ].frequency.value = 110 * Math.pow( 2, musicInterval / 12 );
250-
controller.colliding = true;
251-
group.children[ i ].collided = true;
219+
function handleController( controller ) {
252220

253-
}
221+
controller.userData.colliding = false;
254222

255-
}
223+
const audio = controller.userData.audio;
224+
const gamepad = controller.userData.gamepad;
256225

226+
if ( audio === undefined || gamepad === undefined ) return;
257227

228+
const oscillator = audio.source;
229+
const supportHaptic = 'hapticActuators' in gamepad && gamepad.hapticActuators != null && gamepad.hapticActuators.length > 0;
258230

259-
if ( controller.colliding ) {
231+
const sphere = {
232+
radius: 0.03,
233+
center: controller.position
234+
};
260235

261-
if ( ! controller.playing ) {
236+
for ( let i = 0; i < group.children.length; i ++ ) {
262237

263-
controller.playing = true;
264-
oscillators[ g ].connect( audioCtx.destination );
238+
const child = group.children[ i ];
239+
box.setFromObject( child );
265240

266-
}
241+
if ( box.intersectsSphere( sphere ) ) {
267242

268-
} else {
243+
child.material.emissive.b = 1;
244+
const intensity = child.userData.index / group.children.length;
245+
child.scale.setScalar( 1 + Math.random() * 0.1 * intensity );
269246

270-
if ( controller.playing ) {
247+
if ( supportHaptic ) {
271248

272-
controller.playing = false;
273-
oscillators[ g ].disconnect( audioCtx.destination );
249+
gamepad.hapticActuators[ 0 ].pulse( intensity, 100 );
274250

275251
}
276252

253+
const musicInterval = musicScale[ child.userData.index % musicScale.length ] + 12 * Math.floor( child.userData.index / musicScale.length );
254+
oscillator.frequency.value = 110 * Math.pow( 2, musicInterval / 12 );
255+
controller.userData.colliding = true;
256+
group.children[ i ].collided = true;
257+
277258
}
278259

279260
}
280261

281-
for ( let i = 0; i < group.children.length; i ++ ) {
262+
if ( controller.userData.colliding ) {
282263

283-
const child = group.children[ i ];
284-
if ( ! child.collided ) {
264+
audio.setVolume( 0.5 );
285265

286-
// reset uncollided boxes
287-
child.material.emissive.b = 0;
288-
child.scale.setScalar( 1 );
266+
} else {
289267

290-
}
268+
audio.setVolume( 0 );
291269

292270
}
293271

0 commit comments

Comments
 (0)