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

[r54] I'd like a way to override material diffuse (color) from the mesh level. #2916

Closed
harold opened this issue Jan 10, 2013 · 26 comments
Closed
Labels

Comments

@harold
Copy link

harold commented Jan 10, 2013

I made a minimal test that exercises features that I use in my application...

This scene is quite fast:
http://danceliquid.com/docs/threejs/material-test/index.html?many-materials=false

But sadly, I can't individually control the colors of each cube. (Because there are only 2 materials in the scene)

This scene is slower:
http://danceliquid.com/docs/threejs/material-test/index.html?many-materials=true

In this case, I've given each cube it's own material. (The materials share the textures)

In the second case, I'm able to tint (change the color) of each cube individually, which is what I need to do in my real application. But the performance is degraded. I have two machines that I can use for testing here, and the framerates on the first are 53/46 (15% drop) and the framerates on the other are 60/33 (45% drop).

Ideally, I'd like to have a large number of meshes all made from the same geometry and material, but to be able to tint (color) them individually. Perhaps when the material is setting the color uniform, it could see if there was an override provided by the mesh and use that instead?

Thanks! I love three.js. It's my hero.

@harold
Copy link
Author

harold commented Jan 10, 2013

Additional details in my SO question, in case that's helpful:
http://stackoverflow.com/questions/14145275/

@mrdoob
Copy link
Owner

mrdoob commented Jan 10, 2013

I do notice the degradation. It's about 5fps slower here.
What it's interesting is that in both tests there is only 1 program being generated (which all the materials share).

@harold
Copy link
Author

harold commented Jan 11, 2013

I appreciate you looking at this so quickly.

Your observation is super-interesting. That would be great if the system could optimize similar materials in that way.

Can you explain how you're verifying that about the number of programs? I'm not very familiar with the internals of three.js.

Separately, what do you think about the idea of a mesh-level override for the diffuse color uniform? I believe it would be good for my case, but I don't know a lot about how others use the library. Thanks again!

@mrdoob
Copy link
Owner

mrdoob commented Jan 11, 2013

I just opened the console and typed:

renderer.info.memory.programs

@harold
Copy link
Author

harold commented Jan 11, 2013

Neat, I didn't know about renderer.info. Thanks.

@dubejf
Copy link
Contributor

dubejf commented Jul 23, 2015

(You should try instancing, try per-vertex color with THREE.VertexColors / THREE.FaceColors, or try using a custom shader).

Summary: There are two textured Phong materials. The fast case creates a grid of meshes and assigns alternating materials. The slow case does the same, but assigns a .clone of the original materials.

With r72dev and a 64 x 64 grid, I'm getting

  • many-materials=false (faster) => 45 fps
  • many-materials=true (slow case) => 20 fps

However, I can remove the textures and use a single reference material instead of two and I still get basically the same fps.

The problem is caused by the large number for cloned materials, regardless of their complexity.

@dubejf
Copy link
Contributor

dubejf commented Jul 23, 2015

Using the WebGL Inspector plugin, this is the GL call log for a 2x2 grid, using a single non-textured material (fast case)

matfalse1

An this is the same for the slow case (each mesh has a clone of the original material)
mattrue1

@dubejf
Copy link
Contributor

dubejf commented Jul 23, 2015

And these are the logs for the textured Phong material, using two different material ("snow" and "disco")

Fast (2 materials total):
matfalse

Slow (4 materials total):
mattrue

@dubejf
Copy link
Contributor

dubejf commented Jul 23, 2015

The slow case, using a lot of cloned materials, makes a lot more redundant calls. (I assume that if the properties of the material were more different, there would be less redundancy).

Could/Should WebGLState track those redundant state changes?

@mrdoob
Copy link
Owner

mrdoob commented Jul 23, 2015

Could/Should WebGLState track those redundant state changes?

The more WebGLState can cache the better. But, at the same time, trying to keep the code simple/manageable.

@dubejf
Copy link
Contributor

dubejf commented Jul 23, 2015

More appropriately, WebGLProgram should be responsible for caching the uniforms, not WebGLState.

Each program would do is own monitoring, starting at useProgram until the program is switched off. Anytime the active program is switched, the uniform cache should be reset (at least in the initial implementation).

@WestLangley
Copy link
Collaborator

Perhaps when the material is setting the color uniform, it could see if there was an override provided by the mesh and use that instead?

mesh.onBeforeRender() should solve this.

@harold
Copy link
Author

harold commented May 2, 2017

I am not working in this area any more but I am glad to see progress is being made.

If there's an easy way to make the cases I was trying fast, then that is a huge improvement, and could mean massive perf improvements for many common instancing workflows. Kudos!

