OpenGL: skybox/cubemap is displayed partially, triangles of it are missing - opengl

I tried to create a textured skybox, following this tutorial:
cubemaps. Some triangles of the box (it is triangulated) are not shown at all, but weirdly enough not every second triangle of a square is missing (1 square's texturing is correct). My problem can be seen in the pictures below. The grayish color is "general" color of the scene, it has nothing to do with the skybox.
I believe the problem is caused by one of the shaders, as I get an
invalid operation
error, while trying to use the shaders of the skybox. What might be the problem?
Here the code of vertex shader:
#version 330 core
layout (location = 0) in vec3 aPos;
out vec3 TexCoords;
uniform mat4 projection;
uniform mat4 view;
void main() {
TexCoords = aPos;
vec4 pos = projection * view * vec4(aPos, 1.0);
gl_Position = pos.xyww;
}
and the fragment shader:
#version 330 core
out vec4 FragColor;
in vec3 TexCoords;
uniform samplerCube skybox;
void main() {
FragColor = texture(skybox, TexCoords);
}
and finally the procedure which loads the cubemap:
GLuint loadCubemap(std::vector<std::string> faces) {
GLuint textureID;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);
int width, height, nrChannels;
for (GLuint i = 0; i < faces.size(); i++) {
unsigned char *data = stbi_load(faces[i].c_str(), &width, &height, &nrChannels, 0);
if (data) {
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
stbi_image_free(data);
} else {
std::cout << "Cubemap texture failed to load at path: " << faces[i] << std::endl;
stbi_image_free(data);
}
}
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
return textureID;
}
The requested geometry (it's a .obj file):
o Cube
v 300.000000 -300.000000 -300.000000
v 300.000000 -300.000000 300.000000
v -300.00000 -300.000000 300.000000
v -300.00000 -300.000000 -300.00000
v 300.000000 300.000000 -300.000000
v 300.000000 300.000000 300.00000
v -300.000000 300.000000 300.000000
v -300.000000 300.000000 -300.000000
vn 0.0000 -1.0000 0.0000
vn 0.0000 1.0000 0.0000
vn 1.0000 -0.0000 0.0000
vn -0.0000 -0.0000 1.0000
vn -1.0000 -0.0000 -0.0000
vn 0.0000 0.0000 -1.0000
s off
f 2//1 4//1 1//1
f 8//2 6//2 5//2
f 5//3 2//3 1//3
f 6//4 3//4 2//4
f 3//5 8//5 4//5
f 1//6 8//6 5//6
f 2//1 3//1 4//1
f 8//2 7//2 6//2
f 5//3 6//3 2//3
f 6//4 7//4 3//4
f 3//5 7//5 8//5
f 1//6 4//6 8//6

I have found the problem! It was not caused by the shaders but by my own stupidity. In the main rendering loop, I forgot to remove an extra binding VAO-buffer + drawing triangles pair after the newly inserted one.

Related

Trouble when using OpenGL .obj normals

I'm trying to render a cube using an exported.obj file by Blender but the lighting looks like wrong.
I think it's because my vertices array contains 8 values but the normals array has only 6.
I can not understand how OpenGL uses this index array. It's a little bit magic for me.
Can anyone help me?
This is the file:
v -1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 1.000000 0.999999
v -0.999999 1.000000 -1.000001
v 1.000000 1.000000 -1.000000
v 1.000000 1.000000 1.000000
vn 0.0000 -1.0000 0.0000
vn 0.0000 1.0000 -0.0000
vn -1.0000 -0.0000 0.0000
vn 0.0000 -0.0000 -1.0000
vn 1.0000 -0.0000 0.0000
vn -0.0000 0.0000 1.0000
f 2//1 4//1 1//1
f 8//2 6//2 5//2
f 5//3 2//3 1//3
f 6//4 3//4 2//4
f 3//5 8//5 4//5
f 1//6 8//6 5//6
f 2//1 3//1 4//1
f 8//2 7//2 6//2
f 5//3 6//3 2//3
f 6//4 7//4 3//4
f 3//5 7//5 8//5
f 1//6 4//6 8//6
This is my code:
GLuint cubeVAO, cubeVerticesVBO, cubeColorsVBO, cubeNormalsVBO, cubeIndicesVBO;
glGenVertexArrays(1, &cubeVAO);
glBindVertexArray(cubeVAO);
glGenBuffers(1, &cubeVerticesVBO);
glBindBuffer(GL_ARRAY_BUFFER, cubeVerticesVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(cube_vertices), cube_vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), BUFFER_OFFSET(0));
glEnableVertexAttribArray(0);
glGenBuffers(1, &cubeColorsVBO);
glBindBuffer(GL_ARRAY_BUFFER, cubeColorsVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(cube_colors), cube_colors, GL_STATIC_DRAW);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), BUFFER_OFFSET(0));
glEnableVertexAttribArray(1);
glGenBuffers(1, &cubeNormalsVBO);
glBindBuffer(GL_ARRAY_BUFFER, cubeNormalsVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(cube_normals), cube_normals, GL_STATIC_DRAW);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), BUFFER_OFFSET(0));
glEnableVertexAttribArray(2);
glGenBuffers(1, &cubeIndicesVBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cubeIndicesVBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(cube_indices), cube_indices, GL_STATIC_DRAW);
glBindVertexArray(cubeVAO);
cubeShader.use();
glm::mat4 model;
cubeShader.setMat4("model", model);
cubeShader.setMat4("view", view);
cubeShader.setMat4("projection", projection);
cubeShader.setVec3("lampColor", lampColor);
cubeShader.setVec3("lampPos", lampPos);
cubeShader.setVec3("viewPos", viewPos);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
Vertex Shader
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 color;
layout (location = 2) in vec3 normal;
out vec3 Color;
out vec3 Normal;
out vec3 FragPos;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
vec4 posv4 = vec4(position, 1.0f);
Color = color;
FragPos = vec3(model * posv4);
Normal = normal;
gl_Position = projection*view*model*posv4;
}
Fragment Shader:
#version 330 core
in vec3 Color;
in vec3 Normal;
in vec3 FragPos;
out vec4 FragColor;
uniform vec3 lampColor;
uniform vec3 lampPos;
uniform vec3 viewPos;
void main()
{
// ambient
float ambientStrength = 0.1;
vec3 ambient = ambientStrength * lampColor;
// diffuse
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(lampPos - FragPos);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = diff * lampColor;
// specular
float specularStrength = 0.5;
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
vec3 specular = specularStrength * spec * lampColor;
vec3 result = (ambient + diffuse + specular) * Color;
FragColor = vec4(result, 1.0);
}
What's wrong? ,-,
Demonstration video:
https://vid.me/vy17h
You'll have to expand the data in the OBJ file. OpenGL expects a normal to be specified for each vertex, individually. In the OBJ file vertices and normals are treated separately. What you have to do is find the unique vertex+normal combinations, store that and index into that new vertex+normal array instead of using separate indices.
With modern OpenGL it is somewhat possible to use different indices for each vertex attribute by making use of vertex shader texture fetch, storing vertex data in textures. But this comes with a performance hit.
The normals array only has 6 values because the cube has 6 faces and you have created a model where each face has 4 normals at the corners pointing in the same direction (ie are identical) - which explains the lighting not looking how you expect.
The obj file uses indexing so it can assign one of these 6 unique values to each of the 8 vertices

