google / draco

Draco is a library for compressing and decompressing 3D geometric meshes and point clouds. It is intended to improve the storage and transmission of 3D graphics.
https://google.github.io/draco/
Apache License 2.0
6.46k stars 960 forks source link

Discussion on sub-objects and materials #89

Open NumaNumaNuma opened 7 years ago

NumaNumaNuma commented 7 years ago

Hi,

I'm bringing in an obj model with sub-objects. the suObjectAttribute works fine to assign points back to the correct sub-objects, but uv's don't come out properly. here's what I'm doing:

        for (var i = 0, k = 0, l = 0; i < numVertexCoordinates; i += 3, k++, l +=2) {            

        // Get sub object id
        subObjectId = subObjAttributeData.GetValue(k);

        // Positions
       // globalToLocalMap[] is a map to match each global point index to its corresponding index on a sub-object

        subObjectBuffers[subObjectId].vertices[globalToLocalMap[k]*3]   = -posAttributeData.GetValue(i);
        subObjectBuffers[subObjectId].vertices[globalToLocalMap[k]*3+1] = posAttributeData.GetValue(i + 1);
        subObjectBuffers[subObjectId].vertices[globalToLocalMap[k]*3+2] = posAttributeData.GetValue(i + 2);

        // Normals
        if (normalAttId != -1) {
            subObjectBuffers[subObjectId].normals[globalToLocalMap[k]*3]   = norAttributeData.GetValue(i);
            subObjectBuffers[subObjectId].normals[globalToLocalMap[k]*3+1] = norAttributeData.GetValue(i + 1);
            subObjectBuffers[subObjectId].normals[globalToLocalMap[k]*3+2] = norAttributeData.GetValue(i + 2);
        }
        // Uv's
        if (texCoordAttId != -1) {
            subObjectBuffers[subObjectId].uvs[globalToLocalMap[k]*2] = textCoordAttributeData.GetValue(l);
            subObjectBuffers[subObjectId].uvs[globalToLocalMap[k]*2+1] = textCoordAttributeData.GetValue(l + 1);
        }
    }

result: https://puu.sh/v58lD/bf2c2363d9.png

thanks

ondys commented 7 years ago

@NumaNumaNuma Thanks for the report. Is this happening with the latest version of the javascript decoder? Just checking, because last week we have fixed some issues with UV decoding that may be related to the problem that you are experiencing.

NumaNumaNuma commented 7 years ago

I'm 2 commits behind I think, is this the one you're talking about: "6763aa32 - Our javascript decoders are now built with flag for precise floating point operations. This should resolve some issues with texture coordinate compression."

ondys commented 7 years ago

Yes, that's the one that fixed the issue for other users

NumaNumaNuma commented 7 years ago

I'll pull and check

NumaNumaNuma commented 7 years ago

It looks different but still not right (assuming my code is correct?) http://puu.sh/v7C0M/454a8f779b.png

ondys commented 7 years ago

Can you post your code for generating globalToLocalMap ? Also if you send me the model with the texture + material I can try it on our end. From the last image, it looks like the texture coordinates are decoded correctly (no weird deformations), but the mapping between uvs and subobjects (or textures and subobjects) is somehow wrong.

NumaNumaNuma commented 7 years ago

I think 'k' is ok, it's incremented once while 'i' is incremented 3 times it's basically i/3. points/normals/faces all map correctly.

