Shadow Mapping is not projected correctly - c++

I'm having troubles with the implementation of shadow mapping in my OpenGL graphic engine.
At first stage, I render the shadow map into a frame buffer object (with a depth texture attached to it) from the light point of view:
Vector3f lightPosition = Vector3f(mainLight->getPosition().x, mainLight->getPosition().y, mainLight->getPosition().z);
shadowMapFBO->BindForWriting();
glUseProgramObjectARB(0);
glViewport(0, 0, screenWidth * SHADOW_Q, screenHeight * SHADOW_Q);
glClear(GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK); //Avoid self shadowing
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-20, 20, -20, 20, 0.0f, +300.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(lightPosition.X, lightPosition.Y, lightPosition.Z, 0, 0, 0, 0, 1, 0);
drawSceneTree();
setTextureMatrix();
I draw all the scene by using the function drawSceneTree(), and I store the light matrix into the OpenGL TEXTURE7 using the function setTextureMatrix(), which content is this:
static double modelView[16];
static double projection[16];
const GLdouble bias[16] = {
0.5, 0.0, 0.0, 0.0,
0.0, 0.5, 0.0, 0.0,
0.0, 0.0, 0.5, 0.0,
0.5, 0.5, 0.5, 1.0
};
// Grab modelview and transformation matrices
glGetDoublev(GL_MODELVIEW_MATRIX, modelView);
glGetDoublev(GL_PROJECTION_MATRIX, projection);
glActiveTextureARB(GL_TEXTURE7);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glLoadMatrixd(bias);
// concatating all matrice into one.
glMultMatrixd(projection);
glMultMatrixd(modelView);
// Go back to normal matrix mode
glMatrixMode(GL_MODELVIEW);
Then I render the scene from the camera point of view, and using a shader for rendering the shadows:
glViewport(0, 0, screenWidth, screenHeight);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
// Clear previous frame values
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_LIGHTING);
//Using the shadow shader
glUseProgram(shadowMapFBO->getShader());
glUniform1iARB(shadowMapFBO->getShadowMapUniform(), 7);
glUniform1iARB(shadowMapFBO->getTextureUniform(), 0);
shadowMapFBO->BindForReading(7);
setupMatrices(0, 4, -13, 0, 5, 0);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
drawSceneTree();
The setupMatrices() function set the projection and modelview matrix. I bind the shadowMapFBO into the OpenGL TEXTURE7, using the function BindForReading(7), which content is:
glActiveTexture(GL_TEXTURE0 + TextureUnit);
glBindTexture(GL_TEXTURE_2D, depthTextureId);
Finally, the vertex and fragment shaders are these:
Vertex:
varying vec4 ShadowCoord;
varying vec3 normal;
varying vec3 vertex_to_light_vector;
varying vec2 texture_coordinate;
void main()
{
ShadowCoord = gl_TextureMatrix[7] * gl_Vertex;
gl_Position = ftransform();
gl_FrontColor = gl_Color;
normal = gl_NormalMatrix * gl_Normal;
vec4 vertex_in_modelview_space = gl_ModelViewMatrix * gl_Vertex;
vertex_to_light_vector = vec3(gl_LightSource[0].position -vertex_in_modelview_space);
texture_coordinate = vec2(gl_MultiTexCoord0);
}
Fragment:
uniform sampler2D ShadowMap;
uniform sampler2D Texture;
varying vec4 ShadowCoord;
varying vec3 normal;
varying vec3 vertex_to_light_vector;
varying vec2 texture_coordinate;
void main()
{
const vec4 AmbientColor = vec4(0.7, 0.7, 0.7, 1.0);
const vec4 DiffuseColor = vec4(0.5, 0.5, 0.5, 1.0);
vec3 normalized_normal = normalize(normal);
vec3 normalized_vertex_to_light_vector = normalize(vertex_to_light_vector);
float DiffuseTerm = clamp(dot(normal, vertex_to_light_vector), 0.0, 1.0);
vec4 shadowCoordinateWdivide = ShadowCoord / ShadowCoord.w ;
// Used to lower moiré pattern and self-shadowing
shadowCoordinateWdivide.z += 0.0005;
float distanceFromLight = texture2D(ShadowMap,shadowCoordinateWdivide.st).z;
float shadow = 1.0;
if (ShadowCoord.w > 0.0)
shadow = distanceFromLight < shadowCoordinateWdivide.z ? 0.5 : 1.0 ;
gl_FragColor = texture2D(Texture, texture_coordinate) * shadow * (AmbientColor + DiffuseColor * DiffuseTerm);
gl_FragColor.a = 1.0;
}
And I'm getting the shadow of the game's character projected in all objects of the scene. I've recorded it in a gif:
https://dl.dropboxusercontent.com/u/658766/captura.gif
P.S: The shadow map is also rendered on screen for debug purposes, at the right upper corner.

