OrthographicTrackballControls vs. TrackballControls

时间:2014-11-05 17:36:32

标签: three.js

我实现了一个场景,我使用了Orthographic和Perspective相机,以及它们各自的轨迹球控件。但感觉它们不同步。

有时它们之间的切换结果与预期的一样,而有时输出完全错误。

在下图中,我以透视模式旋转模型,拍摄快照,然后选中该框以将其置于正交模式,并拍摄第二张快照。在切换摄像机之间没有对场景进行其他操作。

在透视模式下轻微旋转后,这是正常工作: Working example

这是在透视模式下进行一些随机旋转之后: Broken example

(我知道我也有缩放问题 - 我正在研究那个问题。)

当然,我对那个完全错误的人的想法持开放态度 - 自从我使用Ortho相机以来已经很久了,所以我可能会忘记一些概念,但它有效有效的事实让我觉得我至少在正确的轨道上,可能只需要在正确的方向上轻推。

我尝试过CombinedCamera,但它与OrthographicTrackballControl表现不佳。

感谢任何意见或建议。 (r68& r69)

jsfiddle:http://jsfiddle.net/TheJim01/rckanx2L/103/

var hostDiv, scene, renderer, oCamera, pCamera, root, oControls, pControls, ctrl, light, shape, o;

var WIDTH = 500,
    HEIGHT = 500,
    FOV = 28,
    NEAR = 1,
    FAR = 60;

function init() {
    o = false;

    hostDiv = document.createElement('div');
    document.body.appendChild(hostDiv);

    renderer = new THREE.WebGLRenderer({ antialias: true, preserverDrawingBuffer: true });
    renderer.setSize(WIDTH, HEIGHT);
    hostDiv.appendChild(renderer.domElement);

    pCamera = new THREE.PerspectiveCamera( FOV, WIDTH / HEIGHT, NEAR, FAR );
    oCamera = new THREE.OrthographicCamera( 0, 0, 0, 0, NEAR, FAR );

    pCamera.position.z = 50;
    oCamera.position.z = 10;

    height = Math.tan(pCamera.fov / 2) * 2 * pCamera.near;
    width = height * pCamera.aspect;

    oCamera.left = width / -2;
    oCamera.right = width / 2;
    oCamera.top = height / 2;
    oCamera.bottom = height / -2;

    pControls = new THREE.TrackballControls(pCamera, renderer.domElement);
    oControls = new THREE.OrthographicTrackballControls(oCamera, renderer.domElement);

    light = new THREE.PointLight(0xffffff, 1, Infinity);

    scene = new THREE.Scene();
    scene.add(pCamera);
    scene.add(oCamera);
    scene.add(light);

    scene.add(new THREE.HemisphereLight(0xffffff, 0xffffff, 0.5));

    var cube = colorCube(5);
    scene.add(cube);

    pControls.target.copy(cube.position);

    animate();
}

function animate() {

    requestAnimationFrame(animate);

    if(o) {
        light.position.copy(oCamera.position);
        renderer.render(scene, oCamera);
    }
    else {
        light.position.copy(pCamera.position);
        renderer.render(scene, pCamera);
    }

    oControls.update();
    pControls.update();
}

function change(e) {
    o = e.checked;
}

function colorCube(scale){
    var geo = new THREE.BufferGeometry();

    var positions = new Float32Array( 72 );
    var normals = new Float32Array( 72 );
    var colors = new Float32Array( 72 );
    var indices = new Uint16Array( 36 );

    var face = 0, idx = 0, vert = 0;
    var x = 0, r = 0, y = 1, g = 1, z = 2, b = 2;

    // front face (RED)
    positions[vert + x] = -0.5; positions[vert + y] = 0.5; positions[vert + z] = 0.5;
    normals[vert + x] = 0.; normals[vert + y] = 0.; normals[vert + z] = 1.;
    colors[vert + r] = 1.; colors[vert + g] = 0.; colors[vert + b] = 0.;
    vert += 3;

    positions[vert + x] = -0.5; positions[vert + y] = -0.5; positions[vert + z] = 0.5;
    normals[vert + x] = 0.; normals[vert + y] = 0.; normals[vert + z] = 1.;
    colors[vert + r] = 1.; colors[vert + g] = 0.; colors[vert + b] = 0.;
    vert += 3;

    positions[vert + x] = 0.5; positions[vert + y] = -0.5; positions[vert + z] = 0.5;
    normals[vert + x] = 0.; normals[vert + y] = 0.; normals[vert + z] = 1.;
    colors[vert + r] = 1.; colors[vert + g] = 0.; colors[vert + b] = 0.;
    vert += 3;

    positions[vert + x] = 0.5; positions[vert + y] = 0.5; positions[vert + z] = 0.5;
    normals[vert + x] = 0.; normals[vert + y] = 0.; normals[vert + z] = 1.;
    colors[vert + r] = 1.; colors[vert + g] = 0.; colors[vert + b] = 0.;
    vert += 3;

    indices[idx + 0] = (face * 4) + 0; indices[idx + 1] = (face * 4) + 1; indices[idx + 2] = (face * 4) + 2;
    indices[idx + 3] = (face * 4) + 0; indices[idx + 4] = (face * 4) + 2; indices[idx + 5] = (face * 4) + 3;
    idx += 6;
    ++face;

    // back face (BLUE)
    positions[vert + x] = -0.5; positions[vert + y] = 0.5; positions[vert + z] = -0.5;
    normals[vert + x] = 0.; normals[vert + y] = 0.; normals[vert + z] = -1.;
    colors[vert + r] = 0.; colors[vert + g] = 0.; colors[vert + b] = 1.;
    vert += 3;

    positions[vert + x] = -0.5; positions[vert + y] = -0.5; positions[vert + z] = -0.5;
    normals[vert + x] = 0.; normals[vert + y] = 0.; normals[vert + z] = -1.;
    colors[vert + r] = 0.; colors[vert + g] = 0.; colors[vert + b] = 1.;
    vert += 3;

    positions[vert + x] = 0.5; positions[vert + y] = -0.5; positions[vert + z] = -0.5;
    normals[vert + x] = 0.; normals[vert + y] = 0.; normals[vert + z] = -1.;
    colors[vert + r] = 0.; colors[vert + g] = 0.; colors[vert + b] = 1.;
    vert += 3;

    positions[vert + x] = 0.5; positions[vert + y] = 0.5; positions[vert + z] = -0.5;
    normals[vert + x] = 0.; normals[vert + y] = 0.; normals[vert + z] = -1.;
    colors[vert + r] = 0.; colors[vert + g] = 0.; colors[vert + b] = 1.;
    vert += 3;

    indices[idx + 0] = (face * 4) + 0; indices[idx + 1] = (face * 4) + 1; indices[idx + 2] = (face * 4) + 2;
    indices[idx + 3] = (face * 4) + 0; indices[idx + 4] = (face * 4) + 2; indices[idx + 5] = (face * 4) + 3;
    idx += 6;
    ++face;

    // right face (GREEN)
    positions[vert + x] = 0.5; positions[vert + y] = 0.5; positions[vert + z] = -0.5;
    normals[vert + x] = 1.; normals[vert + y] = 0.; normals[vert + z] = 0.;
    colors[vert + r] = 0.; colors[vert + g] = 1.; colors[vert + b] = 0.;
    vert += 3;

    positions[vert + x] = 0.5; positions[vert + y] = -0.5; positions[vert + z] = -0.5;
    normals[vert + x] = 1.; normals[vert + y] = 0.; normals[vert + z] = 0.;
    colors[vert + r] = 0.; colors[vert + g] = 1.; colors[vert + b] = 0.;
    vert += 3;

    positions[vert + x] = 0.5; positions[vert + y] = -0.5; positions[vert + z] = 0.5;
    normals[vert + x] = 1.; normals[vert + y] = 0.; normals[vert + z] = 0.;
    colors[vert + r] = 0.; colors[vert + g] = 1.; colors[vert + b] = 0.;
    vert += 3;

    positions[vert + x] = 0.5; positions[vert + y] = 0.5; positions[vert + z] = 0.5;
    normals[vert + x] = 1.; normals[vert + y] = 0.; normals[vert + z] = 0.;
    colors[vert + r] = 0.; colors[vert + g] = 1.; colors[vert + b] = 0.;
    vert += 3;

    indices[idx + 0] = (face * 4) + 0; indices[idx + 1] = (face * 4) + 1; indices[idx + 2] = (face * 4) + 2;
    indices[idx + 3] = (face * 4) + 0; indices[idx + 4] = (face * 4) + 2; indices[idx + 5] = (face * 4) + 3;
    idx += 6;
    ++face;

    // left face (MAGENTA)
    positions[vert + x] = -0.5; positions[vert + y] = 0.5; positions[vert + z] = -0.5;
    normals[vert + x] = -1.; normals[vert + y] = 0.; normals[vert + z] = 0.;
    colors[vert + r] = 1.; colors[vert + g] = 0.; colors[vert + b] = 1.;
    vert += 3;

    positions[vert + x] = -0.5; positions[vert + y] = -0.5; positions[vert + z] = -0.5;
    normals[vert + x] = -1.; normals[vert + y] = 0.; normals[vert + z] = 0.;
    colors[vert + r] = 1.; colors[vert + g] = 0.; colors[vert + b] = 1.;
    vert += 3;

    positions[vert + x] = -0.5; positions[vert + y] = -0.5; positions[vert + z] = 0.5;
    normals[vert + x] = -1.; normals[vert + y] = 0.; normals[vert + z] = 0.;
    colors[vert + r] = 1.; colors[vert + g] = 0.; colors[vert + b] = 1.;
    vert += 3;

    positions[vert + x] = -0.5; positions[vert + y] = 0.5; positions[vert + z] = 0.5;
    normals[vert + x] = -1.; normals[vert + y] = 0.; normals[vert + z] = 0.;
    colors[vert + r] = 1.; colors[vert + g] = 0.; colors[vert + b] = 1.;
    vert += 3;

    indices[idx + 0] = (face * 4) + 0; indices[idx + 1] = (face * 4) + 1; indices[idx + 2] = (face * 4) + 2;
    indices[idx + 3] = (face * 4) + 0; indices[idx + 4] = (face * 4) + 2; indices[idx + 5] = (face * 4) + 3;
    idx += 6;
    ++face;

    // top face (CYAN)
    positions[vert + x] = -0.5; positions[vert + y] = 0.5; positions[vert + z] = -0.5;
    normals[vert + x] = 0.; normals[vert + y] = 1.; normals[vert + z] = 0.;
    colors[vert + r] = 0.; colors[vert + g] = 1.; colors[vert + b] = 1.;
    vert += 3;

    positions[vert + x] = 0.5; positions[vert + y] = 0.5; positions[vert + z] = -0.5;
    normals[vert + x] = 0.; normals[vert + y] = 1.; normals[vert + z] = 0.;
    colors[vert + r] = 0.; colors[vert + g] = 1.; colors[vert + b] = 1.;
    vert += 3;

    positions[vert + x] = 0.5; positions[vert + y] = 0.5; positions[vert + z] = 0.5;
    normals[vert + x] = 0.; normals[vert + y] = 1.; normals[vert + z] = 0.;
    colors[vert + r] = 0.; colors[vert + g] = 1.; colors[vert + b] = 1.;
    vert += 3;

    positions[vert + x] = -0.5; positions[vert + y] = 0.5; positions[vert + z] = 0.5;
    normals[vert + x] = 0.; normals[vert + y] = 1.; normals[vert + z] = 0.;
    colors[vert + r] = 0.; colors[vert + g] = 1.; colors[vert + b] = 1.;
    vert += 3;

    indices[idx + 0] = (face * 4) + 0; indices[idx + 1] = (face * 4) + 1; indices[idx + 2] = (face * 4) + 2;
    indices[idx + 3] = (face * 4) + 0; indices[idx + 4] = (face * 4) + 2; indices[idx + 5] = (face * 4) + 3;
    idx += 6;
    ++face;

    // bottom face (YELLOW)
    positions[vert + x] = -0.5; positions[vert + y] = -0.5; positions[vert + z] = -0.5;
    normals[vert + x] = 0.; normals[vert + y] = -1.; normals[vert + z] = 0.;
    colors[vert + r] = 1.; colors[vert + g] = 1.; colors[vert + b] = 0.;
    vert += 3;

    positions[vert + x] = 0.5; positions[vert + y] = -0.5; positions[vert + z] = -0.5;
    normals[vert + x] = 0.; normals[vert + y] = -1.; normals[vert + z] = 0.;
    colors[vert + r] = 1.; colors[vert + g] = 1.; colors[vert + b] = 0.;
    vert += 3;

    positions[vert + x] = 0.5; positions[vert + y] = -0.5; positions[vert + z] = 0.5;
    normals[vert + x] = 0.; normals[vert + y] = -1.; normals[vert + z] = 0.;
    colors[vert + r] = 1.; colors[vert + g] = 1.; colors[vert + b] = 0.;
    vert += 3;

    positions[vert + x] = -0.5; positions[vert + y] = -0.5; positions[vert + z] = 0.5;
    normals[vert + x] = 0.; normals[vert + y] = -1.; normals[vert + z] = 0.;
    colors[vert + r] = 1.; colors[vert + g] = 1.; colors[vert + b] = 0.;
    vert += 3;

    indices[idx + 0] = (face * 4) + 0; indices[idx + 1] = (face * 4) + 1; indices[idx + 2] = (face * 4) + 2;
    indices[idx + 3] = (face * 4) + 0; indices[idx + 4] = (face * 4) + 2; indices[idx + 5] = (face * 4) + 3;
    idx += 6;
    ++face;

    geo.addAttribute( 'index', new THREE.BufferAttribute( indices, 1 ) );
    geo.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
    geo.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) );
    geo.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) );

    var mat = new THREE.MeshPhongMaterial( {
                    color: 0xffffff,
                    ambient: 0xffffff,
                    specular: 0xffffff,
                    shininess: 50,
                    side: THREE.DoubleSide,
                    vertexColors: THREE.VertexColors
                } );    

    var msh = new THREE.Mesh(geo, mat);
    msh.scale.multiplyScalar(scale);

    return msh;
}

