Giter Site home page Giter Site logo

draco_encoder problem about draco HOT 24 CLOSED

google avatar google commented on July 18, 2024
draco_encoder problem

from draco.

Comments (24)

Frankling avatar Frankling commented on July 18, 2024 4

@ondys
For example ,if i upload a obj file with objloader, I can get a groups that contains three mesh,as show below
ThreeSphereObjFile
|---children
|--Mesh[0]
|--Mesh[1]
|--Mesh[2]
..
so can dracoLoader return bufferGeometry that as a group contains children like objloader does;

from draco.

ondys avatar ondys commented on July 18, 2024 2

I'm glad it worked for you but I would just like to warn you that there may be some potential issues with your solution. First, your proposed loader assumes that all positions and all indices are always stored consecutively in the loaded buffers .. e.g. this code:

for (let j=0, i=(pointCnt * 3); i< ( pointCnt*3 ) + numvert; j+= 3,i+= 3) {
		geom.vertices[j] = posAttributeData.GetValue(i);
		geom.vertices[j + 1] = posAttributeData.GetValue(i + 1);
		geom.vertices[j + 2] = posAttributeData.GetValue(i + 2);
	}

That is true only if the sub-objects are separate mesh components. If the sub-objects were defined on a single mesh component (faces connected together but belonging to different sub-objects), then this is not going to hold anymore.

The same is true for the subObjAttributeIds being stored in a descending order. It's going to be like that for sub-objects that are separate mesh components, but otherwise the subObjAttributeIds can be stored in an arbitrary order.

To solve this, you would have to do something like this:

  1. Count the number of points for each sub-object id the way you already do it
  2. Create a map between global point ids and local point ids in each sub-object (this can be done during the counting step, a simple Int32Array would be probably the best)
  3. Allocate geometries for each sub-object using the counted number of vertices in each sub-object
  4. Go over the points again and copy vertex positions to the sub-object geometries using the map between global and local point ids
  5. Go over all faces and copy indices from the global index buffer to sub-object index buffers using the map between global and local point ids

Overall, it shouldn't be more code than what you already have, but you will need the extra map between the global and local point indices

from draco.

ondys avatar ondys commented on July 18, 2024 2

@Frankling I'm not sure if I understand the question. Draco currently does not parse polygon/smoothing groups so they are all contained within the same bufferGeometry. Do you want to have a separate geometry returned for each group?

from draco.

YouYue123 avatar YouYue123 commented on July 18, 2024 1

Any update on making a direct support for JS encoder or DracoLoader to get sub-object information. Actually if you can add polygon groups (g) or smoothing groups(s) support in a more straight API it would be very helpful

from draco.

ondys avatar ondys commented on July 18, 2024

Are you referring to sub-objects in the .obj file? If so, then yes, the current version of draco_encoder does convert them into a single mesh. Sub object ids are still stored in a GENERIC attribute though, but to separate the mesh into the sub-objects you would have to write your own logic on the client app. If that's what you want to do I can give you some pointers. We will add support for preserving sub-object for .OBJ files in future (when we add support for metadata).

from draco.

Frankling avatar Frankling commented on July 18, 2024

@ondys ,yes,I want to refer to sub-objects in the .obj file.

from draco.

Frankling avatar Frankling commented on July 18, 2024

@ondys my Email address is [email protected]

from draco.

ondys avatar ondys commented on July 18, 2024

I'll just write it here so other people can find it too. Each sub-object of the input OBJ is assigned a id that is equivalent to it's location in the .OBJ file (so the first sub-object has id == 0, second 1, third 2, etc...). No sub-object names are currently preserved. The sub-object ids are stored for every face of the mesh and to get them on the client, you need to get a generic attribute with custom_id() === 1 :

let subObjAttId = -1;
for (let i = 0; i < dracoGeometry.num_attributes(); i++) {
    const attribute = wrapper.GetAttribute(dracoGeometry, i)
    if (attribute.attribute_type() === Module.GENERIC && attribute.custom_id() === 1) {
      subObjAttId = i;
      break;
    }
}
let subObjAttribute = wrapper.GetAttribute(dracoGeometry, subObjAttId);

You can then get the sub-object id values as:

