Understanding shader integration and overall design

I’ve been going through the code to better understand how various shaders are assembled and how they’re submitted to the Engine. I’ve wanted to know more about this out of curiosity, and also to be able to better create materials or effects.

Thus far, I understand that the Engine relies on combining several shaders in a modular fashion and relies heavily on #ifdef blocks. I also see that new Effects are stored within a custom registry. I see how the code executes, but it’d be great to hear more about how it works (and how it’s intended to work!) from someone familiar with the entire codebase and its history.

Does the system always do a single draw pass when possible? Are there specific operations that always require multiple draws? Is there any interleaving? What’s the overall philosophy – to combine everything into a single master shader and handle everything via buffers, or to split effects and meshes into different draw calls, etc.

If anyone can provide a bit more understanding of its design and the reasoning for its design (for example, maybe readability/maintenance has been prized in some places over pure speed), that would be most helpful.

Thank you.

1 Like

@sebavan any thoughts you’d like to share? :slight_smile:


In order to reuse code as much as we can, like you would do in any languages, we introduced our own pre processor (#include) in order to allow code sharing at the shader code level.

Aside of that we write mainly in webgl1 style so that we can auto upgrade to other flavors like webgl2 or webgpu.

This is not totally related to shaders but the pipeline itself. For instance you can use 2 materials of the same type so you ll use the same shader with different parameters and will need several draw calls. Also in some case like multi material or depth pre pass you might need several draw calls for the same objects.

I am not sure what you mean by interleaving ?

We can not combine everything in one shader only as it would for instance makes no sense to combine standard and pbr materials.


I see. That makes sense. Yes, the current state of shaders is a bit…shady. I can’t imagine that future systems will continue to require these hacks. But since we want the future today, we have to do the best with what we have. A custom #include is a good idea.

Yes, I am excited about WebGPU.

You’re right, this is about the pipeline. That’s the right word. This makes sense and is what I was gathering. Sometimes it’s necessary to have several draw calls. I was trying to make sense of how often that occurs and why. Materials are a good reason.

By interleaving I meant something like drawing some objects during one call, and other objects during another, to speed up overall processing. I’ve read that’s a used tactic. I also wasn’t too sure what else it could mean, so I just used the word hoping you’d fill in any other possibilities, haha. :slightly_smiling_face:

Yes, that makes sense. Buffer use is limited now too so we can’t go crazy.

Thanks for the reply.