init();

1 个答案:

答案 0 :(得分:1)

这两个控件似乎确实不同步。当我添加一个观察摄像头和摄像头助手时,我能够立刻看到他们的位置矢量发散。

不管是不是设计,我不知道。无论如何,我能够在下面的jsfiddle中为我的目的使用它。

我放弃了尝试同步控件,现在只依赖于透视摄像头控制。然后我根据透视摄像机的方向更新正射相机,反之亦然。

我不会马上接受这个答案,因为那里可能有更好的解决方案。

<强>更新 我终于让两台摄像机同步了。必须有一个更好的方法,所以我会把这个答案打开几天。

jsfiddle:http://jsfiddle.net/TheJim01/jkbwk4xn/76/

// P/O Camera Tester

var hostDiv, scene, renderer, light, o;
var pCamera, oCamera, watchCamera;
var pControls, oControls;
var pHelper, oHelper;

var WIDTH = 600,
    HEIGHT = 300,
    FOV = 28,
    NEAR = 40,
    FAR = 60;

var oBackup, dist = 0;
function render() {
    oBackup = oCamera.clone();

    light.position.copy(pControls.object.position);

    renderer.clear();

    renderer.setViewport(0, 0, WIDTH/2, HEIGHT);

    if(o) {
        renderer.render(scene, oCamera);
    }
    else {
        renderer.render(scene, pCamera);
    }

    pControls.update();
    oControls.update();

    if(o) {
        // zoom
        if(oBackup.top !== oCamera.top ||
           oBackup.right !== oCamera.right ||
           oBackup.bottom !== oCamera.bottom ||
           oBackup.left !== oCamera.left) {
            oCamera.position.copy(pCamera.position);
        }
        pCamera.position.copy(oCamera.position);
        pCamera.up.copy(oCamera.up);
        pCamera.lookAt(oControls.target);
        pControls.target.copy(oControls.target);
    }
    else {
        oCamera.position.copy(pCamera.position);
        oCamera.up.copy(pCamera.up);
        oCamera.lookAt(pControls.target);
        oControls.target.copy(pControls.target);
    }
    if(pCamera.up.x === undefined) debugger;
    if(oCamera.up.x === undefined) debugger;

    dist = pCamera.position.distanceTo(pControls.target);

    pCamera.near = dist - 10;
    pCamera.far = dist + 10;
    oCamera.near = dist - 10;
    oCamera.far = dist + 10;

    pCamera.updateProjectionMatrix();
    oCamera.updateProjectionMatrix();

    pHelper.update();
    oHelper.update();

    renderer.setViewport(WIDTH/2, 0, WIDTH/2, HEIGHT);
    renderer.render(scene, watchCamera);

    oBackup = null;
}

