Using Mr. Doob's excellent example, available at http://threejs.org/examples/css3d_molecules.html, I want to create a webpage showing TWO 3D chemical structures next to each other:

As you can see, I'm struggling with the structure on the right half. Both halves are <div> with appropriate id's containerleft and containerright and ugly background colors :). I tried duplicating all variables and assigning them each to one container, to no avail.
I have found a three.js example with multiple views using WebGL, unfortunately I can not use WebGL.
Please find the code I am using below. It is a stripped down version from examples/css3d_molecules.html at https://github.com/mrdoob/three.js.
<div id="containerleft"></div>
<div id="containerright"></div>
<!-- *** 3D MOLECULE *** -->
<script src="../../../www/js/three/three.min.js"></script>
<script src="../../../www/js/three/TrackballControls.js"></script>
<script src="../../../www/js/three/CSS3DRenderer.js"></script>
<script src="../../../www/js/three/PDBLoader.js"></script>
<script>
var cameraleft, scene, renderer;
var controls;
var root;
var objects = [];
var tmpVec1 = new THREE.Vector3();
var tmpVec2 = new THREE.Vector3();
var tmpVec3 = new THREE.Vector3();
var tmpVec4 = new THREE.Vector3();
var visualizationType = 2;
var loader = new THREE.PDBLoader();
var colorSpriteMap = {};
var baseSprite = document.createElement( 'img' );
init();
animate();
function init() {
cameraleft = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 5000 );
cameraleft.position.z = 1500;
scene = new THREE.Scene();
root = new THREE.Object3D();
scene.add( root );
//
renderer = new THREE.CSS3DRenderer();
renderer.setSize( window.innerWidth / 2, window.innerHeight);
document.getElementById('containerleft').appendChild( renderer.domElement );
//
controls = new THREE.TrackballControls( cameraleft, renderer.domElement );
controls.rotateSpeed = 0.5;
controls.addEventListener( 'change', render );
//
baseSprite.onload = function () {
loadMolecule( "models/molecules/h2co3.pdb" );
};
baseSprite.src = 'textures/sprites/ball.png';
//
window.addEventListener( 'resize', onWindowResize, false );
}
//
function generateButtonCallback( url ) {
return function ( event ) {
loadMolecule( url );
}
}
function showAtomsBonds() {
for ( var i = 0; i < objects.length; i ++ ) {
var object = objects[ i ];
object.element.style.display = "";
object.visible = true;
if ( ! ( object instanceof THREE.CSS3DSprite ) ) {
object.element.style.height = object.userData.bondLengthShort;
}
}
}
//
function colorify( ctx, width, height, color, a ) {
var r = color.r;
var g = color.g;
var b = color.b;
var imageData = ctx.getImageData( 0, 0, width, height );
var data = imageData.data;
for ( var y = 0; y < height; y ++ ) {
for ( var x = 0; x < width; x ++ ) {
var index = ( y * width + x ) * 4;
data[ index ] *= r;
data[ index + 1 ] *= g;
data[ index + 2 ] *= b;
data[ index + 3 ] *= a;
}
}
ctx.putImageData( imageData, 0, 0 );
}
function imageToCanvas( image ) {
var width = image.width;
var height = image.height;
var canvas = document.createElement( 'canvas' );
canvas.width = width;
canvas.height = height;
var context = canvas.getContext( '2d' );
context.drawImage( image, 0, 0, width, height );
return canvas;
}
//
function loadMolecule( url ) {
for ( var i = 0; i < objects.length; i ++ ) {
var object = objects[ i ];
object.parent.remove( object );
if ( object.element.parentNode === renderer.cameraElement ) {
renderer.cameraElement.removeChild( object.element );
}
if ( object.userData.joint ) {
object.userData.joint.parent.remove( object.userData.joint );
}
}
objects = [];
loader.load( url, function ( geometry, geometryBonds ) {
var offset = THREE.GeometryUtils.center( geometry );
geometryBonds.applyMatrix( new THREE.Matrix4().makeTranslation( offset.x, offset.y, offset.z ) );
for ( var i = 0; i < geometry.vertices.length; i ++ ) {
var position = geometry.vertices[ i ];
var color = geometry.colors[ i ];
var element = geometry.elements[ i ];
if ( ! colorSpriteMap[ element ] ) {
var canvas = imageToCanvas( baseSprite );
var context = canvas.getContext( '2d' );
colorify( context, canvas.width, canvas.height, color, 1 );
var dataUrl = canvas.toDataURL();
colorSpriteMap[ element ] = dataUrl;
}
colorSprite = colorSpriteMap[ element ];
var atom = document.createElement( 'img' );
atom.src = colorSprite;
var object = new THREE.CSS3DSprite( atom );
object.position.copy( position );
object.position.multiplyScalar( 75 );
object.billboard = true;
object.matrixAutoUpdate = false;
object.updateMatrix();
root.add( object );
objects.push( object );
}
for ( var i = 0; i < geometryBonds.vertices.length; i += 2 ) {
var start = geometryBonds.vertices[ i ];
var end = geometryBonds.vertices[ i + 1 ];
start.multiplyScalar( 75 );
end.multiplyScalar( 75 );
tmpVec1.subVectors( end, start );
var bondLength = tmpVec1.length() - 50;
//
var bond = document.createElement( 'div' );
bond.className = "bond";
bond.style.height = bondLength + "px";
var object = new THREE.CSS3DObject( bond );
object.position.copy( start );
object.position.lerp( end, 0.5 );
object.userData.bondLengthShort = bondLength + "px";
object.userData.bondLengthFull = ( bondLength + 55 ) + "px";
//
var axis = tmpVec2.set( 0, 1, 0 ).cross( tmpVec1 );
var radians = Math.acos( tmpVec3.set( 0, 1, 0 ).dot( tmpVec4.copy( tmpVec1 ).normalize() ) );
var objMatrix = new THREE.Matrix4().makeRotationAxis( axis.normalize(), radians );
object.matrix = objMatrix;
object.rotation.setEulerFromRotationMatrix( object.matrix, object.eulerOrder );
object.matrixAutoUpdate = false;
object.updateMatrix();
root.add( object );
objects.push( object );
//
var bond = document.createElement( 'div' );
bond.className = "bond";
bond.style.height = bondLength + "px";
var joint = new THREE.Object3D( bond );
joint.position.copy( start );
joint.position.lerp( end, 0.5 );
joint.matrix.copy( objMatrix );
joint.rotation.setEulerFromRotationMatrix( joint.matrix, joint.eulerOrder );
joint.matrixAutoUpdate = false;
joint.updateMatrix();
var object = new THREE.CSS3DObject( bond );
object.rotation.y = Math.PI/2;
object.matrixAutoUpdate = false;
object.updateMatrix();
object.userData.bondLengthShort = bondLength + "px";
object.userData.bondLengthFull = ( bondLength + 55 ) + "px";
object.userData.joint = joint;
joint.add( object );
root.add( joint );
objects.push( object );
}
showAtomsBonds();
render();
} );
}
//
function onWindowResize() {
cameraleft.aspect = window.innerWidth / window.innerHeight;
cameraleft.updateProjectionMatrix();
renderer.setSize( (window.innerWidth/2), window.innerHeight );
render();
}
function animate() {
requestAnimationFrame( animate );
controls.update();
var time = Date.now() * 0.0004;
root.rotation.x = time;
root.rotation.y = time * 0.7;
render();
}
function render() {
renderer.render( scene, cameraleft );
}
</script>
Thanks!
Using the CSS3DRenderer, looks like duplicating all the code is the only way to achieve that so far.
I am creating an interactive stereo viewer for iPad (like some other students already made, but a HTML version), and for that I need two equal images, with a little difference in the camera position. For the WebGL renderer, there is already a library for that, but looks that CSS3 until holds some limitation that prevents us to make same thing.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With