Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

three.js properly blending css3d and webgl

Tags:

html

css

three.js

I am trying to combine webgl and css3d scenes so that the objects in the two scenes properly blend together. I am following the pattern described here:

and have created a simple example by modifying the three.js example css3d_sandbox.html.

In my version I have added a cube to the webGl scene and expect it to properly blend with the existing planes whether the cube is in front of or behind those objects.

I notice two anomalies. The first is that once the cube is added the planes disappear in unexpected positions as you pan around as if the far and near plane values are not being honored correctly or the objects are being incorrectly determined to be behind something else.

The second issue is that the css3d objects do not render at all when running against three.js r67, but they do render when running against r61. I tried replacing the r67 version of CSS3DRenderer.js with r61, but still do not see any css3d objects.

In r67 when the line to add the webGl dom as a child of the css3d dom is commented out, the css3d objects do appear.

I would appreciate any suggestions on how to resolve these issues. Sample code is below and may be run by dropping into any version of the three.js examples folder (e.g. r61 or r67).

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <style>
            body {
                background-color: #ffffff;
                margin: 0;
                overflow: hidden;
            }
            #info {
                position: absolute;
                top: 0px;
                width: 100%;
                color: #000000;
                padding: 5px;
                font-family: Monospace;
                font-size: 13px;
                text-align: center;
                z-index: 1;
            }

            a {
                color: #000000;
            }

        </style>
    </head>
    <body>
        <div id="info"><a href="http://threejs.org" target="_blank">three.js</a> - css3d sandbox</div>

        <script src="../build/three.min.js"></script>

        <script src="js/controls/TrackballControls.js"></script>

        <!--<script src="js/renderers/CSS3DRenderer-r61.js"></script>-->
        <script src="js/renderers/CSS3DRenderer.js"></script>

        <script>

            var camera, sceneGl, rendererGl;

            var sceneCss, rendererCss;

            var controls;

            init();
            animate();

            function init() {

                camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 1000 );
                camera.position.set( 200, 200, 200 );

                controls = new THREE.TrackballControls( camera );

                sceneGl = new THREE.Scene();
                sceneCss = new THREE.Scene();

                var material = new THREE.MeshBasicMaterial( { color: 0x000000, opacity : 0.0 } );
                material.blending  = THREE.NoBlending;

                //
                var xpos = [50, -10, 30, 70, 110];
                var ypos = [60, -40, 0, 40, 80];
                var zpos = [-30, -50, 0, 50, 100];

                for ( var i = 0; i < 5; i ++ ) {

                    var element = document.createElement( 'div' );
                    element.style.width = '100px';
                    element.style.height = '100px';
                    element.style.opacity = 1.0;
                    element.style.background = new THREE.Color( Math.random() * 0xffffff ).getStyle();

                    var object = new THREE.CSS3DObject( element );
                    object.position.x = xpos[i];
                    object.position.y = ypos[i];
                    object.position.z = zpos[i];
                    object.rotation.x = Math.PI/(i + 5);
                    object.rotation.y = Math.PI/(21 - 2 * i);
                    object.rotation.z = Math.PI/(3 * i + 25);
                    object.scale.x = i/12 + 0.5;
                    object.scale.y =  1/ (12 - i) + 0.5;
                    sceneCss.add( object );


                    var geometry = new THREE.PlaneGeometry( 100, 100 );
                    var mesh = new THREE.Mesh( geometry, material );
                    mesh.position.copy( object.position );
                    mesh.rotation.copy( object.rotation );
                    mesh.scale.copy( object.scale );
                    sceneGl.add( mesh );

                }


                //
                var boxGeom = new THREE.CubeGeometry( 60, 60, 60 );

                var cubeMaterial = new THREE.MeshBasicMaterial( 
                    { color: 0x05009A, shading : THREE.FlatShading, side: THREE.FrontSide } );

                var cube = new THREE.Mesh( boxGeom, cubeMaterial );
                cube.position.copy(  new THREE.Vector3(100, 75, 50) );
                cube.rotation.copy( Math.PI/ 6 );

                sceneGl.add( cube );


                rendererCss = new THREE.CSS3DRenderer();
                rendererCss.setSize( window.innerWidth, window.innerHeight );
                rendererCss.domElement.style.position = 'absolute';
                rendererCss.domElement.style.top = 0;

                rendererGl = new THREE.WebGLRenderer();
                rendererGl.setClearColor( 0xf0f0f0 );

                rendererGl.setSize( window.innerWidth, window.innerHeight );

                rendererGl.domElement.style.position    = 'absolute';
                rendererGl.domElement.style.zIndex = 1;
                rendererGl.domElement.style.top = 0;
                rendererCss.domElement.appendChild( rendererGl.domElement );

                document.body.appendChild( rendererCss.domElement );

            }

            function animate() {

                requestAnimationFrame( animate );

                controls.update();

                rendererGl.render( sceneGl, camera );
                rendererCss.render( sceneCss, camera );

            }

        </script>
    </body>