function animate() {

    requestAnimationFrame(animate);

    render();
}

function init() {
    o = false;

    hostDiv = document.createElement('div');
    hostDiv.style.position = 'relative';
    hostDiv.style.top = '0';
    hostDiv.style.left = '0';
    document.body.appendChild(hostDiv);

    var moveDiv = document.createElement('div');
    moveDiv.style.position = 'absolute';
    moveDiv.style.top = '0';
    moveDiv.style.left = '0';
    moveDiv.style.width = (WIDTH/2).toString() + 'px';
    moveDiv.style.height = (HEIGHT).toString() + 'px';

    scene = new THREE.Scene();

    watchCamera = new THREE.PerspectiveCamera( 14, 0.5 * WIDTH / HEIGHT, 1, 1000 );
    watchCamera.position.x = 200;
    watchCamera.position.y = 200;
    watchCamera.position.z = 200;
    watchCamera.lookAt(new THREE.Vector3(0, 0, 0));

    pCamera = new THREE.PerspectiveCamera( FOV, 0.5* WIDTH / HEIGHT, NEAR, FAR );
    oCamera = new THREE.OrthographicCamera( -12, 12, 12, -12, NEAR, FAR );

    renderer = new THREE.WebGLRenderer({ antialias: true, preserverDrawingBuffer: true });
    renderer.setSize(WIDTH, HEIGHT);
    renderer.domElement.style.position = "relative";
    hostDiv.appendChild(renderer.domElement);
    hostDiv.appendChild(moveDiv);
    renderer.autoClear = false;

    pCamera.position.z = 50;
    oCamera.position.z = 50;

    pControls = new THREE.TrackballControls(pCamera, moveDiv);
    oControls = new THREE.OrthographicTrackballControls(oCamera, moveDiv);

    pControls.target.set(0, 0, 0);
    oControls.target.set(0, 0, 0);

    light = new THREE.PointLight(0xffffff, 1., Infinity);
    var hemi = new THREE.HemisphereLight(0xffffff, 0xffffff, 0.5);

    var cube = colorCube(5);

    scene.add(pCamera);
    scene.add(oCamera);
    scene.add(watchCamera);
    scene.add(light);
    scene.add(hemi);
    scene.add(cube);

    var debug = true;
    if(debug) {
        pHelper = new THREE.CameraHelper( pCamera );
        scene.add( pHelper );
        oHelper = new THREE.CameraHelper( oCamera );    
        scene.add( oHelper );

        var sphereSize = 1;
        var pointLightHelper = new THREE.PointLightHelper( light, sphereSize );
        scene.add( pointLightHelper );

        var arrowXp = new THREE.ArrowHelper(
            new THREE.Vector3(1, 0, 0),
            new THREE.Vector3(0, 0, 0),
            10,
            0x00ff00);
        scene.add(arrowXp);

        var arrowXn = new THREE.ArrowHelper(
            new THREE.Vector3(-1, 0, 0),
            new THREE.Vector3(0, 0, 0),
            10,
            0xff00ff);
        scene.add(arrowXn);

        var arrowYp = new THREE.ArrowHelper(
            new THREE.Vector3(0, 1, 0),
            new THREE.Vector3(0, 0, 0),
            10,
            0x00ffff);
        scene.add(arrowYp);

        var arrowYn = new THREE.ArrowHelper(
            new THREE.Vector3(0, -1, 0),
            new THREE.Vector3(0, 0, 0),
            10,
            0xffff00);
        scene.add(arrowYn);

        var arrowZp = new THREE.ArrowHelper(
            new THREE.Vector3(0, 0, 1),
            new THREE.Vector3(0, 0, 0),
            10,
            0xff0000);
        scene.add(arrowZp);

        var arrowZn = new THREE.ArrowHelper(
            new THREE.Vector3(0, 0, -1),
            new THREE.Vector3(0, 0, 0),
            10,
            0x0000ff);
        scene.add(arrowZn);
    }

    animate();
}