@trusktr
Copy link
Contributor

trusktr commented Jan 3, 2018

@WestLangley

mesh.onBeforeRender() should solve this.

This does not solve the problem.

Here's a pen using one material instance per mesh (the slow case) with different colors:

https://codepen.io/anon/pen/JMydzb

and here's an attempt to use only a single material shared with all meshes, and using onBeforeRender to change the color of each mesh, but what you will notice happens is that all meshes are rendered the same color, probably that of the mesh closest to the camera after sorting (because notice the color changes when moving the camera):

https://codepen.io/anon/pen/zpdGWx

The performance improvement when using a single material is fairly significant. I too was trying to figure out how to use a single material instance and change the color for different objects, which landed me here.

Can you please re-open this? (Or it should be a new issue?)

@trusktr
Copy link
Contributor

trusktr commented Jan 3, 2018

Maybe there's opporrunity to detect certain scenarios and do auto-instancing? Is that possible? Does that cause problems with sorting?

@trusktr
Copy link
Contributor

trusktr commented Jan 3, 2018

Looks like that was attempted in #10093.

@WestLangley
Copy link
Collaborator

@trusktr Apparently the uniforms are not being updated.

If we want to support updating material properties in onBeforeRender(), we may need something like a material.uniformsNeedUpdate flag to force it.

should be a new issue?

If you want to pursue this.

@trusktr
Copy link
Contributor

trusktr commented Jan 4, 2018

@WestLangley So before every draw call of every mesh, it'll update the uniform? Seems like an edge case that should be handled. This also would not work with any of the proposed auto-instancing by @Benjamin-Dobell, right?

@mrdoob
Copy link
Owner

mrdoob commented Jan 4, 2018

@trusktr are you still mainly drawing planes...?

@trusktr
Copy link
Contributor

trusktr commented Jan 4, 2018

@mrdoob I'm making a general purpose HTML interface for 3D. I'd like anyone to be able to make anything with it, so I'm experimenting with ways to improve performance without any specific use case in mind.

The Planes are for the specific "mix DOM with WebGL" use case.

@mrdoob
Copy link
Owner

mrdoob commented Jan 5, 2018

@trusktr have you done performance profiles that shows that this is an issue in your use case?

@trusktr
Copy link
Contributor

trusktr commented Jan 5, 2018

Of those two pens, the second one is definitely faster (disregarding color not working as I hoped).

I do have other performance problems in my lib. I'm trying to make faster any way that I can.

@mrdoob
Copy link
Owner

mrdoob commented Jan 5, 2018

Why are you creating 1000 identical geometries??? You should create just one and reuse it.

Here's your fiddle with same output with, theoretically, 1000x memory reduction, initialises much faster and renders much faster:

https://codepen.io/anon/pen/NXayKj

There is no way the renderer could optimise your code.

@trusktr
Copy link
Contributor

trusktr commented May 1, 2018

Why are you creating 1000 identical geometries??? You should create just one and reuse it.

I wanted to have them be different sizes and have differing amounts of animated scale, so it was easy to do it this way (without thinking much about it, because the API lends to it being easy that way).

What I'd like is a scene graph that has both size and scale, decoupled from each other, like DOM+CSS.

I see how this can be done with Three.js' scene graph, with some book keeping on top of it. But it's not as ideal as DOM+CSS where width/height is decoupled and separate from transform:scale() without me having to write a layer on top of the DOM+CSS in order to have both separate size and scale.

There's much good stuff to learn from DOM. F.e., imagine, various "people" in a game, they are different heights, and all have a scale of 1. Then, they all take some mushrooms, and now their scales start wobbling, but their size numbers haven't changed. (weird example, but valid!). It can be done in Three, but the layer of numbers (size + scale) has to be implemented on top of Three.

In my lib, I will create a non-coupled concept of scale + size, and under the hood, yes, I will re-use geometries.

@trusktr
Copy link
Contributor

trusktr commented May 1, 2018

There is no way the renderer could optimise your code.

Something like #10093 may help! I know, it's a lot to maintain for one person. How can that maintenance problem be solved? CoughsponshorshipfromGoogleCough?

@mrdoob
Copy link
Owner

mrdoob commented May 1, 2018

In my lib, I will create a non-coupled concept of scale + size, and under the hood, yes, I will re-use geometries.

👌

Something like #10093 may help! I know, it's a lot to maintain for one person. How can that maintenance problem be solved? CoughsponshorshipfromGoogleCough?

Responding to conversations like this one is what leaves me with no time/energies left to implement these kind of features.

Please, try to use this section mindfully.

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

No branches or pull requests

5 participants