I need some help with rendering inverted scene to framebuffer. I want to make a mirror effect.
What i have in result:
Initializing frame buffer:
GLuint FramebufferName = 0;
glGenFramebuffers(1, &FramebufferName);
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);
GLuint renderedTexture;
glGenTextures(1, &renderedTexture);
glBindTexture(GL_TEXTURE_2D, renderedTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SCREEN_WIDTH, SCREEN_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, renderedTexture, 0);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glReadBuffer(GL_NONE);
Draw scene to frame buffer:
mView = camera.getViewMatrix();
mProjection = perspective(45.0f, 4.0f / 3.0f, 0.1f, 300.0f) * scale(mat4(1.0f), vec3(1.0f, -1.0f, 1.0f));
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, FramebufferName);
glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glCullFace(GL_FRONT);
glEnable(GL_CULL_FACE);
mWorld = rotate(mWorld, -15.0f, vec3(1, 0, 0));
mWorld = rotate(mWorld, -30.0f, vec3(0, 1, 0));
cubemap.Draw(mView, mProjection, mWorld);
glDisable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glUseProgram(program);
mWorld = translate(mat4(1.0f), vec3(0, -10, 0));
glUniformMatrix4fv(mvp_object, 1, GL_FALSE, value_ptr(mProjection * mView * mWorld * scale(mat4(1.0f), vec3(10.0f))));
cannon.Draw(program);
mWorld = mat4(1.0f);
mWorld = translate(mat4(1.0f), vec3(50, -10, 0));
mWorld = rotate(mWorld, 90.0f, vec3(0, 1, 0));
glUniformMatrix4fv(mvp_object, 1, GL_FALSE, value_ptr(mProjection * mView * mWorld * scale(mat4(1.0f), vec3(10.0f))));
cannon.Draw(program);
mWorld = mat4(1.0f);
mWorld = translate(mat4(1.0f), vec3(0, -10, 50));
mWorld = rotate(mWorld, 140.0f, vec3(0, 1, 0));
glUniformMatrix4fv(mvp_object, 1, GL_FALSE, value_ptr(mProjection * mView * mWorld * scale(mat4(1.0f), vec3(10.0f))));
cannon.Draw(program);
glDisable(GL_DEPTH_TEST);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
I saw some tutorials where used glScalef(1.0, -1.0, 1.0) to invert scene.
glScalef was used in old versions of opengl. How can i invert scene in new versions of opengl?
I've multiplied projection matrix on scale(mat4(1.0f), vec3(1.0, -1.0, 1.0)) for this effect. Is it right?
Here is the vertex shader written in GLSL.
void main(void)
{
// Clean up inaccuracies
vec2 Pos = sign(gl_Vertex.xy);
gl_Position = vec4(Pos.xy, 0.0, 1.0);
// Image-space
gl_TexCoord[0].xy = vec2(-Pos.x, Pos.y) * 0.5 + 0.5; // x texture coord is inverted
}
Pos refers to screen aligned quad for framebuffer output.
Fragment shader
uniform sampler2D framebufferSampler;
void main(void)
{
gl_FragColor = texture2D(framebufferSampler, gl_TexCoord[0].xy);
}
Screen aligned quad can be drawn
glBegin(GL_QUADS)
{
glVertex2f(-1.0f, -1.0f);
glVertex2f(1.0f, -1.0f);
glVertex2f(1.0f, 1.0f);
glVertex2f(-1.0f, 1.0f);
}
glEnd();
or using vertex arrays.
GLfloat vertices[] = {
-1.0f, -1.0f,
1.0f, -1.0f,
1.0f, 1.0f,
-1.0f, 1.0f
};
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, (void*)vertices);
glDrawArrays(GL_QUADS, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY);
texture that is used to be wraped to the quad, is the framebuffer info with previous rendered content (multipass shader technique).
You can also do so with others 2D texture coords or images instead of framebuffer and screen align quads.
Original image.
Inverted image.
More info can be found in Learn OpenGL.
Related
So I am trying to render my texture and i know it works, however when i run my program it renders like this:
Mirrored texture
my code to set the texture coordinates is here:
Vertex vertices[] =
{
//POSITION //COLOR //Texture Co-ordinates
glm::vec3(-.5f, .5f, 0.f), glm::vec3(1.f, 0.f, 0.f), glm::vec2(0.f, 1.f), // [R]
glm::vec3(-.5f, -.5f, 0.f), glm::vec3(0.f, 1.f, 0.f), glm::vec2(0.f, 0.f), // [G]
glm::vec3(.5f, -.5f, 0.f), glm::vec3(0.f, 0.f, 1.f), glm::vec2(1.f, 0.f), // [B]
glm::vec3(.5f, .5f, 0.f), glm::vec3(1.f, 1.f, 0.f), glm::vec2(1.f, 1.f) // [Y]
};
These are my indices:
GLuint indices[] =
{
0, 1, 2, // Triagle 1
0, 2, 3 // Triangle 2
};
unsigned noOfIndices = sizeof(indices) / sizeof(GLuint); // Calculate the number of Indices
I call my image through my header file:
// TEXTURE VALUES //
int imgWidth = 0, imgHeight = 0;
unsigned char* image = stbi_load("images/letterCube.png", &imgWidth, &imgHeight, NULL, STBI_rgb_alpha);
I generate my texture here:
glGenTextures(1, &texture0); // Generate Texture
glBindTexture(GL_TEXTURE_2D, texture0); // Bind Texture
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // Set Texture Params (Wrap S = X)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // Set Texture Params (Wrap T = Y)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR); // A type of anti-ailiasing (magnificaiton)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // A type of anti-ailiasing (minificaiton)
if (image)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imgWidth, imgHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D); // Clones image for different resolutions
}
else
{
GE_CORE_ERROR("Texture loading failed");
}
glActiveTexture(0);
glBindTexture(GL_TEXTURE_2D, 0);
stbi_image_free(image);
in my update function I activate my textures:
glUseProgram(core_program);
glUniform1i(glGetUniformLocation(core_program, "texture0"), 0);
// ACTIVATE TEXTURE
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture0);
In my fragment_core.glsl file I have this:
#version 440
in vec3 vs_position;
in vec3 vs_color;
in vec2 vs_texturePoints;
out vec4 fs_color;
uniform sampler2D texture0;
void main()
{
//fs_color = vec4(vs_color, 1.f);
fs_color = texture(texture0, vs_texturePoints) * vec4(vs_color, 1.f);
}
I am trying to render the texture correctly however it seems like it mirrors from the other triangle. Is it a co-ordinates problem or am i missing the obvious?
I've been trying to implement shadow mapping into my OpenGL engine in SFML 2.2, and they don't seem to be rendering right. I believe I narrowed down the issue to the ortho projection used to calculate the shadows.
/* before the main loop, creating the depth buffer for shadow mapping */
glm::vec3 lightPos(glm::vec3(-45.f, 45.f, -40.f));
const GLuint SHADOW_WIDTH = 1024, SHADOW_HEIGHT = 1024;
GLuint depthMapFBO;
glGenFramebuffers(1, &depthMapFBO);
GLuint depthMap;
glGenTextures(1, &depthMap);
glBindTexture(GL_TEXTURE_2D, depthMap);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
GLfloat borderColor[] = { 1.0, 1.0, 1.0, 1.0 };
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthMap, 0);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
/* in the main loop, sending information to the appropiate shaders and setting viewports */
glm::mat4 lightProjection, lightView;
glm::mat4 lightSpaceMatrix;
GLfloat near_plane = 1.f, far_plane = 300.f;
lightProjection = glm::ortho(-10.f, 10.f, -10.f, 10.f, near_plane, far_plane);
lightView = glm::lookAt(lightPos, glm::vec3(0.0f), glm::vec3(0.0, 1.0, 0.0));
lightSpaceMatrix = lightProjection * lightView;
glUseProgram(simpleDepthShader);
glUniformMatrix4fv(glGetUniformLocation(simpleDepthShader, "lightSpaceMat"), 1, GL_FALSE, glm::value_ptr(lightSpaceMatrix));
glViewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT);
glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
glClear(GL_DEPTH_BUFFER_BIT);
RenderScene();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// reset viewport, and display the scene as normal
glViewport(0, 0, window.getSize().x, window.getSize().y);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUniform3fv(glGetUniformLocation(lightingShader, "lightPos_shade"), 1, &lightPos[0]);
glUniform3fv(glGetUniformLocation(lightingShader, "viewPos"), 1, &getPos()[0]);
glUniformMatrix4fv(glGetUniformLocation(lightingShader, "lightSpaceMat"), 1, GL_FALSE, glm::value_ptr(lightSpaceMatrix));
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, depthMap);
RenderScene();
I've applied the view and projection matrix to the camera to see what the light sees, and this was the result (along with the view from the depth buffer).
Here's what the scene looks like with the shadows (which the shadow for the stall doesn't even cast onto itself for some reason).
It seems that your shader doesn't fetch your shadow pixels correctly.
When you transform your vertices with your light matrix they are in the [-1, 1] range, but texture sampling is in the range [0, 1].
http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-16-shadow-mapping/
Could some one explain for me how can I render multiple objects with different textures in OpenGL?
I think that I'm nearly to the final result but at the moment I got stuck here and I don't know what I need to do next. Really need some helps!
At the moment this is what I have:
drawSphere(): draw an UV sphere based on number of longs and lats
int numberOfVerices = 0;
for(int i = 0; i <= lats; i++) {
double lat0 = M_PI * (-0.5 + (double) (i - 1) / lats);
double z0 = sin(lat0);
double zr0 = cos(lat0);
double lat1 = M_PI * (-0.5 + (double) i / lats);
double z1 = sin(lat1);
double zr1 = cos(lat1);
for(int j = 0; j <= longs; j++) {
double lng = 2 * M_PI * (double) (j - 1) / longs;
double x = cos(lng);
double y = sin(lng);
glNormal3f(x * zr0, y * zr0, z0);
vertices.push_back(x * zr0);
vertices.push_back(y * zr0);
vertices.push_back(z0);
indices.push_back(numberOfVerices);
numberOfVerices++;
vertices.push_back(x * zr1);
vertices.push_back(y * zr1);
vertices.push_back(z1);
indices.push_back(numberOfVerices);
numberOfVerices++;
}
indices.push_back(GL_PRIMITIVE_RESTART_FIXED_INDEX);
}
SetupGeometry(): this method is used to bind vertices and texture coordinates.
drawSphere(300, 300);
glGenBuffers(1, &vboVertex);
glBindBuffer(GL_ARRAY_BUFFER, vboVertex);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(GLfloat), &vertices[0], GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0);
glGenBuffers(1, &vboTexture);
glBindBuffer(GL_ARRAY_BUFFER, vboTexture);
glBufferData(GL_ARRAY_BUFFER, texture.size() * sizeof(GLfloat), &texture[0], GL_STATIC_DRAW);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(1);
glGenBuffers(1, &vboIndex);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIndex);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(GLuint), &indices[0], GL_STATIC_DRAW);
numsToDraw = indices.size();
nums = indices.size();
SetupShader(): create shader and compile shader
char text[1000];
int length;
vertexSource = filetobuf("space/sphere.vert");
fragmentSource = filetobuf("space/sphere.frag");
vertexShader = glCreateShader(GL_VERTEX_SHADER);
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(vertexShader, 1, (const GLchar**) &vertexSource, 0);
glShaderSource(fragmentShader, 1, (const GLchar**) &fragmentSource, 0);
fprintf(stderr, "Compiling vertex shader....\n");
glCompileShader(vertexShader);
fprintf(stderr, "Compiling fragment shader....\n");
glCompileShader(fragmentShader);
fprintf(stderr, "Done....\n");
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glBindAttribLocation(shaderProgram, 0, "in_Position");
glBindAttribLocation(shaderProgram, 1, "Texture_Coord");
printf("Linking program ... \n");
glLinkProgram(shaderProgram);
glGetProgramInfoLog(shaderProgram, 1000, &length, text);
if(length > 0){
fprintf(stderr, "Validate Shader Program\n%s\n", text );
}
glUseProgram(shaderProgram);
SetupTexture(char * filename): loading image, generate 2 arrays of textures, one to GL_TEXTURE0 and other one to GL_TEXTURE1
GLuint texture[2];
glGenTextures(2, texture);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture[0]);
data = stbi_load(fileName, &w, &h, &n, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glUniform1i(glGetUniformLocation(shaderProgram, "texture_Sun"), 0);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
stbi_image_free(data);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture[1]);
data = stbi_load(fileName1, &w, &h, &n, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glUniform1i(glGetUniformLocation(shaderProgram, "texture_Earth"), 1);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
stbi_image_free(data);
Render(int i): rendering 2 objects, which is sphere.
glClearColor(0.0, 0.0, 0.0, 1.0);/* Make our background black */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_PRIMITIVE_RESTART);
glPrimitiveRestartIndex(GL_PRIMITIVE_RESTART_FIXED_INDEX);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIndex);
glPushMatrix();
glLoadIdentity();
glm::mat4 Projection = glm::perspective(50.0f, 5.0f / 3.0f, 1.0f, 100.0f);
glm::mat4 View = glm::lookAt(
glm::vec3(0, 5, 2),
glm::vec3(0, 0, 0),
glm::vec3(0, 1, 0)
);
/* Animations */
GLfloat angle = (GLfloat) (i);
View = glm::translate(View, glm::vec3(2.0f, 0.0f, 0.0f));
View = glm::rotate(View, angle * 0.5f, glm::vec3(0.0f, 0.0f, 1.0f));
/* ******* */
glm::mat4 Model = glm::mat4(1.0f);
glm::mat4 MVP = Projection * View * Model;
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "mvpMatrix"), 1, GL_FALSE, glm::value_ptr(MVP));
glDrawElements(GL_QUAD_STRIP, numsToDraw, GL_UNSIGNED_INT, NULL);
glPopMatrix();
glPushMatrix();
glLoadIdentity();
glm::mat4 Projection1 = glm::perspective(50.0f, 5.0f / 3.0f, 1.0f, 100.0f);
glm::mat4 View1 = glm::lookAt(
glm::vec3(0, 5, 2),
glm::vec3(0, 0, 0),
glm::vec3(0, 1, 0)
);
/* Animations */
GLfloat angle1 = (GLfloat) (i);
View1 = glm::translate(View1, glm::vec3(-2.0f, 0.0f, 0.0f));
View1 = glm::rotate(View1, angle1 * -0.5f, glm::vec3(0.0f, 0.0f, 1.0f));
/* ******* */
glm::mat4 Model1 = glm::mat4(1.0f);
MVP = Projection1 * View1 * Model1;
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "mvpMatrix"), 1, GL_FALSE, glm::value_ptr(MVP));
glDrawElements(GL_QUAD_STRIP, nums, GL_UNSIGNED_INT, NULL);
glPopMatrix();
VertexShader:
#version 330 core
precision highp float;
attribute vec3 in_Position;
attribute vec3 in_Position1;
varying vec4 Texture_Coord;
uniform mat4 mvpMatrix;
void main(void){
gl_Position = mvpMatrix * vec4(in_Position, 1.0);
Texture_Coord = vec4(in_Position, 1.0);
}
FragmentShader:
#version 330 core
precision highp float;
varying vec4 Texture_Coord;
uniform sampler2D texture_Sun;
uniform sampler2D texture_Earth;
out vec4 FragColor;
void main(void){
vec2 longLat = vec2((atan(Texture_Coord.y, Texture_Coord.x)/3.1415926 + 1) * 0.5, (asin(Texture_Coord.z) / 3.1415926 + 0.5));
FragColor = texture2D(texture_Sun, longLat);
FragColor = texture2D(texture_Earth, longLat);
}
Main codes in main:
SetupGeomtry();
SetupShader();
SetupTexture("images/Earth.jpg", "images/sun.jpg");
/*
* Main loop
*/
int i = 0;
while(!glfwWindowShouldClose(window)){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Render(i+=1);
glfwSwapBuffers(window);
glfwPollEvents();
Sleep(10);
}
Normally you would load your textures (i.e. buffer them to GPU):
GLuint texture[2];
glGenTextures(2, texture);
glBindTexture(GL_TEXTURE_2D, texture[0]);
data = stbi_load(fileName, &w, &h, &n, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
stbi_image_free(data);
glBindTexture(GL_TEXTURE_2D, texture[1]);
data = stbi_load(fileName1, &w, &h, &n, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
stbi_image_free(data);
then before drawing each of your objects bind the relevant texture for said object:
// already selected the shader programme for both Sun and Earth
GLint textureLocation = glGetUniformLocation(shaderProgram, "texture_CelestialBody");
// optionally remember more locations for multi texture
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glUniform1i(textureLocation, 0);
// optionally bind more textures for multi texture shader...
// draw Sun now
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture[1]);
glUniform1i(textureLocation, 0);
// optionally bind more textures for multi texture shader...
// draw Earth now
then the texture_CelestialBody identifies the texture for both the Sun and the Earth - i.e. the fragment shader would not discriminate between the two.
I have been trying to implement shadow mapping. Whilst I think that I am now close, I have come stuck with a strange effect (illustrated below):
As you can see, the shadow region appears too small. There is also an unusual effect on the cube itself.
The geometry being rendered is a cube of dimensions 1.0 on a square plane of dimensions 100.0. The scene contains a single spotlight with an angle (from one side to the other) of 0.5 radians and a range of 100.0. This spotlight orbits about the y-axis and adjusts its rotation to look at the origin.
I setup the framebuffer and depth texture (512 x 512) as follows:
// Create and configure the depth texture.
glGenTextures(1, &m_depthTexture);
glBindTexture(GL_TEXTURE_2D, m_depthTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
GLfloat border[] = { 1.0f, 1.0f, 1.0f, 1.0f };
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, (void*)0);
// Assign the depth texture to texture channel 0.
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_depthTexture);
// Create and configure the framebuffer.
glGenFramebuffers(1, &m_framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_depthTexture, 0);
GLenum drawBuffers[] = { GL_NONE };
glDrawBuffers(1, drawBuffers);
I then render the scene to the shadow map framebuffer from the perspective of the spotlight. This seems to be working. Inspecting the depth texture using an OpenGL debugging tool revealed the following:
The scene is rendered a second time, where I set the uniforms for the depth texture and shadow matrix:
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_2D, shadowMap.depthTexture());
program->uniform("shadowMap", 1);
const M3D::Matrix4 lightViewMatrix = lightTransformComponent->transformationMatrix().inverse();
const float invTanHalfFov = 1.0f / std::tan(coneAngle * 0.5f);
const float nearClipPlane = 0.3f;
const float farClipPlane = lightLightComponent->range();
const float zRange = nearClipPlane - farClipPlane;
const Matrix4 lightProjectionMatrix(
invTanHalfFov, 0.0f, 0.0f, 0.0f,
0.0f, invTanHalfFov, 0.0f, 0.0f,
0.0f, 0.0f, -(nearClipPlane + farClipPlane) / zRange, 2.0f * nearClipPlane * farClipPlane / zRange,
0.0f, 0.0f, 1.0f, 0.0f
);
const Matrix4 shadowMatrix = lightProjectionMatrix * lightViewMatrix * modelMatrix;
program->uniform("shadowMatrix", shadowMatrix);
I compute the shadow coordinate in the vertex shader:
f_shadowCoordinate = shadowMatrix * vec4(v_position, 1.0f);
Then, in the fragment shader, I project this coordinate and bias it to range in the interval [0, 1].
vec2 projectedShadowCoordinates = (f_shadowCoordinate.xy / f_shadowCoordinate.w) * 0.5f + vec2(0.5f, 0.5f);
float shadowDistance = texture(shadowMap, projectedShadowCoordinates).x;
return vec4(1.0f) * shadowDistance;
The problem was caused by mistakenly setting the projection matrix uniform to the camera's projection matrix (instead of the light's projection matrix) when rendering to the shadow framebuffer.
I am trying to implement shadow mapping in our game project. I am using render to texture technique with two pass rendering. I have created a FBO first and bound a texture for depth component only. In the first pass, I enable this FBO, disable texture and render my scene from light POV. In the second pass, I pass the depth texture to the shader and render the scene normally. I perform the shadow related calculation in the shader.
But, my code is not working correctly. I am not able to see any shadow. Also, when I render both pass, I see a multiple drawing of the whole world trailing one after another if my camera is looking above a certain angle : 45. If I look below that angle, the rendering looks ok. What may be the source of this problem?
. If I disable the first pass, the world looks darker but the trailing scene is gone. I have also attached my codes below.
I have also another confusion. I have disabled texture for the first shadowmap pass. But I send the texture coordinates with my vertex coordinates to the VBO. Will that cause any problem?
FBO Initialization
LightPosition = glm::vec3(50.0f, 40.0f, 50.0f);
upVector = glm::vec3(0.0f, 1.0f, 0.0f);
glGenTextures(1, &m_shadowMap);
glBindTexture(GL_TEXTURE_2D, m_shadowMap);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32,
WindowWidth, WindowHeight, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glBindTexture(GL_TEXTURE_2D, 0);
glGenFramebuffers(1, &m_fbo);
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
glDrawBuffers(0, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_shadowMap, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
GLenum Status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (Status != GL_FRAMEBUFFER_COMPLETE) {
printf("FB error, status: 0x%x\n", Status);
return false;
}
return true;
Shadow Map Pass:
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);
glViewport(0, 0, windowWidth, windowHeight);
glBindFramebuffer(GL_FRAMEBUFFER, shadowMapFBO.m_fbo);
glClear(GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glm::mat4 lightProjection = glm::perspective(45.0f,
1.0f * windowWidth / windowHeight, 0.125f, 1000.0f);
glGetFloatv(GL_PROJECTION_MATRIX, shadowMapFBO.LightProjectionMatrix);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glm::mat4 lightModelView = glm::lookAt(shadowMapFBO.LightPosition,
glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
glGetFloatv(GL_MODELVIEW_MATRIX, shadowMapFBO.LightModelViewMatrix);
glm::mat4 lmvp = lightProjection * lightModelView;
glCullFace(GL_FRONT);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glDisable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
glUniform1i(Shader::id_uniform_layer, 0);
world->render(lmvp);
printGLError();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
Render Pass:
static glm::vec3 cCameraPosition = glm::vec3(0.0f, 5.0f, 10.0f);
static glm::vec3 cLightPosition = glm::vec3(50.0f, 40.0f, 50.0f);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, windowWidth, windowHeight);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glm::mat4 modelView = player->getView();
float viewAngle = 45.0f;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glm::mat4 projection = glm::perspective(viewAngle,
1.0f * windowWidth / windowHeight, 0.01f, 1000.0f);
glm::mat4 mvp = projection * modelView;
glEnable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, shadowMapFBO.m_shadowMap);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glTranslatef(0.5f, 0.5f, 0.5f);
glScalef(0.5f, 0.5f, 0.5f);
glMultMatrixf(shadowMapFBO.LightProjectionMatrix);
glMultMatrixf(shadowMapFBO.LightModelViewMatrix);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, id_texture_blocks);
glUseProgram(Shader::id_program);
glUniform3fv(Shader::id_uniform_lightPosition, 1,
glm::value_ptr(cLightPosition));
glUniform3fv(Shader::id_uniform_CameraPosition, 1,
glm::value_ptr(*(player->getCoordinates())));
//Enabling color write (previously disabled for light POV z-buffer rendering)
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glUniform1i(Shader::id_shader_shadow, 1);
glUniformMatrix4fv(Shader::id_uniform_mvp, 1, GL_FALSE, glm::value_ptr(mvp));
glEnable(GL_POLYGON_OFFSET_FILL);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glUniform1i(Shader::id_uniform_layer, 0);
world->render(mvp);
printGLError();
Vertex Shader:
attribute vec4 coordinates;
uniform mat4 mvp;
//Fragment shader forward variables.
varying vec4 voxel;
//shadow map
// Used for shadow lookup
varying vec4 ShadowCoord;
uniform vec3 LightPosition, CameraPosition;
varying vec3 LightDirection, LightDirectionReflected, CameraDirection, Normal;
void main(void) {
//shadow map
LightDirection = LightPosition - gl_Vertex.xyz;
LightDirectionReflected = reflect(-LightDirection, gl_Normal);
CameraDirection = CameraPosition - gl_Vertex.xyz;
Normal = gl_Normal;
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_TexCoord[1] = gl_TextureMatrix[1] * gl_Vertex;
voxel = coordinates;
//Calculates projection on xyz.
gl_Position = mvp * vec4(coordinates.xyz, 1);
}
Fragment Shader:
#extension GL_EXT_gpu_shader4 : enable
//Rendering layer.
uniform int layer;
//Colors.
uniform float colorRed;
uniform float colorGreen;
uniform float colorBlue;
uniform float colorAlpha;
//Fog density.
uniform float fogDensity;
varying vec4 voxel;
uniform sampler2D texture;
const float N_TEXTURES = 32.0;
//////////////////////shadow map
uniform sampler2DShadow ShadowMap;
varying vec4 ShadowCoord;
varying vec3 LightDirection, LightDirectionReflected, CameraDirection, Normal;
void main(void) {
vec2 coord2d;
float intensity;
vec4 color = texture2D(texture, coord2d);
float z = gl_FragCoord.z / gl_FragCoord.w;
float fog = clamp(exp(-fogDensity * z * z), 0.2, 1.0);
color.xyz = color.xyz * intensity;
//shadow map
float Shadow = shadow2DProj(ShadowMap, gl_TexCoord[1]).r;
float NdotLD = max(dot(normalize(LightDirection), Normal), 0.0) * Shadow;
float Spec = pow(max(dot(normalize(LightDirectionReflected), normalize(CameraDirection)), 0.0), 32.0) * Shadow;
color.xyz = color.xyz * (0.25 + NdotLD * 0.75 + Spec);
//Final color.
vec4 fogColor = vec4(colorRed, colorGreen, colorBlue, colorAlpha);
gl_FragColor = mix(fogColor, color, fog);
}
At a glance it looks like you're not using glClear so the sky is whatever was in the last frame, or at least its not working. What's the alpha value of the glClearColor?