draco icon indicating copy to clipboard operation
draco copied to clipboard

How to get obj name and sub_obj name from metadata with javascript decoder API

Open loohopen opened this issue 6 years ago • 14 comments

using version 1.3.0

loohopen avatar May 23 '18 02:05 loohopen

After doing some digging in the source I managed to get the sub_obj name with the following:


// initial setup
const decoder = new dracoDecoder.Decoder();
const buffer = new dracoDecoder.DecoderBuffer();

// raw buffer contains the draco file blob
buffer.Init(new Int8Array(rawBuffer), rawBuffer.byteLength);

const dracoGeometry = new dracoDecoder.Mesh();
decodingStatus = decoder.DecodeBufferToMesh(buffer, dracoGeometry);

// get the sub object attribute, and related data
let subObjAttribute = null;
let subObjAttributeData = null;
if (subObjAttributeId !== -1) {
    subObjAttribute = decoder.GetAttribute(dracoGeometry, subObjAttributeId);
    subObjAttributeData = new dracoDecoder.DracoFloat32Array();
    decoder.GetAttributeFloatForAllPoints(dracoGeometry, subObjAttribute, subObjAttributeData);
}

// Query the attributes metadata
const attributeMetadata = decoder.GetAttributeMetadata(dracoGeometry, subObjAttributeId);
const metadataQ = new dracoDecoder.MetadataQuerier();
const numSubObjects = metadataQ.NumEntries(attributeMetadata);
for (let i = 0; i < numSubObjects; i++) {
    const subObjectName = metadataQ.GetEntryName(attributeMetadata, i);
    console.log(subObjectName)
}

My draco file was encoded from an obj looking something like this:

o 2weB5UmZP9GOCGFBRYXrPI
v 161.13 196.15 13.13
v 161.13 195.15 13.5
v 161.63 195.15 13.5
v 161.63 196.15 13.5
v 161.63 195.15 13.5
v 161.63 195.15 13.5
v 161.63 195.15 13.5
v 161.63 195.15 13.5
v 161.63 195.15 13.5
v 161.63 195.15 13.5
v 161.63 195.15 13.5
v 161.63 195.15 13.5
v 161.63 195.15 13.5
v 161.13 196.15 13.5
usemtl surface-style-408402
f 26//26 25//25 28//28
f 40//40 38//38 39//39
f 44//44 43//43 42//42
f 45//45 46//46 48//48
f 46//46 47//47 48//48
o asldkjfasd9sdlkfj

etc....

simenandresen avatar May 30 '18 11:05 simenandresen

that's very kind of you! it's works! thank you very much! @simena86

loohopen avatar Jun 01 '18 03:06 loohopen