Your shadow coordinate has to be processed by ModelWold matrix (without projection nor view matrices). In my shaders, I compute it with this:
ShadowCoord = gl_TextureMatrix[7] * inverse(modelView) * gl_ModelViewMatrix * gl_Vertex;
But you may pass it to your shader as an uniform. This is the transformation matrix applied to each individual objects in your scene after the ModelViewProjectionMatrix has been set to look at origin. (there is surely a smarter way for handling this, but I've not dig much).

Related

Draw two shapes on top of each other in geometry shader?

With this small program I want to achieve:
Publish a point
Transform this point with vertex shader
Create a square and a triangle with geometry shader
Fill both the triangle and the square with fragment shader
Unfortunately, I cannot manage to superpose both shapes. I see either only the triangle or only the square. I tried to play with z but it doesn't change anything.
void main(void) {
finalColour = vec4(1.0, 0.5, 0.5, 1.0);
square(1.0, 0.0);
finalColour = vec4(0.0, 1.0, 1.0, 0.0);
triangle(vec3(0.0, 0.0, 0.0), angle[0], 1.0);
EndPrimitive();
}
void main(void) {
// finalColour = vec4(1.0, 0.5, 0.5, 1.0);
// square(1.0, 0.0);
finalColour = vec4(0.0, 1.0, 1.0, 0.0);
triangle(vec3(0.0, 0.0, 0.0), angle[0], 1.0);
EndPrimitive();
}
Main
#include <SFML/Graphics.hpp>
#include <GL/glew.h>
#include <vector>
#define WIDTH 800
int main() {
sf::RenderWindow window(sf::VideoMode(WIDTH, WIDTH), "Test");
sf::Shader shader;
shader.loadFromFile("shader.vert", "shader.geom", "shader.frag");
sf::Transform matrix = sf::Transform::Identity;
matrix.scale(1.0 / WIDTH, 1.0 / WIDTH);
sf::Glsl::Mat4 projectionViewMatrix = matrix;
shader.setUniform("projectionViewMatrix", projectionViewMatrix);
std::vector<GLfloat> vertices;
vertices.push_back(0.0); vertices.push_back(0.0); vertices.push_back(0.0);
while (window.isOpen()) {
sf::Event currEvent;
while (window.pollEvent(currEvent)) {
switch (currEvent.type) {
case(sf::Event::Closed):
window.close(); break;
}
}
window.clear(sf::Color::Black);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glVertexPointer(3, GL_FLOAT, 0, vertices.data());
glEnableClientState(GL_VERTEX_ARRAY);
glDrawArrays(GL_POINTS, 0, vertices.size() / 3);
glDisableClientState(GL_VERTEX_ARRAY);
sf::Shader::bind(&shader);
window.display();
}
}
Vertex
#version 150
in vec3 position;
out float angle;
uniform mat4 projectionViewMatrix;
void main(void){
gl_Position = projectionViewMatrix * vec4(position.xy, 0.0 ,1.0);
angle = position.z;
}
Geometry
#version 150
layout (points) in;
layout (triangle_strip, max_vertices = 6) out;
in float angle[];
out vec4 finalColour;
uniform mat4 projectionViewMatrix;
void createVertex(vec3 offset) {
vec4 actualOffset = vec4(offset, 1.0);
vec4 worldPosition = gl_in[0].gl_Position + actualOffset;
gl_Position = worldPosition;
EmitVertex();
}
void createAngularVertex(vec3 offset, float angle, float radius) {
vec4 actualOffset = vec4(offset, 1.0);
vec4 worldPosition = gl_in[0].gl_Position + actualOffset;
gl_Position = worldPosition;
gl_Position.x += cos(angle) * radius;
gl_Position.y += sin(angle) * radius;
EmitVertex();
}
void square(float size, float z) {
createVertex(vec3(-size, -size, z));
createVertex(vec3(size, -size, z));
createVertex(vec3(-size, size, z));
createVertex(vec3(size, size, z));
createVertex(vec3(size, -size, z));
createVertex(vec3(-size, size, z));
EndPrimitive();
}
void triangle(vec3 offset, float angle, float radius) {
float pi = 3.1415;
float angleOffset = 0.5;
createAngularVertex(offset, angle, radius);
createAngularVertex(offset, angle + pi + angleOffset, radius);
createAngularVertex(offset, angle + pi - angleOffset, radius);
EndPrimitive();
}
void main(void) {
finalColour = vec4(1.0, 0.5, 0.5, 1.0);
square(1.0, 0.0);
finalColour = vec4(0.0, 1.0, 1.0, 0.0);
triangle(vec3(0.0, 0.0, 0.0), angle[0], 0.1);
EndPrimitive();
}
Fragment
#version 150
in vec4 finalColour;
out vec4 out_Colour;
void main(void){
out_Colour = vec4(finalColour.rgb, 1.0);
}
The geometry shader creates 2 primitives, one with 6 vertices and one with 3 vertices, requiring a total of 9 vertices:
layout (triangle_strip, max_vertices = 6) out;
layout (triangle_strip, max_vertices = 9) out;

The Geometry Shader is duplicating Shapes (in Processing)

I'm trying to generate a simple shape with a Geometry Shader, but the shape is rendering twice and I don't know why.
First we have a really simple Vertex Shader
#version 150
in vec4 position;
void main() {
gl_Position = position;
}
Then there's a Geometry Shader thats generating a simple triangle.
#version 150
layout (triangles) in;
layout (triangle_strip, max_vertices = 5) out;
out FragData {
vec4 color;
} FragOut;
void main(){
//RED TOP LEFT
FragOut.color = vec4(1.0, 0.0, 0.0, 1.0);
gl_Position = gl_in[0].gl_Position + vec4( -1.0, 0.0, 0.0, 0.0);
EmitVertex();
//BLUE BOTTOM LEFT
FragOut.color = vec4(0., 0., 1., 1.);
gl_Position = gl_in[0].gl_Position + vec4( -1.0, -1.0, 0.0, 0.0);
EmitVertex();
//GREEN BOTTOM RIGHT
FragOut.color = vec4(0.0, 1.0, 0.0, 1.0);
gl_Position = gl_in[0].gl_Position + vec4( 1.0, -1.0, 0.0, 0.0);
EmitVertex();
EndPrimitive();
}
And finally a simple Fragment Shader
#version 150
in FragData {
vec4 color;
} FragIn;
out vec4 fragColor;
void main() {
fragColor = FragIn.color;
}
The result should be a triangle, but TWO triangles are being rendered:
Here's the result
The Geometry Shader is executed once for each primitive. A rect() consists of 2 triangles, so the geometry shader is executed twice and generates 2 triangle_strip primitives.
Draw a single POINTS primitive instead of the rectangle:
beginShape(POINTS);
vertex(x, y);
endShape();
Note that you need to change the Primitive input specification:
layout (triangles) in;
layout (points) in;

OpenGL camera movement program vertex shader issue

So, I'm a beginner learning graphics programmer. I'm working on a program for camera movement. I think there's something wrong with the vertex shader. The program runs with no errors but the screen is completely blank. Here is the vertex shader I'm using:
#version 330
in vec4 vPosition;
out vec4 vColor;
uniform mat4 model_view;
uniform mat4 projection;
void main()
{
vec4 pos = projection * model_view * vPosition / vPosition.w;
gl_Position = pos;
vColor = vPosition;
}
If I switch the shader back to basic version:
#version 330
in vec4 vPosition;
out vec4 vColor;
void
main()
{
gl_Position = vPosition;
vColor = vPosition;
}
The program runs and renders a triangle successfully. So, I'm pretty sure the error is with the shader.
The shader is called in the initialize function:
void initialize(void)
{
glClearColor(1.0, 1.0, 1.0, 1.0); // white background
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
// Create and initialize a buffer object
GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
// Load shaders and use the resulting shader program
GLuint program = InitShader("res/shaders/vshader21.glsl", "res/shaders/fshader21.glsl");
model_view = glGetUniformLocation(program, "model_view");
projection = glGetUniformLocation(program, "projection");
glUseProgram(program);
// Initialize the vertex position attribute from the vertex shader
GLuint loc = glGetAttribLocation(program, "vPosition");
glEnableVertexAttribArray(loc);
glVertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
}
the 'points' in glBufferData is as follows:
const int WIDTH = 500, HEIGHT = 500;
/* Positions */
vec4 points[] = {
vec4(0.5,0.5, 1, 1),
vec4(-0.5,0.5, 1, 1),
vec4(0.5,-0.5, 1, 1) ,
vec4(-0.5,-0.5, 1, 1)
};
model_view and projection are of GLuint type in main application and global.
I set the uniform variables (position, model_view) in the display functions.
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT); // clear the window
glPointSize(20.0);
// Projection transformation parameters
GLfloat left = -1.0, right = 1.0;
GLfloat bottom = -1.0, top = 1.0;
GLfloat zNear = 0, zFar = 3.0;
mat4 p = Ortho(left, right, bottom, top, zNear, zFar);
glUniformMatrix4fv(projection, 1, GL_TRUE, p);
vec4 eye(0.0, 0.0, -1.0, 1.0);
vec4 at(0.0, 0.0, 0.0, 1.0);
vec4 up(0.0, 1.0, 0.0, 0.0);
mat4 mv = LookAt(eye, at, up);
glUniformMatrix4fv(model_view, 1, GL_TRUE, mv);
glDrawArrays(GL_TRIANGLES, 0, 3); // draw the points
glFlush();
}
What could possibly be going wrong?
The explicit division by the .w component is superfluous.
vec4 pos = projection * model_view * vPosition / vPosition.w;
vec4 pos = projection * model_view * vPosition;
Note, the Perspective divide is automatically performed after clipping.
Since the vector is multiplied to the uniforms form the right, you do not have to transpose the matrices:
glUniformMatrix4fv(projection, 1, GL_TRUE, p);
glUniformMatrix4fv(projection, 1, GL_FALSE, p);
glUniformMatrix4fv(model_view, 1, GL_TRUE, mv);
glUniformMatrix4fv(model_view, 1, GL_FALSE, mv);
See GLSL Programming/Vector and Matrix Operations

