Skip to content

Commit

Permalink
redesigned link portals
Browse files Browse the repository at this point in the history
also added quest controller interactivity to trigger portals, and fade-in / fade-out effects to smooth visual transition between scenes; all code written as A-Frame components
  • Loading branch information
stemkoski committed Feb 23, 2022
1 parent dfdad02 commit 7a55d9f
Show file tree
Hide file tree
Showing 8 changed files with 236 additions and 186 deletions.
File renamed without changes
Binary file added images/border-rainbow-edge.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/spherical/default-2.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions js/aframe-master-v1.3.0.js
Original file line number Diff line number Diff line change
Expand Up @@ -58922,15 +58922,15 @@ var THREE = require('../lib/three');
module.exports.Component = registerComponent('link', {
schema: {
backgroundColor: {default: 'gray', type: 'color'},
borderColor: {default: 'white', type: 'color'},
borderColor: {default: 'gray', type: 'color'},
highlighted: {default: false},
highlightedColor: {default: '#24CAFF', type: 'color'},
href: {default: ''},
image: {type: 'asset'},
on: {default: 'click'},
peekMode: {default: false},
title: {default: ''},
titleColor: {default: 'white', type: 'color'},
titleColor: {default: '#DDDDDD', type: 'color'},
visualAspectEnabled: {default: false}
},

Expand Down
107 changes: 107 additions & 0 deletions js/camera-fade.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
AFRAME.registerComponent("camera-fade-in", {

schema:
{
active: {type: 'boolean', default: true},
duration: {type: 'float', default: 1.0},
color: {type: 'color', default: "black"},
},

init: function ()
{
this.clock = new THREE.Clock();
this.camera = document.querySelector("a-camera");

if (this.data.active)
this.start();
},

start: function()
{
this.data.active = true;
this.opacity = 1.0;

// add sphere around camera
this.cameraSphere = document.createElement("a-entity");
this.cameraSphere.setAttribute("geometry",
{ primitive: "sphere", radius: 0.5 } );
this.cameraSphere.setAttribute("material",
{ shader: "flat", color: this.data.color,
transparent: true, opacity: 1.0, side: "back" } );
this.camera.appendChild( this.cameraSphere );

this.finished = false;
},

tick: function()
{
let deltaTime = this.clock.getDelta();
if (this.data.active && this.cameraSphere)
{
this.opacity -= deltaTime / this.data.duration;
this.cameraSphere.setAttribute("material", "opacity", this.opacity);
if (this.opacity <= 0)
{
this.data.active = false;
this.finished = true;
// must remove sphere, otherwise causes transparency flickering issues
this.camera.removeChild( this.cameraSphere );
this.cameraSphere = null;
}
}
}
});

AFRAME.registerComponent("camera-fade-out", {

schema:
{
active: {type: 'boolean', default: false},
duration: {type: 'float', default: 1.0},
color: {type: 'color', default: "black"},
},

init: function ()
{
this.clock = new THREE.Clock();
this.camera = document.querySelector("a-camera");

if (this.data.active)
this.start();
},

start: function()
{
this.data.active = true;
this.opacity = 0.0;

// add sphere around camera
this.cameraSphere = document.createElement("a-entity");
this.cameraSphere.setAttribute("geometry",
{ primitive: "sphere", radius: 0.5 } );
this.cameraSphere.setAttribute("material",
{ shader: "flat", color: this.data.color,
transparent: true, opacity: 0.0, side: "back" } );
this.camera.appendChild( this.cameraSphere );

this.finished = false;
},

tick: function()
{
let deltaTime = this.clock.getDelta();
if (this.data.active)
{
this.opacity += deltaTime / this.data.duration;
this.cameraSphere.setAttribute("material", "opacity", this.opacity);
if (this.opacity >= 1)
{
this.data.active = false;
this.finished = true;
// no need to remove sphere, because nothing is visible anyway
// this.camera.removeChild( this.cameraSphere );
// this.cameraSphere = null;
}
}
}
});
81 changes: 81 additions & 0 deletions js/link-extras.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
AFRAME.registerComponent("link-extras", {
init: function ()
{
// note: modified a-frame a-link code directly, to:
// - change default background color of portal when distance to camera is large
// - change default color of title text

// construct a torus surrounding link portal
this.torus = document.createElement("a-entity");
this.torus.setAttribute("geometry",
{ primitive: "torus", radius: 1.0, radiusTubular: 0.04, segmentsTubular: 64} );
this.torus.setAttribute("material",
{ src: "#portalBorder", repeat: "16 1", color: "white"} );
this.el.appendChild( this.torus );

// use for animating torus material
this.clock = new THREE.Clock();
this.materialOffset = {x : 0, y: 0};

// create a single invisible object to get raycaster focus
this.cylinder = document.createElement("a-entity");
this.cylinder.setAttribute("geometry",
{ primitive: "cylinder", radius: 1.1, height: 0.2} );
this.cylinder.setAttribute("material",
{ blending: "additive", color: "#222222",
transparent: true, opacity: 0.0 } );
this.cylinder.setAttribute("rotation", "90 0 0");
this.cylinder.setAttribute("class", "raycaster-target");
this.cylinder.setAttribute("raycaster-hover", "");
this.el.appendChild( this.cylinder );

let self = this;

// change opacity so alpha blending highlights all objects in portal
this.cylinder.addEventListener("raycaster-intersected", function(event)
{
self.cylinder.setAttribute("material", "opacity", 1.0);
}
);
this.el.addEventListener("raycaster-intersected-cleared", function(event)
{
self.cylinder.setAttribute("material", "opacity", 0.0);
}
);

// stop accidental "click" event.
// note: seem to be unable to change this using schema when initialized
this.el.components["link"].data.on = "nope";

// use controller to determine when to activate link
this.rightController = document.querySelector("#right-controller-entity");
this.rightData = this.rightController.components["controller-listener"];

// when link activated,
// will fade out if camera-fade-out component is present on camera
this.camera = document.querySelector("a-camera");
},

tick: function()
{
// update portal texture data
let deltaTime = this.clock.getDelta();
this.materialOffset.x += deltaTime / 4;
this.materialOffset.y -= deltaTime / 2;
this.torus.setAttribute("material", "offset", this.materialOffset);

this.hoverData = this.cylinder.components["raycaster-hover"].data;

// navigate to new page
// TODO: if camera-fade-out is not present, then navigate immediately
if ( this.hoverData.hasFocus && this.rightData.trigger.pressed)
this.camera.components["camera-fade-out"].start();

if ( this.camera.components["camera-fade-out"].finished )
{
this.el.components["link"].navigate();
// change finished to false to prevent spamming navigate function, which causes problems
this.camera.components["camera-fade-out"].finished = false;
}
}
});
109 changes: 21 additions & 88 deletions quest-portal-1.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,85 +10,19 @@
<script src="js/player-move.js"></script>
<script src="js/raycaster-graphics.js"></script>
<script src="js/raycaster-controller-grabber.js"></script>
<script src="js/camera-fade.js"></script>
<script src="js/link-extras.js"></script>
</head>

<body>

<script>
// if raycaster is pointing at this object, press trigger to change color
AFRAME.registerComponent("raycaster-color-change", {
init: function ()
{
this.colors = ["red", "orange", "yellow", "green", "blue", "violet"];

this.intersecting = false;
let self = this;

// this happens once, when intersection begins
this.el.addEventListener("raycaster-intersected", function(event)
{ self.intersecting = true; } );

// this happens once, when intersection ends
this.el.addEventListener("raycaster-intersected-cleared", function(event)
{ self.intersecting = false; } );

this.rightController = document.querySelector("#right-controller-entity");
this.rightData = this.rightController.components["controller-listener"];
},

tick: function()
{
// this.rightData = this.rightController.components["controller-listener"]; // remove?
if (this.intersecting && this.rightData.trigger.pressed )
{
let index = Math.floor( this.colors.length * Math.random() );
let color = this.colors[index];
this.el.setAttribute("color", color);
}

if (!this.intersecting || this.rightData.trigger.released)
{
this.el.setAttribute("color", "#CCCCCC");
}
}
});

AFRAME.registerComponent("link-extras", {
init: function ()
{

// note: modified a-frame code to change background color of portal when fading into the distance

// construct a torus surrounding link portal

// used for animating material
this.clock = new THREE.Clock();

// get controllers listener
this.barAlpha = 0;

// change "go" event on associated link
},

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

// change material offset x or y or both for spinning-rotating effect?

// if holding down both triggers within distance X of portal,
// start to fade; 3-second countdown
// after that emit the event that triggers the URL change set in init
}
});

</script>
<script></script>

<a-scene environment="preset: default;" renderer="antialias: true;">

<a-assets>
<img id="gradient" src="images/gradient-fade.png" />
<img id="portalBorder" src="images/border-rainbow.png" />
<img id="portalBorder" src="images/border-rainbow-edge.png" />
<!-- 360 image for portal preview -->
<img id="previewForest" src="images/spherical/forest.jpg">

Expand All @@ -100,7 +34,10 @@

<a-entity id="player" position="0 0 0" player-move>

<a-camera></a-camera>
<a-camera
camera-fade-in="active: true;"
camera-fade-out>
</a-camera>

<a-entity
visible="true"
Expand All @@ -121,6 +58,19 @@

</a-entity>


<!-- portal -->

<a-link
position="5 1.6 -3"
href="quest-portal-2.html"
title="Forest"
image="#previewForest"
link-extras>
</a-link>

<!-- scenery -->

<a-torus-knot
p="2" q="3" radius="0.5" radius-tubular="0.1"
position = "-2.5 1.5 -4"
Expand Down Expand Up @@ -171,23 +121,6 @@
raycaster-hover>
</a-torus>

<!-- portal -->

<a-link
position="4 1.6 -6"
href="portal-forest.html"
title="Forest"
backgroundColor="blue"
image="#previewForest">
<a-torus
radius="1" radius-tubular="0.04"
position = "0 0 0"
rotation = "0 0 0"
material="src: #portalBorder; repeat: 16 4; color: yellow;"
class="raycaster-target"
raycaster-hover>
</a-torus>
</a-link>



Expand Down
Loading

0 comments on commit 7a55d9f

Please sign in to comment.