Cube's edges in OpenGL

I have drawn a cube in OpenGl to use it as skybox.
I'm using a single texture image and I use the UV coordinates to locate the 6 faces in the right positions.
I send the texture with the following code:
//------------------------------------Luminance--------------------------------------------------------------
glPixelStorei(GL_UNPACK_ROW_LENGTH, m_width);
glBindTexture(GL_TEXTURE_2D, texturePointer[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, m_width, m_height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, m_uYdata);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
//--------------------------------------U component------------------------------------------------------------
glPixelStorei(GL_UNPACK_ROW_LENGTH, m_uvWidth);
glBindTexture(GL_TEXTURE_2D, texturePointer[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, m_uvWidth, m_uvHeight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, m_uUdata);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
//------------------------------------- V component-------------------------------------------------------------
glBindTexture(GL_TEXTURE_2D, texturePointer[2]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, m_uvWidth, m_uvHeight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, m_uVdata);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
I can't remove the white edges between the faces of the cube, see the picture below:
GL_NEAREST remove the problem but the quality of the image is lower,
how can I use GL_LINEAR and remove this effect?
Edit:
The cube is created using the following Tutorial:
Model loading
Considering that the texture is made by six faces stitched in columns.
The actual Blender object is:
# Blender v2.77 (sub 0) OBJ File: 'demo_cube.blend'
# www.blender.org
o Cube
v 1.000000 -1.000000 -1.000000
v 1.0000000 -1.000000 1.000000
v -1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v 1.000000 1.000000 -1.000000
v 1.0000000 1.000000 1.000000
v -1.000000 1.000000 1.000000
v -1.000000 1.000000 -1.000000
vt 0.833333333 0.0000
vt 0.666666666 1.0000
vt 0.833333333 1.0000
vt 0.833333333 0.0000
vt 1.000000000 1.0000
vt 1.000000000 0.0000
vt 0.333333333 1.0000
vt 0.500000000 0.0000
vt 0.333333333 0.0000
vt 0.500000000 1.0000
vt 0.666666666 0.0000
vt 0.500000000 0.0000
vt 0.000000000 0.0000
vt 0.166666666 1.0000
vt 0.166666666 0.0000
vt 0.333333333 0.0000
vt 0.166666666 1.0000
vt 0.333333333 1.0000
vt 0.666666666 0.0000
vt 0.833333333 1.0000
vt 0.500000000 1.0000
vt 0.666666666 1.0000
vt 0.000000000 1.0000
vt 0.166666666 0.0000
s off
f 2/1 4/2 1/3
f 8/4 6/5 5/6
f 5/7 2/8 1/9
f 6/10 3/11 2/12
f 3/13 8/14 4/15
f 1/16 8/17 5/18
f 2/1 3/19 4/2
f 8/4 7/20 6/5
f 5/7 6/21 2/8
f 6/10 7/22 3/11
f 3/13 7/23 8/14
f 1/16 4/24 8/17
//44 and 47
The fragment shader is:
#version 330 core
in vec2 oTexCoord;
uniform sampler2D yChannel;
uniform sampler2D uChannel;
uniform sampler2D vChannel;
out vec4 color;
const vec3 offset = vec3(0.0625, 0.5, 0.5);
const mat3 coef = mat3(
1.164, 0.0, 1.793,
1.164, -0.213, -0.533,
1.164, 2.112, 0.0
);
void main()
{
vec2 nTexCoord = vec2(oTexCoord.x, 1.0 - oTexCoord.y);
vec4 Tcolor = vec4(1.0);
if(oTexCoord.y <1 && oTexCoord.y > 0.0) {
if(oTexCoord.x < 1 && oTexCoord.x > 0.0) {
vec3 yuv = vec3(
texture(yChannel, nTexCoord).r,
texture(uChannel, nTexCoord).r,
texture(vChannel, nTexCoord).r
) - offset;
vec3 rgb = yuv * coef;
Tcolor = vec4(rgb, 1.0);
}
}
color = Tcolor;
}
I think you want to use cubemaps and GL_ARB_seamless_cube_map:
Although it is unlikely that the generated ( s t ) coordinate lies significantly outside the determined cube map face, it is often the case that the locations of the individual elements required during a linear sampling do not lie within the determined face, and their coordinates will therefore be modified by the selected clamping and wrapping rules. This often has the effect of producing seams or other discontinuities in the sampled texture.
This extension allows implementations to take samples from adjacent cube map faces, providing the ability to create seamless cube maps.
(emph. mine).
To use it, first check that you indeed have that extension (this depends on your platform and on which toolkit is eventually helping you into accessing OpenGL), then just write
glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
to enable it (globally).

Shadow map stuck at 1

I am following the shadow tutorial on http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-16-shadow-mapping/ and I can view the depth value in the depth texture when rendered to a screen aligned quad. The problem is when I sample from this depth texture I get only one value.
This is how I setup the depth texture FBO; the size of the texture is set to the window size. I'm not sure if this is part of the problem, but if I half the dimensions of the depth texture and try to view that, I end up seeing a corner quarter of the view. I thought textures are always accessed from [0,1]?
glGenFramebuffers(1, &FramebufferName);
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);
glGenTextures(1, &renderedTexture);
glBindTexture(GL_TEXTURE_2D, renderedTexture);
glTexImage2D(GL_TEXTURE_2D, 0,
GL_DEPTH_COMPONENT,
fbWidth,
fbHeight,
0,
GL_DEPTH_COMPONENT,
GL_FLOAT,
0);
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_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
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_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, renderedTexture, 0);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
assert(false && "framebuffer NOT OK");
1st pass vertex shader
#version 150 core
in vec3 position;
uniform mat4 model;
void main(){
gl_Position = model * vec4(position,1.0);
}
1st pass fragment shader
#version 150 core
void main(){ //letting the default gl_FragDepth assignment happen
}
2nd pass vertex shader
#version 150 core
in vec3 position;
out vec4 shadowCoord;
uniform mat4 model;
uniform mat4 camera;
uniform mat4 DepthBiasMVP;
void main() {
gl_Position = camera * model * vec4(position, 1.0);
shadowCoord = DepthBiasMVP * vec4(position, 1.0);
}
2nd pass fragment shader: the stuck at 1 or 0 problems are in the comments, along with the variations I've tried
#version 150 core
in vec4 shadowCoord;
uniform mat4 model;
out vec4 outColor;
//tried both types
//uniform sampler2D shadowMap;
uniform sampler2DShadow shadowMap;
void main() {
vec3 finalColor = ...
float visibility = 1.0;
vec3 P = shadowCoord.xyz / shadowCoord.w; //doesn't work
// vec3 P =vec3(shadowCoord.x, shadowCoord.y, shadowCoord.z); //no difference
// vec3 P = vec3(shadowCoord.xy, shadowCoord.z / shadowCoord.w); //also no difference
visibility = texture( shadowMap, P); // always 1
// //when shadowMap is set to sampler2D
// vec3 textureCoord = shadowCoord.xyz/ shadowCoord.w;
// if (texture(shadowMap, shadowCoord.xy).z ==0) //always 0
// if (texture(shadowMap, shadowCoord.xy).x ==0) //always 1
// if (shadowCoord.z == 0) //always 0
// visibility = 0.06; //
finalColor *= visibility;
outColor = vec4(finalColor, 1.0);
}
This is how I call the passes, the object I am looking at is located at the origin
glm::vec3 srcPerspective(0,0,-4);
glm::mat4 depthProjectionMatrix = glm::ortho<float>(-1,1,-1,1,-10,10);
glm::mat4 depthViewMatrix = glm::lookAt(srcPerspective, glm::vec3(0,0,0), glm::vec3(0,1,0));
//pass 1
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(shadowMap.shaderProgram);
depthMVP = depthProjectionMatrix * depthViewMatrix * modelMatrix;
shadowMap.drawIndexed(world, camera, depthMVP, shapes[shipIdx].mesh.indices.data());
//pass 2
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, renderedTexture);
glm::mat4 biasMatrix(
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
);
glm::mat4 depthBiasMVP = biasMatrix * depthMVP;
glUniformMatrix4fv(loc, 1, GL_FALSE, &depthBiasMVP[0][0]);
ship.drawIndexed(world, camera, lightPos, mvp, shipColor, shapes[shipIdx].mesh.indices.data());