function change(e) {
    o = e.checked;
}

function colorCube(scale){
    var geo = new THREE.BufferGeometry();

    var positions = new Float32Array( 72 );
    var normals = new Float32Array( 72 );
    var colors = new Float32Array( 72 );
    var indices = new Uint16Array( 36 );

    var face = 0, idx = 0, vert = 0;
    var x = 0, r = 0, y = 1, g = 1, z = 2, b = 2;

    // front face (RED)
    positions[vert + x] = -0.5; positions[vert + y] = 0.5; positions[vert + z] = 0.5;
    normals[vert + x] = 0.; normals[vert + y] = 0.; normals[vert + z] = 1.;
    colors[vert + r] = 1.; colors[vert + g] = 0.; colors[vert + b] = 0.;
    vert += 3;

    positions[vert + x] = -0.5; positions[vert + y] = -0.5; positions[vert + z] = 0.5;
    normals[vert + x] = 0.; normals[vert + y] = 0.; normals[vert + z] = 1.;
    colors[vert + r] = 1.; colors[vert + g] = 0.; colors[vert + b] = 0.;
    vert += 3;

    positions[vert + x] = 0.5; positions[vert + y] = -0.5; positions[vert + z] = 0.5;
    normals[vert + x] = 0.; normals[vert + y] = 0.; normals[vert + z] = 1.;
    colors[vert + r] = 1.; colors[vert + g] = 0.; colors[vert + b] = 0.;
    vert += 3;

    positions[vert + x] = 0.5; positions[vert + y] = 0.5; positions[vert + z] = 0.5;
    normals[vert + x] = 0.; normals[vert + y] = 0.; normals[vert + z] = 1.;
    colors[vert + r] = 1.; colors[vert + g] = 0.; colors[vert + b] = 0.;
    vert += 3;

    indices[idx + 0] = (face * 4) + 0; indices[idx + 1] = (face * 4) + 1; indices[idx + 2] = (face * 4) + 2;
    indices[idx + 3] = (face * 4) + 0; indices[idx + 4] = (face * 4) + 2; indices[idx + 5] = (face * 4) + 3;
    idx += 6;
    ++face;

    // back face (BLUE)
    positions[vert + x] = -0.5; positions[vert + y] = 0.5; positions[vert + z] = -0.5;
    normals[vert + x] = 0.; normals[vert + y] = 0.; normals[vert + z] = -1.;
    colors[vert + r] = 0.; colors[vert + g] = 0.; colors[vert + b] = 1.;
    vert += 3;

    positions[vert + x] = -0.5; positions[vert + y] = -0.5; positions[vert + z] = -0.5;
    normals[vert + x] = 0.; normals[vert + y] = 0.; normals[vert + z] = -1.;
    colors[vert + r] = 0.; colors[vert + g] = 0.; colors[vert + b] = 1.;
    vert += 3;

    positions[vert + x] = 0.5; positions[vert + y] = -0.5; positions[vert + z] = -0.5;
    normals[vert + x] = 0.; normals[vert + y] = 0.; normals[vert + z] = -1.;
    colors[vert + r] = 0.; colors[vert + g] = 0.; colors[vert + b] = 1.;
    vert += 3;

    positions[vert + x] = 0.5; positions[vert + y] = 0.5; positions[vert + z] = -0.5;
    normals[vert + x] = 0.; normals[vert + y] = 0.; normals[vert + z] = -1.;
    colors[vert + r] = 0.; colors[vert + g] = 0.; colors[vert + b] = 1.;
    vert += 3;

    indices[idx + 0] = (face * 4) + 0; indices[idx + 1] = (face * 4) + 1; indices[idx + 2] = (face * 4) + 2;
    indices[idx + 3] = (face * 4) + 0; indices[idx + 4] = (face * 4) + 2; indices[idx + 5] = (face * 4) + 3;
    idx += 6;
    ++face;

    // right face (GREEN)
    positions[vert + x] = 0.5; positions[vert + y] = 0.5; positions[vert + z] = -0.5;
    normals[vert + x] = 1.; normals[vert + y] = 0.; normals[vert + z] = 0.;
    colors[vert + r] = 0.; colors[vert + g] = 1.; colors[vert + b] = 0.;
    vert += 3;

    positions[vert + x] = 0.5; positions[vert + y] = -0.5; positions[vert + z] = -0.5;
    normals[vert + x] = 1.; normals[vert + y] = 0.; normals[vert + z] = 0.;
    colors[vert + r] = 0.; colors[vert + g] = 1.; colors[vert + b] = 0.;
    vert += 3;

    positions[vert + x] = 0.5; positions[vert + y] = -0.5; positions[vert + z] = 0.5;
    normals[vert + x] = 1.; normals[vert + y] = 0.; normals[vert + z] = 0.;
    colors[vert + r] = 0.; colors[vert + g] = 1.; colors[vert + b] = 0.;
    vert += 3;

    positions[vert + x] = 0.5; positions[vert + y] = 0.5; positions[vert + z] = 0.5;
    normals[vert + x] = 1.; normals[vert + y] = 0.; normals[vert + z] = 0.;
    colors[vert + r] = 0.; colors[vert + g] = 1.; colors[vert + b] = 0.;
    vert += 3;

    indices[idx + 0] = (face * 4) + 0; indices[idx + 1] = (face * 4) + 1; indices[idx + 2] = (face * 4) + 2;
    indices[idx + 3] = (face * 4) + 0; indices[idx + 4] = (face * 4) + 2; indices[idx + 5] = (face * 4) + 3;
    idx += 6;
    ++face;

    // left face (MAGENTA)
    positions[vert + x] = -0.5; positions[vert + y] = 0.5; positions[vert + z] = -0.5;
    normals[vert + x] = -1.; normals[vert + y] = 0.; normals[vert + z] = 0.;
    colors[vert + r] = 1.; colors[vert + g] = 0.; colors[vert + b] = 1.;
    vert += 3;

    positions[vert + x] = -0.5; positions[vert + y] = -0.5; positions[vert + z] = -0.5;
    normals[vert + x] = -1.; normals[vert + y] = 0.; normals[vert + z] = 0.;
    colors[vert + r] = 1.; colors[vert + g] = 0.; colors[vert + b] = 1.;
    vert += 3;

    positions[vert + x] = -0.5; positions[vert + y] = -0.5; positions[vert + z] = 0.5;
    normals[vert + x] = -1.; normals[vert + y] = 0.; normals[vert + z] = 0.;
    colors[vert + r] = 1.; colors[vert + g] = 0.; colors[vert + b] = 1.;
    vert += 3;

    positions[vert + x] = -0.5; positions[vert + y] = 0.5; positions[vert + z] = 0.5;
    normals[vert + x] = -1.; normals[vert + y] = 0.; normals[vert + z] = 0.;
    colors[vert + r] = 1.; colors[vert + g] = 0.; colors[vert + b] = 1.;
    vert += 3;

    indices[idx + 0] = (face * 4) + 0; indices[idx + 1] = (face * 4) + 1; indices[idx + 2] = (face * 4) + 2;
    indices[idx + 3] = (face * 4) + 0; indices[idx + 4] = (face * 4) + 2; indices[idx + 5] = (face * 4) + 3;
    idx += 6;
    ++face;

    // top face (CYAN)
    positions[vert + x] = -0.5; positions[vert + y] = 0.5; positions[vert + z] = -0.5;
    normals[vert + x] = 0.; normals[vert + y] = 1.; normals[vert + z] = 0.;
    colors[vert + r] = 0.; colors[vert + g] = 1.; colors[vert + b] = 1.;
    vert += 3;

    positions[vert + x] = 0.5; positions[vert + y] = 0.5; positions[vert + z] = -0.5;
    normals[vert + x] = 0.; normals[vert + y] = 1.; normals[vert + z] = 0.;
    colors[vert + r] = 0.; colors[vert + g] = 1.; colors[vert + b] = 1.;
    vert += 3;

    positions[vert + x] = 0.5; positions[vert + y] = 0.5; positions[vert + z] = 0.5;
    normals[vert + x] = 0.; normals[vert + y] = 1.; normals[vert + z] = 0.;
    colors[vert + r] = 0.; colors[vert + g] = 1.; colors[vert + b] = 1.;
    vert += 3;

    positions[vert + x] = -0.5; positions[vert + y] = 0.5; positions[vert + z] = 0.5;
    normals[vert + x] = 0.; normals[vert + y] = 1.; normals[vert + z] = 0.;
    colors[vert + r] = 0.; colors[vert + g] = 1.; colors[vert + b] = 1.;
    vert += 3;

    indices[idx + 0] = (face * 4) + 0; indices[idx + 1] = (face * 4) + 1; indices[idx + 2] = (face * 4) + 2;
    indices[idx + 3] = (face * 4) + 0; indices[idx + 4] = (face * 4) + 2; indices[idx + 5] = (face * 4) + 3;
    idx += 6;
    ++face;

    // bottom face (YELLOW)
    positions[vert + x] = -0.5; positions[vert + y] = -0.5; positions[vert + z] = -0.5;
    normals[vert + x] = 0.; normals[vert + y] = -1.; normals[vert + z] = 0.;
    colors[vert + r] = 1.; colors[vert + g] = 1.; colors[vert + b] = 0.;
    vert += 3;

    positions[vert + x] = 0.5; positions[vert + y] = -0.5; positions[vert + z] = -0.5;
    normals[vert + x] = 0.; normals[vert + y] = -1.; normals[vert + z] = 0.;
    colors[vert + r] = 1.; colors[vert + g] = 1.; colors[vert + b] = 0.;
    vert += 3;

    positions[vert + x] = 0.5; positions[vert + y] = -0.5; positions[vert + z] = 0.5;
    normals[vert + x] = 0.; normals[vert + y] = -1.; normals[vert + z] = 0.;
    colors[vert + r] = 1.; colors[vert + g] = 1.; colors[vert + b] = 0.;
    vert += 3;

    positions[vert + x] = -0.5; positions[vert + y] = -0.5; positions[vert + z] = 0.5;
    normals[vert + x] = 0.; normals[vert + y] = -1.; normals[vert + z] = 0.;
    colors[vert + r] = 1.; colors[vert + g] = 1.; colors[vert + b] = 0.;
    vert += 3;

    indices[idx + 0] = (face * 4) + 0; indices[idx + 1] = (face * 4) + 1; indices[idx + 2] = (face * 4) + 2;
    indices[idx + 3] = (face * 4) + 0; indices[idx + 4] = (face * 4) + 2; indices[idx + 5] = (face * 4) + 3;
    idx += 6;
    ++face;

    geo.addAttribute( 'index', new THREE.BufferAttribute( indices, 1 ) );
    geo.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
    geo.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) );
    geo.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) );

    var mat = new THREE.MeshPhongMaterial( {
                    color: 0xffffff,
                    ambient: 0xffffff,
                    specular: 0xffffff,
                    shininess: 50,
                    side: THREE.DoubleSide,
                    vertexColors: THREE.VertexColors
                } );    

    var msh = new THREE.Mesh(geo, mat);
    msh.scale.multiplyScalar(scale);

    return msh;
}

init();