subObjAttributeData = new DracoModule.DracoFloat32Array();
          wrapper.GetAttributeFloatForAllPoints(dracoGeometry, subObjAttribute,   subObjAttributeData);

This array will store a sub-object id for every point of the mesh, but all points that belong to the same face are always going to be mapped to the same sub-object id value. You can then use these ids to split the mesh into different geometries.

from draco.

kappa-gooner avatar kappa-gooner commented on July 18, 2024

@ondys
Rather surprising that I'm having the exact same requirement right now.
I notice however that the num_attributes() is always 2; and there are no attributes with type GENERIC.
Does it depend on the compression level cl or quantization parameters qp while encoding the file?

from draco.

ondys avatar ondys commented on July 18, 2024

@kappa-gooner The generic attribute is not going to be created if there is only one sub-object in the obj file. If that's not your case, can you please post a link to an .OBJ that shows the problem?

from draco.

kappa-gooner avatar kappa-gooner commented on July 18, 2024

@ondys Please scratch that request.
I was referring to sub-meshes and not sub-objects.
Is there any way we can retrieve individual sub-mesh info from the encoded file?

from draco.

ondys avatar ondys commented on July 18, 2024

@kappa-gooner Depends what sub-mesh info you are looking for. We store material ids in another generic attribute (with custom id 0). The file that you originally linked was also using g symbol for polygon groups and s symbol for smoothing groups. Both of these are currently ignored. We may add support for them later on if there is demand.

from draco.

kappa-gooner avatar kappa-gooner commented on July 18, 2024

@ondys
Thank you for looking into this.
Looks like most obj files I work with use g and s for polygon/smoothing groups.
Is there any way I can add support for these myself?
Also, even if I manage to retrieve the sub-mesh ids; would it be possible to get hold of the geometric information (say bounding box) of these groups?

from draco.

kappa-gooner avatar kappa-gooner commented on July 18, 2024

@ondys
Ok, here's what I ended up doing. I followed your cue and replaced all the g in my obj file with o so that the polygon groups are represented as sub-objects.

I was able to pull out the subObjAttributeData as directed by you and ended up using that to first, map it to points and then to faces. My result is rather weird.
screen shot 2017-03-02 at 4 28 01 pm

  1. Any clues as to why this could be happening? Would it be possible for you to throw more light onto how this is achieved?

This array will store a sub-object id for every point of the mesh, but all points that belong to the same face are always going to be mapped to the same sub-object id value. You can then use these ids to split the mesh into different geometries.

  1. I rather found it painful to map the subObjAttributeData to the points in the individual sub objects and then to the faces.

from draco.

ondys avatar ondys commented on July 18, 2024

@kappa-gooner

  1. Does the model look correct when you don't use the sub-object ids?
  2. If so, can you post an short snipped of your code where you use the sub-object ids to split the mesh into multiple geometries?

from draco.

kappa-gooner avatar kappa-gooner commented on July 18, 2024

@ondys :

  1. Sorry, there are problems with this particular model when I don't use sub-object ids. That's got to do with the faces being polygons and not simple triangles as you pointed out in the other issue.
  2. But, regardless here's a simplified snippet of my code that splits sub-objects into meshes...
// First get subObjAttributeData by using your code above

// Build an object that holds every subobjectID as the key and a member count that indicates the number of points in each sub-object (This is achieved by simple looping and counting)

// Build subobjectArray that contains the points (Ignoring normals and colors for simplicity
const subObjectArray = [];
let pointCnt = 0;
for (let key in subObjInfo) {
	const numPts = subObjInfo[key].count;
	const numvert = numPts * 3;

	const geom = {
		vertices: new Float32Array(numvert),
		indices: [],
		minPtInd: pointCnt // The minPtIndex and MaxPtIndex are required to associtate the mesh faces to the sub-object points later-on 
	}

	for (let j=0, i=(pointCnt * 3); i< ( pointCnt*3 ) + numvert; j+= 3,i+= 3) {
		geom.vertices[j] = posAttributeData.GetValue(i);
		geom.vertices[j + 1] = posAttributeData.GetValue(i + 1);
		geom.vertices[j + 2] = posAttributeData.GetValue(i + 2);
	}
	pointCnt += numPts;
	geom.maxPtInd = pointCnt;
	subObjectArray.push(geom);
}

