TheJim01
TheJim01

Reputation: 8876

Groups & THREE.MultiMaterial

As part of prototyping some debugger objects and methods, I created a simple cube with a different color on each side. Rather than creating multiple meshes, I decided to use draw groups and THREE.Multimaterial. Unfortunately, it's only half-working, and I don't understand why.

What IS working is the first two sides (4 triangles). What's NOT working is any of the other sides. None of the other sides are visible. I've added debug code to draw the (index-based) vertex normals, the (index-based, manually calculated) face normals, and the wireframe (THREE.WireframeHelper).

If I increase the count for the second group to 9, nothing happens. If I change the groups to reference different start/count values within the first 8 vertices, those changes work as expected. Doing anything above 8th vertex has no effect.

I've also checked that the drawRange is set to draw from 0 to Infinity. I've also ruled out typos in my data, because otherwise the normals and wireframe wouldn't work. Is there anything else I'm missing? Thanks!

(I found the issue in r76. Code below referenced r79 at the time of writing.)

jsfiddle: http://jsfiddle.net/TheJim01/gumftkm4/

HTML:

<script src="http://threejs.org/build/three.js"></script>
<script src="http://threejs.org/examples/js/controls/TrackballControls.js"></script>
<script src="http://threejs.org/examples/js/libs/stats.min.js"></script>
<div id="host"></div>

<script>
// INITIALIZE
var WIDTH = window.innerWidth,
    HEIGHT = window.innerHeight,
    FOV = 35,
    NEAR = 1,
    FAR = 1000;

var renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(WIDTH, HEIGHT);
document.getElementById('host').appendChild(renderer.domElement);

var stats= new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0';
document.body.appendChild(stats.domElement);


var camera = new THREE.PerspectiveCamera(FOV, WIDTH / HEIGHT, NEAR, FAR);
camera.position.z = 250;

var trackballControl = new THREE.TrackballControls(camera, renderer.domElement);
trackballControl.rotateSpeed = 5.0; // need to speed it up a little

var scene = new THREE.Scene();

var light = new THREE.PointLight(0xffffff, 1, Infinity);
light.position.copy(camera.position);

scene.add(light);

function draw(){
    light.position.copy(camera.position);
    renderer.render(scene, camera);
  stats.update();
}
trackballControl.addEventListener('change', draw);

function navStartHandler(e) {
  renderer.domElement.addEventListener('mousemove', navMoveHandler);
  renderer.domElement.addEventListener('mouseup', navEndHandler);
}
function navMoveHandler(e) {
  trackballControl.update();
}
function navEndHandler(e) {
  renderer.domElement.removeEventListener('mousemove', navMoveHandler);
  renderer.domElement.removeEventListener('mouseup', navEndHandler);
}

renderer.domElement.addEventListener('mousedown', navStartHandler);
renderer.domElement.addEventListener('mousewheel', navMoveHandler);
</script>

CSS:

html *{
    padding: 0;
    margin: 0;
    width: 100%;
    overflow: hidden;
}

#host {
    width: 100%;
    height: 100%;
}

JavaScript:

