This is kind of a philosophical question.
I was wondering, if there are any elegant ways to include shader code in a standard QtCreator project. The only two ways I am aware of are:
The shader code is in a seperate file, e.g. "fragmentshader.frag", this file is read in runtime and the shader code gets compiled and linked.
The shader code is a hardcoded string in one of the source files included in the project.
Both ways seem a little annoying to me. The first possibility requires files on the harddrive that have to be either in the same directory as the executable (so I would have to put them in each debug/release directory and end up with several duplicates of my shader file) or in a specific hardcoded directory on my drive, which seems bad for portability.
The second possibility bugs me, because you have to include things like \n
in your shader code, which makes the formatting kind of ugly.
How is the "right" way to do this? If it is of any significance, I am coding in c/c++, OpenGL and GLSL.
EDIT: I kept on Googling about this... I noticed that for example an icon file can be kept in a special resources folder in the project. That way it is a file and can be edited as such but still hasn't to be loaded in runtime. Is there a way to do that with shaders?
Shaders are written in the OpenGL Shading Language.
Shaders are most commonly used to produce lit and shadowed areas in the rendering of 3D models. Phong shading (right) is an improvement on Gouraud shading, and was one of the first computer shading models ever developed after the basic flat shader (left), greatly enhancing the appearance of curved surfaces in renders.
The vertex shader that is given in the program is very simple: GLbyte vShaderStr[] = "attribute vec4 vPosition; \n" "void main() \n" "{ \n" " gl_Position = vPosition; \n" "}; \n"; This shader declares one input attribute that is a four-component vector named vPosition.
Another thing you can do is use raw string literals, if you have C++11:
const char shaderSource[] = R"glsl(
#version 450 core
...
void main() {
...
}
)glsl";
No \n
in sight :)
I feel it's not a proper answer, but it's also too long for a comment.
Roughly speaking, you are right - either you have your shaders available at compile-time and hard-coded, or loaded in runtime. I'm going to elaborate on the various ways you can achieve this. Note that everything said can be applied to any other kind of data resource that your program needs to run.
Hard-coding can be done in a bit more elegant manner: keep resources in separate files, but set up your build system so that it automatically generates source files with hard-coded resource (as a static or dynamic array of std::uint8_t
or char
, for example), and compiles those generated files into your program. Here you probably will need an utility that generates C++ sources files from binary data. I am not aware of good, featured programs like this; when I needed one, I wrote my own, since it's quite simple.
To make runtime loading more portable, you can use loads of options, but it seems that the most important is to make the resources location on the file system configurable; at runtime or compile time, that's up to you. It can be a compilation flag (f.e. a macro RUNTIME_RESOURCE_PATH
, which is set up by the build system). It can be a command-line option with some reasonable default.
I have no answer on which way is right
. One should be chosen considering the use case.
Hard-coded data simplifies deployment (less files, less explicit io, less errors), while resources in separate files enable you to update them without touching the program itself, including modification by users.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With