I'm experimenting this frustrating error while compiling a fragment shader. If I try to compile the shader as it is :
#version 450 core
in vec2 tex_coord;
in flat int vertex_id;
out vec4 color;
layout (binding = 20) uniform sampler2D buildingTex;
layout (binding = 21) uniform sampler2D groundTex;
const int cube_vertices = 36;
const int ground_vertices = 4;
void main(void)
{
if(vertex_id < cube_vertices)
{
float scaleF = .5f;
vec2 scale = vec2(scaleF,scaleF);
color = texture(buildingTex,tex_coord*scale);
}
if(vertex_id >= cube_vertices)
{
color = texture(groundTex,tex_coord);
}
}
the compailer complains with : glsl UNEXPECTED NEW_IDENTIFIER, expecting $end.
However if I add to my fragment shader another fragment shader, that i had in another file , and then i comment all its rows like follows :
// #version 450 core
// in vec2 tex_coord;
// in flat int vertex_id;
// out vec4 color;
// layout (binding = 20) uniform sampler2D buildingTex;
// layout (binding = 21) uniform sampler2D groundTex;
// int cube_vertices;
// int ground_vertices;
// void main(void)
// {
// if(vertex_id < cube_vertices)
// {
// float scaleF = .5f;
// vec2 scale = vec2(scaleF,scaleF);
// color = texture(buildingTex,tex_coord*scale);
// //color = vec4(1.0,1.0,1.0,1.0);
// }
// if(vertex_id >= cube_vertices)
// {
// color = texture(groundTex,tex_coord);
// //color = vec4(1.0,0.0,0.0,1.0);
// }
#version 450 core
in vec2 tex_coord;
in flat int vertex_id;
out vec4 color;
layout (binding = 20) uniform sampler2D buildingTex;
layout (binding = 21) uniform sampler2D groundTex;
const int cube_vertices = 36;
const int ground_vertices = 4;
void main(void)
{
if(vertex_id < cube_vertices)
{
float scaleF = .5f;
vec2 scale = vec2(scaleF,scaleF);
color = texture(buildingTex,tex_coord*scale);
}
if(vertex_id >= cube_vertices)
{
color = texture(groundTex,tex_coord);
}
}
in this case the shader is compiled!
I tried to remove the commented line of the old code, and seems like I can remove just some of them, while others I cannot touch, to have the shader compiled.
At this moment the shader is :
// #version 450 core
// in vec2 tex_coord;
// in flat int vertex_id;
// out vec4 color;
// layout (binding = 20) uniform sampler2D buildingTex;
// layout (binding = 21) uniform sampler2D groundTex;
// int cube_vertices;
// if(vertex_id < cube_vertices)
#version 450 core
in vec2 tex_coord;
in flat int vertex_id;
out vec4 color;
layout (binding = 20) uniform sampler2D buildingTex;
layout (binding = 21) uniform sampler2D groundTex;
const int cube_vertices = 36;
const int ground_vertices = 4;
void main(void)
{
if(vertex_id < cube_vertices)
{
float scaleF = .5f;
vec2 scale = vec2(scaleF,scaleF);
color = texture(buildingTex,tex_coord*scale);
}
if(vertex_id >= cube_vertices)
{
color = texture(groundTex,tex_coord);
}
}
and seems I cannot remove anymore from the commented code.
Since this seems the most illogical problem I ever had in my life,and since the others questions having this same error warning, were solved in a way that doesn't match my case, I'm opening a new quest.
ps: I tried to make a completely new shader but it didn't work.
pps: the problem comes up after I changed the major-mode (through M-x and not modifying the init file of emacs!) of emacs in order to use the ordinary shortcut I use in cpp files, in the shaders files (.vert, .frag ...), however even restoring the default-mode and restarting emacs the shader does not compile!
EDIT: this is the method I use to load the shader
const char* Shader::loadShader(std::string shaderPath)
{
std::ifstream temp_ss(shaderPath,std::ifstream::in);
if(temp_ss)
{
char c;
char *ss = new char[shader_size];
unsigned i = 0 ;
while(temp_ss.get(c))
{
ss[i++] = c;
}
std::cout<<std::ends;
//ends adds a null, and then flushes the buffer
//if i don't use it , often, the window does not show anything
//I could use std::cout<<std::endl; in place of ends,
//but ends seem a more polite solution to me
//CHECK SHADER
for(int i = 0; i < shader_size; i++)
if(ss[i] == '\0')
std::cout<<"shader.cpp::ERROR: NULL CHARACTER FOUND ON SHADER "<<
shaderPath<<std::endl;
return ss;
}
else
std::clog<<"shader.cpp::loadShader() : ERROR ::: no shaders found at the path : "<<shaderPath<<std::endl;
}
From the OP:
TO SUMMARIZE : shader files MUST be null terminated , I modify the function that loads the shader source into the buffer like follows:
const char* Shader::loadShader(std::string shaderPath)
{
std::ifstream temp_ss(shaderPath,std::ifstream::in);
if(temp_ss)
{
char c;
char *ss = new char[shader_size];
unsigned i = 0 ;
while(temp_ss.get(c))
{
ss[i++] = c;
}
//CHECK SHADER
bool nullTerminated = false;
for(int i = 0; i < shader_size; i++)
if(ss[i] == '\0')
nullTerminated = true;
if(!nullTerminated)
ss[shader_size++] = '\0';
return ss;
}
else
std::clog<<"shader.cpp::loadShader() : ERROR ::: no shaders found at the path : "<<shaderPath<<std::endl;
}
and the fragment shader compiles!
Related
Does anyone know why I keep getting the error that says:
The ♦ shader uses varying _I;DATA;g_mapCoord, but previous shader does not write to it.
The ♦ shader uses varying _I;DATA;worldPosition, but previous shader does not write to it.
Take a look at my shaders here.
Vertex
#version 430
layout (location = 0) in vec2 position0;
out DATA {
vec2 v_mapCoord;
vec3 worldPosition;
} Out;
uniform vec3 u_cameraPosition;
uniform mat4 u_localMatrix;
uniform mat4 u_worldMatrix;
uniform float u_scaleY;
uniform int u_lod;
uniform vec2 u_index;
uniform float u_gap;
uniform vec2 u_location;
uniform sampler2D s_heightmap;
uniform int u_lodMorphArea[8];
float morphLatitude(vec2 position)
{
//not important code
return 0;
}
float morphLongitude(vec2 position)
{
//not important code
return 0;
}
vec2 morph(vec2 localPosition, int morph_area){
//not important code
return vec2(0);
}
void main()
{
vec2 localPosition = (u_localMatrix * vec4(position0.x,0,position0.y,1)).xz;
if (u_lod > 0) {
localPosition += morph(localPosition, u_lodMorphArea[u_lod-1]); // Translate position by morphing vector
}
float height = texture(s_heightmap, localPosition).r;
Out.v_mapCoord = localPosition;
vec4 _worldPosition = u_worldMatrix * vec4(localPosition.x, height, localPosition.y,1);
Out.worldPosition = _worldPosition.xyz;
gl_Position = u_worldMatrix * vec4(localPosition.x, height, localPosition.y,1);
}
Fragment
#version 430
layout (location = 0) out vec4 outputColor;
in DATA {
vec2 g_mapCoord;
vec3 worldPosition;
} In;
const vec3 lightDirection = vec3(-0.2, -1.0, -0.2);
const float intensity = 1.2;
uniform sampler2D s_textureNormal;
uniform sampler2D s_textureWater;
uniform sampler2D s_textureLand;
float diffuse(vec3 direction, vec3 normal, float intensity)
{
return max(0.01, dot(normal, -direction) * intensity);
}
void main()
{
vec3 normal = texture(s_textureNormal, In.g_mapCoord).rgb;
float diff = diffuse(lightDirection, normal, intensity);
outputColor = vec4(1,0,0,1);
}
Geom
#version 430
layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;
in vec2 te_mapCoord[];
out vec2 g_mapCoord;
uniform mat4 u_viewProjection;
void main() {
for (int i = 0; i < gl_in.length(); ++i)
{
vec4 position = gl_in[i].gl_Position;
gl_Position = u_viewProjection * position;
g_mapCoord = te_mapCoord[i];
EmitVertex();
}
EndPrimitive();
}
TCS
#version 430
layout(vertices = 16) out;
in DATA {
vec2 v_mapCoord;
vec3 worldPosition;
} In[];
out vec2 tc_mapCoord[];
const int AB = 2;
const int BC = 3;
const int CD = 0;
const int DA = 1;
uniform int u_tessellationFactor;
uniform float u_tessellationSlope;
uniform float u_tessellationShift;
uniform vec3 u_cameraPosition;
// Calculate tessellation levels
float lodFactor(float dist)
{
float tessellationLevel = max(0.0, u_tessellationFactor/pow(dist, u_tessellationSlope) + u_tessellationShift);
return tessellationLevel;
}
void main()
{
if (gl_InvocationID == 0){
// Calculate mid points of the edges of the quad
vec3 abMid = vec3(gl_in[0].gl_Position + gl_in[3].gl_Position)/2.0; //Bottom left, Bottom right
vec3 bcMid = vec3(gl_in[3].gl_Position + gl_in[15].gl_Position)/2.0; //Bottom right Top right
vec3 cdMid = vec3(gl_in[15].gl_Position + gl_in[12].gl_Position)/2.0; //Top right, Top left
vec3 daMid = vec3(gl_in[12].gl_Position + gl_in[0].gl_Position)/2.0; //Top left, Bottom left
// Calculate distance between camera and mid points of the edges of the quad
float distanceAB = distance(abMid, u_cameraPosition);
float distanceBC = distance(bcMid, u_cameraPosition);
float distanceCD = distance(cdMid, u_cameraPosition);
float distanceDA = distance(daMid, u_cameraPosition);
// Tesselation levels used by tessellation primitive generator (define how much tessellation to apply to the patch). Value between 1 and gl_MaxTessGenLevel, depending on lodFactor.
gl_TessLevelOuter[AB] = mix(1, gl_MaxTessGenLevel, lodFactor(distanceAB));
gl_TessLevelOuter[BC] = mix(1, gl_MaxTessGenLevel, lodFactor(distanceBC));
gl_TessLevelOuter[CD] = mix(1, gl_MaxTessGenLevel, lodFactor(distanceCD));
gl_TessLevelOuter[DA] = mix(1, gl_MaxTessGenLevel, lodFactor(distanceDA));
gl_TessLevelInner[0] = (gl_TessLevelOuter[BC] + gl_TessLevelOuter[DA])/4;
gl_TessLevelInner[1] = (gl_TessLevelOuter[AB] + gl_TessLevelOuter[CD])/4;
}
tc_mapCoord[gl_InvocationID] = In[gl_InvocationID].v_mapCoord; // Just pass to the next stage
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
}
TES
#version 430
layout(quads, fractional_odd_spacing, cw) in;
in vec2 tc_mapCoord[];
out vec2 te_mapCoord;
uniform sampler2D s_heightmap;
uniform float u_scaleY;
void main(){
float u = gl_TessCoord.x;
float v = gl_TessCoord.y;
// Compute new position for each tessellated vertex within the patch. gl_in with index 12, 0, 3, 15 are corners of the patch.
vec4 position = ((1 - u) * (1 - v) * gl_in[12].gl_Position + u * (1 - v) * gl_in[0].gl_Position + u * v * gl_in[3].gl_Position +(1 - u) * v * gl_in[15].gl_Position);
vec2 mapCoord = ((1 - u) * (1 - v) * tc_mapCoord[12] + u * (1 - v) * tc_mapCoord[0] + u * v * tc_mapCoord[3] +(1 - u) * v * tc_mapCoord[15]);
float height = texture(s_heightmap, mapCoord).r;
height *= u_scaleY;
position.y = height;
te_mapCoord = mapCoord;
gl_Position = position;
}
Can anyone help me find the error here which is why I'm getting that error message?
When you introduce a geometry shader you need to pass the varyings for the fragment shader from the geometry shader, not the vertex shader.
You can see how your geometry shader doing this:
out vec2 g_mapCoord;
is incompatible with your fragment shader expecting this:
in DATA {
vec2 g_mapCoord;
vec3 worldPosition;
} In;
Related question and subsequent answers here.
I am trying to use FreeType (v2) library for 2D drawing in my OpenGL (v4.1) scene using C++. The text is rendered, but not correctly: one glyph hides another. How to prevent this behavior? My drawing code is below:
void CFreeTypeFont::Print(string sText, int x, int y, int iPXSize) {
glBindVertexArray(uiVAO);
glUniform1i(shp->uniform("gSampler"), 0);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
int iCurX = x, iCurY = y;
if(iPXSize == -1)iPXSize = iLoadedPixelSize;
float fScale = float(iPXSize)/float(iLoadedPixelSize);
FOR(i, ESZ(sText)) {
if(sText[i] == '\n') {
iCurX = x;
iCurY -= iNewLine*iPXSize/iLoadedPixelSize;
continue;
}
int iIndex = int(sText[i]);
iCurX += iBearingX[iIndex]*iPXSize/iLoadedPixelSize;
if(sText[i] != ' ') {
tCharTextures[iIndex].BindTexture(0);
glm::mat4 mModelView = glm::translate(glm::mat4(1.0f), glm::vec3(float(iCurX), float(iCurY), 0.0f));
mModelView = glm::scale(mModelView, glm::vec3(fScale));
glUniformMatrix4fv(shp->uniform("matrices.modelViewMatrix"),
1, GL_FALSE, glm::value_ptr(mModelView));
// Draw character
glDrawArrays(GL_TRIANGLE_STRIP, iIndex*4, 4);
}
iCurX += (iAdvX[iIndex]-iBearingX[iIndex])*iPXSize/iLoadedPixelSize;
}
glDisable(GL_BLEND);
}
The output is like this:
Must be "Hellow, World!"
If I disable blend mode, then picture clearly shows characters overlaying:
The same text without opacity
My vertex shader:
#version 410
uniform struct Matrices {
mat4 modelViewMatrix;
} matrices;
uniform float screenWidth;
uniform float screenHeight;
layout (location = 0) in vec2 inPosition;
layout (location = 1) in vec2 inCoord;
out vec2 texCoord;
void main() {
texCoord = inCoord;
vec4 pre = matrices.modelViewMatrix*vec4(inPosition, 0.0, 1.0);
pre.x = pre.x / screenWidth - 1;
pre.y = pre.y / screenHeight - 1;
gl_Position = pre;
}
The fragment shader:
#version 410
in vec2 texCoord;
out vec4 outputColor;
uniform sampler2D gSampler;
uniform vec4 vColor;
void main() {
vec4 vTexColor = texture(gSampler, texCoord);
outputColor = vTexColor*vColor;
}
The results look as if you haven't disabled depth testing when rendering the fonts. The depth-test prevents other glyphs from being drawn at the same position as previous ones.
To disable depth-testing call
glDisable(GL_DEPTH_TEST);
Part of the geometry shader code looks like this:
layout(std430) restrict coherent buffer BufferName
{
uint bufferName[][MAX_EXPECTED_ENTRIES];
};
...
void main()
{
...
bufferName[a][b] = someValue;
...
}
Everything works as expected until I add a writeonly statement to either BufferName, bufferName or both.
With the writeonly statement I get the following error: error C7586: OpenGL does not allow reading writeonly variable 'bufferName'.
What's going on here?
All I do is writing to bufferName and the spec says that writeonly is allowed. This also happens for one-dimensional arrays within a storage block.
Thanks in advance.
Here's the full shader code (BufferName from the example is now IDsPerVertex):
#version 450
#define MAX_EXPECTED_VERTEX_PRIMITIVE_IDS 10
layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
layout(std430) restrict coherent buffer IDsPerVertex
{
uint iDsPerVertex[][MAX_EXPECTED_VERTEX_PRIMITIVE_IDS];
};
layout(std430) restrict coherent buffer Counter
{
uint counter[];
};
in int ID[3]; // contains gl_VertexID
out vec4 debugColor;
uint index[3];
void writeIDsPerVertex()
{
// get the next free location for each vertex
index[0] = atomicAdd(counter[ID[0]], 1u);
index[1] = atomicAdd(counter[ID[1]], 1u);
index[2] = atomicAdd(counter[ID[2]], 1u);
// write the triangle primitive ID to each vertex list
iDsPerVertex[ID[0]][index[0]] = gl_PrimitiveIDIn;
iDsPerVertex[ID[1]][index[1]] = gl_PrimitiveIDIn;
iDsPerVertex[ID[2]][index[2]] = gl_PrimitiveIDIn;
}
void passThrough()
{
for(int i = 0; i < gl_in.length(); i++)
{
gl_Position = projection * view * model * gl_in[i].gl_Position;
debugColor = vec4(1);
EmitVertex();
}
EndPrimitive();
}
void main()
{
writeIDsPerVertex();
passThrough();
}
The full error message my environment gives me:
SHADER PROGRAM 37 LOG
Geometry info
-------------
(0) : error C7586: OpenGL does not allow reading writeonly variable 'iDsPerVertex'
Follow examples online, here is the code in the vertex shader:
The attributes are defined as follows:
// Option 1:
layout (location = 0) in vec3 colorvec3;
layout (location = 1) in mat4x2 xyInBaseImageMat4x2;
out vec2 xyInElementTextureImage;
out vec3 elementTintColorVec3;
In the vertex shader, they are used:
// Option 1
vec2 xyInBaseImageVec2 = xyInBaseImageMat4x2[gl_VertexID];
gl_Position = vec4(xyInBaseImageVec2, 0.0, 1.0);
elementTintColorVec3 = colorvec3;
But the result is weird, totally random. Sometimes it is black, sometimes it is random shape.
But if I change to use:
// Option 2:
layout (location = 0) in vec3 colorvec3;
layout (location = 1) in vec2 xyInBaseImageVec2_p0;
layout (location = 2) in vec2 xyInBaseImageVec2_p1;
layout (location = 3) in vec2 xyInBaseImageVec2_p2;
layout (location = 4) in vec2 xyInBaseImageVec2_p3;
out vec2 xyInElementTextureImage;
out vec3 elementTintColorVec3;
In the vertex shader:
// Option 2:
vec2 xyInBaseImageVec2;
if (gl_VertexID==0) {
xyInBaseImageVec2 = xyInBaseImageVec2_p0;
} else if (gl_VertexID==1) {
xyInBaseImageVec2 = xyInBaseImageVec2_p1;
} else if (gl_VertexID==2) {
xyInBaseImageVec2 = xyInBaseImageVec2_p2;
} else if (gl_VertexID==3) {
xyInBaseImageVec2 = xyInBaseImageVec2_p3;
}
gl_Position = vec4(xyInBaseImageVec2, 0.0, 1.0);
elementTintColorVec3 = colorvec3;
Then it works as desired.
The data buffer for the color and vertex positions are the same for the two examples. [Update: add the feeding code below]
// refer to the code in: http://sol.gfxile.net/instancing.html
// refer to the code in: http://www.gamedev.net/page/resources/_/technical/opengl/opengl-instancing-demystified-r3226
// Case: instaced vertex positions. So each instance should have 4 vec2
{
// in mat4x2; later try in vec2[4] xyInBaseImage_vec2list if mat4x2 does not work.
GLuint instanceVBO = instancevbo_4pts;
int pos = 1;
int componentsSize = 2; // vec2 has 2 components
// if it is mat, then componentsNum is the column number of the matrix; for example, for mat4x2 it is 4
int componentsNum = 4; // mat4x2
GLenum type = GL_FLOAT;
GLboolean normalized = GL_FALSE;
GLsizei stride = componentsSize * sizeof(GL_FLOAT) * componentsNum;
char* pointerFirstComponentOffset = 0;
int offsetInteger = 0;
int byteSizeOfOneVertexAttribute = componentsSize * sizeof(GL_FLOAT);
GLuint divisor = 1; // 0 not instance
glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
for (int i = 0; i < componentsNum; i++) {
glEnableVertexAttribArray(pos + i);
// the offset can also be: (void*) (offsetInteger + i * byteSizeOfOneVertexAttribute)
glVertexAttribPointer(pos + i, componentsSize, type,
normalized, stride, pointerFirstComponentOffset + i * byteSizeOfOneVertexAttribute );
glVertexAttribDivisor(pos + i, divisor);
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
What's wrong with the first option?
I am trying to get a hold of how memoryBarrier() works in OpenGL 4.4
I tried the following once with a texture image and once with Shader Storage Buffer Object (SSBO).
The basic idea is to create an array of flags for however many objects that need to be rendered in my scene and then perform a simple test in the geometry shader.
For each primitive in GS, if at least one vertex passes the test, it
sets the corresponding flag in the array at the location specified
by this primitive's object ID (Object IDs are passed to GS as vertex
attributes).
I then perform a memoryBarrier() to make sure all threads have written their values.
Next, I have all primitives read from the flags array and only emit a vertex if the flag is set.
Here is some code from my shaders to explain:
// Vertex Shader:
#version 440
uniform mat4 model_view;
uniform mat4 projection;
layout(location = 0) in vec3 in_pos;
layout(location = 1) in vec3 in_color;
layout(location = 2) in int lineID;
out VS_GS_INTERFACE
{
vec4 position;
vec4 color;
int lineID;
} vs_out;
void main(void) {
vec4 pos = vec4(in_pos, 1.0);
vs_out.position = pos;
vs_out.color = vec4(in_colo, 1.0);
vs_out.lineID = lineID;
gl_Position = projection * model_view * pos;
}
and here is a simple Geometry shader in which I use only a simple test based on lineID ( I realize this test doesn't need a shared data structure but this is just to test program behavior)
#version 440
layout (lines) in;
layout (line_strip, max_vertices = 2) out;
layout (std430, binding = 0) buffer BO {
int IDs[];
};
in VS_GS_INTERFACE
{
vec4 position;
vec4 color;
int lineID;
} gs_in[];
out vec4 f_color;
void main()
{
if(gs_in[0].lineID < 500)
{
IDs[gs_in[0].lineID] = 1;
}
else
{
IDs[gs_in[0].lineID] = -1;
}
memoryBarrier();
// read back the flag value
int flag = IDs[gs_in[0].lineID];
if ( flag > 0)
{
int n;
for( n = 0; n < gl_in.length(), n++)
{
f_color = gs_in[n].color;
gl_Position = gl_in[n].gl_Position;
emitVertex();
}
}
}
No matter what value I put instead of 500, this code always renders only 2 objects. If I change the condition for rendering in the GS to if( flag > = 0) it seems to me that all objects are rendered which means the -1 is never written by the time these IDs are read back by the shader.
Can someone please explain why the writes are not coherently visible to all shader invocations despite the memoryBarrier() and what would be the most efficient work around to get this to work?
Thanks.