Here is the code:

    // Count
    for (var i = 0, k = 0; i < numVertexCoordinates; i += 3, k ++) {

        subObjectId = subObjAttributeData.GetValue(k);

        // If subObjectId isn't in the list yet, create it and give it a count of 1
        if (!(subObjectId in subObjectInfo)) {
            subObjectInfo[subObjectId] = 1;
        }
        // Otherwise increment count
        else {
            subObjectInfo[subObjectId]++;
        }
        // Map global index with local index, (count -1)
        globalToLocalMap[k] = subObjectInfo[subObjectId] - 1;
    }

    // Create buffers for each subobject
    for (var key in subObjectInfo){

        geometryBuffer = {
            indices: [],
            vertices: new Float32Array(subObjectInfo[key] * 3),
            normals: new Float32Array(subObjectInfo[key] * 3),
            uvs: new Float32Array(subObjectInfo[key] * 2)                
        };
        subObjectBuffers[key] = geometryBuffer;
    }

    for (var i = 0, k = 0, l = 0; i < numVertexCoordinates; i += 3, k++, l +=2) {

        subObjectId = subObjAttributeData.GetValue(Math.floor(k));

        // Positions
        subObjectBuffers[subObjectId].vertices[globalToLocalMap[k]*3]   = -posAttributeData.GetValue(i);
        subObjectBuffers[subObjectId].vertices[globalToLocalMap[k]*3+1] = posAttributeData.GetValue(i + 1);
        subObjectBuffers[subObjectId].vertices[globalToLocalMap[k]*3+2] = posAttributeData.GetValue(i + 2);

        // Normals
        if (normalAttId != -1) {
            subObjectBuffers[subObjectId].normals[globalToLocalMap[k]*3]   = norAttributeData.GetValue(i);
            subObjectBuffers[subObjectId].normals[globalToLocalMap[k]*3+1] = norAttributeData.GetValue(i + 1);
            subObjectBuffers[subObjectId].normals[globalToLocalMap[k]*3+2] = norAttributeData.GetValue(i + 2);
        }
        // Uv's
        if (texCoordAttId != -1) {
            subObjectBuffers[subObjectId].uvs[globalToLocalMap[k]*2] = textCoordAttributeData.GetValue(l);
            subObjectBuffers[subObjectId].uvs[globalToLocalMap[k]*2+1] = textCoordAttributeData.GetValue(l + 1);
        }
    }
NumaNumaNuma commented 7 years ago

I have emailed you the files. thanks!

NumaNumaNuma commented 7 years ago

Ok I found the problem, your latest patch DID fix it. The engine I'm using has inverted Y coordinates, so I had to flip the second UV value and it's all good now. thanks very much!

ondys commented 7 years ago

@NumaNumaNuma Thanks for the update. Good to know!

openforus commented 7 years ago

@NumaNumaNuma I want to know how you get the subObjAttributeData and the subObjectId? Also the subObject model is mesh or point ? use wrapper.GetAttributeId(dracoGeometry, dracoDecoder.GENERIC)?

ondys commented 7 years ago

@openforus Sub object attribute are automatically created when encoding .obj files that define object groups using o property. More details how to get the attribute can be found for example here: https://github.com/google/draco/issues/67#issuecomment-283124761

openforus commented 7 years ago

thanks I find the example in draco_encoder problem #67

At 2017-04-06 00:45:06, "Ondrej Stava" notifications@github.com wrote:

@openforus Sub object attribute are automatically created when encoding .obj files that define object groups using o property. More details how to get the attribute can be found for example here: #67 (comment)

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.

openforus commented 7 years ago

Hi ondys NumaNumaNuma, Is it only supported point cloud for sub-objects?So for TRIANGULAR_MESH I want to know how to get the MeshFace to set the sub-object's geometryBuffer.indices

ondys commented 7 years ago

@openforus I believe it's actually supported only for triangular meshes (not point clouds). To add indices for sub-objects above you can for example add one extra loop before the Create buffers for each subobjects comment:

numSubObjectIndices = new Int32Array(subObjectInfo.length);
for (let i = 0; i < subObjectInfo.length; ++i) numSubObjectIndices[i] = 0;
for (let i = 0; i < 3 * numFaces; ++i) {
  const pointId = indices.GetValue(i);
  subObjectId = subObjAttributeData.GetValue(pointId);
  numSubObjectIndices[subObjectId]++;
}

then you allocate indices for each subobject: replace indices: [], in the Numa's code above with:

 indices: new Uint32Array(numSubObjectIndices[key]),

lastly you add one more loop at the end where you fill the indices as:

for (let i = 0; i < subObjectInfo.length; ++i) numSubObjectIndices[i] = 0;
for (let i = 0; i < 3 * numFaces; ++i) {
  const pointId = indices.GetValue(i);
  subObjectId = subObjAttributeData.GetValue(pointId);
  subObjectBuffers[subObjectId].indices[numSubObjectIndices[subObjectId]++] = globalToLocalMap[pointId];
}
openforus commented 7 years ago

@ondys thaks ondys ,I will try later ! Thanks again for your help!

shubhamagarwal003 commented 7 years ago

@NumaNumaNuma @ondys I used the approach suggested here to get subobjects and apply material on them which are stored in a separate .mtl file. The approach works fine. But sometimes the subobject have multiple materials associated with them. For ex; the model at the link, https://drive.google.com/open?id=0B5ZnEve9BlcVWldWUFU5cS1IQ3M. For including such cases I separated subobjects with both different subobject id and material id. For ex

 for (var i = 0, k = 0; i < numVertexCoordinates; i += 3, k ++) {

        subObjectId = subObjAttributeData.GetValue(k);
        var matId = materialAttributeData.GetValue(k);
        var key = subObjectId.toString() + ":" + matId.toString();
        // If key isn't in the dict yet, create it and give it a count of 1
        if (!(key in subObjectInfo)) {
            subObjectInfo[key] = 1;
        }
        // Otherwise increment count
        else {
            subObjectInfo[key]++;
        }
        // Map global index with local index, (count -1)
        globalToLocalMap[k] = subObjectInfo[key] - 1;
    }

Changing the subsequent code accordingly. But the issue occurs when the same sub-object have same material repeated twice in .obj file (For ex; the one in the link). So can you suggest what can be done to include that case (Though these may not occur very frequently)?

JackC09 commented 7 years ago

Hi, I’m little bit confused when I try to decode models materialAttrId and subObjAttId return always -1. For shubhamagarwal003’s ex (you add extra 'a' at the end of your link) if I encode it with command

$ ./draco_encoder -i car.obj -o car.drc --metadata

I have:

Encoder options: Compression level = 7 Positions: Quantization = 14 bits Texture coordinates: Quantization = 12 bits Normals: Quantization = 10 bits

Encoded mesh saved to car.drc (42 ms to encode)

Encoded size = 133520 bytes

And same size without --metadata tag

@shubhamagarwal003 can you share me your DracoLoader code please?

ondys commented 7 years ago

@shubhamagarwal003 I believe there is a bug in Draco obj loader with repeated materials in one obj files that should be fixed in our next release

@JackC09 Thanks for the report, I'll investigate

shubhamagarwal003 commented 7 years ago

@JackC09 which commit are you using. I suppose this PR should fix your issue

JackC09 commented 7 years ago

@shubhamagarwal003 I use the latest commit. I think I'm doing something wrong in DracoLoader. Can you send me yours?

shubhamagarwal003 commented 7 years ago

@JackC09 I've done changes in DracoLoader.js in the repo. Mostly in function convertDracoGeometryTo3JS. Here is my modified function (Sorry for the code quality).

