steveOw steveOw - 5 months ago 65
Javascript Question

THREE.js 1 Renderer 2 Viewports: Camera inversion not working correctly

See jsfiddle

I have one scene and two cameras.
Each camera is mapped to a viewport and the two viewports sit side by side on the same renderer object.

I want the second camera to display a mirrored representation of the scene.

Here is the rendering code.

function render() {

//... clear entire renderer
renderer.setViewport
(0 , 0,
renderer_width, renderer_height);
renderer.clear();

//... 1st viewport (left)
renderer.setViewport
(0 , 0,
renderer_width * 0.5, renderer_height);
renderer.render(scene, camera1);

renderer.clearDepth(); //... seems to have no effect in this case (no VP overlap)

//... 2nd viewport (right)
renderer.setViewport
(renderer_width * 0.5, 0,
renderer_width * 0.5, renderer_height);
renderer.render(scene, camera2);

}


I wish to invert the view from the second camera to look like a mirror reflection of the view from the first camera. I use the following code:-

camera2.projectionMatrix.scale(new THREE.Vector3(-1, 1, 1));
camera2.updateProjectionMatrix();


...but as the jsfiddle shows (when you click on the button "Invert Camera2 (VP2)" ) the static cube appears as if it is viewed from the inside.

N.B. Both viewports must be on the same renderer. (An alternative solution, using multiple renderers, was given by the answer of /u/stdob--/ here:- (Simulate an optically-inverted (mirror-image) camera in Three.js)

EDIT 20160622

I have posted an answer with jsfiddle. It combines rendering methods described by Lee Stemkoski and West Langley.

Answer

As requested by /u/Vito Gentile/ , here is code which works for the current R78 version of THREE.js

I have put it into a jsfiddle .

HTML

<!--- Using latest THREE.js (r70+) -->
<!-- script src="http://threejs.org/build/three.min.js"></script>
<script src="http://threejs.org/examples/js/controls/OrbitControls.js"></script>

<h1 id="title_A">1 camera, 2 displays (1  mirrored)</h1>


<!-- NB In jsfiddle Frameworks & Extensions select No wrap - in <body> -->

CSS

body {
    background-color: #eeeeee;
    margin: 0px;
    overflow: hidden;
}

JAVASCRIPT

//... Copies methods presented by Lee Stemkoski and West Langley.

//... Global variables.
var camera1, camera2, scene, renderer, geometry, material, mybox, mybox2;
var renderer_width, renderer_height;
//

init();
animate();

//-------------------------------------------------------------
function init() {

    scene222 = new THREE.Scene();

    camera1 = new THREE.PerspectiveCamera
                (50, window.innerWidth / window.innerHeight, 1, 10000);

    camera1.position.set(0,350,2500);

    //...no effect these two commands
    camera1.projectionMatrix.scale(new THREE.Vector3(1, 1, 1));
    camera1.updateProjectionMatrix();

    scene222.add(camera1);

    //---------------------------------------------------------

    // 2 BOXES

    var myboxGeometry = new THREE.CubeGeometry(100, 100, 100);
    var myboxMaterial = new THREE.MeshLambertMaterial({
        color: 0x00aaff,
        side: THREE.DoubleSide
    });


    var mybox2Geometry = new THREE.CubeGeometry(150, 150, 150);
    var mybox2Material = new THREE.MeshNormalMaterial();

    mybox = new THREE.Mesh(myboxGeometry, myboxMaterial);
    mybox.position.set(0, 0, 0);
    scene222.add(mybox);

    mybox2 = new THREE.Mesh(mybox2Geometry, mybox2Material);
    scene222.add(mybox2);
    mybox2.position.set(0, -100, 0);

    // LIGHT
    var light = new THREE.PointLight(0xffffff);
    light.position.set(0, 200, 400);

    //var light = new THREE.AmbientLight(0xffffff);
    scene222.add(light);

    //RENDERER
    //renderer = new THREE.CanvasRenderer();
    renderer = new THREE.WebGLRenderer({
        antialias: true
    });

    renderer_width = window.innerWidth;
    renderer_height = window.innerHeight;
    renderer.setSize(renderer_width, renderer_height);
    renderer.setClearColor(0x443300, 1);
    renderer.autoClear = false;
    document.body.appendChild(renderer.domElement);

    //... Need OrbitControls.js.
    camera1.lookAt(0, 0, 0); //R70
    controls1 = new THREE.OrbitControls(camera1, renderer.domElement);
    //...without a controls1 command, no graphics are seen in viewport2.

    //------------------------------------------------------------------

    xxx = F_Init_Scene222_Eyeballs()
}

//-------------------------------------------------------------

function animate() {

    requestAnimationFrame(animate);

    render();

    update();

}

//-------------------------------------------------------------
function update() {

    //mybox.rotation.x += 0.01;
    mybox.rotation.y += 0.015;

}

//-------------------------------------------------------------
function render() 
{

    renderer.clear();

    xxx = F_Render_Eyeball_Stuff();

    renderer.render( scene222, camera1 );

    //xxx = F_Render_Eyeball_Stuff();

}


function F_Render_Eyeball_Stuff()
{

        renderer.clearDepth();

        // put the result of EyeBall_textureCamera into the moby_Buffer which will feed the texture of moby_quad object.

        renderer.render( scene222, EyeBall_textureCamera, moby_Buffer, true );

        renderer.render( moby_Scene, moby_Camera, final_Buffer1, true );

        renderer.render( moby_Scene, moby_Camera, final_Buffer2, true );
}

//-------------------------------------------
function F_Init_Scene222_Eyeballs()
{

    //... EyeBall_textureCamera

    var VIEW_ANGLE = 45, ASPECT = window.innerWidth / window.innerHeight, NEAR = 0.1, FAR = 50000; 
    EyeBall_textureCamera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR);
    EyeBall_textureCamera.name ="EyeBall_textureCamera"


    scene222.add(EyeBall_textureCamera);

    EyeBall_textureCamera.position.set( 0,100,200); 

    moby_Scene = new THREE.Scene();

    moby_Camera = new THREE.OrthographicCamera( 
        window.innerWidth  / -2, window.innerWidth  /  2, 
        window.innerHeight /  2, window.innerHeight / -2, 
        -10000, 10000 );
        //moby_Camera.position.set = (-2200,200,-1000);
        moby_Camera.position.z = -1;
        moby_Camera.position.set = (-2200, 0,-1000);
    moby_Scene.add( moby_Camera );


    moby_Buffer = new THREE.WebGLRenderTarget( 512, 512, { format: THREE.RGBFormat } ); 
    var moby_Material = new THREE.MeshBasicMaterial( { map: moby_Buffer } );

    var moby_Geometry = new THREE.PlaneGeometry( window.innerWidth, window.innerHeight );
    var moby_quad = new THREE.Mesh( moby_Geometry, moby_Material );
    // moby_quad.rotation.x = Math.PI / 2;
    moby_Scene.add( moby_quad );


    // final version of camera texture, used in scene. 

    final_Buffer1 = new THREE.WebGLRenderTarget( 512, 512, { format: THREE.RGBFormat } );
    final_Buffer2 = new THREE.WebGLRenderTarget( 512, 512, { format: THREE.RGBFormat } );


    var plane1Material = new THREE.MeshBasicMaterial( { map: final_Buffer1 } );
    var plane2Material = new THREE.MeshBasicMaterial( { map: final_Buffer2 } );

    var planeGeometry = new THREE.CubeGeometry( 800, 400, 1, 1 );

    //... Plane 1
    var plane1 = new THREE.Mesh( planeGeometry, plane1Material );
    plane1.position.set( -450,300,-400);
    plane1.rotation.y = Math.PI;    
    scene222.add(plane1);

    //... Plane 2 ( = Plane1 picture but Mirrored in the YZ plane )
    var plane2 = new THREE.Mesh( planeGeometry, plane2Material );
    plane2.position.set( 450,300,-400);
    plane2.rotation.y = Math.PI;
    //plane2.scale.x = -1; // xxxxx THREE.js doesn't support negative scale factors.

    //... Mirror, reverse the orientation of picture along the x axis.
    //... from West Langley's answer at http://stackoverflow.com/questions/29974578/how-to-flip-a-three-js-texture-horizontally
    plane2.material.map.wrapS = THREE.RepeatWrapping;
    plane2.material.map.repeat.x = -1; 

    scene222.add(plane2);

    EyeBall_textureCamera.lookAt( mybox.position );

    //... Border Planes

    var plane1BGeometry = new THREE.CubeGeometry( 820, 420, 1, 1 );
    var plane1BMaterial = new THREE.MeshBasicMaterial( { color: 0xaa2222 } );
    var plane1B = new THREE.Mesh( plane1BGeometry, plane1BMaterial );
    plane1B.position.set(-450,300,-400-2);
    scene222.add(plane1B);

    var plane2BGeometry = new THREE.CubeGeometry( 820, 420, 1, 1 );
    var plane2BMaterial = new THREE.MeshBasicMaterial( { color: 0x22aa22 } );
    var plane2B = new THREE.Mesh( plane2BGeometry, plane2BMaterial );
    plane2B.position.set( 450,300,-400-2);
    scene222.add(plane2B);

    //...Eyeball Object, just for checking where the camera is in the scene.

        // Eyeball_Sphere //
        var parameterlist = 
        {   radius: 40, 
            segmentsAlongWidth: 32, 
            segmentsAlongHeight: 16,
            materialType: "Lambert",
            materialColor: 0xffff00,
            objectName: "ob_sphere999",
            posX: 0,
            posY: 0,
            posZ: 0 
        };

        //...make and attach a sphere to visually indicate the camera's position in scene.
        ob_EBsphere1 = SOW_F_grob_Make_New_Sphere ( parameterlist );        

        EyeBall_textureCamera.add ( ob_EBsphere1 ); //... sphere is at camera position

}
//... EOF F_Init_Scene222_Eyeballs()

//==================================================

function SOW_F_grob_Make_New_Sphere( param_list)

{
            sphere_Geometry 
            = new THREE.SphereGeometry( 
                param_list.radius, 
                param_list.segmentsAlongWidth,
                param_list.segmentsAlongHeight);

            if (param_list.materialType == "Lambert")
            {
                sphere_Material 
                = new THREE.MeshLambertMaterial
                ( {color: param_list.materialColor} ); 
            }
            else if (param_list.materialType == "Normal")
            {
                sphere_Material 
                = new THREE.MeshNormalMaterial
                ( { overdraw: 0.2 } ); 
            }
            else if (param_list.materialType == "Basic")
            {
                sphere_Material 
                = new THREE.MeshBasicMaterial
                ( {color: param_list.materialColor} );
            }

            ipObject = new THREE.Mesh(sphere_Geometry, sphere_Material);

            ipObject.position.set(param_list.posX,param_list.posY,param_list.posZ);

            return ipObject;

} //... E O Function  SOW_F_grob_Make_New_Sphere
Comments