accessing Objects in Multiple Functions C++ - c++

I was seperating my main function from it's loop by creating a new function loop. Now I got the problem that some objects I created in main can't be accessed in loop. Creating multiple function parameters in loop is not an option because it will end in like 30 parameters and more for each Shader and other objects. So I made the objects global:
main.cpp
Shader light("Shaders/light.shader");
Shader depth("Shaders/depth.shader");
Shader.cpp
Shader::Shader(const std::string& filePath)
{
source = parseShader(filePath);
if (shaderGeometry)
ID = createShader(source.vertexSource, source.fragmentSource, source.geometrySource);
else
ID = createShader(source.vertexSource, source.fragmentSource);
use();
}
The problem here is that parsing the file paths outside of a function causes an exception at:
int Shader::createShader(const std::string& vertexShader, const std::string& fragmentShader)
{
program = glCreateProgram(); //<-- HERE
//some further code...
}
The vertexShader and fragmentShader are parsed correctly, so there is no problem.
I guess the exception is thrown because the Shaders need to be created inside a function where the GL function pointers are loaded before.
I tried to play around with extern. But something like this just leaves a compiling error:
global variable
extern Shader light;
extern Shader depth;
in the function
int main()
{
Window wnd(width, height);
Shader light("Shaders/light.shader");
Shader depth("Shaders/depth.shader");
wnd.loop();
//some further code
return 0;
}
Swithing The extern Shader light to the Metod and reversed would end up in the same error from before.
I maybe could access the shader with a getter Method and some kind of Array that safes every vertex, fragment and geometry Shader but maybe there is a more simple way and i just missed something.

Related

Using the "setUniformArray" method in the SFML library for a GLSL fragment shader

I have a problem using the "setUniformArray" method. I want to pass a std::vector to the shader in this way:
void OutputShader::setUniform(const std::string &name, const std::vector<float>& arr) {
outputShader.setUniformArray(name, arr.data(), arr.size());
}
In fragment shader I wrote like this:
uniform float "vector_name"[];
As a result I am getting the error:
Uniform "vector_name" not found in shader
Can you tell me the cause of the error and how to fix it please
My problem is solved
The fact is that this array was not used anywhere else and it seems that it was "thrown out" during compilation, so when I was trying to set a value to it, an error was generated

How do I pass uniforms between different shader programs in OpenGL?

I'm wondering if there is a way to communicate data between two separate shader programs.
I have one geometry shader that uses a uniform float, and I would like to send the value of that float to a fragment shaders that is used by another program.
Is this possible? I know that OpenGL uses pre-defined global variables, but is there a way to create my own?
Geometry shader from program 1:
uniform float uTime;
Fragment shader from program 2:
if (uTime > 0.){
...
}
I would like to send the value of that float to a fragment shaders that is used by another program. Is this possible?
There is no "interface" between different shader programs.
If you want to use the same uniform in your second shader program, then you simply need to declare and upload that same uniform in your second shader program, just like you did it for your first shader program.
(I am not getting into uniform buffer objects for the rest of this answer, since you used top-level uniform variables in the unnamed block. But, you can use a uniform buffer object holding your uniform values, which you then bind to both shader programs.)
So: Declare the uniform in the fragment shader of your second shader program just like you did with the geometry shader of your first shader program:
uniform float uTime;
void main(void) {
...
if (uTime > 0.){
...
}
...
}
Then, as usual, compile and link that program and obtain the location of the uniform in that second shader program via glGetUniformLocation() once:
// do once:
GLint uTimeLocationInSecondShaderProgram = glGetUniformLocation(yourSecondShaderProgram, "uTime");
and then send a value to the uniform via e.g. glUniform1f() whenever the value changes (e.g. once per render loop iteration):
// do before drawing:
float time = ...; // <- whatever time you also used in your first shader program
glUseProgram(yourSecondShaderProgram);
glUniform1f(uTimeLocationInSecondShaderProgram, time);

Multiple Shaders in OpenGL