convertDracoGeometryTo3JS: function(dracoDecoder, decoder, geometryType, buffer) {
        if (this.getAttributeOptions('position').skipDequantization === true) {
          decoder.SkipAttributeTransform(dracoDecoder.POSITION);
        }
        var dracoGeometry;
        var decodingStatus;
        const start_time = performance.now();
        if (geometryType === dracoDecoder.TRIANGULAR_MESH) {
          dracoGeometry = new dracoDecoder.Mesh();
          decodingStatus = decoder.DecodeBufferToMesh(buffer, dracoGeometry);
        } else {
          dracoGeometry = new dracoDecoder.PointCloud();
          decodingStatus =
              decoder.DecodeBufferToPointCloud(buffer, dracoGeometry);
        }
        if (!decodingStatus.ok() || dracoGeometry.ptr == 0) {
          var errorMsg = 'THREE.DRACOLoader: Decoding failed: ';
          errorMsg += decodingStatus.error_msg();
          console.error(errorMsg);
          dracoDecoder.destroy(decoder);
          dracoDecoder.destroy(dracoGeometry);
          throw new Error(errorMsg);
        }

        var decode_end = performance.now();
        dracoDecoder.destroy(buffer);
        /*
         * Example on how to retrieve mesh and attributes.
         */
        var numFaces, numPoints;
        var numVertexCoordinates, numTextureCoordinates, numColorCoordinates;
        var numAttributes;
        var numColorCoordinateComponents = 3;
        // For output basic geometry information.
        var geometryInfoStr;
        if (geometryType == dracoDecoder.TRIANGULAR_MESH) {
          numFaces = dracoGeometry.num_faces();
          if (this.verbosity > 0) {
            console.log('Number of faces loaded: ' + numFaces.toString());
          }
        } else {
          numFaces = 0;
        }
        numPoints = dracoGeometry.num_points();
        numVertexCoordinates = numPoints * 3;
        numTextureCoordinates = numPoints * 2;
        numColorCoordinates = numPoints * 3;
        numAttributes = dracoGeometry.num_attributes();
        console.log("dracoGeometry", dracoGeometry);
        if (this.verbosity > 0) {
          console.log('Number of points loaded: ' + numPoints.toString());
          console.log('Number of attributes loaded: ' +
              numAttributes.toString());
        }

        // Get position attribute. Must exists.
        var posAttId = decoder.GetAttributeId(dracoGeometry,
                                                dracoDecoder.POSITION);
        if (posAttId == -1) {
          var errorMsg = 'THREE.DRACOLoader: No position attribute found.';
          console.error(errorMsg);
          dracoDecoder.destroy(decoder);
          dracoDecoder.destroy(dracoGeometry);
          throw new Error(errorMsg);
        }

        var posAttribute = decoder.GetAttribute(dracoGeometry, posAttId);
        var posAttributeData = new dracoDecoder.DracoFloat32Array();
        decoder.GetAttributeFloatForAllPoints(
            dracoGeometry, posAttribute, posAttributeData);
        console.log("posAttribute", posAttribute);

        // Get color attributes if exists.
        var colorAttId = decoder.GetAttributeId(dracoGeometry,
                                                  dracoDecoder.COLOR);
        var colAttributeData;
        if (colorAttId != -1) {
          if (this.verbosity > 0) {
            console.log('Loaded color attribute.');
          }
          var colAttribute = decoder.GetAttribute(dracoGeometry, colorAttId);
          if (colAttribute.num_components() === 4) {
            numColorCoordinates = numPoints * 4;
            numColorCoordinateComponents = 4;
          }
          colAttributeData = new dracoDecoder.DracoFloat32Array();
          decoder.GetAttributeFloatForAllPoints(dracoGeometry, colAttribute,
                                                colAttributeData);
        }

        // Get normal attributes if exists.
        var normalAttId =
            decoder.GetAttributeId(dracoGeometry, dracoDecoder.NORMAL);
        var norAttributeData;
        if (normalAttId != -1) {
          if (this.verbosity > 0) {
            console.log('Loaded normal attribute.');
          }
          var norAttribute = decoder.GetAttribute(dracoGeometry, normalAttId);
          norAttributeData = new dracoDecoder.DracoFloat32Array();
          decoder.GetAttributeFloatForAllPoints(dracoGeometry, norAttribute,
                                                norAttributeData);
        }

        // Get texture coord attributes if exists.
        var texCoordAttId =
            decoder.GetAttributeId(dracoGeometry, dracoDecoder.TEX_COORD);
        var textCoordAttributeData;
        if (texCoordAttId != -1) {
          if (this.verbosity > 0) {
            console.log('Loaded texture coordinate attribute.');
          }
          var texCoordAttribute = decoder.GetAttribute(dracoGeometry,
                                                         texCoordAttId);
          textCoordAttributeData = new dracoDecoder.DracoFloat32Array();
          decoder.GetAttributeFloatForAllPoints(dracoGeometry,
                                                texCoordAttribute,
                                                textCoordAttributeData);
        }

        var materialAttrId = decoder.GetAttributeIdByName(dracoGeometry, "material");

        var materialAttributeData;
        if (materialAttrId != -1) {
          if (this.verbosity > 0) {
            console.log('Loaded material attribute.');
          }
        }

        var materialAttribute = decoder.GetAttribute(dracoGeometry,
                                                       materialAttrId);
        materialAttributeData = new dracoDecoder.DracoFloat32Array();
        decoder.GetAttributeFloatForAllPoints(dracoGeometry,
                                              materialAttribute,
                                              materialAttributeData);

        var subObjAttId = decoder.GetAttributeIdByName(dracoGeometry, "sub_obj");
        var subObjAttributeData;
        if (subObjAttId != -1) {
          if (this.verbosity > 0) {
            console.log('Loaded Sub Obj attribute.');
          }
        }

        var subObjAttribute = decoder.GetAttribute(dracoGeometry,
                                                       subObjAttId);
        subObjAttributeData = new dracoDecoder.DracoFloat32Array();
        decoder.GetAttributeFloatForAllPoints(dracoGeometry,
                                              subObjAttribute,
                                              subObjAttributeData);

        var subObjectInfo = {};
        var subObjectBuffers = [];
        var globalToLocalMap = {};
        for (var i = 0, k = 0; i < numVertexCoordinates; i += 3, k ++) {
            var subObjectId = subObjAttributeData.GetValue(k);
            var matId = materialAttributeData.GetValue(k);
            var key = subObjectId.toString() + ":" + matId.toString();
            // If subObjectId isn't in the list yet, create it and give it a count of 1
            if (!(key in subObjectInfo)) {
                subObjectInfo[key] = 1;
            }
            // Otherwise increment count
            else {
                subObjectInfo[key]++;
            }
            // Map global index with local index, (count -1)
            globalToLocalMap[k] = subObjectInfo[key] - 1;
        }
        var indices;

        if (geometryType == dracoDecoder.TRIANGULAR_MESH) {
          if (this.drawMode === THREE.TriangleStripDrawMode) {
            var stripsArray = new dracoDecoder.DracoInt32Array();
            var numStrips = decoder.GetTriangleStripsFromMesh(
                dracoGeometry, stripsArray);
            indices = new Uint32Array(stripsArray.size());
            for (var i = 0; i < stripsArray.size(); ++i) {
              indices[i] = stripsArray.GetValue(i);
            }
            dracoDecoder.destroy(stripsArray);
          } else {
            var numIndices = numFaces * 3;
            indices = new Uint32Array(numIndices);
            var ia = new dracoDecoder.DracoInt32Array();
            for (var i = 0; i < numFaces; ++i) {
              decoder.GetFaceFromMesh(dracoGeometry, i, ia);
              var index = i * 3;
              indices[index] = ia.GetValue(0);
              indices[index + 1] = ia.GetValue(1);
              indices[index + 2] = ia.GetValue(2);
            }
            dracoDecoder.destroy(ia);
         }
        }

        var subObjectInfoKeys = Object.keys(subObjectInfo);

        var numSubObjectIndices = {}; //new Int32Array(subObjectInfoKeys.length);
        for (var i in subObjectInfo) numSubObjectIndices[i] = 0;
        for (var i = 0; i < 3 * numFaces; ++i) {
          const pointId = indices[i];
          var subObjectId = subObjAttributeData.GetValue(pointId);
          var matId = materialAttributeData.GetValue(pointId);
          var key = subObjectId.toString() + ":" + matId.toString();
          numSubObjectIndices[key]++;
        }

        for (var key in subObjectInfo){
            var geometryBuffer = {
                indices: new Uint32Array(numSubObjectIndices[key]),
                vertices: new Float32Array(subObjectInfo[key] * 3),
                normals: new Float32Array(subObjectInfo[key] * 3),
                uvs: new Float32Array(subObjectInfo[key] * 2),
                colors: new Float32Array(subObjectInfo[key] * 3)
            };
            subObjectBuffers[key] = {"geometryBuffer": geometryBuffer, "materialId": -1};
        }

        for (var i = 0, k = 0, l = 0; i < numVertexCoordinates; i += 3, k++, l +=2) {
            var subObjectId = subObjAttributeData.GetValue(k);
            var matId = materialAttributeData.GetValue(k);
            var key = subObjectId.toString() + ":" + matId.toString();

            // Positions
            subObjectBuffers[key].geometryBuffer.vertices[globalToLocalMap[k]*3]   = posAttributeData.GetValue(i);
            subObjectBuffers[key].geometryBuffer.vertices[globalToLocalMap[k]*3+1] = posAttributeData.GetValue(i + 1);
            subObjectBuffers[key].geometryBuffer.vertices[globalToLocalMap[k]*3+2] = posAttributeData.GetValue(i + 2);

            // Normals
            if (normalAttId != -1) {
                subObjectBuffers[key].geometryBuffer.normals[globalToLocalMap[k]*3]   = norAttributeData.GetValue(i);
                subObjectBuffers[key].geometryBuffer.normals[globalToLocalMap[k]*3+1] = norAttributeData.GetValue(i + 1);
                subObjectBuffers[key].geometryBuffer.normals[globalToLocalMap[k]*3+2] = norAttributeData.GetValue(i + 2);
            }
            if (colorAttId != -1) {
              // Draco colors are already normalized.
              subObjectBuffers[key].geometryBuffer.colors[globalToLocalMap[k]*3] = colAttributeData.GetValue(i);
              subObjectBuffers[key].geometryBuffer.colors[globalToLocalMap[k]*3+1] = colAttributeData.GetValue(i + 1);
              subObjectBuffers[key].geometryBuffer.colors[globalToLocalMap[k]*3+2] = colAttributeData.GetValue(i + 2);
            } else {
              // Default is white. This is faster than TypedArray.fill().
              subObjectBuffers[key].geometryBuffer.colors[globalToLocalMap[k]*3] = 1.0;
              subObjectBuffers[key].geometryBuffer.colors[globalToLocalMap[k]*3+1] = 1.0;
              subObjectBuffers[key].geometryBuffer.colors[globalToLocalMap[k]*3+2] = 1.0;
            }
            // Uv's
            if (texCoordAttId != -1) {
                subObjectBuffers[key].geometryBuffer.uvs[globalToLocalMap[k]*2] = textCoordAttributeData.GetValue(l);
                subObjectBuffers[key].geometryBuffer.uvs[globalToLocalMap[k]*2+1] = textCoordAttributeData.GetValue(l + 1);
            }
            if(materialAttrId != -1){
              subObjectBuffers[key].materialId = materialAttributeData.GetValue(k);
              /*if(subObjectBuffers[key].materialId.indexOf(matId) == -1){
                   subObjectBuffers[key].materialId.push(matId);
              }*/
            }
        }

        for (var i in subObjectInfo) numSubObjectIndices[i] = 0;
        for (var i = 0; i < 3 * numFaces; ++i) {
          const pointId = indices[i];
          var subObjectId = subObjAttributeData.GetValue(pointId);
          var matId = materialAttributeData.GetValue(pointId);
          var key = subObjectId.toString() + ":" + matId.toString();
          subObjectBuffers[key].geometryBuffer.indices[numSubObjectIndices[key]++] = globalToLocalMap[pointId];
        }

        var container = new THREE.Group();
        var scales = [];
        var materialKeys = Object.keys(this.materials.materials);

        for(var key in subObjectBuffers){
            var geometryBuffer = subObjectBuffers[key].geometryBuffer;
            var geometry = new THREE.BufferGeometry();
            geometry.drawMode = this.drawMode;
            if (geometryType == dracoDecoder.TRIANGULAR_MESH) {
              geometry.setIndex(new(geometryBuffer.indices.length > 65535 ?
                    THREE.Uint32BufferAttribute : THREE.Uint16BufferAttribute)
                  (geometryBuffer.indices, 1));
            }
            geometry.addAttribute('position',
                new THREE.Float32BufferAttribute(geometryBuffer.vertices, 3));
            var posTransform = new dracoDecoder.AttributeQuantizationTransform();
            if (posTransform.InitFromAttribute(posAttribute)) {
              // Quantized attribute. Store the quantization parameters into the
              // THREE.js attribute.
              geometry.attributes['position'].isQuantized = false;
              geometry.attributes['position'].maxRange = posTransform.range();
              geometry.attributes['position'].numQuantizationBits =
                  posTransform.quantization_bits();
              geometry.attributes['position'].minValues = new Float32Array(3);
              for (var i = 0; i < 3; ++i) {
                geometry.attributes['position'].minValues[i] =
                    posTransform.min_value(i);
              }
            }
            dracoDecoder.destroy(posTransform);
            geometry.addAttribute('color',
                new THREE.Float32BufferAttribute(geometryBuffer.colors,
                                                 numColorCoordinateComponents));
            if (normalAttId != -1) {
              geometry.addAttribute('normal',
                  new THREE.Float32BufferAttribute(geometryBuffer.normals, 3));
            }
            if (texCoordAttId != -1) {
              geometry.addAttribute('uv',
                  new THREE.Float32BufferAttribute(geometryBuffer.uvs, 2));
            }

            var material = this.materials.materials[materialKeys[subObjectBuffers[key].materialId]];
            material.shading = THREE.SmoothShading;
            var mesh = new THREE.Mesh( geometry, material );

            mesh.drawMode = this.drawMode;
            geometry.computeBoundingBox();

            mesh.name = key;
            container.add( mesh );
        }
        return container;
}