Sending transformation to vertex shader fails

I'm doing my first steps with OpenGL and currently fail to send some transformations to my vertex shader. When I use following shader program, everything works fine and I can see my object (a simple triangle):
layout (location = 0) in vec3 aPos;
void main()
{
gl_Position = vec4(aPos, 1.0);
}
In next step I changed the shader program to accept transformations from outside:
layout (location = 0) in vec3 aPos;
uniform mat4 inputTransform;
void main()
{
gl_Position = inputTransform * vec4(aPos, 1.0);
}
...and my main loop to send transformation data to the shader:
unsigned int transformLoc = glGetUniformLocation(shaderProgram,"inputTransform");
glUseProgram(shaderProgram);
GLfloat trans[4] = {1.0, 0.0, 0.0, 1.0};
glUniformMatrix4fv(transformLoc, 1, GL_FALSE,trans);
Now my triangle disapperas as some very invalid transformation would have been applied. Value in "shaderProgram" is correct, it works properly with a prior call to the fragment shader. I also do not get any compilation errors for the shader programs.
So any idea what could be wrong here?
The uniform mat4 inputTransform is a 4*4 matrix and not a vector with 4 components.
See Data Type (GLSL) - Matrices
You have to initialize it with an array of 16 floats, e.g. by an Identity matrix:
GLfloat trans[16] = {
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0
};
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, trans);
The matrix contains the translation, orientation (and scale). In GLSL a mat4 can be initialized:
mat4 m44 = mat4(
vec4( Xx, Xy, Xz, 0.0),
vec4( Yx, Xy, Yz, 0.0),
vec4( Zx Zy Zz, 0.0),
vec4( Tx, Ty, Tz, 1.0) );
This means, if you want to init the matrix with an translation vector, then you can do it manually initializing the translation component of the matrix:
Glfloat Tx = 1.0;
Glfloat Ty = 0.0;
Glfloat Tz = 0.0;
GLfloat trans[16] = {
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
Tx, Ty, Tz, 1.0
};
In C++ I recommend to use the GLM library for matrix and vector operations, which are related to OpenGL and GLSL.