Happy to help! :smile: Btw. there seems to be a problem mapping the names to the right sub objects. (Seems to be a problem with decoder_webidl_wrapper.cc's use of unordered_map -> vector.) Also, I'm getting name as one of the sub_obj names, without having this in the obj file. Perhaps you could confirm if you're having the same problem @loohopen ?

I'll try to create a PR for this.

simenandresen avatar Jun 01 '18 08:06 simenandresen

#408 should fix getting the correct name for each sub_obj's face

simenandresen avatar Jun 01 '18 14:06 simenandresen

For completeness (with the fix from #408), this is how one could the relationship between a mesh's faces and corresponding sub object name:

// initial setup
const decoder = new dracoDecoder.Decoder();
const buffer = new dracoDecoder.DecoderBuffer();

// raw buffer contains the draco file blob
buffer.Init(new Int8Array(rawBuffer), rawBuffer.byteLength);

const dracoGeometry = new dracoDecoder.Mesh();
decodingStatus = decoder.DecodeBufferToMesh(buffer, dracoGeometry);

// get the sub object attribute, and related data
let subObjAttribute = null;
let subObjAttributeData = null;
if (subObjAttributeId !== -1) {
    subObjAttribute = decoder.GetAttribute(dracoGeometry, subObjAttributeId);
    subObjAttributeData = new dracoDecoder.DracoFloat32Array();
    decoder.GetAttributeFloatForAllPoints(dracoGeometry, subObjAttribute, subObjAttributeData);
}

// Query the attributes metadata
const attributeMetadata = decoder.GetAttributeMetadata(dracoGeometry, subObjAttributeId);
const metadataQ = new dracoDecoder.MetadataQuerier();

let face = new dracoDecoder.DracoInt32Array();
for (let i = 0; i < dracoGeometry.num_faces(); i++) {
    decoder.GetFaceFromMesh(dracoGeometry, i, face);
    const subObjIndex = subObjAttributeData.GetValue(face.GetValue(0));
    const subObjectName = metadataQ.GetEntryName(attributeMetadata, subObjIndex);
    console.log(`Sub object name : ${subObjectName} for face with index ${i}`)
}

simenandresen avatar Jun 04 '18 07:06 simenandresen

@simena86 yes, you are right, i just tested my project, and i meet the same problem: there is an extra name named name, and those names are not mapped with subObject_id... seems you have fixed this problem in #408, i'll try it later. thank you for help!

loohopen avatar Jun 04 '18 09:06 loohopen

@simena86 does #408 means that i just should re-complie the source use this method and generate a new draco_wasm_wrapper.js ?

loohopen avatar Jun 06 '18 03:06 loohopen

and i meet the same problem: there is an extra name named name, and those names are not mapped with subObject_id...

yep, found that too, and as you mention #408 solves this

does #408 means that i just should re-complie the source use this method and generate a new draco_wasm_wrapper.js ?

Yep, just recompile from 66770f968648df360f69c6f064920cb9f5a9f001 and use the newly created draco_wasm_wrapper.js and also draco_decoder.wasm I guess.

simenandresen avatar Jun 07 '18 10:06 simenandresen

@simena86 and @loohopen, sorry it took so long to get back to you. Can you try this code without Simen's patch to see if it works for your files?

  const subobjAttrId = decoder.GetAttributeId(dracoGeometry, decoderModule.GENERIC);
  const attributeMetadata = decoder.GetAttributeMetadata(dracoGeometry, subobjAttrId);
  const entryCount = metadataQuerier.NumEntries(attributeMetadata);

  let subobjIndexToName = {};
  for (let i = 0; i < entryCount; ++i) {
    const entryName = metadataQuerier.GetEntryName(attributeMetadata, i);
    // Check entry is not "reserved" sub-object entry.
    if (entryName !== 'name') {
      const intEntry = metadataQuerier.GetIntEntry(attributeMetadata, entryName);
      subobjIndexToName[intEntry.toString()] = entryName;
    }
  }

  const subobjAttr = decoder.GetAttribute(dracoGeometry, subobjAttrId);
  let subobjAttrData = new decoderModule.DracoInt32Array();
  decoder.GetAttributeInt32ForAllPoints(dracoGeometry, subobjAttr, subobjAttrData);

  let face = new decoderModule.DracoInt32Array();
  for (let i = 0; i < dracoGeometry.num_faces(); i++) {
    decoder.GetFaceFromMesh(dracoGeometry, i, face);
    const subobjIndex = subobjAttrData.GetValue(face.GetValue(0));
    const subobjName = subobjIndexToName[subobjIndex.toString()];
    console.log(`Sub object name : ${subobjName} for face with index ${i}`)
  }


FrankGalligan avatar Aug 10 '18 07:08 FrankGalligan

Thanks for your reply @FrankGalligan . Not sure why, but with your code I only seem to get the material names, e.g. surface-style-408402 as in the example obj in https://github.com/google/draco/issues/401#issuecomment-393126211.

At least in my case, I was interested in the sub_obj names, e.g. 2weB5UmZP9GOCGFBRYXrPI from the obj example in https://github.com/google/draco/issues/401#issuecomment-393126211 and not the material names. Would be nice to see if anyone else gets the same result.

Also, for some draco files, I got the following error:

2a4dd3f….worker.js:50663 Uncaught TypeError: a.UTF8ToString is not a function
    at n (2a4dd3f….worker.js:50663)
    at r.DracoDecoderModule.r.GetEntryName.r.GetEntryName (2a4dd3f….worker.js:51785)
    at convertDracoGeometryTo3JS (2a4dd3f….worker.js:50316)
    at decodeDracoFileInternal (2a4dd3f….worker.js:50152)
    at Object.onLoad (2a4dd3f….worker.js:784)
    at XMLHttpRequest.<anonymous> (2a4dd3f….worker.js:34919)

simenandresen avatar Aug 15 '18 14:08 simenandresen

@FrankGalligan see this fiddle:

https://jsfiddle.net/turbowhale/h0t179pa/25/

where I'v tried without using my patch.

Notice that only the material names are written out

The original obj file looks like this:

mtllib cube.mtl
v 0.500000 0.500000 -0.500000
v 0.500000 -0.500000 -0.500000
v -0.500000 -0.500000 -0.500000
v -0.500000 -0.500000 0.500000
v 0.500000 -0.500000 0.500000
v 0.500000 0.500000 0.500000
v -0.500000 0.500000 -0.500000
v -0.500000 0.500000 0.500000
vn 0.000000 0.000000 -1.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 0.000000 -1.000000
vn 1.000000 0.000000 0.000000
vn 1.000000 0.000000 0.000000
vn 1.000000 0.000000 0.000000
vn 1.000000 0.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 1.000000 0.000000
vn -1.000000 0.000000 0.000000
vn -1.000000 0.000000 0.000000
vn -1.000000 0.000000 0.000000
vn -1.000000 0.000000 0.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 0.000000 1.000000
vn 0.000000 0.000000 1.000000
vn 0.000000 0.000000 1.000000
vn 0.000000 0.000000 1.000000
o cube-object
usemtl cube-material
f 3//3 1//1 2//2
o cube-object2
usemtl cube-material2
f 2//7 1//5 6//6
o cube-object
usemtl cube-material
f 6//11 1//9 7//10
f 1//1 3//3 7//4
o cube-object2
usemtl cube-material2
f 7//15 3//13 4//14
f 3//19 2//17 4//18
f 4//18 2//17 5//20
f 2//7 6//6 5//8
o cube-object
usemtl cube-material
f 5//23 6//21 8//22
f 6//11 7//10 8//12
o cube-object2
usemtl cube-material2
f 7//15 4//14 8//16
o cube-object
usemtl cube-material
f 5//23 8//22 4//24

Link to files:

https://storage.googleapis.com/simens_misc/draco-test/cube.mtl https://storage.googleapis.com/simens_misc/draco-test/cube.obj https://storage.googleapis.com/simens_misc/draco-test/cube2.drc

simenandresen avatar Aug 30 '18 09:08 simenandresen

Here's a fiddle with my patch

https://jsfiddle.net/turbowhale/h0t179pa/42/

Notice that the object names are logged cube-object etc..

simenandresen avatar Aug 30 '18 12:08 simenandresen

I met a problem:

when there is multiple sub-object, the sequence of sub-object name will not be preserved. Any similar issue from you guys?

YouYue123 avatar Oct 25 '18 14:10 YouYue123

I am trying to create an array with the indices of faces that belong to a sub-object with a specific id, but only 17 faces are found in the script whereas the sub-object contains 301 faces in the original obj. I have no idea what is going wrong here, the code is similar to simenandresen's example.

const subObjAttributeId = decoder.GetAttributeIdByName(dracoGeometry, 'sub_obj');

// get the sub object attribute, and related data
let subObjAttribute = null;
let subObjAttributeData = null;
if (subObjAttributeId !== -1) {
    subObjAttribute = decoder.GetAttribute(dracoGeometry, subObjAttributeId);
    subObjAttributeData = new dracoDecoder.DracoFloat32Array();
    decoder.GetAttributeFloatForAllPoints(dracoGeometry, subObjAttribute, subObjAttributeData);
}

// Query the attributes metadata
const attributeMetadata = decoder.GetAttributeMetadata(dracoGeometry, subObjAttributeId);
const metadataQ = new dracoDecoder.MetadataQuerier();

// Array with face ids
var objectFaces = [];

let face = new dracoDecoder.DracoInt32Array();
for (let i = 0; i < dracoGeometry.num_faces(); i++) {
    decoder.GetFaceFromMesh(dracoGeometry, i, face);
    const subObjIndex = subObjAttributeData.GetValue(face.GetValue(0));
    const subObjectName = metadataQ.GetEntryName(attributeMetadata, subObjIndex);

    // Append face id to array if it has the correct id
    if (subObjectName == "b69a8d7bc-2d38-11e6-9a38-393caa90be70"){
      objectFaces.push(i);
    }
}
console.log(objectFaces.length);

The obj and drc files that I am using can be found here: https://we.tl/t-l43we3Dyqb

I'd be very grateful for any help.

jliempt avatar Mar 23 '20 18:03 jliempt