// New Color Cube
(function () {

    var pos = new Float32Array([
        // front
        -1, 1, 1,
        -1, -1, 1,
        1, 1, 1,
        1, -1, 1,
        // right
        1, 1, 1,
        1, -1, 1,
        1, 1, -1,
        1, -1, -1,
        // back
        1, 1, -1,
        1, -1, -1,
        -1, 1, -1,
        -1, -1, -1,
        // left
        -1, 1, -1,
        -1, -1, -1,
        -1, 1, 1,
        -1, -1, 1,
        // top
        -1, 1, -1,
        -1, 1, 1,
        1, 1, -1,
        1, 1, 1,
        // bottom
        -1, -1, 1,
        -1, -1, -1,
        1, -1, 1,
        1, -1, -1
    ]),
    nor = new Float32Array([
        // front
        0, 0, 1,
        0, 0, 1,
        0, 0, 1,
        0, 0, 1,
        // right
        1, 0, 0,
        1, 0, 0,
        1, 0, 0,
        1, 0, 0,
        // back
        0, 0, -1,
        0, 0, -1,
        0, 0, -1,
        0, 0, -1,
        // left
        -1, 0, 0,
        -1, 0, 0,
        -1, 0, 0,
        -1, 0, 0,
        // top
        0, 1, 0,
        0, 1, 0,
        0, 1, 0,
        0, 1, 0,
        // bottom
        0, -1, 0,
        0, -1, 0,
        0, -1, 0,
        0, -1, 0
    ]),
    idx = new Uint32Array([
        // front
        0, 1, 2,
        3, 2, 1,
        // right
        4, 5, 6,
        7, 6, 5,
        // back
        8, 9, 10,
        11, 10, 9,
        // left
        12, 13, 14,
        15, 14, 13,
        // top
        16, 17, 18,
        19, 18, 17,
        // bottom
        20, 21, 22,
        23, 22, 21
    ]);

    var sideColors = new THREE.MultiMaterial([
        new THREE.MeshLambertMaterial({ color: 'red' }), // front
        new THREE.MeshLambertMaterial({ color: 'green' }), // right
        new THREE.MeshLambertMaterial({ color: 'orange' }), // back
        new THREE.MeshLambertMaterial({ color: 'blue' }), // left
        new THREE.MeshLambertMaterial({ color: 'white' }), // top
        new THREE.MeshLambertMaterial({ color: 'yellow' }) // bottom
    ]);

    var cubeGeometry = new THREE.BufferGeometry();
    cubeGeometry.addAttribute("position", new THREE.BufferAttribute(pos, 3));
    cubeGeometry.addAttribute("normal", new THREE.BufferAttribute(nor, 3));
    cubeGeometry.setIndex(new THREE.BufferAttribute(idx, 3));
    cubeGeometry.clearGroups();
    cubeGeometry.addGroup(0, 6, 0);
    cubeGeometry.addGroup(6, 6, 1);
    cubeGeometry.addGroup(12, 6, 2);
    cubeGeometry.addGroup(18, 6, 3);
    cubeGeometry.addGroup(24, 6, 4);
    cubeGeometry.addGroup(30, 6, 5);

    THREE.ColorCube = function (scaleX, scaleY, scaleZ) {
        THREE.Mesh.call(this, cubeGeometry, sideColors);
        var scaler = new THREE.Matrix4().makeScale(scaleX, scaleY, scaleZ);
        this.applyMatrix(scaler);
    };
    THREE.ColorCube.prototype = Object.create(THREE.Mesh.prototype);
    THREE.ColorCube.prototype.constructor = THREE.ColorCube;

    THREE.ColorCube.prototype.clearVertexNormals = function () {
        if (this.vNormals === undefined) {
            this.vNormals = [];
        }
        for (var i = 0, len = this.vNormals.length; i < len; ++i) {
            this.parent.remove(this.vNormals[i]);
        }
        this.vNormals.length = 0;
    }
    THREE.ColorCube.prototype.drawVertexNormals = function (scale, color) {
        this.clearVertexNormals();
        scale = (scale === undefined) ? 1 : scale;
        color = (color === undefined) ? 0xff : color;
        var origin = new THREE.Vector3(),
            normalArrow = null,
            vert = null,
            norm = null,
            index = null,
            vertexArray = this.geometry.attributes.position.array,
            normalArray = this.geometry.attributes.normal.array,
            indexArray = this.geometry.index.array;

        for (var i = 0, len = indexArray.length; i < len; ++i) {
            index = indexArray[i];
            vert = new THREE.Vector3(...vertexArray.slice((index * 3), (index * 3) + 3)).applyMatrix4(this.matrix);
            norm = new THREE.Vector3(...normalArray.slice((index * 3), (index * 3) + 3));

            normalArrow = new THREE.ArrowHelper(
                norm,
                origin,
                1 * scale,
                color,
                0.2 * scale,
                0.1 * scale
            );

            normalArrow.position.copy(vert);

            this.vNormals.push(normalArrow);
            this.parent.add(normalArrow);
        }
    };

    THREE.ColorCube.prototype.clearFaceNormals = function () {
        if (this.fNormals === undefined) {
            this.fNormals = [];
        }
        for (var i = 0, len = this.fNormals.length; i < len; ++i) {
            this.parent.remove(this.fNormals[i]);
        }
        this.fNormals.length = 0;
    }
    THREE.ColorCube.prototype.drawFaceNormals = function (scale, color) {
        this.clearFaceNormals();
        scale = (scale === undefined) ? 1 : scale;
        color = (color === undefined) ? 0xffaa00 : color;
        var origin = new THREE.Vector3(),
            normalArrow = null,
            vertices = [new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3()],
            normals = [new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3()],
            indices = [0, 0, 0],
            centroid = new THREE.Vector3(),
            faceNormal = new THREE.Vector3(),
            vertexArray = this.geometry.attributes.position.array,
            normalArray = this.geometry.attributes.normal.array,
            indexArray = this.geometry.index.array;

        for (var i = 0, len = indexArray.length; i < len; i += 3) {
            indices = indexArray.slice(i, i + 3);

            vertices[0].set(...vertexArray.slice((indices[0] * 3), (indices[0] * 3) + 3)).applyMatrix4(this.matrix);
            vertices[1].set(...vertexArray.slice((indices[1] * 3), (indices[1] * 3) + 3)).applyMatrix4(this.matrix);
            vertices[2].set(...vertexArray.slice((indices[2] * 3), (indices[2] * 3) + 3)).applyMatrix4(this.matrix);

            normals[0].set(...normalArray.slice((indices[0] * 3), (indices[0] * 3) + 3));
            normals[1].set(...normalArray.slice((indices[1] * 3), (indices[1] * 3) + 3));
            normals[2].set(...normalArray.slice((indices[2] * 3), (indices[2] * 3) + 3));

            centroid.set(
                (vertices[0].x + vertices[1].x + vertices[2].x) / 3,
                (vertices[0].y + vertices[1].y + vertices[2].y) / 3,
                (vertices[0].z + vertices[1].z + vertices[2].z) / 3
            );

            faceNormal.set(
                (normals[0].x + normals[1].x + normals[2].x) / 3,
                (normals[0].y + normals[1].y + normals[2].y) / 3,
                (normals[0].z + normals[1].z + normals[2].z) / 3
            );
            faceNormal.normalize();

            normalArrow = new THREE.ArrowHelper(
                faceNormal,
                origin,
                1 * scale,
                color,
                0.2 * scale,
                0.1 * scale
            );

            normalArrow.position.copy(centroid);

            this.fNormals.push(normalArrow);
            this.parent.add(normalArrow);
        }
    };

    THREE.ColorCube.prototype.clearAllNormals = function () {
        THREE.ColorCube.prototype.clearVertexNormals();
        THREE.ColorCube.prototype.clearFaceNormals();
    }

    THREE.ColorCube.prototype.drawWireframe = function (color) {
        if (this.wireframe === undefined) {
            color = (color === undefined) ? 0 : color;
            this.wireframe = new THREE.WireframeHelper(this, color);
            this.parent.add(this.wireframe);
        }
    }

    THREE.ColorCube.prototype.clearWireframe = function () {
        if (this.wireframe) {
            this.parent.remove(this.wireframe);
            delete this.wireframe;
        }
    }

})();

var cc = new THREE.ColorCube(25, 25, 25);
scene.add(cc);

cc.drawVertexNormals(25);
cc.drawFaceNormals(25);
cc.drawWireframe(0xffffff);
draw();

Upvotes: 0

Views: 854

Answers (1)

Hasan
Hasan

Reputation: 2552

You are setting indices wrong. You have 1 index per vertex. However your code shows 3 index per vertex which does not make sense.

if you change

cubeGeometry.setIndex(new THREE.BufferAttribute(idx, 3));

to

cubeGeometry.setIndex(new THREE.BufferAttribute(idx, 1));

your problem is solved.

Here is the working jsfiddle

Upvotes: 1

Related Questions