draco icon indicating copy to clipboard operation
draco copied to clipboard

Discussion on sub-objects and materials

Open NumaNumaNuma opened this issue 8 years ago • 29 comments

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

NumaNumaNuma avatar Apr 01 '17 02:04 NumaNumaNuma

@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.

ondys avatar Apr 03 '17 05:04 ondys

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."

NumaNumaNuma avatar Apr 03 '17 05:04 NumaNumaNuma

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

ondys avatar Apr 03 '17 05:04 ondys

I'll pull and check

NumaNumaNuma avatar Apr 03 '17 05:04 NumaNumaNuma

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

NumaNumaNuma avatar Apr 03 '17 05:04 NumaNumaNuma

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.

ondys avatar Apr 03 '17 06:04 ondys

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 avatar Apr 03 '17 06:04 NumaNumaNuma

I have emailed you the files. thanks!

NumaNumaNuma avatar Apr 03 '17 06:04 NumaNumaNuma

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!

NumaNumaNuma avatar Apr 03 '17 06:04 NumaNumaNuma

@NumaNumaNuma Thanks for the update. Good to know!

ondys avatar Apr 03 '17 06:04 ondys

@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)?

openforus avatar Apr 05 '17 09:04 openforus

@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

ondys avatar Apr 05 '17 16:04 ondys

thanks I find the example in draco_encoder problem #67

At 2017-04-06 00:45:06, "Ondrej Stava" [email protected] 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 avatar Apr 06 '17 01:04 openforus

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

openforus avatar Apr 10 '17 02:04 openforus

@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];
}

ondys avatar Apr 11 '17 05:04 ondys

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

openforus avatar Apr 17 '17 03:04 openforus

@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)?

shubhamagarwal003 avatar Aug 28 '17 10:08 shubhamagarwal003

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?

JackC09 avatar Sep 06 '17 09:09 JackC09

@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

ondys avatar Sep 06 '17 22:09 ondys

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

shubhamagarwal003 avatar Sep 07 '17 09:09 shubhamagarwal003

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

JackC09 avatar Sep 07 '17 11:09 JackC09

@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);
    });
});

shubhamagarwal003 avatar Sep 07 '17 13:09 shubhamagarwal003

@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

JackC09 avatar Sep 07 '17 14:09 JackC09

@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

ondys avatar Sep 07 '17 19:09 ondys

@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?

JackC09 avatar Sep 13 '17 08:09 JackC09

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.

ondys avatar Sep 29 '17 22:09 ondys

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

yuerdev avatar Jan 10 '18 03:01 yuerdev

@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.

ondys avatar Jan 10 '18 19:01 ondys

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?

FarhadG avatar Apr 04 '18 20:04 FarhadG