Is there a way to create multiple shaders (both vertex, fragment, even geometry and tessellation) that can be compounded in what they do?
For example: I've seen a number of uses of the in and out keywords in the later versions of OpenGL, and will use these to illustrate my question.
Is there a way given a shader (doesn't matter which, but let's say fragment shader) such as
in inVar;
out outVar;
void man(){
var varOne = inVar;
var varTwo = varOne;
var varThr = varTwo;
outVar = varThr;
}
To turn it into the fragment shader
in inVar;
out varOne;
void main(){
varOne = inVar;
}
Followed by the fragment shader
in varOne;
out varTwo;
void main(){
varTwo = varOne;
}
Followed by the fragment shader
in varTwo(
out varThr;
void main(){
varThr = varTwo
}
And finally Followed by the fragment shader
in varThr;
out outVar;
void main(){
outVar = varThr;
}
Are the in and out the correct "concepts" to describe this behavior or should I be looking for another keyword(s)?
In OpenGL, you can attach multiple shaders of the same type to a program object. In OpenGL ES, this is not supported.
This is from the OpenGL 4.5 spec, section "7.3 Program Objects", page 88 (emphasis added):
Multiple shader objects of the same type may be attached to a single program object, and a single shader object may be attached to more than one program object.
Compared with the OpenGL ES 3.2 spec, section "7.3 Program Objects", page 72 (emphasis added):
Multiple shader objects of the same type may not be attached to a single program object. However, a single shader object may be attached to more than one program object.
However, even in OpenGL, using multiple shaders of the same type does not work they way you outline it in your question. Only one of the shaders can have a main(). The other shaders typically only contain functions. So your idea of chaining multiple shaders of the same type into a pipeline will not work in this form.
The way this is sometimes used is that there is one (or multiple) shaders that contain a collection of generic functions, which only needs to be compiled once, and can then be used for multiple shader programs. This is comparable to a library of functions in general programming. You could call this, using unofficial terminology, a "library shader".
Then each shader program has a single shader of each type containing a main(), and that shader contains the specific logic and control flow for that program, while calling generic functions from the "library shaders".
Following the outline in your question, you could achieve something similar with defining a function in each shader. For example, the first fragment shader could contain this code:
void shaderOne(in vec4 varIn, out vec4 varOut) {
varOut = varIn;
}
Second shader:
void shaderTwo(in vec4 varIn, out vec4 varOut) {
varOut = varIn;
}
Third shader:
void shaderThr(in vec4 varIn, out vec4 varOut) {
varOut = varIn;
}
Then you need one shader with a main(), where you can chain the other shaders:
in vec4 varOne;
out vec4 outVar;
void main() {
vec4 varTwo, varThr;
shaderOne(varOne, varTwo);
shaderTwo(varTwo, varThr);
shaderThr(varThr, outVar);
}
Generate your shaders. That's what pretty much all 3D engines and game engines do.
In other words they manipulate text using code and generate source code at runtime or build time.
Sometimes they use GLSL's preprocessor. Example
#ifdef USE_TEXTURE
uniform sampler2D u_tex;
varying vec2 v_texcoord;
#else
uniform vec4 u_color;
#endif
void main() {
#ifdef USE_TEXTURE
gl_FragColor = texture2D(u_tex, v_texcoord);
#else
gl_FragColor = u_color;
#endif
}
Then at runtime prepend a string to define USE_TEXTURE.
JavaScript
var prefix = useLighting ? '#define USE_TEXTURE' : '';
var shaderSource = prefix + originalShaderSource;
Most engines though do a lot more string manipulation by taking lots of small chunks of GLSL and combining them with various string substitutions.

OpenGL - glUniformBlockBinding after or before glLinkProgram?

I'm trying to use Uniform Buffer Objects to share my projection matrix accross different shaders (e.g., Deferred pass for solid objects and Forward pass for transparent ones). I think that I'll add more data to the UBO later on, when the complexity grows up. My problem is that the Red Book says:
To explicitly control a uniform block's binding, call glUniformBlockBinding() before calling glLinkProgram().
But the online documentation says:
When a program object is linked or re-linked, the uniform buffer object binding point assigned to each of its active uniform blocks is reset to zero.
What am I missing? Should I bind the Uniform Block after or before the linking?
Thanks.
glUniformBlockBinding​ needs the program name and the index where to find the block in this particular program.
void glUniformBlockBinding​( GLuint program​, GLuint uniformBlockIndex​, GLuint uniformBlockBinding​ );
uniformBlockIndex​ can be obtained by calling glGetUniformBlockIndex on the program.
GLuint glGetUniformBlockIndex​( GLuint program​, const char *uniformBlockName​ );
From the API (http://www.opengl.org/wiki/GLAPI/glGetUniformBlockIndex):
program​ must be the name of a program object for which the command glLinkProgram​ must have been called in the past, although it is not required that glLinkProgram​ must have succeeded. The link could have failed because the number of active uniforms exceeded the limit.
So the correct order is:
void glLinkProgram(GLuint program​);
GLuint glGetUniformBlockIndex​( GLuint program​, const char *uniformBlockName​ );
void glUniformBlockBinding​( GLuint program​, GLuint uniformBlockIndex​, GLuint uniformBlockBinding​ );

0(3) : error C1013: function "main" is already defined at 0(4)

I've google this a little bit and I can't figure out what is wrong. My shader:
#version 120
attribute vec2 coord2d;
void main(void)
{
gl_Position = vec4(coord2d, 0.0, 1.0);
}
This shader I know works, but when I try to link the program I get:
glLinkProgram:Vertex info
-----------
0(3) : error C1013: function "main" is already defined at 0(4)
I've checked to make sure that the viles are getting into memory properly and what not. they compile just fine. it is the linking step that something goes wrong. I'm clueless as to what and I've been hitting my head on this for quite some time. any tips?
Edit:
Here is the code i use to create the shader. it gets all the way to the conditional, it actually completes execution entirely, but the log prints out what you saw above.
GLuint updateProg()
{
prog = glCreateProgram();
if (vs == 0 || fs == 0) return 0;
glAttachShader(prog, vs);
glAttachShader(prog, fs);
int link_ok;
glLinkProgram(prog);
glGetProgramiv(prog, GL_LINK_STATUS, &link_ok);
if (!link_ok)
{
fprintf(stderr, "glLinkProgram:");
print_log(prog);
return 0;
}
return prog;
}
The error sounds like you might be trying to link two copies of the shader? Check the code for creating shader object(s), loading code into them, and linking them into the program object. That is, double-check all the calls to glCreateShader, glShaderSource, glCreateProgram, and glAttachShader to make sure they make sense.
edit
You've added the code that calls glCreateProgram above, but not the code that calls glCreateShader. Your error is consistent with accidentally (incorrectly) passing GL_VERTEX_SHADER to glCreateShader for the fragment shader.
I had this error today.
It happened because I copy/pasted too much code.
I called glCreateShader(GL_VERTEX_SHADER); for both my vertex and fragment shader.
They compiled just fine, but they wouldn't link, because they were both vertex shaders.
GLSL is not C or C++. void cannot be used as the only parameter, as in void main(void). What you want is void main().
The error is admittedly cryptic though.