OpenGL scene rendering as black with shadow mapping

I am trying to implement shadow mapping in my OpenGL engine using this tutorial : http://www.fabiensanglard.net/shadowmapping/index.php
I don't have any problems while making the shadow map (i think ). But using it the scene is totally shadowed.
The way I am rendering my scene is as follows:
Set up the depth FBO
GLuint sdepthtex;
GLuint sframebuffer ;
glGenTextures(1, &sdepthtex);
glBindTexture(GL_TEXTURE_2D, sdepthtex);
glTexImage2D(GL_TEXTURE_2D, 0,GL_DEPTH_COMPONENT16, 1024, 1024, 0,GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
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_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, sdepthtex, 0);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
displayMessage("Error loading the Depth Framebuffer");
return;
}
Make the ModelViewProjection matrix from light's perspective and store it in a shadowMatrix variable.
The function i use :
Matrix getMVPmatrix(vector3 position,vector3 lookat )
{
glPushMatrix();
double projection[16];
double modelView[16];
SDL_Surface*screen = SDL_GetVideoSurface();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(FOVY,screen->w/screen->h,NEAR,FAR);
glMatrixMode(GL_MODELVIEW);
glEnable(GL_DEPTH_TEST);
glLoadIdentity();
gluLookAt(position.x,position.y,position.z,lookat.x,lookat.y,lookat.z,0,1,0);
glGetDoublev(GL_MODELVIEW_MATRIX, modelView);
glGetDoublev(GL_PROJECTION_MATRIX, projection);
Matrix m1(projection);
Matrix m2(modelView);
glPopMatrix();
return m1*m2;
}
Render the scene in the depth framebuffer. The shaders :
Vertex Shader:
uniform mat4 shadowMatrix;
void main()
{
gl_Position = shadowMatrix*gl_Vertex;
}
Fragment Shader:
void main(void)
{
gl_FragDepth = gl_FragCoord.z;
}
For my 3 boxes scene, the linearized depth look like this :
http://www.2shared.com/photo/IExy9aUo/Depth.html
So i think the shadowMatrix and the depth rendering are right.
The last pass is just about drawing the scene with the shadow map
Vertex Shader:
varying vec4 ShadowCoord;
uniform mat4 shadowMatrix;
mat4 biasMatrix = mat4(
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
);
void main (void)
{
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_FrontColor = gl_Color;
gl_Position = ftransform();
ShadowCoord = biasMatrix*shadowMatrix *vec4(gl_Vertex.xyz,1.0);
}
Fragment Shader:
uniform sampler2D tex;
uniform sampler2D shadowtex;//the non linearized depth texture we made in the 3rd step.
varying vec4 ShadowCoord;
float getShadowFactor(void)
{
vec4 shadowCoordinateWdivide = ShadowCoord / ShadowCoord.w ;
shadowCoordinateWdivide.z += 0.0005;
float distanceFromLight = texture2D(shadowtex,shadowCoordinateWdivide.st).z;
float shadow = 1.0;
if (ShadowCoord.w > 0.0)
shadow = distanceFromLight < shadowCoordinateWdivide.z ? 0.5 :1.0 ;
return shadow ;
}
void main (void)
{
gl_FragColor =texture2D(tex, gl_TexCoord[0].st);
gl_FragColor.rgb *= getShadowFactor() ;//add shadows Here
}
The result ? all my scene is shadowed !
It looks like your code has an inconsistency between the texture setup and the shader. In the texture setup code, you have this:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
When GL_TEXTURE_COMPARE_FUNC is not GL_NONE, you need to use a shadow texture sampler in your shader code. But in your fragment shader, you use a regular sampler for this texture:
uniform sampler2D shadowtex;
This needs to be changed to this to be compatible with the texture settings:
uniform sampler2DShadow shadowtex;
To match the type, shadow2D() is then used instead of texture2D() to sample the texture.
The other option is that you keep GL_TEXTURE_COMPARE_FUNC at its default value of GL_NONE. This is then consistent with using a sampler2D for sampling.

