From https://learnopengl.com/Getting-started/Shaders I read:
Shaders always begin with a version declaration, ...
But on OpenGL Window Example there is no version on shader code. What's the version then?
static const char *vertexShaderSource =
"attribute highp vec4 posAttr;\n"
"attribute lowp vec4 colAttr;\n"
"varying lowp vec4 col;\n"
"uniform highp mat4 matrix;\n"
"void main() {\n"
" col = colAttr;\n"
" gl_Position = matrix * posAttr;\n"
"}\n";
static const char *fragmentShaderSource =
"varying lowp vec4 col;\n"
"void main() {\n"
" gl_FragColor = col;\n"
"}\n";
Following seems to be related: How to Convert GLSL #version 330 core to GLSL ES #version 100?
In qt 5.12.2 source file : qopenglshaderprogram.cpp
LINE 604:
bool QOpenGLShader::compileSourceCode(const char *source){
Q_D(QOpenGLShader);
// This method breaks the shader code into two parts:
// 1. Up to and including an optional #version directive.
// 2. The rest.
// If a #version directive exists, qualifierDefines and redefineHighp
// are inserted after. Otherwise they are inserted right at the start.
// In both cases a #line directive is appended in order to compensate
// for line number changes in case of compiler errors.
if (d->shaderGuard && d->shaderGuard->id() && source) {
const QVersionDirectivePosition versionDirectivePosition = findVersionDirectivePosition(source);
QVarLengthArray<const char *, 5> sourceChunks;
QVarLengthArray<GLint, 5> sourceChunkLengths;
QOpenGLContext *ctx = QOpenGLContext::currentContext();
if (versionDirectivePosition.hasPosition()) {
// Append source up to and including the #version directive
sourceChunks.append(source);
sourceChunkLengths.append(GLint(versionDirectivePosition.position));
} else {
// QTBUG-55733: Intel on Windows with Compatibility profile requires a #version always
if (ctx->format().profile() == QSurfaceFormat::CompatibilityProfile) {
const char *vendor = reinterpret_cast<const char *>(ctx->functions()->glGetString(GL_VENDOR));
if (vendor && !strcmp(vendor, "Intel")) {
static const char version110[] = "#version 110\n";
sourceChunks.append(version110);
sourceChunkLengths.append(GLint(sizeof(version110)) - 1);
}
}
}
and
static QVersionDirectivePosition findVersionDirectivePosition(const char *source){
Q_ASSERT(source);
// According to the GLSL spec the #version directive must not be
// preceded by anything but whitespace and comments.
// In order to not get confused by #version directives within a
// multiline comment, we need to do some minimal comment parsing
// while searching for the directive.
If version is not available, "#version 110\n" will be added.
static const char version110[] = "#version 110\n";
sourceChunks.append(version110);
Related
The following Shaders fail with a return of -1, when i try.
col_attr = glGetAttribLocation(prog, "v_col");
i tried different settings including
switching ,
gl_FragColor
to
outColor
and
#version 300 es
to
#version 150 core
and many more, before i realized i'm completely lost and there are so many variables i dont know. i just need these simple shaders converted to something that works with GLESv3 for Android NDK in C++. All the help is highly appreciated. Thank you.
Original Vertex Shader
#version 150 core
in vec3 v_pos;
in vec4 v_col;
out vec4 color;
uniform mat4 projection;
uniform mat4 view;
void main(){
color = v_col;
gl_Position = projection * view * vec4(v_pos, 1.0);
}
Original Fragment Shader
#version 150 core
in vec4 color;
void main(){
gl_FragColor = color;
}
Update: Found that only the Fragment Shader fails at compilation.
New Vertex Shader - Compiles!
return "#version 300 es \n"
"in vec3 v_pos; \n"
"in vec4 v_col; \n"
"out vec4 color; \n"
"uniform mat4 projection; \n"
"uniform mat4 view; \n"
"void main() \n"
"{ \n"
" color = v_col; \n"
" gl_Position = projection * view * vec4(v_pos, 1.0); \n"
"} \n";
New Fragment Shader - Doesn't Compile!
return "#version 300 es \n"
"in vec4 color; \n"
"out vec4 outColor; \n"
"void main() \n"
"{ \n"
" outColor = color; \n"
"} \n";
New Fragment Shader - Compiles!
return "#version 300 es \n"
"precision mediump float; \n"
"in vec4 color; \n"
"out vec4 outColor; \n"
"void main() \n"
"{ \n"
" outColor = color; \n"
"} \n";
You've to declare the fragment shader output variable out vec4 outColor.
Further you've to add a precision qualifier:
A valid GLSL ES 3.00 fragment shader would be:
#version 300 es
precision mediump float;
in vec4 color;
out vec4 outColor;
void main(){
outColor = color;
}
The version information (#version 300 es) has to be changed in the vertex shader, too.
See OpenGL ES Shading Language 3.00 Specification - 4.3.6 Output Variables page 42:
Fragment outputs are declared as in the following examples:
out vec4 FragmentColor;
out uint Luminosity;
See OpenGL ES Shading Language 3.00 Specification - 4.5.4 Default Precision Qualifiers page 56:
The fragment language has no default precision qualifier for floating point types. Hence for float, floating point vector and matrix variable declarations, either the declaration must include a precision qualifier or the default float precision must have been previously declared.
I want to porting demo project of Box2D from VS2013 in Qt. But i have one unusual problem. When i run demo project in VS i get message with info about my openGL configuration.
I replaced code on Qt and changed initialization of shaders and calls of opengl funcitons with QOpeGL wrappers.
Firstly, i change default surface format like this:
QSurfaceFormat format;
format.setVersion(3, 1);
format.setProfile(QSurfaceFormat::CoreProfile);
QSurfaceFormat::setDefaultFormat(format);
But when i debug program is format of my surface stay on 3.0.
And when i try to create shaders i get error message like this:
QOpenGLShader::compile(Vertex): ERROR: 0:1: '140' : version number not supported
ERROR: 0:2: 'layout' : syntax error
*** Problematic Vertex shader source code ***
#version 140
#line 1
uniform mat4 projectionMatrix;
layout(location = 0) in vec2 v_position;
layout(location = 1) in vec4 v_color;
layout(location = 2) in float v_size;
out vec4 f_color;
void main(void)
{
f_color = v_color;
gl_Position = projectionMatrix * vec4(v_position, 0.0f, 1.0f);
gl_PointSize = v_size;
}
Why VS can create shaders and work with OpenGL 3.1/GLSL 1.40, but Qt doesn't do this?
Initialize of GL (m_functions - QOpenGLExtraFunctions)
void MainOpenGLWidget::initializeGL()
{
makeCurrent();
qDebug() << "OPENGL " << QSurfaceFormat::defaultFormat().majorVersion() <<
"." << QSurfaceFormat::defaultFormat().minorVersion();
m_functions.initializeOpenGLFunctions();
m_functions.glClearColor(0, 0, 0, 0);
g_camera.m_width = 1024;
g_camera.m_height = 640;
g_debugDraw.Create(&m_functions);
}
function g_debugDraw.Create(...):
void Create(QOpenGLExtraFunctions *functions)
{
const char *vs = \
"#version 140\n"
"uniform mat4 projectionMatrix;\n"
"layout(location = 0) in vec2 v_position;\n"
"layout(location = 1) in vec4 v_color;\n"
"layout(location = 2) in float v_size;\n"
"out vec4 f_color;\n"
"void main(void)\n"
"{\n"
" f_color = v_color;\n"
" gl_Position = projectionMatrix * vec4(v_position, 0.0f, 1.0f);\n"
" gl_PointSize = v_size;\n"
"}\n";
...
m_program.addShaderFromSourceCode(QOpenGLShader::Vertex, vs);
...
m_functions = *functions;
m_functions.glGenVertexArrays(1, &m_vaoId);
m_functions.glGenBuffers(3, m_vboIds);
m_functions.glBindVertexArray(m_vaoId);
m_functions.glEnableVertexAttribArray(m_vertexAttribute);
m_functions.glEnableVertexAttribArray(m_colorAttribute);
m_functions.glEnableVertexAttribArray(m_sizeAttribute);
...
}
I get error when call m_program.addShaderFromSourceCode(QOpenGLShader::Vertex, vs);
If you really want to stick to GLSL #version 140, then replace the following lines
layout(location = 0) in vec2 v_position;
layout(location = 1) in vec4 v_color;
layout(location = 2) in float v_size;
by
in vec2 v_position;
in vec4 v_color;
in float v_size;
Explicit attribute location is not part of GLSL until #version 330.
Be careful after that to query your shader's attribute location before enabling it in your C++ code. The shader compiler may or may not order them in the order of declaration.
const int POS_LOCATION = glGetAttribLocation(program_id, "v_position");
if(-1 != POS_LOCATION)
{
glEnableVertexAttribArray(POS_LOCATION);
...
glVertexAttribPointer(POS_LOCATION, ... );
...
}
I've found no mention of layout(location = x) in documentation of GLSL #version 140.
https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.1.40.pdf
Not mentioned until #version 330 at page 35.
https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.3.30.pdf
In your case the shader compiler error message is a little misleading. Maybe if you update you graphic card driver you'll get a better shader compiler.
I didn't took into account that GLSL for desktop is not the same that GLSL from OpenGL ES. This topic little helped me. I change all in to attribute or varying and all out to varying and also set precision on float. After change my shader was compile. Finally my shader code looks like this:
precision lowp float;
uniform mat4 projectionMatrix;
attribute vec2 v_position;
attribute vec4 v_color;
attribute float v_size;
varying vec4 f_color;
void main(void)
{
f_color = v_color;
gl_Position = projectionMatrix * vec4(v_position, 0.0, 1.0);
gl_PointSize = v_size;
}
Thank Octo for support!
const GLchar* vertexSource1 = "#version 330 core\n"
"layout (location = 0) in vec2 position;\n"
"layout (location = 1) in vec3 color;\n"
"out vec3 Color;\n"
"void main()\n"
"{\n"
"gl_Position = vec4(position, 0.0, 1.0);\n"
"Color = color;\n"
"}\0";
const GLchar* fragmentSource1 = "#version 330 core\n"
" in vec3 Color;\n"
" out vec4 outColor;\n"
" void main()\n"
" {\n"
" outColor = vec4(Color, 1.0);\n"
" }\n";
GLuint shaderProgram1 = glCreateProgram();
glAttachShader(shaderProgram1, vertexShader1);
glAttachShader(shaderProgram1, fragmentShader1);
// glBindFragDataLocation(shaderProgram1, 0, "Color");
glLinkProgram(shaderProgram1);
Whether I add glBindFragDataLocation or not, the GL works correctly, Why?
Because you're "lucky". The OpenGL specification provides no guarantees about how fragment shader output locations are assigned if you don't assign them. It only says that each one will have a separate location; what locations those are is up to the implementation.
However, considering the sheer volume of code that writes to a single output variable without explicitly assigning it to a location, it's highly unlikely that an OpenGL implementation would ever assign the first FS output location to anything other than 0. So while it isn't a spec guarantee, at this point, it is a de-facto requirement of implementations.
Note: That doesn't mean you shouldn't assign that location manually. It's always best to be on the safe and explicit side.
FYI: layout(location) works for fragment shader outputs too. So you should use that if you're using it on vertex attributes. Then you don't have to worry about doing it from code.
I've created a very basic shader:
static const char *frag_showImage =
"#version 150\n"
"uniform sampler2D textureSampler;\n"
"in mediump vec2 texc;\n"
"out highp vec4 fragColor;\n"
"void main() {\n"
" fragColor = texture2D(textureSampler, texc.st);\n"
"}\n";
And it works as expected, now a bit more complex one:
"#version 150\n"
"uniform sampler2D textureSampler;\n"
"uniform sampler2D maskSampler;\n"
"in mediump vec2 texc;\n"
"out highp vec4 fragColor;\n"
"void main() {\n"
" fragColor = texture2D(textureSampler, texc.st);\n"
" fragColor.x = texture2D(maskSampler, texc.st).x;\n"
" fragColor.y =0;\n"
"}\n";
It doesn't work but it has no warnings neither errors:
in both cases I bind the first texture as:
QOpenGLFunctions *f =this->context()->functions();
f->glActiveTexture(GL_TEXTURE0);
glBaseTexture->bind();
m_program->setUniformValue("textureSampler", 0);
and the second texture is binded as:
f->glActiveTexture(GL_TEXTURE1);
glMaskTexture->bind();
m_program->setUniformValue("maskSampler", 1);
Notice that if I bind glMaskTexture for the first shader it works ok so the problem is not on that QOpenGlTexture.
Any idea? Thank you in advance!
Goblins: renaming maskSampler to other name it works ok, I have no idea about why this is happening since "maskSampler" is not used in any other part of the code.
I have const char* variable with vertex shader code:
const char* FS_source_a =
#include "fs_a.h"
;
in fs_a.h:
"#version 100\n"
"varying lowp vec4 v_color;\n"
"void main(void)\n"
"{\n"
"gl_FragColor = v_color;\n"
"}\n";
Now, I have some defined/static variable, and I want to put it in my shader code, like this[pseudocode]:
"#version "+SHADER_VERSION+"\n"
Well.... Is this possible somehow, or I have to concat them? I want to keep shader source code in separate file.
P.S. This is not opengl question.
You cannot do what you wrote, but you can do this:
code.c
#include "code.h"
const char* FS_source_a = DEFINEDVALUE;
char FS_dest_a[1024] = {0};
sprintf(FS_dest_a, FS_source_a, 100);
code.h
#define DEFINEDVALUE "#version %d\n\
varying lowp vec4 v_color;\n\
void main(void)\n\
{\n\
gl_FragColor = v_color;\n\
}\n"