question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Exposing internals + onProject, onRender and onRenderShadow

See original GitHub issue

These 3 simple callbacks + exposing some internal renderer objects allow to implement a set of new fundamental features. The callbacks are for the Object3D class.

onProject

To override the culling routine, i made a spatial index “IndexedVolume” based on Object3D. By returning false in this callback THREE cancels the current projectObject call, the IndexedVolume will perform indexed hierarchical culling and then push the visible objects into the renderList, but projectObject can be called as well to let THREE take over again, furthermore i implemented auto-instancing, impostors and other in this routine.

Asides of custom culling implementations this can be used to render additional objects that aren’t part of the scene hierarchy. Also a module based selection, having render objects in the main scene hierarchy but rendering in a different pass, working as a more flexible version to layers.

The onProject callback receives renderer, camera, frustum, renderList, groupOrder, sortObjects.

onRender

ImmediateRenderObject is nice but very limited, only allowing triangle mode and a specific set of attributes. onRender allows to implement a custom render call to renderBufferDirect and using + updating any geometries or other operations only possible at this stage, but not with onBeforeRender. It basically also works as ImmediateRenderObject but both gl buffers or THREE managed BufferGeometry can be used, but without being limited to the renderBufferImmediate imlementation.

I replaced isImmediateRenderObject, with isCustomRenderObject , but could be as well a else if case of course.

onRenderShadow

Basically like onProject but for shadows, receiving renderer, camera, frustum, shadowCamera, light, type, scope and returns if onRenderShadow returns false. It would be nice if any needed methods such as getDepthMaterial could be exposed as well, as it gives much more control to replace renderObject with a modified approach as shadow proxies might be used or a different depth materials management.

Internals

There are some internal objects such as frustum, textures, geometries, properties, objects that are as well private yet, i needed those for various cases in those callbacks, but especially for onRender. Regarding methods: in WebGLRenderer projectObject, setProgram as well as in WebGLShadowMap renderObject, i called the shadowMap callback version onRenderShadow.

These additions all together would be just a few lines but opening a vast amount of possibilities and more control, it would be great if they could find their way officially into the core.

Additional note: instead calling empty callbacks like onBeforeRender i implemented those as the following, declaring them on the prototype with null: if ( object.onProject instanceof Function && object.onProject( ... ) === false ) return;

Issue Analytics

  • State:open
  • Created 3 years ago
  • Reactions:2
  • Comments:14 (5 by maintainers)

github_iconTop GitHub Comments

2reactions
Fyrestarcommented, Oct 12, 2020

Interesting, so the null test is the biggest offender, but instanceof can be either insignificantly slower, or much much faster? The null test seems logical, i’d guess a if ( object.onBeforeRender ) could be faster, but calling a empty function is much less obvious, especially since the empty ones don’t have any parameters declared while parameters are passed. But that also shows how conditions can get costly in hot places, and THREE unfortunately still has a condition forest in the WebGLRenderer, which could be uncluttered and get faster by references and class specific implementations, such as material specific handling being on their prototype rather than if ( material.isMeshStandardMaterial || material.isMeshBasicMaterial ... ).

What i hear is that you would like to pass a few of these internal objects into the callbacks? If that is so, could it indicate that these three may not be enough / most flexible / give most control? It may be worth investigating this as a more generic pattern - the renderer has many internal objects, which ones would be worth exposing and when.

The mentioned internals make a lot sense to use outside as they are needed in a lot cases to make use of those callbacks, some internals make only sense internally, the mentioned ones really give most of control you could need. But there sure are more that would be reasonable to expose, i don’t see a reason to keep them hidden honestly.

There would be one other callback that would be really helpful as well, i currently implemented it as a monkey patch plugin: https://discourse.threejs.org/t/chainable-onbeforecompile-uniforms-per-mesh/8905 (the uniforms per mesh part)

There is almost no project i don’t need it, for some cases having uniform values stored on object/mesh level (or anywhere you need), so you can use 1 material instance for multiple objects, but use different uniform values per object/render call, without having to clone entire materials just for 1 different uniform. I currently implemented it through onBeforeRender which is okay as not always needed and not blocking it, but it would be better at the actual setup, to be implemented on the material class prototype or on the renderer.

1reaction
Fyrestarcommented, Oct 6, 2020

I did some tests though i forgot console gives different results than actual scripts. However the difference there was interesting, instanceof performed in chrome couple hundred times faster than null test or empty call. Otherwise a empty call often is faster but sometimes equal, that’s a really odd js quirk.

Not sure how you picked these three, but it would be nice to add more.

Those already give most control of the render routine (like the examples i mentioned) in a flexible component way without internal changes.

The more the merrier!

Yes especially for exposing internals there are many objects that would make it much more flexible if they were public.

Read more comments on GitHub >

github_iconTop Results From Across the Web

No results found

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found