Rendering an InstancedBufferGeometry with no (used) attributes does not render.
This happens when a shader uses only (implicit) gl_InstanceID and/or gl_VertexID,
and user program establishes count with 'geom.maxInstancedCount = ...'
(It only applies to WebGL2 as earlier shaders do not support this.)
The internal value geometry._maxInstanceCount is never established, so
var instanceCount = Math.min( geometry.instanceCount, geometry._maxInstanceCount );
does not set a sensible value.
A workaround is to set geometry._maxInstanceCount in the user's program (eg to Infinity),
but this is obviously not the correct solution.
With earlier versions of three.js (eg 109) a program could provide a 'dummy' attribute not actually used in the shader to establish count; but 117 is clever enough to realize this dummy is not used, and therefore does not take account of it in the count calculation.
example to follow
r.117 is clever enough to realize this dummy is not used
For reference, that was changed in #19135.
In #1935, the renderer ensures the user-specified draw count does not exceed the maximum possible, based on the buffer size.
Can you please provide a simple live example to demonstrate the issue?
By the way, the new version will be an improvement when this bug is fixed as it does not require a placebo buffer instancing attribute ... Thank you.
Just a problem in its current state where it does not work even with a placebo; as it detects and ignores the placebo so there is no buffer size to base it on.
It would be nice to have a similar mechanism for vertices where we are using gl_VertexID and no vertex buffers. The use case for both is with procedural geometry, with the procedure embedded in the vertex shader.
In your fiddle, you have no scene. Instead you have
renderer.render( mesh, camera );
Why?
It would be nice to have a similar mechanism for vertices where we are using gl_VertexID and no vertex buffers
Can you please clarify, and provide one example for each of your edge cases before we pursue this?
I guess these two PRs are relevant, too: #17982, #18044
A geometry with no attributes is interpreted as initial and not rendered. This is no bug but the intended behavior.
No scene in the fiddle is because there is no need for one. I could of course create a scene and add the mesh to it in the conventional way, but in this simple example the scene would not be adding any useful contribution. It would make no difference to the rendering of the mesh itself.
The initial start of this thread was to do with rendering without instance attributes; this is covered in the fiddle.
The second point is the case of rendering without vertex attributes (indeed related to but not the same as #18044).
You already have the field to cover the number of vertices, which is geometry.drawRange.count. (line to use this added to the fiddle and marked +++++++++).
Once geometry.drawRange.count has been validly specified the geometry is no longer in initial state, and so should not be interpreted as such.
The only situation where you can't sensibly draw is the initial state where there is no index, no vertex attributes, and drawRange.count is Infinity (or drawRange is invalid in some other way).
The need is to be able correctly to deduce the values for
renderer.renderInstances( geometry, drawStart, drawCount, instanceCount );
I have made a pull request for an implementation of both aspects of this request.
Changed file is https://github.com/sjpt/three.js/blob/noAttributes/src/renderers/WebGLRenderer.js,
changed method is renderBufferDirect(), changes marked <<<
The fiddle https://jsfiddle.net/sjpt/Lrhjkstz/44/ references a copy of the three build with this change:
I could not find how to get CORS access to my github version.
You will see the geometry needs just three lines to be fully operational
geom = new THREE.InstancedBufferGeometry();
geom.instanceCount = 4;
geom.drawRange.count = 3;
Note this does not change the three.js API, just makes its interpretation broader and more consistent.
Once geometry.drawRange.count has been validly specified the geometry is no longer in initial state, and so should not be interpreted as such.
TBH, I see this different. drawRange is defined _in context_ of existing geometry data. Setting just a value to drawRange without a position attribute or index should have no effect.
Sorry but your PR introduces an unnecessarily complexity and feels like over-engineering. It helps supporting an edge case which is not relevant for 99% of use cases.
There are broadly two styles of computer graphics; asset based and procedural. Games and similar are traditionally asset based, where the assets get implemented as attribute buffers and textures. I agree that this is the bulk, though not 99%. Procedural graphics often runs the procedures in the shaders with no need for attribute buffers or textures. We use procedural graphics for scientific applications (where the positions are generated by GPU simulations) and art and mathematical applications (where the positions are generated by rules embedded in the shaders). Procedural graphics has limited need for external attributes and textures, indeed often no need at all.
It was not possible with Webgl to implement pure procedural shaders; as gl_VertexID and gl_InstanceID were not permitted. We often had to resort to attribute buffers that just held the values 0,1,2,... up to the number of vertices/instances needed. (We could at least share a very long buffer and limit its effective length with instanceCount and drawRange.count.)
This changed with Webgl2 and '#version 300 es' shaders, so it is now possible to implement fully procedural shaders with no input other then the necessary counts. The suggested change allows these shaders to be used without the need for generating artificial attributes. In the pure procedural case the arguments to renderer.renderInstances( geometry, drawStart, drawCount, instanceCount ) are derived directly from drawRange.start, drawRange.count and geometry.instanceCount. In the asset based case the arguments are derived from the attribute (or index) asset data as before.
The complexity added to three.js to support this is very small. This single change to three.js is actually smaller than the change needed in each and every procedural application to generate unnecessary attributes.
The complexity is considerably less than the complexity added in the breaking change in 117 that detects unused attributes and ignores them.
Thanks for the additional information. I think I understand your use case better now.
Indeed, in context of WebGL 2 and gl_VertexID I have to admit that this use case makes sense and it's probably valid to support it. It's just not clear to me yet if your suggested approach is the right one. Let's discuss this at your PR 馃憤
Most helpful comment
Thanks for the additional information. I think I understand your use case better now.
Indeed, in context of WebGL 2 and
gl_VertexIDI have to admit that this use case makes sense and it's probably valid to support it. It's just not clear to me yet if your suggested approach is the right one. Let's discuss this at your PR 馃憤