Yet Another Procedural Planet (and some shader advice please)

Started by
4 comments, last by cgrant 9 years, 2 months ago

Hi everybody,

I've been lurking for a while reading the (usually great) answers on the site and thought I'd finally post.

I'm a professional C++/Python programmer working in finance and I thought I'd try my hand at something more interesting/challenging... 3d graphics! Inspired by Frontier and the Elite Dangerous Kickstarter, I thought I'd have a hand at writing my own procedural universe thing as a hobby project.

I worked on it for a few weeks last year but I've decided to get back in to it and eventually open source it, ideally (I know it's ambitious) with procedurally generated vegetation, cities, etc etc. But first things first...

I'm in the process of upgrading the atmosphere model from O'Neil to Bruneton. I'm trying to go for code neatness and modularity, but I am having a hell of a time "cleaning up" the sample Bruneton code (found here: http://evasion.inrialpes.fr/~Eric.Bruneton/PrecomputedAtmosphericScattering2.zip) - right now, despite the algorithm being great, the code is (imho) a bit of a nightmare. What's more, it seems to defy refactoring - also possibly due to my relative ignorance in how to neatly structure GLSL shaders.

My question is: given the lack of #include in GLSL, in a situation with multiple complex shaders (as in Bruneton) where there is a lot of overlap between functions, #defined constants, uniforms, is there any good generic advice on how to structure things? Part of me wants to stick all of the uniforms/#defined constants in a big uniform block and include that. But I could use some advice from the pros.

Cheers

David

Advertisement


My question is: given the lack of #include in GLSL, in a situation with multiple complex shaders (as in Bruneton) where there is a lot of overlap between functions, #defined constants, uniforms, is there any good generic advice on how to structure things?

I use a pre-processor like mcpp to generate my final shader files, this way you get your include. smile.png


My question is: given the lack of #include in GLSL, in a situation with multiple complex shaders (as in Bruneton) where there is a lot of overlap between functions, #defined constants, uniforms, is there any good generic advice on how to structure things? [...]

While GLSL lacks a build-in #include directive, OpenGL allows the shader code to be supplied in several pieces (see glShaderSource()). This is one way to implement an inclusion system by yourself, either implicitly (simply by "knowing" the structure) or explicitly (by some superimposed pre-processing).


[...] Part of me wants to stick all of the uniforms/#defined constants in a big uniform block and include that. But I could use some advice from the pros.

Nowadays uniforms are usually provided by UBOs. As such they are declared in one or more blocks. I don't know how relevant it is for your use case, but in a typical 3D scenario one defines several uniform blocks dependent on the sources and update frequencies: 1 block with pipeline stage parameters, 1 block with camera/view parameters, 1 block with material parameters, and so on.


Nowadays uniforms are usually provided by UBOs. As such they are declared in one or more blocks. I don't know how relevant it is for your use case, but in a typical 3D scenario one defines several uniform blocks dependent on the sources and update frequencies: 1 block with pipeline stage parameters, 1 block with camera/view parameters, 1 block with material parameters, and so on.

Thanks - I was planning to divide the blocks up into static and dynamic/per-frame. From what I understand, uploading a uniform buffer in a program that doesn't use half of the buffer's variables is not at all inefficient - the combined buffer size might be a few hundred bytes. The bigger problem is that I'm just not sure how best to store the shader code. The existing Bruneton code stores all shaders in the pipeline in the same glsl file with #ifdef _VERTEX_ (etc) guards. The code I've written before uses separate files. It's probably not such a big deal, and perhaps there is no one best way to structure things? If it compiles/links it's good :)

K+ for interesting achivement

My question is: given the lack of #include in GLSL, in a situation with multiple complex shaders (as in Bruneton) where there is a lot of overlap between functions, #defined constants, uniforms, is there any good generic advice on how to structure things?

It is a question wheather you want to clean up your code, or your runtime.

When you set uniforms, you generaly reduce the problem to issue of setting them from cpu side. If a shader source and vertex function input differs, then you need to issue uniforms/vertex declaration/buffer but it is not a rule. It is a good practice to nail down uniforms to simple vec4 array, and not declare anything else, what allows one to utilize rather more global shared shaders instructions, uniforms should be the last thing forcing you to revolve shaders. This of course does not touch vertex function input, but even that can be utilized to be shared (meaning you can use the same vertex buffer and its feed declaration onto multiple shaders of "differing" vertex declarations in vertex function).

My advice is to share as much as possible (considering vertex byte size in the very gpu memory buffer, interleaving, and other things are more prior than data redundancy).

Another thing to note is that just because GLSL does not natively handle #include file doesn't mean you can't add your own system to handle include in your shader source. GL doesn't care about all that stuff because all it needs for the shader are the tokens( shader source)...not that difficult to add from my own experience. Another piece of advice would be not to worry about the author code being messy as it was most likely written to be used as a guide along with the paper for your own implementation instead of cut-paste-cleanup..You could stuff all the uniforms in a 1 buffer like you said and that would work since you would just need to update the buffer once per frame.

This topic is closed to new replies.

Advertisement