This is driving me nuts! I've not done much with OpenGL before, so any pointers appreciated.
Can anyone tell me any reason why some of my objects appear in my shadow map, and others don't?
I have 2 object I am rendering; southernHemisphere and Frame. Both of these are rendered to the scene and to the shadow map texture. The scene is working perfectly showing all objects, but only southernHemisphere is appearing in the shadow map.
My shadow map texture is bound like this:
- (void)setupShadowmapBuffers {
glGenTextures(1, &_shadowTexture);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, _shadowTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1024, 1024, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
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_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glGenFramebuffers(1, &_shadowFBO);
glGenRenderbuffers(1, &_shadowRenderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, _shadowRenderBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, 1024, 1024);
glBindFramebuffer(GL_FRAMEBUFFER, _shadowFBO);
glBindTexture(GL_TEXTURE_2D, _shadowTexture);
glFramebufferRenderbuffer(GL_FRAMEBUFFER,
GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER,
_shadowRenderBuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _shadowTexture, 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
printf("Error: FrameBufferObject is not complete!\n");
}
}
In my render function, I render to the shadow map texture:
// Render the shadow map
glUseProgram(_shadowProgramHandle);
glUniformMatrix4fv(_shadowProjectionUniform, 1, 0, LSprojection.glMatrix);
glUniformMatrix4fv(_shadowLightMPVUniform, 1, 0, lightsourcemat.glMatrix);
glBindFramebuffer(GL_FRAMEBUFFER, _shadowFBO);
glBindRenderbuffer(GL_RENDERBUFFER, _shadowRenderBuffer);
glClearColor(0,0,0,0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, 1024, 1024);
glUniformMatrix4fv(_shadowModelViewUniform, 1, 0, southernHemispheremat.glMatrix);
[self drawSouthernHemisphere];
glUniformMatrix4fv(_shadowModelViewUniform, 1, 0, framemat.glMatrix);
[self drawFrame];
Then I render to the scene:
// Reset buffers and finally render the scene
glUseProgram(_mainProgramHandle);
glBindFramebuffer(GL_FRAMEBUFFER, msaaFramebuffer);
glBindRenderbuffer(GL_RENDERBUFFER, msaaRenderBuffer);
glClearColor(0,0,0,0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, vFrame.size.width, vFrame.size.height);
glUniformMatrix4fv(_modelViewUniform, 1, 0, shadowmat.glMatrix);
[self drawShadow];
glUniformMatrix4fv(_modelViewUniform, 1, 0, southernHemispheremat.glMatrix);
[self drawSouthernHemisphere];
glUniformMatrix4fv(_modelViewUniform, 1, 0, framemat.glMatrix);
[self drawFrame];
My drawing functions look like this:
- (void)drawSouthernHemisphere {
// Southern Hemisphere
glEnable(GL_CULL_FACE);
glBindTexture(GL_TEXTURE_2D, _globeTexture);
glBindVertexArrayOES(_southernHemisphere);
// Draw outside (textured)
glUniform1f(_useTextureSlot, 1);
glCullFace(GL_BACK);
glDrawElements(GL_TRIANGLES, sizeof(Southern)/sizeof(Southern[0]), GL_UNSIGNED_SHORT, 0);
// Draw inside (coloured)
glCullFace(GL_FRONT);
glUniform1f(_useTextureSlot, 0);
glUniform4f(_runTimeColorSlot, 0, 0, 0, 0);
glDrawElements(GL_TRIANGLES, sizeof(Southern)/sizeof(Southern[0]), GL_UNSIGNED_SHORT, 0);
glBindVertexArrayOES(0);
}
- (void)drawFrame {
// Frame
glEnable(GL_CULL_FACE);
glBindTexture(GL_TEXTURE_2D, _frameTexture);
glBindVertexArrayOES(_frame);
// Draw outside (textured)
glUniform1f(_useTextureSlot, 1);
glCullFace(GL_BACK);
glDrawElements(GL_LINES, sizeof(Frame)/sizeof(Frame[0]), GL_UNSIGNED_SHORT, 0);
glBindVertexArrayOES(0);
}
Thanks.
EDIT:
I have isolated the issue being down to my vertex arrays - in particular the normals.
I swapped the values in the frame array with the ones in my southernHemisphere array, and bingo - the object appears in both the scene, and the shadow map!
After some adjustment of values, it appears that it will only work if the direction of the normals are the same as the direction of each vector itself.
What baffles me is that in my shadow map shader, I don't even access the normals so why do they have any effect on the rendering at all??
Here is my vertex shader for my shadow map:
attribute vec4 Position;
uniform mat4 Projection;
uniform mat4 Modelview;
uniform mat4 Light;
varying vec4 TexCoord;
void main()
{
TexCoord = Projection * Light * Modelview * Position;
gl_Position = Projection * Light * Modelview * Position;
}
and fragment:
precision mediump float;
varying vec4 TexCoord;
void main()
{
/* Generate shadow map - write fragment depth. */
float value = 10.0 - TexCoord.z;
float v = floor(value);
float f = value - v;
float vn = v * 0.1;
gl_FragColor = vec4(vn, f, 0.0, 1.0);
}
EDIT2:
Here are my set up function for VAOs
// Southern Hemisphere
glGenVertexArraysOES(1, &_southernHemisphere);
glBindVertexArrayOES(_southernHemisphere);
GLuint vb2;
glGenBuffers(1, &vb2);
glBindBuffer(GL_ARRAY_BUFFER, vb2);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(_positionSlot);
glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Position));
glEnableVertexAttribArray(_colorSlot);
glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Color));
glEnableVertexAttribArray(_normalSlot);
glVertexAttribPointer(_normalSlot, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal));
glEnableVertexAttribArray(_texCoordSlot);
glVertexAttribPointer(_texCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, TexCoord));
GLuint southernBuffer;
glGenBuffers(1, &southernBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,southernBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Southern) * sizeof(Southern[0]), Southern, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArrayOES(0);
// Frame
glGenVertexArraysOES(1, &_frame);
glBindVertexArrayOES(_frame);
GLuint vb4;
glGenBuffers(1, &vb4);
glBindBuffer(GL_ARRAY_BUFFER, vb4);
glBufferData(GL_ARRAY_BUFFER, sizeof(Frame_Vertices), Frame_Vertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(_positionSlot);
glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Position));
glEnableVertexAttribArray(_colorSlot);
glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Color));
glEnableVertexAttribArray(_normalSlot);
glVertexAttribPointer(_normalSlot, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal));
glEnableVertexAttribArray(_texCoordSlot);
glVertexAttribPointer(_texCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, TexCoord));
GLuint legsBuffer;
glGenBuffers(1, &frameBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,frameBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Frame) * sizeof(Frame[0]), Frame, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArrayOES(0);
My Arrays all follow the same form of:
const Vertex Vertices[] = {
{{0.0000,-1.5000,0.0000},{0.3843137254902,0.14117647058824,0.082352941176471,1},{0.0000,-1.0000,0.0000},{0.0000,1.0000}},
{{0.0000,-1.4872,0.1958},{0.3843137254902,0.14117647058824,0.082352941176471,1},{0.0000,-0.9914,0.1305},{0.0000,0.9583}},
....
}
which consists of Position, Colour, Normal, Texture Coordinates as you can see from the set up code.
After my shaders are linked, I finish set up with these:
- (void)useMainProgram:(GLfloat[])lightsource {
const GLfloat l_ambient = 0.7;
glUseProgram(_mainProgramHandle);
_positionSlot = glGetAttribLocation(_mainProgramHandle, "Position");
_colorSlot = glGetAttribLocation(_mainProgramHandle, "Color");
_normalSlot = glGetAttribLocation(_mainProgramHandle, "Normal");
_lightingSlot = glGetUniformLocation(_mainProgramHandle, "l1");
_ambientLightingSlot = glGetUniformLocation(_mainProgramHandle, "l_ambient");
_texCoordSlot = glGetAttribLocation(_mainProgramHandle, "TexCoordIn");
_useTextureSlot = glGetUniformLocation(_mainProgramHandle, "use_texture");
_runTimeColorSlot = glGetUniformLocation(_mainProgramHandle, "RunTimeColor");
glEnableVertexAttribArray(_positionSlot);
glEnableVertexAttribArray(_colorSlot);
glEnableVertexAttribArray(_normalSlot);
glEnableVertexAttribArray(_texCoordSlot);
_projectionUniform = glGetUniformLocation(_mainProgramHandle, "Projection");
_modelViewUniform = glGetUniformLocation(_mainProgramHandle, "Modelview");
for (int i=0;i<_num_bottles; i++){
_bottlesUniform[i] = glGetUniformLocation(_mainProgramHandle, "Modelview");
}
_textureUniform = glGetUniformLocation(_mainProgramHandle, "Texture");
// Lighting doesn't change, so we set it here.
glUniform3fv(_lightingSlot, 1, lightsource);
glUniform1fv(_ambientLightingSlot, 1, &l_ambient);
}
- (void)useShadowProgram:(GLfloat[])lightsource {
glUseProgram(_shadowProgramHandle);
_shadowPositionSlot = glGetAttribLocation(_shadowProgramHandle, "Position");
_shadowLightMPVUniform = glGetUniformLocation(_shadowProgramHandle, "Light");
_shadowProjectionUniform = glGetUniformLocation(_shadowProgramHandle, "Projection");
_shadowModelViewUniform = glGetUniformLocation(_shadowProgramHandle, "Modelview");
glEnableVertexAttribArray(_shadowPositionSlot);
}