I have some code to render GUI's, and if I dont use a vertex shader then it renders exactly where its meant to :
However, as soon as I use a vertex shader, even simply one that calls
gl_position = vec4(position,1.0);
It hides, or moves, or otherwise makes my GUI disappear
Whats the correct way to have a shader for GUIs in OpenGL?
GUI render :
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, width, 0, height, -10, 10);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
RendererUtils.setWireframeMode(false);
for (Interface i : interfaces)
{
i.updateShaderForThisB();
if (i instanceof InterfaceContainer)
{
((InterfaceContainer) i).draw();
}
else
{
((InterfaceControl) i).draw();
}
}
InterfaceShader.getInstance().unbind();
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
InterfaceContainer and InterfaceControl's draw call is largely the same, so I'll only add one of them.
InterfaceControl.draw()
public void draw()
{
this.updateShaderForThisB();
this.getMesh().draw();
if (this.hasText)
{
//this.updateShaderForThisF();
//drawText();
}
}
InterfaceControl.updateShaderForThisB()
public void updateShaderForThisB()
{
InterfaceShader shader = InterfaceShader.getInstance();
shader.bind();
shader.setColour(this.getActingColour());
shader.setLocation(this.getLocation());
shader.setSize(this.getBounds());
shader.setGradient(this.getShouldGradient());
shader.updateUniforms();
}
Mesh.draw()
public void draw()
{
glEnableVertexAttribArray(0); //Vertices
glEnableVertexAttribArray(1); //Tex coords
glEnableVertexAttribArray(2); //Normals
glBindBuffer(GL_ARRAY_BUFFER,vbo);
glVertexAttribPointer(0, 3, GL_FLOAT, false, Vertex.SIZE * 4, 0);
glVertexAttribPointer(1, 2, GL_FLOAT, false, Vertex.SIZE * 4, 12);
glVertexAttribPointer(2, 3, GL_FLOAT, false, Vertex.SIZE * 4, 20);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glDrawElements(GL_TRIANGLES, size, GL_UNSIGNED_INT,0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
}
InterfaceShader.vs
#version 330
layout(location = 0) in vec3 position;
layout(location = 1) in vec2 texCoord;
uniform mat4 viewMatrix;
out vec2 texCoord0;
void main()
{
gl_Position = viewMatrix * vec4(position,1.0);
texCoord0 = texCoord;
}
Can anyone see an obvious problem that i've overlooked? My first thought was that the shader was translating my interface-oriented coordinates (ie 50,50,1) into real world coordinates, but I dont know
Edit : As requested, updated shader code and added matrix projection code
https://pastebin.com/gKdewDVi
pastebin for Transform class, for getting the view matrix and such, and how it's related back to the shader
The fixed function vertex processing pipeline multiplies the vertex positions by the current matrix given by GL_PROJECTION * GL_MODELVIEW. You have to do the same thing in your vertex shader like so:
gl_Position = gl_ModelViewProjectionMatrix * vec4(position,1.0);
Please note that you are using outdated OpenGL programming practices by using the fixed-function processing. This has been deprecated for a while now.
Related
I have created a program that renders a 3d cube, and now I'd like to change the position of the cube. The matrix multiplication I'm doing now seems to distort the cube instead of changing it's position. The distortion is small for values in the 0.1 - 0.4 range and fill the whole screen for larger values.
The vertex shader:
#version 330 core
layout(location = 0) in vec3 vertexPosition_modelspace;
layout(location = 1) in vec3 vertexColor;
uniform mat4 projectionMatrix;
uniform mat4 cameraMatrix;
uniform mat4 modelMatrix;
out vec3 fragmentColor;
void main()
{
gl_Position = projectionMatrix * cameraMatrix * modelMatrix * vec4(vertexPosition_modelspace,1);
fragmentColor = vertexColor;
}
Model.cpp (note that modelMatrix is initialized to an identity matrix and I'm using glm)
void Model::SetPos(glm::vec3 coords)
{
modelMatrix[0][3] = coords[0];
modelMatrix[1][3] = coords[1];
modelMatrix[2][3] = coords[2];
}
void Model::Render()
{
// Select the right program
glUseProgram(program);
// Set the model matrix in the shader
GLuint MatrixID = glGetUniformLocation(program, "modelMatrix");
glUniformMatrix4fv(MatrixID, 1, GL_FALSE, value_ptr(modelMatrix));
// Setup the shader color attributes
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
// Setup the shader vertex attributes
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
// Draw the model
glDrawArrays(GL_TRIANGLES, 0, triangles);
// Now disable the attributes
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
}
The other matrices are initialized like this and remain unchanged:
cameraMatrix = glm::lookAt(pos, target, orient);
projectionMatrix = glm::perspective(45.0f, 1280.0f / 720.0f, 0.1f, 100.0f);
The glm library produces column major matrices. You've also specified GL_FALSE to glUniformMatrix4fv which is correct for column major matrices. However, when you are setting the position you are setting wrong values. This code:
void Model::SetPos(glm::vec3 coords)
{
modelMatrix[0][3] = coords[0];
modelMatrix[1][3] = coords[1];
modelMatrix[2][3] = coords[2];
}
Causes the matrix produce non 1.0 values in the w component after multiplication. This can cause some weird distortions. You should change SetPos to this:
void Model::SetPos(glm::vec3 coords)
{
modelMatrix[3][0] = coords[0];
modelMatrix[3][1] = coords[1];
modelMatrix[3][2] = coords[2];
}
I'm having trouble figuring out how to position a 2D object in my scene using screen coordinates. At the moment I have something working (code below) but it want NDC coordinates which isn't easy to work with. I can't figure out where it's going wrong. I think I've used everything like it should be so I think I'm forgetting something.
Here's the code that handles the drawing of the objects in my scene:
glClearDepth(1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// RENDERING HERE
colorProgram.bind();
for (size_t t = 0; t < objectsWithGraphicsComponentInThisScene.size(); ++t)
{
// set texture
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, objectsWithGraphicsComponentInThisScene[t]->getComponent<GraphicsComponent>()->getTexture());
GLint texLocation = colorProgram.getUniformLocation("texSampler");
glUniform1i(texLocation, 0);
glm::mat4 trans;
trans = glm::translate(glm::mat4x4(1.0f), glm::vec3(objectsWithGraphicsComponentInThisScene[t]->getPosition().x, objectsWithGraphicsComponentInThisScene[t]->getPosition().y, 0));
GLint transMatLocation = colorProgram.getUniformLocation("transformMatrix");
glUniformMatrix4fv(transMatLocation, 1, GL_FALSE, glm::value_ptr(trans));
// set camera Matrix
GLint projMatLocation = colorProgram.getUniformLocation("projectionMatrix");
glm::mat4 cameraMatrix = camera->getCameraMatrix();
glUniformMatrix4fv(projMatLocation, 1, GL_FALSE, glm::value_ptr(cameraMatrix));
objectsWithGraphicsComponentInThisScene[t]->getComponent<GraphicsComponent>()->getSprite()->draw();
// unbind all
glBindTexture(GL_TEXTURE_2D, 0);
}
colorProgram.unbind();
where colorProgram is the shader my sprites use and getPosition() simply returns a value which I've set. (where the x y and z value should be given as screen coordinates). so for example, getPosition might return [100, 50, 0] but that will render the object outside of the screen (the screen is 1280x720).
Now the code that renders the sprite (objectsWithGraphicsComponentInThisScene[t]->getComponent()->getSprite()->draw();):
void Sprite::draw()
{
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glEnableVertexAttribArray(0);
// position
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, position));
//color
glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), (void*)offsetof(Vertex, color));
// uv
glVertexAttribPointer(2, 2, GL_FLOAT, GL_TRUE, sizeof(Vertex), (void*)offsetof(Vertex, uv));
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
And here's the code in the shader (colorProgram):
VERTEX SHADER:
#version 130
// per vertex
// input data from VBO
in vec2 vertexPosition;
in vec4 vertexColor;
in vec2 vertexUV;
// output to fragment shader
out vec4 fragmentColor;
out vec2 fragmentUV;
uniform mat4 projectionMatrix;
uniform mat4 transformMatrix;
void main()
{
mat4 resultMatrix = transformMatrix * projectionMatrix;
gl_Position.xy = (resultMatrix * vec4(vertexPosition, 0.0, 1.0)).xy;
gl_Position.z = 0.0;
// Indicate that the coordinates are normalized
gl_Position.w = 1.0;
fragmentColor = vertexColor;
fragmentUV = vec2(vertexUV.x, 1.0 - vertexUV.y);
}
FRAGMENT SHADER
#version 130
// per pixel
// input from vertex shader
in vec4 fragmentColor;
in vec2 fragmentUV;
out vec4 color;
uniform sampler2D texSampler;
void main()
{
vec4 textureColor = texture(texSampler, fragmentUV);
if (textureColor.a < 0.5) discard;
color = fragmentColor * textureColor;
}
If you need more code I'd be happy to add more although I think this is everything that is needed.
This sequence in your vertex shader
mat4 resultMatrix = transformMatrix * projectionMatrix;
gl_Position.xy = (resultMatrix * vec4(vertexPosition, 0.0, 1.0)).xy;
is very unlikely what you actually want. Since you use the matrix * vector convention, you'll end up with
position = transform * projection * v
= transform * (projection * v)
In other words: you apply the transformation after the projection. Since after the projection, the viewing volume is in the [-1,1]^3 range (in euclidean NDC space after the perspecitive divide. In reality, we are working in clip space here, where it is [-w,w]^3, but this is not really important in this context,), translating the object by values like 100 units will certainly move it out of the frustum.
You should just reverse the order of your matrix multiplication.
I am working on a game, and trying to implement the instancized CPU-Particle System programmed on http://www.opengl-tutorial.org/intermediate-tutorials/billboards-particles/particles-instancing/
i managed to get it working in my code structure, but i am trying to draw other objects in the same window, which i can't, i have tested it, and it only allows me to draw one, either draw the particle system or draw the object i want.
The problem happens specifically at this code part :
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Use our shader
glUseProgram(particleprogramID->programHandle);
unit2 +=1;
glActiveTexture(GL_TEXTURE0 + unit2);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(TextureID, unit2);
glm::mat4 ViewMatrix = camera->getViewMatrix();
// Same as the billboards tutorial
glUniform3f(CameraRight_worldspace_ID, ViewMatrix[0][0], ViewMatrix[1][0], ViewMatrix[2][0]);
glUniform3f(CameraUp_worldspace_ID , ViewMatrix[0][1], ViewMatrix[1][1], ViewMatrix[2][1]);
glUniformMatrix4fv(ViewProjMatrixID, 1, GL_FALSE, &mvp[0][0]);
//glUniformMatrix4fv(modviewprojID, 1, GL_FALSE, &mvp[0][0]);
//1rst attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, billboard_vertex_buffer);
glVertexAttribPointer(
0,
3,
GL_FLOAT,
GL_FALSE,
0,
(void*)0
);
// 2nd attribute buffer : positions of particles' centers
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, particles_position_buffer);
glVertexAttribPointer(
1,
4,
GL_FLOAT,
GL_FALSE,
0,
(void*)0
);
// 3rd attribute buffer : particles' colors
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, particles_color_buffer);
glVertexAttribPointer(
2,
4,
GL_UNSIGNED_BYTE,
GL_TRUE,
0,
(void*)0
);
glVertexAttribDivisor(0, 0);
glVertexAttribDivisor(1, 1);
glVertexAttribDivisor(2, 1);
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, ParticlesCount);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
then i try to draw my star:
unit2 += 1;
starTexture->Bind(unit2);
shaderObject ->useShader();
glUniform1i(glGetUniformLocation(shaderObject->programHandle, "colorTexture"), unit2);
glUniformMatrix4fv(glGetUniformLocation(shaderObject->programHandle, "modelMatrix"), 1, GL_FALSE, glm::value_ptr(star1->getModelMatrix()));
glUniformMatrix4fv(glGetUniformLocation(shaderObject->programHandle, "projectionMatrix"), 1, GL_FALSE, glm::value_ptr(projectionViewMatrix));
star1->draw();
the vertex and fragment shader for the particle system:
#version 330 core
// Input vertex data, different for all executions of this shader.
layout(location = 0) in vec3 squareVertices;
layout(location = 1) in vec4 xyzs; // Position of the center of the particule and size of the square
layout(location = 2) in vec4 color; // Position of the center of the particule and size of the square
// Output data ; will be interpolated for each fragment.
out vec2 UV;
out vec4 particlecolor;
// Values that stay constant for the whole mesh.
uniform vec3 CameraRight_worldspace;
uniform vec3 CameraUp_worldspace;
uniform mat4 VP; // Model-View-Projection matrix, but without the Model (the position is in BillboardPos; the orientation depends on the camera)
void main()
{
float particleSize = xyzs.w; // because we encoded it this way.
vec3 particleCenter_wordspace = xyzs.xyz;
vec3 vertexPosition_worldspace =
particleCenter_wordspace
+ CameraRight_worldspace * squareVertices.x * particleSize
+ CameraUp_worldspace * squareVertices.y * particleSize;
// Output position of the vertex
gl_Position = VP * vec4(vertexPosition_worldspace, 1.0f);
// UV of the vertex. No special space for this one.
UV = squareVertices.xy + vec2(0.5, 0.5);
particlecolor = color;
}
frragment shader:
#version 330 core
// Interpolated values from the vertex shaders
in vec2 UV;
in vec4 particlecolor;
// Ouput data
out vec4 color;
uniform sampler2D myTexture;
void main(){
// Output color = color of the texture at the specified UV
color = texture2D( myTexture, UV ) * particlecolor;
}
and it only displays the particle system:
worth mentioning is:
the object i want to draw is a star modelled in blender and is displayed correctly when drawn alone or with other objects other than the particle system. and has its own class having buffers for psitions, UVs, indices and normals...
it seems like the star data are being swallowed by the buffer...
i appreciate every help...
I have a scene that consists of a lot of objects, and when I'm rendering them I iterate through all items that are in the scene and call glDrawElements on them. This works fine. However, now I'm implementing shadow mapping to the scene, and I am using the same way to draw to the shadow buffer. However, only the first element in the scene is drawn to the texture in a correct way, I'm checking this by attaching the depth texture to a scene element which you will see below.
The code is as follows:
glBindFramebuffer(GL_FRAMEBUFFER, vFrameBuffers[ShadowFB]);
glViewport(0,0,1024,1024);
glClearDepth(1.0f);
glClear(GL_DEPTH_BUFFER_BIT);
glUseProgram(shadowShader);
depth_loc = glGetUniformLocation(shadowShader, "depthProj");
model_view_loc = glGetUniformLocation(shadowShader, "modelmat");
glUniformMatrix4fv(depth_loc, 1, GL_FALSE, depthproj);
depthproj = mat4(1.0);
depthproj = Ortho(-250.0f, 250.0f, -200.0f, 200.0f, -200.0f, 200.0f);
depthproj = depthproj * RotateX(15);
depthproj = depthproj * RotateY(220);
for (int i = 0; i < _objectArray.size(); i++)
{
modelmat = mat4(1.0);
modelmat = modelmat*Translate(_objectArray[i]->getLocation()->getX(),
_objectArray[i]->getLocation()->getY(),
_objectArray[i]->getLocation()->getZ());
glUniformMatrix4fv(model_view_loc, 1, GL_FALSE, modelmat);
if (_objectArray[i]->getType() == TypeMountain)
{
glBindVertexArray(vArrays[ShadowMountainA]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vElements[ShadowMountainE]);
glDrawElements(GL_TRIANGLES, 40*40*6, GL_UNSIGNED_SHORT, NULL);
glBindVertexArray(0);
}
else if (_objectArray[i]->getType() == TypePasture)
{
glBindVertexArray(vArrays[ShadowPastureA]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vElements[ShadowPastureE]);
glDrawElements(GL_TRIANGLES, 40*40*6, GL_UNSIGNED_SHORT, NULL);
glBindVertexArray(0);
}
else if (_objectArray[i]->getType() == TypeWater)
{
glBindVertexArray(vArrays[ShadowWaterA]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vElements[ShadowWaterE]);
glDrawElements(GL_TRIANGLES, 40*40*6, GL_UNSIGNED_SHORT, NULL);
glBindVertexArray(0);
}
else if (_objectArray[i]->getType() == TypeTree)
{
glBindVertexArray(vArrays[ShadowTreeA]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vElements[ShadowTreeE]);
glDrawElements(GL_TRIANGLES, 180, GL_UNSIGNED_SHORT, NULL);
glBindVertexArray(0);
}
}
glUseProgram(0);
When I run it only on the mountain object, this is the resulting image I get, as you can see it is correct.
It works on other scene elements individually as well.
My question is how do I draw without problems into the same buffer using multiple draws?
edit:
Just because it was requested here are the shadow shader components:
Vertex shader:
#version 330 core
uniform mat4 depthProj;
uniform mat4 modelmat;
layout(location = 0) attribute vec4 vPosition;
void main()
{
gl_Position = depthProj * modelmat * vPosition;
}
Fragment shader:
#version 330 core
layout(location = 0) out float fragmentDepth;
void main()
{
}
I don't know why, but when the lines,
glUniformMatrix4fv(depth_loc, 1, GL_FALSE, depthproj);
and
glUniformMatrix4fv(model_view_loc, 1, GL_FALSE, modelmat);
are turned into;
glUniformMatrix4fv(depth_loc, 1, GL_TRUE, depthproj);
and
glUniformMatrix4fv(model_view_loc, 1, GL_TRUE, modelmat);
the scene is drawn as it should.
I have been successful in rendering primitives with a colour component via the shader and also translating them. However, upon attempting to load a texture and render it for the primitive via the shader, the primitives glitch, they should be squares:
As you can see, it successfully loads and applies the texture with the colour component to the single primitive in the scene.
If I then remove the color component, I again have primitives, but oddly, they are scaled by changing the uvs - this should not be the case, only the uvs should scale! (also their origin is offset)
My shader init code:
void renderer::initRendererGfx()
{
shader->compilerShaders();
shader->loadAttribute(#"Position");
shader->loadAttribute(#"SourceColor");
shader->loadAttribute(#"TexCoordIn");
}
Here is my object handler rendering function code:
void renderer::drawRender(glm::mat4 &view, glm::mat4 &projection)
{
//Loop through all objects of base type OBJECT
for(int i=0;i<SceneObjects.size();i++){
if(SceneObjects.size()>0){
shader->bind();//Bind the shader for the rendering of this object
SceneObjects[i]->mv = view * SceneObjects[i]->model;
shader->setUniform(#"modelViewMatrix", SceneObjects[i]->mv);//Calculate object model view
shader->setUniform(#"MVP", projection * SceneObjects[i]->mv);//apply projection transforms to object
glActiveTexture(GL_TEXTURE0); // unneccc in practice
glBindTexture(GL_TEXTURE_2D, SceneObjects[i]->_texture);
shader->setUniform(#"Texture", 0);//Apply the uniform for this instance
SceneObjects[i]->draw();//Draw this object
shader->unbind();//Release the shader for the next object
}
}
}
Here is my sprite buffer initialisation and draw code:
void spriteObject::draw()
{
glVertexAttribPointer((GLuint)0, 3, GL_FLOAT, GL_FALSE, sizeof(SpriteVertex), NULL);
glVertexAttribPointer((GLuint)1, 4, GL_FLOAT, GL_FALSE, sizeof(SpriteVertex) , (GLvoid*) (sizeof(GL_FLOAT) * 3));
glVertexAttribPointer((GLuint)2, 2, GL_FLOAT, GL_FALSE, sizeof(SpriteVertex) , (GLvoid*)(sizeof(GL_FLOAT) * 7));
glDrawElements(GL_TRIANGLE_STRIP, sizeof(SpriteIndices)/sizeof(SpriteIndices[0]), GL_UNSIGNED_BYTE, 0);
}
void spriteObject::initBuffers()
{
glGenBuffers(1, &vertexBufferID);
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID);
glBufferData(GL_ARRAY_BUFFER, sizeof(SpriteVertices), SpriteVertices, GL_STATIC_DRAW);
glGenBuffers(1, &indexBufferID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(SpriteIndices), SpriteIndices, GL_STATIC_DRAW);
}
Here is the vertex shader:
attribute vec3 Position;
attribute vec4 SourceColor;
varying vec4 DestinationColor;
uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
uniform mat4 MVP;
attribute vec2 TexCoordIn;
varying vec2 TexCoordOut;
void main(void) {
DestinationColor = SourceColor;
gl_Position = MVP * vec4(Position,1.0);
TexCoordOut = TexCoordIn;
}
And finally the fragment shader:
varying lowp vec4 DestinationColor;
varying lowp vec2 TexCoordOut;
uniform sampler2D Texture;
void main(void) {
gl_FragColor = DestinationColor * texture2D(Texture, TexCoordOut);
}
If you want to see any more specifics of certain elements, just ask.
Many thanks.
Are you sure your triangles have the same winding? The winding is the order in which the triangle points are listed ( either clockwise or counter-clockwise ). The winding is used in face culling to determine if the triangle is facing or back-facing.
You can easily check if your triangle are wrongly winded by disabling face culling.
glDisable( GL_CULL_FACE );
More information here ( http://db-in.com/blog/2011/02/all-about-opengl-es-2-x-part-23/#face_culling )