0

I am working on a game scene with multiple objects that need multiple materials. I extensively searched online, but I could not find any satisfactory solution.

My scene will have like a river flowing by and the material there will require a separate shader anyway (it will combine many specular and normal maps into what would look like a river) then there is a terrain that would mix two (grass and sand textures) requiring another shader. There is also a player with hands and amour and all.

EDIT: Essentially I wish to find out the most efficient way of making the most flexible multiple material/shader implementation.

Briefly, there is a lot of complex objects around requiring varied shaders. They are not many in number, but there is a lot of complexity.

So using glUseProgram() a lot of times dosn't seem like the brightest idea. Also Much of the shader code could be made univeral like point light calculation. Making a generic shader and using if's and state uniforms could possibly work, still requiring different shaders for the river and likewise diverging materials.

I basically don't understand the organization and implementation of such a generic system. I have used engines like Unreal or possibly Blender which use Node based materials and allowing the customization of every single material without much lag. How would such a system translate into base GPU code?

  • 1
    Either your question is really broad or it's just unclear. I'm not really sure what you're asking about. – Nicol Bolas Jul 02 '16 at 13:43
  • I think you need a game engine that builds on top of opengl, is java required ? – niceman Jul 02 '16 at 14:14
  • @NicolBolas Question: How can I efficiently implement multiple materials that would otherwise require separate shaders? – HuraToTheRescue Jul 02 '16 at 14:45
  • @HuraToTheRescue: What's inefficient about your current implementation? – Nicol Bolas Jul 02 '16 at 14:46
  • @niceman No Java isn't necessary but I have been using Java for this project for a long time. I can port almost any code examples. I am writing my own samples and engine to understand the process in depth. So knowing the concept is more important that being able to do it for me. – HuraToTheRescue Jul 02 '16 at 14:48
  • @NicolBolas I use way too many `glUseProgram()` calls and much of my shader code is duplicate ( like processing point light in every shader), so larger scenes just lag like anything even though I use extremely simple geometry – HuraToTheRescue Jul 02 '16 at 14:49
  • for real projects, I would go for a game engine like Unreal engine, for learning proposes .... sorry not an expert in game development :( – niceman Jul 02 '16 at 14:54
  • @niceman I have used UDK in much depth, but it just abstracts out the details of the process of game making. Like The Unreal Kismet is node implemenation of just basic programming. :) – HuraToTheRescue Jul 02 '16 at 14:57
  • I think the reason you don't find a lot of info about this is because it's a very broad problem that doesn't have a solution, it only has approaches. When you say: "Essentially I wish to find out the most efficient way of making the most flexible multiple material/shader implementation.", you are trying to find something that is perfect, something that does not exist. You must always sacrifice flexibility for performance or vice versa. Even the engines you mention do this, but it is perhaps not very visible. We could help you better with more detailed info. As a start, look up "uber shader". – TWT Jul 02 '16 at 22:19
  • Thats sad. Not having an organised solution to a problem isn't a part of coding. Then writing need specific code for every level is the only performance solution. All those Scenes which aren't complex should use a generic shader and change them once while initialization. While more complicated scenes will have to compromise elsewhere. – HuraToTheRescue Jul 03 '16 at 08:32
  • Have you tried sorting your objects per shader and material to minimize the state changes ? (to have a loop that looks like `for each light { for each shader { for each material { for each object { render(object); } } } }`) – cmourglia Jul 03 '16 at 17:34
  • @Zouch yes, but that doesn't help much cause there are like 50 different shaders applied on and Array of 100-110 things. Extra looping would just add to the CPU cost. – HuraToTheRescue Jul 03 '16 at 18:49
  • Why would there be any extra looping ? I just suggested you to _sort_ your data to make it look like that (and avoir unnecessary state changes). Also, I can see why terrain and water might require different shaders, but why do you need to have like 50 other shaders ? – cmourglia Jul 03 '16 at 18:58
  • @Zouch Okay 50 might be an exaggeration, but there really is a lot of shaders for trees and shrubs, fires, water, player picking up stuff that gives him shields etc, in all, the looping doesn't have much improvement in performance. I'm looking for a more general solution. And as I mentioned, in superior engines like Unreal, each material gets its own shader and I have no clue how it manages to keep up performance with that. – HuraToTheRescue Jul 04 '16 at 06:54
  • Actually, are you _sure_ swapping shaders is the real issue ? Have you timed it ? Maybe the problem is somewhere else, like trying to render to much geometry, etc. Maybe you need to do some frustum culling to avoid rendering geometry that is not visible, you might also need to have some LOD for distant objects, etc. I'm honestly not sure the problem is having many shaders (though you might still be able to use one shader for most of your shading, and eventually use stuff like subroutines, etc) – cmourglia Jul 04 '16 at 13:48
  • @Zouch Thanks for the suggestive answer! It's true that I am not employing any such methods of optimizations yet, but the organization of tons of shaders still remains an issue. – HuraToTheRescue Jul 05 '16 at 04:44

1 Answers1

1

If you really face timing problems because of too many glUseProgram() calls, you might want to have a look at shader subroutines and use less but bigger programs. Before that, sort your data to change states only when needed (sort per shader then per material for example). I guess this is always a good practice anyway.

Honestly, I do not think your timing problems come from the use of too many programs. You might for example want to use frustum culling (to avoid sending geometry to the GPU that will be culled) and early z-culling (to avoid complex lighting computations for fragments that will be overriden). You can also use level of detail for complex geometries that are far away, thus do not need as much details.

cmourglia
  • 2,423
  • 1
  • 17
  • 33
  • Indeed there is no other way. We must organize the shaders and employ proper optimizations in order to get our desired performance. Its all about the balance between quality and performance. – HuraToTheRescue Jul 06 '16 at 14:23