the camera position is currently a bit off in the Vive. checkout this commit commit hash 48e99fbb1bc66bd4b890d8bb170287d61092109e
for a version where the camera position tracks the Vive HMD position when in VR. follow the stackoverflow question how to reset camera position on enter VR? for a possible method to show a custom camera position in 2D mode and a glued-to-the-hmd camera position when in VR
–<>–
a roomscale VR scene targeting the HTC Vive
use the front-trigger on either Vive controller to pick up and inspect a block
block a-boxes positions are closer to the origin than in previous examples so that they are within reach from in roomscale VR. ROADMAP: teleport locomotion ;-)
many thanks to @bryik_ws, @utopiah, @donrmccurdy over at the A-Frame slack for help getting the interaction working.
do get a slack invite of your own and check out the other places the A-Frame community gathers
all the blocks with thumbnail images created during the 2016 #d3unconf
here we use aframe’s a-boxes
, which are kind of like SVG rects
a fork of aframe + d3 + bl.ocks from @donrmccurdy
falling blocks brought to you by the aframe-physics-system, also from @donrmccurdy
inspired by the conversations at the 3d and VR 11am session in the Alcatraz Room at the 2016 d3 unconference
forked from micahstubbs‘s block: aframe-blocks roomscale 03
forked from anonymous‘s block: aframe-blocks roomscale 03 -
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>A-Frame / Bl.ocks / D3</title>
<script src="https://rawgit.com/aframevr/aframe/master/dist/aframe-master.min.js"></script>
<script src="https://cdn.rawgit.com/donmccurdy/aframe-physics-system/v1.2.0/dist/aframe-physics-system.min.js"></script>
<script src="aframe-extras.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.7/d3.js"></script>
</head>
<body>
<!-- normal earth gravity, normal physics mode -->
<a-scene physics="debug: false; restitution: 0.001; friction: 0.5; gravity: -2">
<!-- Player -->
<a-entity id='cameraWrapper' position='1 1.8034 1' rotation='-35 30 0'>
<a-entity camera look-controls wasd-controls="fly: true"></a-entity>
</a-entity>
<!-- Terrain -->
<a-plane static-body color="#CCCCCC" height="100" width="100" rotation="-90 0 0"></a-plane>
<!-- Lighting -->
<a-entity light="type: point; color: #f4f4f4; intensity: 0.2; distance: 0" position="8 10 18"></a-entity>
<a-entity light="type: point; color: #f4f4f4; intensity: 0.6; distance: 0" position="-8 10 -18"></a-entity>
<a-entity light="type: ambient; color: #f4f4f4; intensity: 0.4;" position="-8 10 -18"></a-entity>
</a-scene>
<script>
function render () {
d3.json('blocks.json', function(blocks) {
//
// build a table
//
const table = {
center: {
x: 0.2,
y: 0.75,
z: -0.5
},
width: 3.6,
height: 0.05,
depth: 1.6,
color: 'darkgray',
leg: {
width: 0.1,
depth: 0.1
}
}
// table top
d3.select('a-scene')
.append('a-box')
.attr('static-body', '')
.attr('position', `${table.center.x} ${table.center.y} ${table.center.z}`)
.attr('width', table.width)
.attr('height', table.height)
.attr('depth', table.depth)
.attr('color', table.color);
// //stackoverflow.com/questions/5834318/are-variable-operators-possible
// operators
const ops = {
'+': (a, b) => a + b,
'-': (a, b) => a - b
};
legPositionSigns = [
['+', '-', '+', '-'],
['-', '+', '+', '-'],
['+', '-', '-', '+'],
['-', '+', '-', '+']
];
legPositionSigns.forEach(d => {
const x = ops[d[1]](ops[d[0]](table.center.x, (table.width / 2)), (table.leg.width / 2));
const y = 0;
const z = ops[d[3]](ops[d[2]](table.center.z, (table.depth / 2)), (table.leg.depth / 2));
d3.select('a-scene')
.append('a-box')
.attr('static-body', '')
.attr('position', `${x} ${y} ${z}`)
.attr('width', table.leg.width)
.attr('height', table.center.y * 2)
.attr('depth', table.leg.depth)
.attr('color', table.color);
})
//
// create cards with d3 blocks on them
// drop the cards on the table
//s
//
// for each d3 example in the blocks data
// add an a-box to the scene
// with the thumbnail of that d3 example
// as the image texture for that a-box
//
const r = 0.5;
d3.select('a-scene')
.append('a-entity')
.attr('id', 'blocks')
.selectAll('.throwable')
.data(blocks)
.enter()
.append('a-box')
.classed('block', true)
.classed('throwable', true)
//.attr('dynamic-body', '')
.attr('dynamic-body', '')
// .attr('velocity', '')
.attr('width', 0.48)
.attr('height', 0.25)
.attr('depth', 0.25)
//.attr('scale', {x: 0.48, y: 0.25, z: 0.025})
.attr('position', (d, i) => ({
x: (i + 2) * 0.008,
y: (i / 3) + 0.075 + table.center.y,
z: 0.05 - (Math.random() *2)
}))
.attr('rotation', "-90 0 0")
.attr('material', (d) => {
const thumbnailUrl = `url(//gist.githubusercontent.com/${d.owner.login}/${d.id}/raw/${d.sha}/thumbnail.png)`;
// const thumbnailUrl = `url(//bl.ocks.org/${d.owner.login}/raw/${d.id}/${d.sha}/thumbnail.png)`
return { src: thumbnailUrl };
});
//
// after adding all grabbable objects to the scene
// add the Vive controllers
//
// add left controller
d3.select('a-scene')
.append('a-entity')
.attr('id', 'leftController')
.attr('vive-controls', 'hand: left')
.attr('static-body', 'shape: sphere; sphereRadius: 0.02;')
.attr('sphere-collider', 'objects: .throwable')
.attr('grab', '');
// add right controller
d3.select('a-scene')
.append('a-entity')
.attr('id', 'rightController')
.attr('vive-controls', 'hand: right')
.attr('static-body', 'shape: sphere; sphereRadius: 0.02;')
.attr('sphere-collider', 'objects: .throwable')
.attr('grab', '');
//
// if a VR display (like the Vive headset begins presenting
// (if the scene goes into VR mode)
// reset the camera position and rotation
//
window.onvrdisplaypresentchange = function() {
const VRDisplays = Navigator.getVRDisplays()
const VRDisplay = VRDisplays[0];
const pose = VRDisplay.getPose();
console.log('VRDisplay pose', pose);
// d3.select('#cameraWrapper')
// .attr('position', '0 0 0')
// .attr('rotation', '0 0 0');
}
});
}
var sceneEl = document.querySelector('a-scene');
if (sceneEl.hasLoaded) {
render();
} else {
sceneEl.addEventListener('loaded', render);
}
</script>
</body>
</html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no,user-scalable=no,maximum-scale=1">
<title>Examples • Vive</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r81/three.min.js"></script>
<script src="aframe.min.js"></script>
<script src="aframe-extras.js"></script>
</head>
<body>
<a-scene physics="debug: true">
<!-- Player -->
<a-entity camera look-controls></a-entity>
<a-entity static-body="shape: sphere; sphereRadius: 0.02;" vive-controls="hand: left" sphere-collider="objects: .cube;" grab></a-entity>
<a-entity static-body="shape: sphere; sphereRadius: 0.02;" vive-controls="hand: right" sphere-collider="objects: .cube;" grab></a-entity>
<a-box class="cube" dynamic-body position="0 0.25 -1" width="0.5" height="0.5" depth="0.5" color="red"></a-box>
<a-box class="cube" dynamic-body position="-1 0.25 -1" width="0.5" height="0.5" depth="0.5" color="green"></a-box>
<a-box class="cube" dynamic-body position="1 0.25 -1" width="0.5" height="0.5" depth="0.5" color="blue"></a-box>
<!-- Terrain -->
<a-grid static-body></a-grid>
<!-- Lighting -->
<a-entity light="type: point; color: #f4f4f4; intensity: 0.2; distance: 0" position="8 10 18"></a-entity>
<a-entity light="type: point; color: #f4f4f4; intensity: 0.6; distance: 0" position="-8 10 -18"></a-entity>
<a-entity light="type: ambient; color: #f4f4f4; intensity: 0.4;" position="-8 10 -18"></a-entity>
</a-scene>
</body>
</html>
[
{
"id":"3757fe53ea94da4100db2e5071ea8289",
"sha":"f37923e838ee6db8fcb20091d305ebce04404f1b",
"description":"d3 blocks on a-boxes",
"owner":{
"login":"micahstubbs"
}
},
{
"id":"e70e14483fe01eb0a3ea7d1d46a30571",
"sha":"7e3906f8d8a9e5d79d61f2b77cc16f2829cb4a92",
"description":"Musical Hexagons",
"owner":{
"login":"vasturiano"
}
},
{
"id":"0ba5ee8bd3773d70462523679d4ef5a4",
"sha":"30d1ebaccc65e061989090e948526917c09db5f7",
"description":"Delaunay Force Mesh II",
"owner":{
"login":"erlenstar"
}
},
{
"id":"de2b023d968abb7276b894409efdac56",
"sha":"2a168d34c566b37bbdacbeb144c8ff9e14a32175",
"description":"merging selections",
"owner":{
"login":"enjalot"
}
},
{
"id":"7d3f8beb9faa183fc8d4fe3fd1610e00",
"sha":"b92274a2b8d9e8653ca020d89bc42e75c086bf09",
"description":"d3 yoga",
"owner":{
"login":"enjalot"
}
},
{
"id":"57fbb830ba7e62caa46a82891168bc29",
"sha":"a5ae874d673654d9fc7a18e09efca0591082b8bb",
"description":"CMYK zoom",
"owner":{
"login":"veltman"
}
},
{
"id":"e8ccca52559796be775553b467593a9f",
"sha":"269b11fe342729ca6a70db087ff0e3f2fd8b2122",
"description":"Continuous Legend",
"owner":{
"login":"syntagmatic"
}
},
{
"id":"6c73711f8f24af9808a9031a69f75b18",
"sha":"52e696e66b5bb8d833b82ea5b429532a4336f96f",
"description":"Stereographic",
"owner":{
"login":"erlenstar"
}
},
{
"id":"a1eb3bdecd2ab1be1de2425a260cc0f7",
"sha":"feca193fc32e1606b0e53a9a873c797f2e332b64",
"description":"Spirograph Geometric Flowers",
"owner":{
"login":"EfratVil"
}
},
{
"id":"8c5a0e697673fd676be6823589e1ce31",
"sha":"40dcc4e31ed53cb403e36dd07288678f21ae6cfe",
"description":"stroke-dash-array",
"owner":{
"login":"jermspeaks"
}
},
{
"id":"b04d673fbfc665f2c98f382e2c79a9ad",
"sha":"6e7cf7e122c99bfa6bfa47e6f035472020e9730a",
"description":"Voronoi Tessellation",
"owner":{
"login":"git-ashish"
}
},
{
"id":"1fd92b8c309a0fdc71b0a64c788a70e7",
"sha":"227f453f79e7f56e2c4cbec1dc0110bfe5960e18",
"description":"Canvas Voronoi",
"owner":{
"login":"git-ashish"
}
},
{
"id":"6a6c2f11f9493adba658003a5a18a107",
"sha":"d7c669281c38b23d8b21eecb56ed6991e6d2c10b",
"description":"Voronoi Labels",
"owner":{
"login":"git-ashish"
}
},
{
"id":"a5d147cd45c624e8811238f0a5480439",
"sha":"7341de0028d33120fa8316619b8d0e6fdb170410",
"description":"Comunidad Valenciana population(d3v4)",
"owner":{
"login":"LuisSevillano"
}
},
{
"id":"cd0c38a20141e997e926592264067db3",
"sha":"5766833b6df73d777c7b6f10b3fc088bf32d99b2",
"description":"cluster force",
"owner":{
"login":"ericsoco"
}
},
{
"id":"50a350e86de82278ffb2df248499d3e2",
"sha":"137caaf4c0de8590d808ee35bf2ab6668109374c",
"description":"CMYK halftone printing",
"owner":{
"login":"veltman"
}
},
{
"id":"32f369bb437d7c23198b9b9ccc8d4751",
"sha":"c7f2be04e7fe9a4781940e73fb1896eb471714db",
"description":"d3.unconf 2016, v11",
"owner":{
"login":"micahstubbs"
}
},
{
"id":"a7495ca3d5b322a6697530feb62fceef",
"sha":"719e306c9885a691244c01a228aa84ca594b299a",
"description":"Painting Manhattan-distance Voronoi",
"owner":{
"login":"Fil"
}
},
{
"id":"99767e64051096388078913afca3ff4e",
"sha":"ac755a56347c9941c8e0d27067e69cdc41b4c0b9",
"description":"Choropleth with d3-cluster-scale",
"owner":{
"login":"schnerd"
}
},
{
"id":"82144236b9a920f77e3af1776d265c57",
"sha":"ff6b6f78560e73ddc3735ded012fba7524bfbc8b",
"description":"d3.unconf 2016, v10",
"owner":{
"login":"sxywu"
}
}
]