saward
saward

Reputation: 439

Trouble with merging model with materials in three.js

I have in this fiddle an example of the problem I'm having: http://jsfiddle.net/saward/78Bjk/7/

If you uncomment scene.add(tree_mesh) and scene.add(mesh2), and comment out scene.add(mesh) then you can see both objects. But when I merge both, the material information for tree_mesh seems to be lost. If I modify the mesh to use the same material as mesh2, then both objects display but obviously with the wrong material.

I would appreciate help in understanding what's going on here and how to fix it!

Thanks

Here is the code from the fiddle (requires three.js r57):

var camera, scene, renderer, geometry, material, mesh1, mesh2, mesh;

init();
animate();



function init() {
    var tree = {

    "metadata" :
    {
        "formatVersion" : 3.1,
        "sourceFile"    : "tree.obj",
        "generatedBy"   : "OBJConverter",
        "vertices"      : 24,
        "faces"         : 18,
        "normals"       : 0,
        "colors"        : 0,
        "uvs"           : 0,
        "materials"     : 1
    },

    "scale" : 1.000000,

    "materials": [  {
    "DbgColor" : 15658734,
    "DbgIndex" : 0,
    "DbgName" : "Material",
    "colorAmbient" : [0.0, 0.0, 0.0],
    "colorDiffuse" : [0.64, 0.64, 0.64],
    "colorSpecular" : [0.5, 0.5, 0.5],
    "illumination" : 2,
    "opticalDensity" : 1.0,
    "specularCoef" : 96.078431,
    "transparency" : 1.0
    }],

    "vertices": [1.000000,-1.000000,-1.000000,1.000000,-1.000000,1.000000,-1.000000,-1.000000,1.000000,-1.000000,-1.000000,-1.000000,0.590806,-0.802478,-0.590806,0.590806,-0.802478,0.590807,-0.590806,-0.802478,0.590806,-0.590806,-0.802478,-0.590806,0.406036,0.737103,-0.406036,0.406036,0.737103,0.406036,-0.406036,0.737103,0.406036,-0.406036,0.737103,-0.406036,0.406036,-0.810673,-0.406036,0.406036,-0.810673,0.406036,-0.406036,-0.810673,0.406036,-0.406036,-0.810673,-0.406036,-0.703524,0.091037,0.703524,-0.703524,0.091037,-0.703524,0.703524,0.091037,-0.703524,0.703524,0.091037,0.703524,-0.703524,1.498086,0.703524,-0.703524,1.498086,-0.703524,0.703524,1.498086,-0.703524,0.703524,1.498086,0.703524],

    "morphTargets": [],

    "morphColors": [],

    "normals": [],

    "colors": [],

    "uvs": [[]],

    "faces": [3,0,1,2,3,0,3,4,7,6,5,0,3,0,4,5,1,0,3,1,5,6,2,0,3,2,6,7,3,0,3,4,0,3,7,0,3,12,8,9,13,0,3,13,9,10,14,0,3,14,10,11,15,0,3,15,11,8,12,0,3,8,9,10,11,0,3,15,14,13,12,0,3,20,21,17,16,0,3,21,22,18,17,0,3,22,23,19,18,0,3,23,20,16,19,0,3,16,17,18,19,0,3,23,22,21,20,0]

};

    scene = new THREE.Scene();

    camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 10000);
    camera.position.z = 500;
    scene.add(camera);

    geometry = new THREE.CubeGeometry(200, 200, 200);
    material = new THREE.MeshNormalMaterial();

    var loader = new THREE.JSONLoader();
    var tree_obj = loader.parse(tree, null);
    var tree_materials = tree_obj.materials;
    var tree_face_materials = new THREE.MeshFaceMaterial(tree_materials);
    var tree_geo = tree_obj.geometry;
    var tree_mesh = new THREE.Mesh(tree_geo, tree_face_materials);
    tree_mesh.scale.x = tree_mesh.scale.y = tree_mesh.scale.z = 100;

    mesh2 = new THREE.Mesh(geometry, material);
    mesh2.position.y = 200;
    console.log(tree_mesh.scale);
    //scene.add(tree_mesh);
    //scene.add(mesh2);

    materials = [];

    THREE.GeometryUtils.setMaterialIndex(tree_mesh.geometry, 0);
    THREE.GeometryUtils.setMaterialIndex(mesh2.geometry, 1);
    materials.push(tree_face_materials);
    materials.push(material);
    var new_geo = new THREE.Geometry();
    THREE.GeometryUtils.merge(new_geo, tree_mesh);
    THREE.GeometryUtils.merge(new_geo, mesh2);
    mesh = new THREE.Mesh(new_geo, new THREE.MeshFaceMaterial(materials));

    scene.add(mesh);

    renderer = new THREE.CanvasRenderer();
    renderer.setSize(window.innerWidth, window.innerHeight);

    document.body.appendChild(renderer.domElement);

}

function animate() {

    requestAnimationFrame(animate);
    render();

}

function render() {

    mesh.rotation.x += 0.01;
    mesh.rotation.y += 0.02;


    renderer.render(scene, camera);
}

Update: The way I specifically solved this was by using the current dev version of three.js 58, to add the materials for each model to a larger array.

As noted by the accepted answer, you can't use MeshFaceMaterial as a material, so iterate over all the materials within the MeshFaceMaterial, adding them in order.

Then note the index of the first material in the larger array for each model. Then when it comes time to merge the meshes, instead of using setMaterialIndex, give it the index of the first material in the array for that specific model. Along these lines:

THREE.GeometryUtils.merge(large_geo, some_mesh, some_mesh.material_offset);
large_mesh = new THREE.Mesh(large_geo, new THREE.MeshFaceMaterial(materials_list));

Where "some_mesh.material_offset" will be a new value you set and store for yourself somewhere. This will not work with r57 or lower.

Upvotes: 1

Views: 2174

Answers (1)

WestLangley
WestLangley

Reputation: 104783

When using MeshFaceMaterial( materials ), then materials must be an array of materials. You can't include MeshFaceMaterial as one of the materials.

In your case, it would be:

materials = [];

materials.push( tree_obj.materials[0] );
materials.push( material );

mesh = new THREE.Mesh( new_geo, new THREE.MeshFaceMaterial( materials ) );

Fiddle: http://jsfiddle.net/78Bjk/8/

three.js r.57

Upvotes: 1

Related Questions