I got a few things straightened out with using both CSS3D and WebGl in a family tree viz. Lots still to do (especially on colors), but this seems pretty cool so far. Screenshots and some notes are below.
The name is a hyperlink that works
Styling of the div is from basic css - scrollbar just to see if that worked (it does)
The latest efforts leaned heavily on:
- Jerome Etienne's slick work from 2013 using CSS3D and WebGl - Mixing HTML Pages Inside Your WebGL/
- Steve Hall's work incorporating d3 and three.js using the CSS3DRenderer - http://projects.delimited.io/experiments/d3-threejs/ (which itself is partially based on mrdoob's periodic table example
The initial things worked out here had to do with getting html components to show up and be (mostly) placed properly in a 3D scene. This is done using the THREE.js CSS3DRenderer that mrdoob initially created back in 2012, coupled with Etienne's example. I also had to pull out the CSS3DRenderer.js and Projector.js from version 58 of three.js - I haven't gone back to see what the underlying problems were, but the latest wasn't working, and Etienne's (working) example used version 58.
The main idea is that for every little html element you want to use as a CSS3D object, you need to create a plane of the same size in the webgl space with opacity 0 and having blending function THREE.NoBlending:
//create the div that will ultimately be put into 3D vis CSS3
var element = document.createElement('div');
//...details left out on adding the name and lifespan info
var eInfo = {width:200, height:50, scaleX:0.25, scaleY: 0.25,z:1};
element.style.width = eInfo.width + 'px';
element.style.height = eInfo.height + 'px';
element.style.opacity = 1;
element.style.top = '0';
element.className += ' css3d-name-div';
//"node" contains info on the person;
// node color is based on gender
element.style.border = '3px solid ' + node.getBasicColor();
//create the CSS3D Object
var objectCSS = new THREE.CSS3DObject( element );
//place it where the original node was (//flip the y here)
objectCSS.position.set(node.x,height-node.y,eInfo.z);
objectCSS.scale.set(eInfo.scaleX,eInfo.scaleY,1);
//separate scene is used for the CSS3D objects
sceneCSS.add(objectCSS);
//create the webgl plane that has the same size, scaling, position, and
// rotation of the corresponding CSS3D object
var geometry = new THREE.PlaneGeometry(eInfo.width, eInfo.height);
//material with special properties for this!
var material = new THREE.MeshBasicMaterial({
blending: THREE.NoBlending,
transparent: true,
opacity:0.0,
side: THREE.DoubleSide,
color: 0x000000} );
var plane = new THREE.Mesh( geometry, material );
plane.scale.copy(objectCSS.scale);
plane.position.copy(objectCSS.position);
// do this in general so that the plane is oriented the
// same as the CSS3DObject:
plane.rotation.copy(objectCSS.rotation);
//separate scene is used for the webgl objects
scene.add(plane);
and the correspondig webgl plane object
I also confirmed that it's not hard to transition Bezier curves to the side of a cylinder - this was done as part of a test transition of the family tree to a cylinder, implemented based on how Steve Hall transitioned his d3 graphs to a helix shape.
- Fixed. This was due to a stray copy-paste margin-top of -2px.Proper placement of the "hidden" plane behind every CSS3D object that handles the magic of letting the CSS3D object blend in the scene - this means understanding what the "NoBlending" even does, and exactly how the size of the CSS3D rectangles is determined. There are some slight unwanted offsets in the current implementation.
- More 3D cues - there are a number of things to look at here
Longer-term, it's unclear what the best way is - if any - to incorporate 3D into something like this. However, there are certainly lots of things to explore. And once the Oculus Rift is out early next year, it will be interesting to see what possibilities open up - for example, you could be in the middle of the cylindrical family tree. Cool stuff.
No comments:
Post a Comment