Pointlight Shadow Cube Mapping

So i managed to create shadow maps for a directional light (extended at infinity). Now i am trying to create point light shadow cube map, so the shadows spread in the direction of the light->fragment. I created a new FBO like so:
//gen new fbo
glGenFramebuffers(1, &framebuffer_object);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_object);
//gen color texture
glGenTextures(1, &texture_color);
glBindTexture(GL_TEXTURE_2D, texture_color);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
//gen cubemap
glGenTextures(1, &shadow_cubemap);
glBindTexture(GL_TEXTURE_2D_ARRAY, shadow_cubemap);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
//bind color texture
unsigned int attachment_index_color_texture = 0;
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+attachment_index_color_texture, texture_color,0);
//add attachments
std::vector<GLenum> drawbuffers;
drawbuffers.push_back(GL_COLOR_ATTACHMENT0+attachment_index_color_texture);
glDrawBuffers(drawbuffers.size(),&drawbuffers[0]);
//check the fbo state
if(glCheckFramebufferStatus(GL_FRAMEBUFFER)!=GL_FRAMEBUFFER_COMPLETE){
std::cout<<"Error.FBO not integral."<<std::endl;
std::cin.get();
std::terminate();
}
//Unbind
glBindFramebuffer(GL_FRAMEBUFFER,0);
This function is called upon reshaping(so you could say at init time) reshape is called once at program start.
Next i create my light_view matrixes , each view for a different cube face, and my projection matrix like so :
//view matrix for +x
lightView_matrix[0]=glm::lookAt(light_position,light_position+glm::vec3(1,0,0),glm::vec3(0,1,0));
//view_matrix for -x
lightView_matrix[1]=glm::lookAt(light_position,light_position+glm::vec3(-1,0,0),glm::vec3(0,1,0));
//view_matrix for +z
lightView_matrix[2]=glm::lookAt(light_position,light_position+glm::vec3(0,0,1),glm::vec3(0,1,0));
//view_matrix for -z
lightView_matrix[3]=glm::lookAt(light_position,light_position+glm::vec3(0,0,-1),glm::vec3(0,1,0));
//view_matrix for +y
lightView_matrix[4]=glm::lookAt(light_position,light_position+glm::vec3(0,1,0),glm::vec3(0,0,-1));
//view_matrix for -y
lightView_matrix[5]=glm::lookAt(light_position,light_position+glm::vec3(0,-1,0),glm::vec3(0,0,1));
lightProjection_matrix = glm::perspective(90.0f, 1.0f, 0.5f, 140.0f);
Is the projection matrix ok? Should it be perspective when doing a cubemap instead of ortographic like i did for a directional light? I don't know if the values are ok : here is what i have, the width and height of the texture is 1366 x 768 which is my window size, my entire scene is from -70 to 70 on the z axis so 140 total,i chose a fov of pi/4 .
Moving on, to the first pass - hopefully generating the 6 faces of the cubemap:
cube_fbo.bind();
{
for(int i=0;i<6;i++){
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, cube_fbo.shadow_cubemap, 0);
//clear screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//use shader
glUseProgram(program_shader);
//send uniform values
glUniformMatrix4fv(glGetUniformLocation(program_shader,"light_view_matrix"),1,false,glm::value_ptr(lightView_matrix[i]));
glUniformMatrix4fv(glGetUniformLocation(program_shader,"light_projection_matrix"),1,false,glm::value_ptr(lightProjection_matrix));
//draw my objects with textures,i also have an alpha texture hence the has_alpha in the shaders (will post below )
}
}
//unbind fbo
cube_fbo.unbind();
Now the second pass which should draw the shadows based on the fragment position(should i do this in the drawing function or in the shader? )
{
//clear screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(program_shadow);
//send uniform values
glUniformMatrix4fv(glGetUniformLocation(program_shadow,"view_matrix"),1,false,glm::value_ptr(view_matrix));
glUniformMatrix4fv(glGetUniformLocation(program_shadow,"projection_matrix"),1,false,glm::value_ptr(projection_matrix));
glUniformMatrix4fv(glGetUniformLocation(program_shadow,"light_view_matrix"),1,false,glm::value_ptr(light_view_matrix));
glUniformMatrix4fv(glGetUniformLocation(program_shadow,"light_projection_matrix"),1,false,glm::value_ptr(light_projection_matrix));
glUniformMatrix4fv(glGetUniformLocation(program_shadow,"BiasMatrix"),1,false,glm::value_ptr(BiasMatrix));
glUniform3f(glGetUniformLocation(program_shadow,"light_position"),light_position.x,light_position.y,light_position.z);
//sphere at light position for reference------------------------
glUniformMatrix4fv(glGetUniformLocation(program_shadow,"model_matrix"),1,false,glm::value_ptr(light_model_matrix));
lab::drawSolidSphere(2,6,6);
//glEnable(GL_CULL_FACE);
//glCullFace(GL_BACK);
//ground----------------------------
glUniformMatrix4fv(glGetUniformLocation(program_shadow,"model_matrix"),1,false,glm::value_ptr(ground_model_matrix));
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, ground_texture);
glUniform1i( glGetUniformLocation(program_shadow, "textura1"), 1 );
glUniform1i( glGetUniformLocation(program_shadow, "has_alpha"), 0);
//glDisable(GL_CULL_FACE);
//send cubemap texture(GLuint bound in the first part (shadow_cubemap))
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_CUBE_MAP, cube_fbo[0].getCubeMapTexture());
glUniform1i(glGetUniformLocation(program_shadow, "textura_depth"), 2);
glBindVertexArray(ground_vao);
glDrawElements(GL_TRIANGLES, ground_num_indices, GL_UNSIGNED_INT, 0);
//bamboo(s)----------------------------
glActiveTexture(GL_TEXTURE0+1);
glBindTexture(GL_TEXTURE_2D, bamboo_texture_color);
glActiveTexture(GL_TEXTURE0+2);
glBindTexture(GL_TEXTURE_2D, bamboo_texture_alpha);
glUniform1i( glGetUniformLocation(program_shadow, "textura1"), 1 );
glUniform1i( glGetUniformLocation(program_shadow, "textura2"), 2 );
glUniform1i( glGetUniformLocation(program_shadow, "has_alpha"), 1);
//send cubemap texture
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, cube_fbo[0].getCubeMapTexture());
glUniform1i(glGetUniformLocation(program_shadow, "textura_depth"), 3);
glBindVertexArray(bamboo_vao);
for(int i=0;i<10;i++) for(int j=0;j<10;j++) {
if(j==5){
glUniformMatrix4fv(glGetUniformLocation(program_shadow,"model_matrix"),1,false,glm::value_ptr(bamboo_model_matrix[i*10+j]));
glDrawElements(GL_TRIANGLES, bamboo_num_indices, GL_UNSIGNED_INT, 0);
}
}
}
As you can see in this last part i draw from the camera position and pass to the shader the cubemap generate from the first pass. I have a few misunderstandings and probably some mistakes untill this point.
What do i return from the first pass (from the shader), when i did shadow mapping for a directional light i returned the depth (glFragcoord.z) but now i have to return a vec3 direction ? How do i compute that.Do i need something else to pass to the shader?
Is the second part ok ? Do i just draw the objects and pass the cube map to the shader and let him calculate which fragment is where in relation to the light ? If so , how do i compute this ?
Here is my shader for the first pass(so generate the cubemap from the 6 light views):
#version 330 /*VERTEX SHADER*\
layout(location = 0) in vec3 in_position;
layout(location = 2) in vec2 in_texcoord;
uniform mat4 model_matrix;
uniform mat4 light_view_matrix,light_projection_matrix;
out vec2 texcoord;
out vec4 v_position;
void main(){
texcoord = in_texcoord;
gl_Position = light_projection_matrix*light_view_matrix*model_matrix*vec4(in_position,1);
}
#version 330 /*FRAGMENT SHADER*\
layout(location = 0) out vec4 out_color;
//layout(location = 1) out float depth;
uniform sampler2D textura1;
uniform sampler2D textura2;
uniform int has_alpha;
in vec2 texcoord;
in vec4 v_position;
void main(){
vec3 tex1 = texture(textura1, texcoord).xyz;
vec3 tex2 = texture(textura2, texcoord).xyz;
if(has_alpha>0.5) if((tex2.r<0.1) && (tex2.g<0.1) && (tex2.b<0.1)) discard;
out_color = vec4(tex1, 1);
}
And the shader for the second pass (tried to calculate shadow by getting the vec3 from pixel position in world space - light position in world space)
#version 330 core /*VERTEX SHADER*\
layout(location = 0) in vec3 in_position;
layout(location = 1) in vec3 in_normal;
layout(location = 2) in vec2 in_texcoord;
out vec3 lightPosw;
out vec3 pixelPosw;
out vec2 texcoord;
uniform mat4 model_matrix,view_matrix,projection_matrix;
uniform vec3 light_position;
void main(){
texcoord=in_texcoord;
gl_Position = projection_matrix*view_matrix*model_matrix*vec4(in_position,1);
lightPosw= (model_matrix * vec4(light_position,1)).xyz;
pixelPosw = (model_matrix * vec4(in_position, 1)).xyz;
}
#version 330 core /*FRAGMENT SHADER*\
in vec3 lightPosw;
in vec3 pixelPosw;
in vec2 texcoord;
out vec4 out_color;
uniform samplerCube textura_depth;
uniform sampler2D textura1,textura2;
uniform mat4 view_matrix,model_matrix;
uniform int has_alpha;
void main(){
vec3 lightToPixel=pixelPosw-lightPosw;
vec3 tex1 = texture(textura1, texcoord).xyz;
vec3 tex2 = texture(textura2, texcoord).xyz;
if(has_alpha>0.5) if((tex2.r<0.1) && (tex2.g<0.1) && (tex2.b<0.1)) discard;
float shadowDepth = texture(textura_depth, normalize(lightToPixel));
float shadowFactor=1.0;
if(length(lightToPixel) < shadowDepth)
shadowFactor=0.5;
out_color = vec4(tex1*shadowFactor,1);
}
Sorry for the wall of code, i wanted to post all the relevant stuff so i can get better help. My problem is , everything renders semi-black, because i set the output color in the fragment shader to 0.5, if I wouldn't , then it all renders black.