Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Combine primitives #162

Merged
merged 27 commits into from
Nov 11, 2016
Merged

Combine primitives #162

merged 27 commits into from
Nov 11, 2016

Conversation

lasalvavida
Copy link
Contributor

@lasalvavida lasalvavida commented Aug 12, 2016

This is worth an initial look and some testing while I add tests for everything.

This pull request contains a few things:

  1. Re-adds combine primitives, closing out Combine Primitives needs to be fixed #108 and by proxy BrainStem sample model combinePrimitives throws exception #85 and Buggy model gets mangled by pipeline #103.
  2. Splits out some primitive helper functions from combineNodes into PrimitiveHelpers.
  3. Removes underscore usage Remove underscore usage from combineNodes #160.
  4. mergeBuffers will no longer fail if the new buffer name is the same as an already existing one.
  5. Fixes an error in removeDuplicatePrimitives.removePrimitivesFromMesh
  6. Adds a second pass of light optimization

Some preliminary testing with the buggy model:

Original Master Master w/ combine primitives
File size 10,414 KB 6,091 KB 6,046 KB
Nodes 208 179 179
Meshes 109 163 68
Draw Calls 236 273 236


var AccessorReader = require('./AccessorReader');
var readAccessor = require('./readAccessor');
var writeAccessor = require('./writeAccessor');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same note about include order from the other PR.

@lilleyse
Copy link
Contributor

Looks great! I did some simple testing and it seems to work well.

@pjcozzi
Copy link
Contributor

pjcozzi commented Aug 12, 2016

@lasalvavida can you verify that it makes sense for the buggy model to have 95 fewer meshes, but only 37 fewer draw calls?

var readAccessor = require('./readAccessor');
var writeAccessor = require('./writeAccessor');

module.exports = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lilleyse @lasalvavida can you two please review the design of this class? I don't think it is needed. Some functions could be private in the files they are used in; others could be standalone functions.

Let me know if you need help.

@lasalvavida
Copy link
Contributor Author

lasalvavida commented Aug 12, 2016

@pjcozzi Master currently bloats the number of meshes in cases where two meshes that are in node endpoints that can't be combined contain identical primitives. That is what drives up the draw call count. The output with this PR removes that bloating by recombining meshes after primitives get combined. The primitives are consolidated to fewer mesh endpoints, but there is still the same number of primitives.

tl;dr It has the same number of draw calls as the version in the sampleModels, the current output of master is adding more unnecessary draw calls.

@pjcozzi
Copy link
Contributor

pjcozzi commented Aug 13, 2016

Gotcha.

@lilleyse
Copy link
Contributor

lilleyse commented Oct 3, 2016

@lasalvavida Is there more to do for this? The latest merge commit has a few issues.

@lasalvavida
Copy link
Contributor Author

There was a bad merge; it still needs tests. I'll add those now.

@lasalvavida
Copy link
Contributor Author

@lilleyse This is updated and ready for a look

@lasalvavida
Copy link
Contributor Author

I have removed the second mergeDuplicateVertices call. With the light optimization, it is no longer needed; the files produced with and without it are the same size.

@pjcozzi
Copy link
Contributor

pjcozzi commented Oct 31, 2016

@lilleyse will you be able to review this soon? We have a lot of open PRs in this branch and I would like to get them merged.

@lilleyse
Copy link
Contributor

Yes I will review this today.

MergeDuplicateProperties.mergeAccessors(gltfWithExtras);
removeDuplicatePrimitives(gltfWithExtras);
combinePrimitives(gltfWithExtras);
combineMeshes(gltfWithExtras);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we talked offline about this a while ago, but I forget the conversation...

If possible we should try to avoid the second cleanup, and ideally our stages shouldn't be producing unoptimized gltf's. Sorry if I forgot the reason behind this.

}

function transformPrimitives(gltf, primitives, transform) {
var inverseTranspose = new Matrix4();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't you just do a simple loop over the position and normal arrays, transforming each set of 3 values with the transform and then writing back into the buffer. I don't see the need for involving indices.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, you cannot. Primitives may share large attribute accessors of which they only index into a portion. Those primitives in turn may have different transforms. We cannot assume that a primitive uses its entire accessor, we must only transform the positions and normals that it uses.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, this should use AccessorReader instead of readAccessor. I will make that change.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah right, thanks for the correction.

function generateIndices(v, k) {
void(v); // v is an unused parameter
return k;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If still needed, just put this code in transformPrimitives.

if (primitivesShareAttributeAccessor(primitive, comparePrimitive)) {
if (primitivesHaveOverlappingIndexAccessors(gltf, primitive, comparePrimitive)) {
if (PrimitiveHelpers.primitivesShareAttributeAccessor(primitive, comparePrimitive)) {
if (PrimitiveHelpers.primitivesHaveOverlappingIndexAccessors(gltf, primitive, comparePrimitive)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Create a function for this in PrimitiveHelpers that is called here and inside markPrimitiveConflicts.

var primitives = mesh.primitives;
if (defined(primitives)) {
mesh.primitives = combineMeshPrimitives(gltf, meshId, primitives);
PrimitiveHelpers.markPrimitiveConflicts(gltf, PrimitiveHelpers.getAllPrimitives(gltf));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a little awkward to save the conflicts in the pipeline object. If possible try to keep it in here.

@lilleyse
Copy link
Contributor

lilleyse commented Nov 1, 2016

Thanks for the update @lasalvavida
It's been a while since I looked at this so fill me in case my comments don't make sense. I'll do some testing tomorrow.

@lilleyse
Copy link
Contributor

lilleyse commented Nov 2, 2016

I'm having issues converting this model:
dragon_low.gltf.txt

@lasalvavida
Copy link
Contributor Author

This is mostly done now. I'm still getting slightly smaller models if I run them through the pipeline twice, and I'm still trying to pinpoint exactly why.

@lasalvavida
Copy link
Contributor Author

This is ready for review. Referring to my original benchmarks the stats are now:

Original Master Master w/ combine primitives
File size 10,414 KB 6,091 KB 6,023 KB
Nodes 208 179 179
Meshes 109 163 61
Draw Calls 236 273 196

}
var semantics = getPrimitiveAttributeSemantics(primitive, semantic);
if (semantics.length <= 0) {
primitive.attributes[semantic] = createAccessor(gltf, packedLength, 'VEC3', WebGLConstants.FLOAT, WebGLConstants.ARRAY_BUFFER);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is hardcoding VEC3 a problem for texture coordinates?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, you're right

@lilleyse
Copy link
Contributor

This is really close. Every model I've tested works fine. Those numbers are nice!

@lasalvavida
Copy link
Contributor Author

Updated

@lilleyse
Copy link
Contributor

Nice, I'm glad to finally get this in! Also because of adjustments here the pipeline just runs a lot faster.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants