-
-
Notifications
You must be signed in to change notification settings - Fork 35.5k
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
Added GLBufferAttribute #13196
Added GLBufferAttribute #13196
Conversation
More hooks like this!! |
Now a new
|
Do you mind renaming it to |
I see your point, but all of them (buffer types) are of GL kind...
I think prefix Edit: I found out that the name |
@mrdoob, since no answer from you, I've decided to take some action and finally rename the class to |
I still prefer Sorry I couldn't elaborate in time for r92, moving to r93. |
Ok, will do soon |
Done, |
Nice demo. :-) Can you please: add your new example to |
src/core/GLBufferAttribute.js
Outdated
this.buffer = buffer; | ||
this.type = type; | ||
this.itemSize = itemSize; | ||
this.elementSize = this.sizes[ type ]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is elementSize
also intended to be private?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is intended to be public. The idea is as follows: you know the type of your data, you pass it, the elementSize
becomes available, carrying the size-in-bytes value for you.
It is not necessary. We could let the app do all the calculations and leave here only what's necessary for three.js to handle the attribute.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah wait, I found it here: src\renderers\webgl\WebGLAttributes.js
buffers.set( attribute, {
buffer: attribute.buffer,
type: attribute.type,
bytesPerElement: attribute.elementSize,
version: attribute.version
} );
so basically it is there for three.js to get the byte size, because there is no Array
instance to do so (bytesPerElement: array.BYTES_PER_ELEMENT,
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Um, have you considered to let the user set this value? I mean GLBufferAttribute
is obviously a low-level API not necessarily intended for beginners. Devs who use it should also know the correct bytes per element.
I would suggest to put as less logic as possible into the ctor and let instead the user defined such information. In this way, you probably don't even need a WebGL rendering context in GLBufferAttribute
which I find a bit strange anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logic behind this is that passing both type
and elementSize
to the constructor is redundant, because the type
always implies the only possible elementSize
. So it kind of creates a room for an error to occur when you ask the user to pass both. So I decided to calculate it on the ctor side.
But in general it would be fine either way. If the ctor takes elementSize
, we get rid of all the logic and the contraversial this.sizes
member. Also no need for gl
then. Do you approve of the latter scenario?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would say yes. Keeping GLBufferAttribute
simple and let the app handle this bit sound like the better design to me. Especially since we can assume the user knows the relationship between type
and elementSize
if this class is going to be used.
The final decision is up to @mrdoob though 😉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's wait for @mrdoob's feedback.
|
If you are unsure about this, use |
Sorry for bothering you but I'm really looking forward to this addition. So the current status is that the PR is waiting for @mrdoob's feedback? Regarding that TypeScript question on Apr 27, may I suggest declaring an array of number pairs with
|
Ah, too close to release now... Lets see if we can merge this at the beginning on the next dev cycle. |
@mrdoob Before merging, can you please review https://github.com/mrdoob/three.js/pull/13196/files#r416037718? I'm not sure about the current public interface of |
|
Thanks @raub! This looks much better to me now! |
I think you can delete |
I'll merge and clean up. |
Thanks! |
@@ -176,6 +176,8 @@ | |||
const cachedAttribute = cachedAttributes[ key ]; | |||
const geometryAttribute = geometryAttributes[ key ]; | |||
|
|||
if ( geometryAttribute.isGLBufferAttribute ) return true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@raub Can you please explain why you have added this line? When removed, the respective demo does not seem to work correctly anymore.
It's actually not correct to always force a call of setupVertexAttributes()
on each frame if e.g. only the buffer contents change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't exactly understand what this part of the system is supposed to do. But my guess is:
- if there is no VAO, bind appropriate buffers
- if there is a VAO and the attributes were not changed, just switch to that VAO
- if attributes changed, update the VAO, i.e. switch to it and bind the updated buffers
That all sounds good in theory. But when I noticed my demo was broken, I started debugging and ended up here. So basically I set needsUpdate
to my attribute and expect the engine to do the job of updating whatever was changed (the buffer). That was not the case here.
For some reason, cachedAttribute
always contained an already-updated version of my attribute. So the VAO never got updated (hence the demo was broken). I double-checked this fact by adding some custom properties directly into the buffer, like buffer.name=111
.
So I decided to opt-out from this optimization with my attribute type. I expect that line 179 effectively makes VAO unused for GLBufferAttribute
. That is fine with me. Although if you understand what is going wrong and how to make it work with this optimization, that would also be great.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem is that the current implementation is bad for performance since a lot of unnecessary state changes are done.
We definitely have to revisit this issue otherwise I vote to revert GLBufferAttribute
before the next release.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current implementation is vastly superior than having no implementation. And if I'm right, for webgl1
people the further discussion makes no sense, since they always get exactly this level of performance. So there is a considerable group of people who either get this feature or not, regardless of VAO optimizations.
Now to optimizations. I would gladly fixed the VAO issue, given it was at all possible for you (or anybody) to explan why the cached attribute is always the updated attribute itself. And if it is the correct behavior, how it can be possibly fixed.
If you want, I might go on and report this behavior as a bug in a separate issue. Because now it is my understanding, that when I set needsUpdate
on my attribute, the cache should contain the old version. If I have just updated the attribute, and the "cached" version does already contain what I have updated, it is a bug in WebGLBindingStates unless proven otherwise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This has nothing to do with WebGL 1 or 2. VAO is available for most WebGL 1 users. Besides, even without VAO the buffer attribute bindings should only be done if necessary. Not if just buffer data changes.
I think the problem in your demo is this line:
posAttr.buffer = ( posAttr.buffer === pos ) ? pos2 : pos;
You should exchange the entire attribute and not just the buffer. Or you keep the buffer the same and only change the contents. But just exchanging buffers is not something the engine wants to promote (it's not supported anyway and support will NOT be added).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This pattern works without the hack in WebGLBindingStates
:
var posAttr1 = new THREE.GLBufferAttribute( pos, gl.FLOAT, 3, 4, particles );
var posAttr2 = new THREE.GLBufferAttribute( pos2, gl.FLOAT, 3, 4, particles );
geometry.setAttribute( 'position', posAttr1 );
setInterval( function () {
var attr = geometry.getAttribute( 'position' );
geometry.setAttribute( 'position', ( attr === posAttr1 ) ? posAttr2 : posAttr1 );
}, 2000 );
If present, would delegate VBO creation to the user-supplied function. See more info on this in #11883. The default behavior is untouched.