Skip to content

Commit

Permalink
performance improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
stemkoski committed Mar 22, 2022
1 parent b06dbe7 commit 96f26a8
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 85 deletions.
94 changes: 48 additions & 46 deletions js/player-move.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ AFRAME.registerComponent("player-move", {

this.moveSpeed = 1; // units per second

// create a vector to store camera direction
this.cameraDirection = new THREE.Vector3();

// quick turns
this.turnReady = true;
this.startAngle = 0;
Expand Down Expand Up @@ -77,7 +80,7 @@ AFRAME.registerComponent("player-move", {
tick: function()
{
// always update deltaTime!
let deltaTime = this.clock.getDelta();
this.deltaTime = this.clock.getDelta();

if ( !this.enabled )
return;
Expand All @@ -92,29 +95,29 @@ AFRAME.registerComponent("player-move", {
this.raycaster.intersectionDetail.els[0].classList.contains(this.data.navigationMeshClass) )
{
// show marker to indicate teleport zone
let point = this.raycaster.intersectionDetail.intersections[0].point;
this.point = this.raycaster.intersectionDetail.intersections[0].point;

let t = this.clock.elapsedTime/3 % 1;
let alpha = Math.min(2*t, 0.5);
this.navTarget1.object3D.position.set(point.x, point.y, point.z);
this.t = this.clock.elapsedTime/3 % 1;
this.alpha = Math.min(2*this.t, 0.5);
this.navTarget1.object3D.position.set(this.point.x, this.point.y, this.point.z);
this.navTarget1.object3D.visible = true;
this.navTarget1.object3D.scale.set( 1-t, 1-t, 1 );
this.navTarget1.object3D.children[0].material.opacity = alpha;
this.navTarget1.object3D.scale.set( 1-this.t, 1-this.t, 1 );
this.navTarget1.object3D.children[0].material.opacity = this.alpha;

t = (this.clock.elapsedTime/3 + 0.5) % 1;
alpha = Math.min(2*t, 0.5);
this.navTarget2.object3D.position.set(point.x, point.y, point.z);
this.t = (this.clock.elapsedTime/3 + 0.5) % 1;
this.alpha = Math.min(2*this.t, 0.5);
this.navTarget2.object3D.position.set(this.point.x, this.point.y, this.point.z);
this.navTarget2.object3D.visible = true;
this.navTarget2.object3D.scale.set( 1-t, 1-t, 1 );
this.navTarget2.object3D.children[0].material.opacity = alpha;
this.navTarget2.object3D.scale.set( 1-this.t, 1-this.t, 1 );
this.navTarget2.object3D.children[0].material.opacity = this.alpha;

if (this.controllerData.rightTrigger.pressed && !this.fadeInProgress)
{
// fade out, then set position, then fade back in
this.fadeSphere.object3D.visible = true;
this.fadeInProgress = true;
this.fadeTime = 0;
this.point = {x:point.x, y:point.y, z:point.z};
this.teleportPoint = {x:this.point.x, y:this.point.y, z:this.point.z};
}
}
else
Expand All @@ -127,15 +130,15 @@ AFRAME.registerComponent("player-move", {
// currently teleporting
if (this.fadeInProgress)
{
this.fadeTime += deltaTime;
this.fadeTime += this.deltaTime;

// fade to dark and then to light
let alpha = -Math.abs(this.fadeTime - this.fadeDuration)/this.fadeDuration + 1;
this.fadeSphere.setAttribute("material", "opacity", alpha);
this.alpha = -Math.abs(this.fadeTime - this.fadeDuration)/this.fadeDuration + 1;
this.fadeSphere.setAttribute("material", "opacity", this.alpha);

if (this.fadeTime >= this.fadeDuration)
{
this.el.object3D.position.set(this.point.x, this.point.y, this.point.z);
this.el.object3D.position.set(this.teleportPoint.x, this.teleportPoint.y, this.teleportPoint.z);
}
if (this.fadeTime >= 2 * this.fadeDuration)
{
Expand All @@ -150,34 +153,33 @@ AFRAME.registerComponent("player-move", {

// move with left joystick (while not pressing left grip);
// move faster when pressing trigger
let leftJoystickLength = Math.sqrt(this.controllerData.leftAxisX * this.controllerData.leftAxisX +
this.leftJoystickLength = Math.sqrt(this.controllerData.leftAxisX * this.controllerData.leftAxisX +
this.controllerData.leftAxisY * this.controllerData.leftAxisY );

if ( this.data.motionEnabled &&
leftJoystickLength > 0.001 &&
this.leftJoystickLength > 0.001 &&
!this.controllerData.leftGrip.pressing )
{
// create a vector to store camera direction
let cameraDirection = new THREE.Vector3();
this.el.sceneEl.camera.getWorldDirection(cameraDirection);
let cameraAngle = Math.atan2(cameraDirection.z, cameraDirection.x);
// this.cameraDirection: a vector to store camera direction
this.el.sceneEl.camera.getWorldDirection(this.cameraDirection);
this.cameraAngle = Math.atan2(this.cameraDirection.z, this.cameraDirection.x);

let leftJoystickAngle = Math.atan2(this.controllerData.leftAxisY, this.controllerData.leftAxisX);
this.leftJoystickAngle = Math.atan2(this.controllerData.leftAxisY, this.controllerData.leftAxisX);

let moveAngle = cameraAngle + leftJoystickAngle;
this.moveAngle = this.cameraAngle + this.leftJoystickAngle;

let moveDistance = this.moveSpeed * deltaTime;
this.moveDistance = this.moveSpeed * this.deltaTime;

// move faster if pressing trigger at same time
moveDistance *= (1 + 9 * this.controllerData.leftTrigger.value);
this.moveDistance *= (1 + 9 * this.controllerData.leftTrigger.value);

// convert move distance and angle to right and forward amounts
// scale by magnitude of joystick press (smaller press moves player slower)
let moveRight = -leftJoystickLength * Math.sin(moveAngle) * moveDistance;
let moveForward = leftJoystickLength * Math.cos(moveAngle) * moveDistance;
this.moveRight = -this.leftJoystickLength * Math.sin(this.moveAngle) * this.moveDistance;
this.moveForward = this.leftJoystickLength * Math.cos(this.moveAngle) * this.moveDistance;

this.el.object3D.position.x = this.el.object3D.position.x + moveRight;
this.el.object3D.position.z = this.el.object3D.position.z + moveForward;
this.el.object3D.position.x = this.el.object3D.position.x + this.moveRight;
this.el.object3D.position.z = this.el.object3D.position.z + this.moveForward;
}

// =====================================================================
Expand All @@ -187,23 +189,23 @@ AFRAME.registerComponent("player-move", {
// while pressing left grip, press left joystick left/right to turn left/right by N degrees;
// -or- just press right joystick left/right to turn left/right by N degrees.
// joystick must return to rest/center position before turning again
let leftX = this.controllerData.leftAxisX;
let rightX = this.controllerData.rightAxisX;
this.leftX = this.controllerData.leftAxisX;
this.rightX = this.controllerData.rightAxisX;

if ( Math.abs(leftX) < 0.10 && Math.abs(rightX) < 0.10 )
if ( Math.abs(this.leftX) < 0.10 && Math.abs(this.rightX) < 0.10 )
{
this.turnReady = true;
}

if ( this.data.motionEnabled && this.turnReady &&
((this.controllerData.leftGrip.pressing && Math.abs(leftX) > 0.90) || Math.abs(rightX) > 0.90)
((this.controllerData.leftGrip.pressing && Math.abs(this.leftX) > 0.90) || Math.abs(this.rightX) > 0.90)
)
{
this.startAngle = this.el.getAttribute("rotation").y;

if ( leftX > 0.90 || rightX > 0.90 )
if ( this.leftX > 0.90 || this.rightX > 0.90 )
this.endAngle = this.startAngle - this.turnAngle;
if ( leftX < -0.90 || rightX < -0.90 )
if ( this.leftX < -0.90 || this.rightX < -0.90 )
this.endAngle = this.startAngle + this.turnAngle;

this.turnInProgress = true;
Expand All @@ -213,10 +215,10 @@ AFRAME.registerComponent("player-move", {

if (this.turnInProgress)
{
this.turnTime += deltaTime;
let rot = this.el.getAttribute("rotation");
rot.y = this.lerp(this.startAngle, this.endAngle, this.turnTime/this.turnDuration);
this.el.setAttribute("rotation", rot);
this.turnTime += this.deltaTime;
this.rot = this.el.getAttribute("rotation");
this.rot.y = this.lerp(this.startAngle, this.endAngle, this.turnTime/this.turnDuration);
this.el.setAttribute("rotation", this.rot);

if (this.turnTime >= this.turnDuration)
this.turnInProgress = false;
Expand All @@ -234,13 +236,13 @@ AFRAME.registerComponent("player-move", {
this.controllerData.leftGrip.pressing &&
Math.abs(this.controllerData.leftAxisY) > 0.25 )
{
let y = this.controllerData.leftAxisY;
y = Math.sign(y) * (Math.abs(y) - 1/4);
let moveDistance = -this.moveSpeed * y * deltaTime;
this.y = this.controllerData.leftAxisY;
this.y = Math.sign(this.y) * (Math.abs(this.y) - 1/4);
this.moveDistance = -this.moveSpeed * this.y * this.deltaTime;
// move faster if pressing trigger at same time
moveDistance *= (1 + 9 * this.controllerData.leftTrigger.value);
this.moveDistance *= (1 + 9 * this.controllerData.leftTrigger.value);

this.el.object3D.position.y = this.el.object3D.position.y + moveDistance;
this.el.object3D.position.y = this.el.object3D.position.y + this.moveDistance;
}
}
});
80 changes: 43 additions & 37 deletions js/raycaster-extras.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ AFRAME.registerComponent('raycaster-extras', {
this.beamEntity.setAttribute("material", "src", this.data.beamImageSrc);
this.beamEntity.setAttribute("material", "color", this.data.beamColor);
this.beamEntity.setAttribute("material", "opacity", this.data.beamOpacity);
this.beamColorDefault = new THREE.Color(this.data.beamColor);
this.beamColorActive = new THREE.Color("cyan");
this.el.appendChild(this.beamEntity);


Expand Down Expand Up @@ -77,50 +79,52 @@ AFRAME.registerComponent('raycaster-extras', {
this.clock = new THREE.Clock();
this.moveSpeed = 1;

this.raycasterConfig = null;

},

tick: function ()
{
let deltaTime = this.clock.getDelta();
this.deltaTime = this.clock.getDelta();

// change color of beam when interacting with trigger or grip button ==================================

if ( this.controllerData.rightTrigger.pressing || this.controllerData.rightGrip.pressing )
this.beamEntity.setAttribute("material", "color", "cyan");
this.beamEntity.object3D.children[0].material.color = this.beamColorActive; // setAttribute("material", "color", "cyan");
else
this.beamEntity.setAttribute("material", "color", this.data.beamColor);
this.beamEntity.object3D.children[0].material.color = this.beamColorDefault; // setAttribute("material", "color", this.data.beamColor);

// calculate position and rotation of beam ============================================================

// based on model-specific values that customize raycaster line;
// note: this data may change when switching from browser to VR mode, so need to keep checking in tick()
let raycasterConfig = this.el.getAttribute("raycaster");
let currentRayDirection = raycasterConfig.direction;
let currentRayOrigin = raycasterConfig.origin;
if (this.raycasterConfig == null)
this.raycasterConfig = this.el.getAttribute("raycaster");

this.currentRayDirection = this.raycasterConfig.direction;
this.currentRayOrigin = this.raycasterConfig.origin;

if ( this.currentBeamDirection == null || this.currentBeamOrigin == null ||
!this.vectorsEqual(this.currentBeamOrigin, currentRayOrigin) ||
!this.vectorsEqual(this.currentBeamDirection, currentRayDirection) )
!this.vectorsEqual(this.currentBeamOrigin, this.currentRayOrigin) ||
!this.vectorsEqual(this.currentBeamDirection, this.currentRayDirection) )
{

// align beam rotation with ray direction angle
// (beam is always only rotated around x-axis)
let beamAngleX = 180 + Math.atan2(currentRayDirection.z, currentRayDirection.y) * 180/Math.PI;
let rot = {x: beamAngleX, y: 0, z: 0};
this.beamEntity.setAttribute("rotation", rot);
this.currentBeamDirection = currentRayDirection;
this.beamAngleX = 180 + Math.atan2(this.currentRayDirection.z, this.currentRayDirection.y) * 180/Math.PI;
this.rot = {x: this.beamAngleX, y: 0, z: 0};
this.beamEntity.setAttribute("rotation", this.rot);
this.currentBeamDirection = this.currentRayDirection;

this.beamAngleX = beamAngleX;

// align beam position with ray origin point
// and shift so beam cylinder end is at origin
let angleRad = beamAngleX * Math.PI/180;
let cylinderShift = this.data.beamLength / 2.05;
let pos = { x: currentRayOrigin.x,
y: currentRayOrigin.y - Math.cos(angleRad) * cylinderShift,
z: currentRayOrigin.z - Math.sin(angleRad) * cylinderShift };
this.beamEntity.setAttribute("position", pos);
this.currentBeamOrigin = currentRayOrigin;
this.angleRad = this.beamAngleX * Math.PI/180;
this.cylinderShift = this.data.beamLength / 2.05;
this.pos = { x: this.currentRayOrigin.x,
y: this.currentRayOrigin.y - Math.cos(this.angleRad) * this.cylinderShift,
z: this.currentRayOrigin.z - Math.sin(this.angleRad) * this.cylinderShift };
this.beamEntity.setAttribute("position", this.pos);
this.currentBeamOrigin = this.currentRayOrigin;
}

// update which element has focus ===================================================================
Expand Down Expand Up @@ -152,21 +156,23 @@ AFRAME.registerComponent('raycaster-extras', {

if ( this.focusedElement != null )
{
this.cursorEntity.setAttribute("visible", true)
this.cursorEntity.object3D.visible = true;

this.cursorEntity.setAttribute("position",
{ x: this.intersectionPoint.x,
y: this.intersectionPoint.y,
z: this.intersectionPoint.z } );
this.cursorEntity.object3D.position.set(
this.intersectionPoint.x,
this.intersectionPoint.y,
this.intersectionPoint.z );

// shorten raycaster
let dist = this.raycaster.intersectionDetail.intersections[0].distance;
this.el.setAttribute("raycaster", "far", dist + 0.1);
this.raycaster.raycaster.far = dist + 0.1;
// equivalent to: this.el.setAttribute("raycaster", "far", dist + 0.1);
}
else
{
this.cursorEntity.setAttribute("visible", false)
this.el.setAttribute("raycaster", "far", 12);
this.cursorEntity.object3D.visible = false;
this.raycaster.raycaster.far = 12;
// equivalent to: this.el.setAttribute("raycaster", "far", 12);
}

// grab element =====================================================================================
Expand All @@ -187,8 +193,8 @@ AFRAME.registerComponent('raycaster-extras', {
// raycaster-graphics keeps setting cursorEntity visible true,
// so force cursor hidden by making setting children visibility to false
// why? easier to focus on object without cursor in the way.
this.cursorCenter.setAttribute("visible", false);
this.cursorBorder.setAttribute("visible", false);
this.cursorCenter.object3D.visible = false;
this.cursorBorder.object3D.visible = false;

// turn off emission (set by raycaster-hover-glow)
this.focusedElement.setAttribute("material", "emissive", "#000000");
Expand Down Expand Up @@ -222,11 +228,11 @@ AFRAME.registerComponent('raycaster-extras', {
// if not pulling entity that is too close, then okay to move it
if ( !(this.controllerData.rightAxisY > 0 && distance < 0.05) )
{
let moveDistance = 2 * this.moveSpeed * deltaTime * this.controllerData.rightAxisY;
this.moveDistance = 2 * this.moveSpeed * this.deltaTime * this.controllerData.rightAxisY;
// move faster if pressing trigger at same time
moveDistance *= (1 + 1 * this.controllerData.rightTrigger.value);
this.moveDistance *= (1 + 1 * this.controllerData.rightTrigger.value);

this.tempVector.setLength(moveDistance);
this.tempVector.setLength(this.moveDistance);


// temporarily attach element back to root scene
Expand All @@ -241,7 +247,7 @@ AFRAME.registerComponent('raycaster-extras', {
let material = this.beamEntity.getAttribute("material");
material.repeat.x = 2;
material.repeat.y = 30;
material.offset.y -= 10 * moveDistance;
material.offset.y -= 10 * this.moveDistance;
this.beamEntity.setAttribute("material", material);

}
Expand All @@ -268,8 +274,8 @@ AFRAME.registerComponent('raycaster-extras', {
material.offset.y = 0.001;
this.beamEntity.setAttribute("material", material);

this.cursorCenter.setAttribute("visible", true);
this.cursorBorder.setAttribute("visible", true);
this.cursorCenter.object3D.visible = true;
this.cursorBorder.object3D.visible = true;

this.grabbedElement.components["raycaster-target"].isGrabbed = false;

Expand Down
15 changes: 13 additions & 2 deletions quest-extras.html
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,21 @@
color = "#000337">
</a-sky>

<!-- using .environmentGround in raycasting makes performance lag badly; use a simple mesh instead -->
<a-plane
width="100" height="100"
rotation="-90 0 0"
position="0 0.1 0"
visible="false"
class="groundPlane"
raycaster-target>
</a-plane>

<a-entity
id="player"
position="0 0 0"
player-move="controllerListenerId: #controller-data;
navigationMeshClass: environmentGround;">
navigationMeshClass: groundPlane;">

<a-camera></a-camera>

Expand All @@ -72,10 +82,11 @@
oculus-touch-controls="hand: left">
</a-entity>

<!-- experiment with raycasting interval; slight performance improvement but jittery appearance in world -->
<a-entity
id="right-controller"
oculus-touch-controls="hand: right"
raycaster="objects: .raycaster-target, .environmentGround;"
raycaster="objects: .raycaster-target; interval: 0;"
raycaster-extras="controllerListenerId: #controller-data;
beamImageSrc: #gradient; beamLength: 0.5;">
</a-entity>
Expand Down

0 comments on commit 96f26a8

Please sign in to comment.