// Here's where I'm trying to associate the faces to the sub-objects
const ia = new dracoDecoder.DracoInt32Array();
for (let i = 0; i < numFaces; ++i) {
         wrapper.GetFaceFromMesh(dracoGeometry, i, ia);
            
	// COPYING INDICES
	for (let j=0; j<subObjectArray.length; j++) {
		const subObj = subObjectArray[j];
		if (ia.GetValue(0) >= subObj.minPtInd &&
			ia.GetValue(0) < subObj.maxPtInd) {
			subObj.indices.push(ia.GetValue(0) - subObj.minPtInd)
			subObj.indices.push(ia.GetValue(1) - subObj.minPtInd)
			subObj.indices.push(ia.GetValue(2) - subObj.minPtInd)
			break;
		}
	}
}

Any pointers that could help me out? :-/

from draco.

kappa-gooner avatar kappa-gooner commented on July 18, 2024

@ondys : I figured out the problem.
The subObjAttributeIds are sequenced in an descending order...
For instance,

points = [0,1,2,3,4,5,6,7,8,9]
subObjId = [2,2,2,1,1,1,0,0,0]

So, point 0 ends up being subObjectId 250 which is counter-intuitive at first; but rather makes sense now.
It would be a good idea to have this information documented somewhere. Let me know if you need help with any of this...

And a big thank you for helping me over the last 2 days.

from draco.

kappa-gooner avatar kappa-gooner commented on July 18, 2024

@ondys:
This works perfectly, but at a heavy performance cost.
Especially step 5; to do a lookup for every point index on every face against each sub-object's global-to-local point map is quite expensive (I'm dealing with large large models that have 1 million faces and a few thousand sub objects).

Do consider exposing an interface that provides the sub-object data in a more straight forward fashion that does not require such data manipulation at load time. 🥇

from draco.

ondys avatar ondys commented on July 18, 2024

@kappa-gooner Can you share your code? I would think that it should be relatively fast. Note that you need only one global-to-local point map that is common for all sub-objects (from your post it sounds like you may be using multiple maps).

What I'm thinking that we could do in future is to add more direct support for sub-meshes into Draco.. for example we could split the input mesh into multiple sub-meshes based on some per-face attribute (sub-object id, material id, or whatever) and then encode these sub-meshes separately. It may hurt compression somehow, but it would definitely make it much easier to handle these cases on client apps.

from draco.

Frankling avatar Frankling commented on July 18, 2024

@ondys I found that most obj files I with use g and s for polygon/smoothing groups. Meanwhile,can DracoLoader return bufferGeometry which will contain all groups that the obj file owns not just one mesh?

from draco.

shubhamagarwal003 avatar shubhamagarwal003 commented on July 18, 2024

@ondys there seems to be no attribute.custom_id() function in latest version 1.0.0. There is a unique_id() function but the condition (attribute.attribute_type() === dracoDecoder.GENERIC && attribute.unique_id() === 1) is not true for any attribute. Is there some changes in version 1.0.0?

from draco.

ondys avatar ondys commented on July 18, 2024

@shubhamagarwal003 That's correct. With the newly introduced support for metadata, we have decided to remove custom_id as it was redundant. If you parse .obj file with multiple generic attributes (sub objects + material ids) then I you can turn on metadata by passing --metadata flag to our draco_encoder app. The generic attributes can then be identified by metadata entries <"name", "material"> for the material attribute and <"name", "sub_obj"> for the sub-object attribute.

In javascript you can get the attribute id for a given metadata entry using this method:

const matt_att_id = decoder.GetAttributeIdByMetadataEntry(geometry, "name", "material");

Note that if you do the encoding directly using C++ api, you can still set the unique_id to whatever value you want and use that to identify the attributes.

from draco.

FrankGalligan avatar FrankGalligan commented on July 18, 2024

I'm closing this issue. If you are still having problems please re-open.

from draco.

lednhatkhanh avatar lednhatkhanh commented on July 18, 2024

Any updates on adding support to preserve sub-objects?

from draco.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.