OpenGL 3.2 trouble setting up matrices

I am using GLM to manage my matrices, but I am running in to some problems that make no sense to me. When I set the projection matrix to anything other than an identity matrix, I can't see the square I am trying to draw. If it is an identity it will work. Something similiar happens with my view matrix. If I try and translate past -1 or +1 the square will dissapear, otherwise it seems to have no effects.
There are no OpenGL errors, GLSL linker/compiler errors, and glGetUniformLocation returns a valid location. Also the shader program is correctly being used.
Also I have tested the shader to see if it is getting the correct values passed to each of the matrices (by changing the color of the square if the value is correct).
Here's how I set up the projection matrix:
projectionMatrix = glm::perspective(60.0f, (float)windowWidth / (float)windowHeight, 0.1f, 100.0f);
And here's my draw function:
void OpenGLContext::render(void) {
glViewport(0, 0, windowWidth, windowHeight); // Set the viewport size to fill the window
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // Clear required buffers
//Set up matrices
viewMatrix = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -5.0f));
modelMatrix = glm::scale(glm::mat4(1.0f), glm::vec3(.5f));
shader->bind();
int projectionMatrixLocation = glGetUniformLocation(shader->id(), "projectionMatrix");
int viewMatrixLocation = glGetUniformLocation(shader->id(), "viewMatrix");
int modelMatrixLocation = glGetUniformLocation(shader->id(), "modelMatrix");
glUniformMatrix4fv(projectionMatrixLocation, 1, GL_FALSE, &projectionMatrix[0][0]);
glUniformMatrix4fv(viewMatrixLocation, 1, GL_FALSE, &viewMatrix[0][0]);
glUniformMatrix4fv(modelMatrixLocation, 1, GL_FALSE, &modelMatrix[0][0]);
glBindVertexArray(vaoID[0]);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
shader->unbind();
SwapBuffers(hdc);
}
Here's the shader.vert
#version 150 core
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
in vec3 in_Position;
in vec3 in_Color;
out vec3 pass_Color;
void main(void)
{
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(in_Position, 1.0);
pass_Color = in_Color;
}
Here's shader.frag
#version 150 core
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
in vec3 pass_Color;
out vec4 out_Color;
void main(void)
{
out_Color = vec4(pass_Color, 1.0);
}
Sorry forgot about what i'm drawing:
void OpenGLContext::createSquare(void)
{
float* vertices = new float[18];
vertices[0] = -0.5; vertices[1] = -0.5; vertices[2] = 0.0; // Bottom left corner
vertices[3] = -0.5; vertices[4] = 0.5; vertices[5] = 0.0; // Top left corner
vertices[6] = 0.5; vertices[7] = 0.5; vertices[8] = 0.0; // Top Right corner
vertices[9] = 0.5; vertices[10] = -0.5; vertices[11] = 0.0; // Bottom right corner
vertices[12] = -0.5; vertices[13] = -0.5; vertices[14] = 0.0; // Bottom left corner
vertices[15] = 0.5; vertices[16] = 0.5; vertices[17] = 0.0; // Top Right corner
glGenVertexArrays(1, &vaoID[0]);
glBindVertexArray(vaoID[0]);
glGenBuffers(1, vboID);
glBindBuffer(GL_ARRAY_BUFFER, vboID[0]);
glBufferData(GL_ARRAY_BUFFER, 18 * sizeof(GLfloat), vertices, GL_STATIC_DRAW);
glVertexAttribPointer((GLuint) 0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0); // Disable our Vertex Array Object
glBindVertexArray(0);
delete [] vertices;
}
Setting my matrices like this results in nothing being drawn on the screen. Like I said if I set the projection and view matrices to an identity it will work. The scaling on the modelMatrix seems to always work as well.
There is no attribute on position 1 (in_Color). If you just left it out of this question, then the problem are the locations, which you are not defining in the shaders. I've never actually tested it without the location part, but I think it's necessary, at least for multiple values: you should use e.g. layout(location = 0) in in_Position.