I have shaders which work with GLES 3.0:
#version 300 es
#ifdef GL_ES
precision mediump float;
#endif
in vec2 v_tex_coord;
uniform sampler2D s_texture;
uniform vec4 u_color;
out vec4 fragmentColor;
void main()
{
fragmentColor = texture(s_texture, v_tex_coord)*u_color;
}
I'd like them to work with OpenGL 4.1 (not ES).
Does there exist a way to declare both ES and desktop versions in one shader?
You will need to use a prefix string. glShaderSource takes an array of strings, which will conceptually be concatenated together before processing. So you will need to remove the #version declaration from your shader files and put the version declaration into a string that is generated at runtime. Something like this:
GLuint CreateShader(const std::string &shader)
{
GLuint shaderName = glCreateShader(GL_VERTEX_SHADER);
const GLchar *strings[2];
if(IS_USING_GLES)
strings[0] = "#version 300 es";
else
strings[0] = "#version 410 core\n";
strings[1] = (const GLchar*)shader.c_str();
glShaderSource(shaderName, 2, strings, NULL);
//Compile your shader and check for errors.
return shaderName;
}
Your runtime should know whether it's ES or desktop GL.
Also, there is no need for that ifdef around your precision statement. Precision declarations have been part of desktop GL for a while, well before 4.1. Though admittedly, they don't actually do anything ;)
Related
When I try to compile this GLSL code in OpenGL 4.0 I get error 1282
Vertex shader:
#version 330 core
layout(location = 0) in vec2 aPos;
uniform mat4 model[100];
uniform mat4 projection;
out int instanceID;
void main()
{
instanceID = gl_InstanceID;
gl_Position = projection * model[gl_InstanceID] * vec4(aPos.x, aPos.y, 0.0, 1.0);
}
Fragment shader:
#version 330 core
in int instanceID;
out vec4 FragColor;
uniform vec4 color[100];
void main()
{
FragColor = color[instanceID];
}
The code is regular ShaderProgram creation because I get the error before drawing or anything like that but just in case here is the code:
unsigned int vertex, fragment;
vertex = glCreateShader(GL_VERTEX_SHADER);
std::string vShaderCode = ReadEntireTextFile(vertPath);
const char* c_vShaderCode = vShaderCode.c_str();
glShaderSource(vertex, 1, &c_vShaderCode, NULL);
glCompileShader(vertex);
std::string fShaderCode = ReadEntireTextFile(fragPath);
fragment = glCreateShader(GL_FRAGMENT_SHADER);
const char* c_fShaderCode = fShaderCode.c_str();
glShaderSource(fragment, 1, &c_fShaderCode, NULL);
glCompileShader(fragment);
// shader Program
m_RendererID = glCreateProgram();
glAttachShader(m_RendererID, vertex);
glAttachShader(m_RendererID, fragment);
glLinkProgram(m_RendererID);
// delete the shaders as they're linked into our program now and no longer necessery
glDeleteShader(vertex);
glDeleteShader(fragment);
glUseProgram(m_RendererID);
I know for sure that the error is because of instanceID because it worked when the shader didn't have that. but I tried to find where the problem is exactly with no luck.
UPDATE:
Made sure shaders were compiled successfully. and turns out they are compiled successfully.
I was able to pinpoint where the error occurs and it was the glUseProgram funtion.
I think the error is because of instanceID because when I change:
FragColor = color[instanceID];
to
FragColor = color[0];
the program works.
UPDATE(2):
I solved the problem.
Turns out I had 2 problems one being that I had too many components and I fixed that thanks to one of the answers alerting me.
The other was that I can't put uniforms directly in the fragment shader which I thought you could do.So I put the colors in the vertex shader and passed the one color I needed for the fragment shader.
Thanks for the help!
uniform mat4 model[100];
That is way outside of what is guaranteed by the spec. The limit here is GL_MAX_VERTEX_UNIFORM_COMPONENTS, which the spec guarantees to be at least 1024. Since a mat4 consumes 16 components, that's 64 matrices at most. Now your particular limit might be higher, but you also have the other uniforms in your program, like color[100].
(from comments):
It does not return anything for both fragment and vertex shaders and glGetShaderiv(shader, GL_COMPILE_STATUS, &output); returns true for both shaders.
But that does not imply that the program object linked successfully. Such ressource limits are usually enforced during linking.
I'm pretty sure program is an object created by openGL successfully, I'm not really sure about the others though. you see if i change the fragment shader main function to FragColor = color[0]; it will work so the issue is with instanceID I think.
That conclusion does not follow. If you write color[0], it will optimize your vec4r[100] array to vec4[1], and you might get below your particular limit.
I'm encountering something really really strange.
I have a very simple program that renders a simple full-screen billboard using the following shader pipeline:
VERTEX SHADER:
#version 430
layout(location = 0) in vec2 pos;
out vec2 tex;
void main()
{
gl_Position = vec4(pos, 0, 1);
tex = (pos + 1) / 2;
}
FRAGMENT SHADER:
#version 430
in vec2 tex;
out vec3 frag_color;
void main()
{
frag_color = vec3(tex.x, tex.y, 1);
}
The program always renders the quad in the correct positions (so I've ruled out the VAO as culprit), but for some reason ignores whatever values I set for tex and always set it to vec2(0,0), rendering a blue box.
Is there something I'm missing here? I've done many opengl apps before, and I've never encountered this. :/
I've seen implementations of OpenGL 2.0 having problems at compile time when adding floats and not explicitly casted integers.
Even if it is not a problem I would think possible on a 4.3 implementation, maybe you should just add dots and suffixes to your "integer" constants.
The last line of you're vertex shader seems to be the only one that could be a problem (I believe values are always casted in constructors :p ) so you would have something like this instead:
tex = (pos + 1.0f) / 2.0f;
Remember that you're shaders can compile on thousands of different implementations so it's a good habit to always be explicit!!!
I have the following piece of shader code that works perfectly with GLSL #130, but I would like to convert it to code that works with version #330 (as somehow the #130 version doesn't work on my Ubuntu machine with a Geforce 210; the shader does nothing). After several failed attempts (I keep getting undescribed link errors) I've decided to ask for some help. The code below dynamically changes the contrast and brightness of a texture using the uniform variables Brightness and Contrast. I have implemented it in Python using PyOpenGL:
def createShader():
"""
Compile a shader that adjusts contrast and brightness of active texture
Returns
OpenGL.shader - reference to shader
dict - reference to variables that can be passed to the shader
"""
fragmentShader = shaders.compileShader("""#version 130
uniform sampler2D Texture;
uniform float Brightness;
uniform float Contrast;
uniform vec4 AverageLuminance;
void main(void)
{
vec4 texColour = texture2D(Texture, gl_TexCoord[0].st);
gl_FragColor = mix(texColour * Brightness,
mix(AverageLuminance, texColour, Contrast), 0.5);
}
""", GL_FRAGMENT_SHADER)
shader = shaders.compileProgram(fragmentShader)
uniform_locations = {
'Brightness': glGetUniformLocation( shader, 'Brightness' ),
'Contrast': glGetUniformLocation( shader, 'Contrast' ),
'AverageLuminance': glGetUniformLocation( shader, 'AverageLuminance' ),
'Texture': glGetUniformLocation( shader, 'Texture' )
}
return shader, uniform_locations
I've looked up the changes that need to made for the new GLSL version and tried changing the fragment shader code to the following, but then only get non-descriptive Link errors:
fragmentShader = shaders.compileShader("""#version 330
uniform sampler2D Texture;
uniform float Brightness;
uniform float Contrast;
uniform vec4 AverageLuminance;
in vec2 TexCoord;
out vec4 FragColor;
void main(void)
{
vec4 texColour = texture2D(Texture, TexCoord);
FragColor = mix(texColour * Brightness,
mix(AverageLuminance, texColour, Contrast), 0.5);
}
""", GL_FRAGMENT_SHADER)
Is there anyone that can help me with this conversion?
I doubt that raising the shader version profile will solve any issue. #version 330 is OpenGL-3.3 and according to the NVidia product website the maximum OpenGL version supported by the GeForce 210 is OpenGL-3.1, i.e. #version 140
I created no vertex shader cause I didn't think I'd need one (I wouldn't know what I should make it do). It worked before without any vertex shader as well.
Probably only as long as you didn't use a fragment shader or before you were attempting to use a texture. The fragment shader needs input variables, coming from a vertex shader, to have something it can use as texture coordinates. TexCoord is not a built-in variable (and with higher GLSL versions any builtin variables suitable for the job have been removed), so you need to fill that with value (and sense) in a vertex shader.
the glGetString(GL_VERSION) on the NVidia machine reads out OpenGL version 3.3.0. This is Ubuntu, so it might be possible that it differs with the windows specifications?
Do you have the NVidia propriatary drivers installed? And are they actually used? Check with glxinfo or glGetString(GL_RENDERER). OpenGL-3.3 is not too far from OpenGL-3.1 and in theory OpenGL major versions map to hardware capabilities.
I have a couple of examples that I want to run on my PC. The problem is that they're written with glsl target 150 and my PC only supports version 120. I'm pretty sure that the program itself is simple enough not to require any extended functionality of OpenGL 3.1. I have found some information on what steps should be taken to transform glsl(f.e. changing in to attribute, out to varying) but it's still not compiling(is it actually possible to somehow get a meaningful error message out of this?).
original .vert
#version 150
in vec2 in_Position;
in vec3 in_Color;
out vec3 ex_Color;
void main(void) {
gl_Position = vec4(in_Position.x, in_Position.y, 0.0, 1.0);
ex_Color = in_Color;
}
original .frag
#version 150
precision highp float;
in vec3 ex_Color;
out vec4 gl_FragColor;
void main(void) {
gl_FragColor = vec4(ex_Color,1.0);
}
changed .vert
#version 120
attribute vec2 in_Position;
attribute vec3 in_Color;
varying vec3 ex_Color;
void main(void) {
gl_Position = vec4(in_Position.x, in_Position.y, 0.0, 1.0);
ex_Color = in_Color;
}
changed .frag
#version 120
precision highp float;
attribute vec3 ex_Color;
void main(void) {
gl_FragColor = vec4(ex_Color,1.0);
}
So can anyone spot a problem here?
To get the compile/link error messages, you need to use the commands glGetShaderInfoLog for shaders, and glGetProgramInfoLog for programs.
These will tell you what your particular errors are.
Just taking a stab at what the error might be, you're declaring an attribute input in the fragment shader, which I believe should be a varying. Attributes are for data->vertex shader, and varyings are for vertex shader -> fragment shader.
The glsl 120 spec also mentions that precision qualifier is "reserved for future use", so it may not be applicable to version 120. You can probably leave it out.
But you should still get familiar with the infolog functions regardless, you'll definitely need them eventually.
You can get the compile errors by retrieving the "info log":
GLuint nVertexShader, nPixelShader; // handles to objects
GLint vertCompiled, fragCompiled; // status values
GLint linked;
glCompileShader(nVertexShader);
glGetShaderiv(nVertexShader, GL_COMPILE_STATUS, &vertCompiled);
if vertCompiled (or fragCompile) == 0, do this to see why:
int infologLength = 0;
int charsWritten = 0;
glGetShaderiv(nVertexShader, GL_INFO_LOG_LENGTH, &infologLength);
if (infologLength > 0)
{
GLchar* infoLog = (GLchar *)malloc(infologLength);
if (infoLog == NULL)
{
printf( "ERROR: Could not allocate InfoLog buffer");
exit(1);
}
glGetShaderInfoLog(nVertexShader, infologLength, &charsWritten, infoLog);
printf( "Shader InfoLog:\n%s", infoLog );
free(infoLog);
}
You can do the same with linking, just check for linked == 0 and retrieve the log as above:
glLinkProgram(m_nProgram);
glGetProgramiv(m_nProgram, GL_LINK_STATUS, &linked);
precision highp float;
That is not legal in GLSL 1.20. I don't even know why it was put in the 1.50 shader anyway, since the precision qualifiers only do useful things in GLSL ES, and you can't share 1.50 shaders with GLSL ES.
I am currently using 3 different shaders (Vertex, Geometry and Fragment), each belonging to a different program, all collected in a single Program Pipeline.
The problem is that the Geometry and Fragment have their in varyings zeroed, that is, they do not contain the value previously written by the preceeding shader in the pipeline.
for each shader:
glCreateShader(...)
glShadersource(...)
glCompileShader(...)
glGetShaderiv(*shd,GL_COMPILE_STATUS,&status)
for each program:
program[index] = glCreateProgram()
glAttachShader(program[index],s[...])
glProgramParameteri(program[index],GL_PROGRAM_SEPARABLE,GL_TRUE)
glLinkProgram(program[index])
glGetProgramiv(program[index],GL_LINK_STATUS,&status)
then:
glGenProgramPipelines(1,&pipeline_object)
in gl draw:
glBindProgramPipeline(pipeline_object)
glUseProgramStages(pipeline_object,GL_VERTEX_SHADER_BIT,program[MY_VERTEX_PROGRAM])
and again for the geometry and fragment programs
vertex shader:
#version 330
//modelview and projection mat(s) skipped
...
//interface to geometry shader
out vec3 my_vec;
out float my_float;
void main() {
my_vec = vec3(1,2,3);
my_float = 12.3;
gl_Position = <whatever>
}
geometry shader:
#version 330
//input/output layouts skipped
...
//interface from vertex shader
in vec3 my_vec[];
in float my_float[];
//interface to fragment shader
out vec3 my_vec_fs;
out float my_float_fs;
void main() {
int i;
for(i=0;i<3;i++) {
my_vec_fs = my_vec[i];
my_float_fs = my_float[i];
EmitVertex();
}
EndPrimitive();
}
fragment shader:
#version 330
//interface from geometry
in vec3 my_vec_fs;
in float my_float_fs;
void main() {
here my_vec_fs and my_float_fs come all zeroed
}
Am I missing some crucial step in writing/reading varying between different stages in a program pipeline?
UPDATE:
I tried with the layout location qualifier just to be sure everyone was 'talking' on the same vector, since the GLSL specs states:
layout-qualifier-id location = integer-constant
Only one argument is accepted. For example, layout(location = 3) in vec4 normal; will establish that the shader input normal is assigned to vector location number 3. For vertex shader inputs, the location specifies the number of the generic vertex attribute from which input values are taken. For inputs of all other shader types, the location specifies a vector number that can be used to match against outputs from a previous shader stage, even if that shader is in a different program object.
but adding
layout(location = 3) out vec3 my_vec;
does not compile
So I tried to do the same via glBindAttribLocation(), I get no errors, but the behaviour is still unchanged
UPDATE 2
If I add
"#extension GL_ARB_separate_shader_objects: enable"
then I can use layout(location = n) in/out var; and then it works.
found:
GLSL 330: Vertex shaders cannot have output layout qualifiers
GLSL 420: All shaders allow location output layout qualifiers on output variable declarations
This is interesting.. If you declare #version 330 you shouldnt be able to use a layout out qualifier, even if you enable an extension..
..but again the extension states:
This ARB extension extends the GLSL language's use of layout qualifiers to provide cross-stage interfacing.
Now Idlike to know why it does not work using glBindAttribLocation() or just with plain name matches + ARB extension enabled!
In at least one implementation (webgl on and older chrome I think) I found bugs with glBindAttribLocation() I think the issue was, you had to bind vertex attribs in numerical order. So it proved not useful to use it. I had to switch to getAttribLocation() to get it to work.