I've another function setMaterials in which I set the materials loaded from Mtl-Loader.

mtlLoader.setPath('<path-to-your-mtl-file>');
    mtlLoader.load('<mtl-filename>', function(materials) {
    materials.preload();
    dracoLoader.setMaterials(materials);
    dracoLoader.decodeDracoFile(reader.result, function(contain) {
        scene.add(contain);
    });
});
JackC09 commented 7 years ago

@shubhamagarwal003 thanks it's really useful for me.

@ondys by placing --metadata flag before like this

$ ./draco_encoder --metadata -i car.obj -o car.drc

result is better with shubhamagarwal003's model:

Encoded size = 133614 bytes

Now I have subObjAttId but materialAttrId still return -1

ondys commented 7 years ago

@JackC09 Yes there was a bug in Draco when --metadata was the last argument passed in (in which case it was ignored). It's fixed now in our private repo and we will push the fix to public in the coming days.

I'll look into the issue with materialAttrId == -1

JackC09 commented 7 years ago

@ondys Hi, I tried the latest commit 1.1.0 and for some models materialAttrId was ok but subObjAttId == -1 https://drive.google.com/drive/folders/0B7BhishE3I-cc1VkMS0xekd4Wjg?usp=sharing

In the description it is written 'Draco can preserve material or sub-object names' how can I get the subObjName?

ondys commented 6 years ago

Which of the shared model had the problem with subObjAttId ? Note that subobject ids are currently generated only when the obj uses "o " keyword. When the .obj is encoded with --metadata flag, the metadata for sub object id attribute will then contain mapping between sub-object ids and the corresponding sub object names.

yuerdev commented 6 years ago

@ondys where map between sub-object ids and the corresponding sub object names? or how get sub object name?

ondys commented 6 years ago

@pumpkindev In c++ you can see an example in ObjEncoder::GetSubObjects() method (in obj_encoder.cc). For javascript, it seems we miss some API that is needed to accomplish this. I'll make the necessary changes and try to push into into our next update.

FarhadG commented 6 years ago

Do we have any programmatic way of loading a .drc file that has several textures? I have a large model (.obj) that was generated using a photogrammetry service. When I compress the file to .drc, I cannot get the multiple textures that the photogrammetry services generates for the single .obj to map properly. If you have any suggestions, it would be extremely helpful, as it's becoming a huge blocker for us.

I am thinking of writing a parser to separate the OBJ into several sub OBJs to reference each materials file individually, but perhaps we already have a working version of something similar (or better) than this approach?