</html>

Here is a fiddle with the code.

like image 321
David Avatar asked Jul 10 '14 15:07

David


1 Answers

The link in the comment was helpful. As that solution mentions, setting alpha to true solves the issue of getting the css3d objects to render using r67. Making the webGl background transparent solves the problem of the css3d objects disappearing when panning around.

The solution mentioned in the link however adds both the webgl and css3d dom as child elements of the document. This approach did not work in my case. I find it necessary to still have the webgl dom as a child of the css3d dom for the cube to blend correctly with the planes when it is both in front of and behind those objects.

Working code below:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <style>
            body {
                background-color: #ffffff;
                margin: 0;
                overflow: hidden;
            }

        </style>
    </head>
    <body>

        <script src="../build/three.min.js"></script>

        <script src="js/controls/TrackballControls.js"></script>

        <script src="js/renderers/CSS3DRenderer.js"></script>

        <script>

        var camera, sceneGl, rendererGl;
var sceneCss, rendererCss;
var controls;

init();
animate();

function init() {

    camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
    camera.position.set(200, 200, 200);

    controls = new THREE.TrackballControls(camera);

    sceneGl = new THREE.Scene();
    sceneCss = new THREE.Scene();

    var material = new THREE.MeshBasicMaterial({
        color: 0x000000,
        opacity: 0.0,
        side: THREE.DoubleSide
    });

    var xpos = [50, -10, 30, 70, 110];
    var ypos = [60, -40, 0, 40, 80];
    var zpos = [-30, -50, 0, 50, 100];

    for (var i = 0; i < 5; i++) {

        var element = document.createElement('div');
        element.style.width = '100px';
        element.style.height = '100px';
        element.style.opacity = 1.0;
        element.style.background = new THREE.Color(Math.random() * 0xff0000).getStyle();

        var object = new THREE.CSS3DObject(element);
        object.position.x = xpos[i];
        object.position.y = ypos[i];
        object.position.z = zpos[i];
        object.rotation.x = Math.PI / (i + 5);
        object.rotation.y = Math.PI / (21 - 2 * i);
        object.rotation.z = Math.PI / (3 * i + 25);
        object.scale.x = i / 12 + 0.5;
        object.scale.y = 1 / (12 - i) + 0.5;
        sceneCss.add(object);


        var geometry = new THREE.PlaneGeometry(100, 100);
        var mesh = new THREE.Mesh(geometry, material);
        mesh.position.copy(object.position);
        mesh.rotation.copy(object.rotation);
        mesh.scale.copy(object.scale);
        sceneGl.add(mesh);

    }


    var boxGeom = new THREE.CubeGeometry(60, 60, 60);

    var cubeMaterial = new THREE.MeshBasicMaterial({
        color: 0x05009A,
        shading: THREE.FlatShading,
        side: THREE.DoubleSide
    });

    var cube = new THREE.Mesh(boxGeom, cubeMaterial);
    cube.position.copy(new THREE.Vector3(100, 75, 50));
    cube.rotation.copy(Math.PI / 6);

    sceneGl.add(cube);


    rendererCss = new THREE.CSS3DRenderer();
    rendererCss.setSize(window.innerWidth, window.innerHeight);
    rendererCss.domElement.style.position = 'absolute';
    rendererCss.domElement.style.top = 0;

    rendererGl = new THREE.WebGLRenderer({alpha:true});
    rendererGl.setClearColor(0x00ff00, 0.0);

    rendererGl.setSize(window.innerWidth, window.innerHeight);

    rendererGl.domElement.style.position = 'absolute';
    rendererGl.domElement.style.zIndex = 1;
    rendererGl.domElement.style.top = 0;
    rendererCss.domElement.appendChild(rendererGl.domElement);

    document.body.appendChild(rendererCss.domElement);

}

function animate() {

    requestAnimationFrame(animate);

    controls.update();

    rendererGl.render(sceneGl, camera);
    rendererCss.render(sceneCss, camera);

}
        </script>
    </body>
</html>
like image 163
David Avatar answered Nov 15 '22 04:11

David