-
-
Notifications
You must be signed in to change notification settings - Fork 35.3k
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
Change uniforms on a per object basis to keep the materials count low #6010
Comments
Have thought some more about the implementation of this. Apparently, just changing uniform values before However, by introducing a
the following sub-classing of
This is the least intrusive way, requiring only one change to the library, I could come up with so far. |
Another iteration, again by sub-classing
I guess my feature request would now be to make |
Without passing judgement on your proposal, which I will leave to others, here are a few comments:
If your model is unscaled (which, of course, may not be your case), you do not need to pass in the inverse of the
You can
This should result in only one shader program used by all object instances. Is that not sufficiently performant for your use case? |
Thanks @WestLangley for that insightful comment! I did not knew about that spacial case to get the inverse of such a matrix. It might come in handy when, as you said, no scaling of the model is involved. Still, to make the case for my suggestion, it only works for the
I had to look into this one as I did not use
My performance problem is not with the rendering phase but with the objects creation phase. In a particular instance object creation is ~300 ms (with a single material) vs ~1000 ms (with a separate material for each object instance). |
Yes, I know. I should have phrased my question differently. "Is using |
I see. No it isn't. I now did some performance measurement with my application and with JsPerf. Note that I am on a different machine, so the numbers have changed. My application, creating 10,080 object instances (note that this more then just material creation):
JsPerf (http://jsperf.com/three-js-material-instancing):
The numbers indicate that material creation/cloning is the bottleneck here. More specifically uniform creation/cloning. Not surprising, but always good to see real numbers. So, when you create a lot of materials it might help performance to use only the uniforms you need in those materials. |
@arose Is this still an issue for you? |
It was solved with #7048 at the time. As for the current version of three, I can't say as I am not using it. Going to close it. |
I would like to propose a new feature in the
WebGLRenderer
that allows changing uniform values on a per-object basis. Currently an object-specific uniform value requires the use of a separate material for the object. To keep the materials count low uniforms could be changed in the rendering process. This is in fact already used for the object-specific matrices including the modelViewMatrix. However, to my knowledge this part of the rendering process is private and not exposed by any kind of api.The use-cases I have for such a feature are the following. Generally I have multiple objects that share the same geometry and material but differ in their world position and orientation (i.e. the object matrix). Such instancing quite common but leaves all instances with the same material and hence the same uniform values. So far so good. Now I have a shader that requires the inverse of the modelViewMatrix as a uniform, which depends on the on the object matrix. Adding the inverse of the modelViewMatrix to a material and calculating as well as updating it works fine as long their is a material for every object instance. The second thing I would like to do is supporting picking specific object instances in the gpu-based object picking approach (i.e. each object gets a unique "picking" color). This can be implemented using a instance-specific "picking" color via a uniform that gets updated before each object instance is rendered and thus not requiring a separate material for each instance.
Having separate materials somewhat defeats the purpose of instancing -- albeit not as much as having separate geometries. Still, constructing 1000 materials for 1000 object instances can be quite noticeable, especially in the initialization phase. This is what I want to avoid and I hope I expressed it clearly.
EDIT: see my third comment for a better approach than what I wrote in the next paragraph.
Looking at the
WebGLRenderer
I think changing uniforms on a per object basis can be achieved by a hook for user-defined code inrenderBuffer
,renderBufferDirect
andrenderImmediateObject
, just beforesetProgram
is called and the uniform values are send to the gpu.Ok, these are my thoughts. I am curious what you guys think about it and if you find it useful. Or if there are better ways to achieve what want. Thanks.
The text was updated successfully, but these errors were encountered: