1
\$\begingroup\$

I am fairly new to graphics programming, and I am working on a rudimentary game engine in C++. I had some old graphics code written in Java that I translated, but for some reason the shadows are not working. I have spent 5 hours staring at this code trying to figure out what's wrong.

My render code:

mat4 perspective(float fovy, float aspect, float n, float f)
{

    float q = 1.0f / ((float) tan(util::toRadians(0.5f * fovy)));
    float A = q / aspect;
    float B = (n + f) / (n - f);
    float C = (2.0f * n * f) / (n - f);
    mat4 r(A, 0, 0, 0,
           0, q, 0, 0,
           0, 0, B, C,
           0, 0, -1, 0);
    return r;

}

mat4 lookAt(point3 eye, point3 target, vec3 y)
{
    vec3 eyeV{eye};
    vec3 targetV(target);
    vec3 fwd = (targetV - eyeV).normalize();
    vec3 side = (fwd.cross(y)).normalize();
    vec3 up = (side.cross(fwd)).normalize();
    mat4 look{
        side[0], side[1], side[2], side.dot(eyeV * -1),
        up[0], up[1], up[2], up.dot(eyeV * -1),
        -fwd[0], -fwd[1], -fwd[2], (fwd * -1).dot(eyeV * -1),
        0, 0, 0, 1
    };
    return look;
}

Renderer::Renderer(int _width, int _height, std::string _title) : width(_width), height(_height), title(_title),
                   pMat(perspective(60.0f, (float)_width/(float)_height, 0.1f, 1000.0f))
{

    b = mat4{
        .5, 0, 0, .5,
        0, .5, 0, .5,
        0, 0, .5, .5,
        0, 0, 0, 1
    };

    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);                                              // Note 5 is max value atm
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    window = glfwCreateWindow(width, height, title.c_str(), NULL, NULL);

    if (window == NULL)
    {

        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        status = GLFW_WINDOW_ERROR;
        return;

    }
    glfwMakeContextCurrent(window);

    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to Initalize GLAD" << std::endl;
        status = GLAD_INIT_ERROR;
        return;
    }

    // TODO Shader error handling
    Shader _passoneshader("GLSL\\pass1.vert");
    pass1_shader = _passoneshader;

    Shader _shader("GLSL\\basic.vert", "GLSL\\basic.frag");
    basic_shader = _shader;

    Shader _texshader("GLSL\\textured_pass2.vert", "GLSL\\textured_pass2.frag");
    textured_shader = _texshader;

    glViewport(0, 0, 800, 600);

    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);

    float borderColor[] = { 1.0f, 1.0f, 0.0f, 1.0f };
    glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    glGenVertexArrays(1, &VAO);
    glBindVertexArray(VAO);

    StateManager& sm = StateManager::get();

    std::vector<Object> objects = sm.get_objects();
    std::vector<Object> tobjects = sm.get_textured_objects();

    VBO = (GLuint*) malloc(objects.size() * sizeof(GLuint));
    TVBO = (GLuint*) malloc(tobjects.size() * sizeof(GLuint));
    TCBO = (GLuint*) malloc(tobjects.size() * sizeof(GLuint));
    NBO = (GLuint*) malloc(tobjects.size() * sizeof(GLuint));
    std::cout << "size: " << objects.size() << std::endl;

    glGenBuffers(objects.size(), VBO);
    glGenBuffers(tobjects.size(), TVBO);
    glGenBuffers(tobjects.size(), TCBO);
    glGenBuffers(tobjects.size(), NBO);

//    for (int i = 0; i < objects.size(); ++i)
//    {
//      Object obj = objects[i];
//      std::cout << VBO[i] << std::endl;
//      glBindBuffer(GL_ARRAY_BUFFER, VBO[i]);
//      glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
//      glEnableVertexAttribArray(0);
//      std::vector<float> verts = obj.get_vertices();
//      float* vertices = &verts[0];
//      glBufferData(GL_ARRAY_BUFFER, verts.size() * sizeof(float), vertices, GL_STATIC_DRAW);
//    }

    shadow_buffer = (GLuint*) malloc(sizeof(GLuint));
    glGenFramebuffers(1, shadow_buffer);

    shadow_tex = (GLuint*) malloc(sizeof(GLuint));

    glGenTextures(1, shadow_tex);
//  glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, shadow_tex[0]);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT,
                 width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);

    glBindFramebuffer(GL_FRAMEBUFFER, shadow_buffer[0]);
    glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, shadow_tex[0], 0);

    glDrawBuffer(GL_NONE);
    glReadBuffer(GL_NONE);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    textures = (unsigned int*) malloc(tobjects.size() * sizeof(unsigned int));
    glGenTextures(tobjects.size(), textures);

    for (int i = 0; i < tobjects.size(); ++i)
    {

        Object obj = tobjects[i];

        int tex_width, tex_height, nrChannels;
        std::cout << obj.get_tex_path() << std::endl;
        unsigned char* data = stbi_load(obj.get_tex_path().c_str(), &tex_width, &tex_height, &nrChannels, 0);

        glBindTexture(GL_TEXTURE_2D, textures[i]);

        if (data)
        {
            std::cout << "got data" << std::endl;
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex_width, tex_height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
            glGenerateMipmap(GL_TEXTURE_2D);
        }
        else
        {
            std::cout << "Failed to load texture" << std::endl;
        }

        stbi_image_free(data);

        std::vector<float> verts = obj.get_vertices();
        float* vertices = &verts[0];
        std::vector<float> texcoords = obj.get_tex_coords();
        float* tex = &texcoords[0];
        std::vector<float> normals = obj.get_normals();
        float* norms = &normals[0];
//      glBindVertexArray(VAO);
        glBindBuffer(GL_ARRAY_BUFFER, TVBO[i]);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
        glEnableVertexAttribArray(0);
        glBufferData(GL_ARRAY_BUFFER, verts.size() * sizeof(float), vertices, GL_STATIC_DRAW);
        glBindBuffer(GL_ARRAY_BUFFER, TCBO[i]);
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
        glEnableVertexAttribArray(1);
        glBufferData(GL_ARRAY_BUFFER, texcoords.size() * sizeof(float), tex, GL_STATIC_DRAW);
        glBindBuffer(GL_ARRAY_BUFFER, NBO[i]);
        glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
        glEnableVertexAttribArray(2);
        glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(float), norms, GL_STATIC_DRAW);

    }


//  glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

    timeValue = glfwGetTime();
    lastTimeValue = timeValue;

    status = INITIALIZED;

}

void Renderer::RenderLoop()
{

    // input
    processInput();

    float depthClearVal[] = {1.0f};
//  depthClearVal[0] = 1.0f;
    glClearBufferfv(GL_DEPTH, 0, depthClearVal);

    // rendering commands
    glClearColor(.2f, .3f, .3f, 1.f);
    glClear(GL_COLOR_BUFFER_BIT);

    glEnable(GL_CULL_FACE);
    glFrontFace(GL_CCW);

    glClear(GL_DEPTH_BUFFER_BIT);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);

    glBindFramebuffer(GL_FRAMEBUFFER, shadow_buffer[0]);
    glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, shadow_tex[0], 0);

    glDrawBuffer(GL_NONE);
//  glReadBuffer(GL_NONE);
    glEnable(GL_DEPTH_TEST);

    glEnable(GL_POLYGON_OFFSET_FILL);   // for reducing
    glPolygonOffset(2.0f, 4.0f);        // shadow artifacts

//  std::cout << "before pass one" << std::endl;
    passOne();

    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    glDisable(GL_POLYGON_OFFSET_FILL);  // artifact reduction, continued

    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, shadow_tex[0]);

    glDrawBuffer(GL_FRONT);

//  std::cout << "before pass two" << std::endl;
    passTwo();

    glfwSwapBuffers(window);
    glfwPollEvents();

    status = LOOP_SUCCESS;  // TODO error handling on LOOP_FAILURE

}

void Renderer::passOne()
{

//  basic_shader.use();
    pass1_shader.use();

    StateManager& sm = StateManager::get();

    std::vector<Object> objects = sm.get_objects();
    std::vector<Object> tobjects = sm.get_textured_objects();

    PositionalLight light = sm.get_lights()[0]; // TODO allow more lights
    point3 light_pos = light.get_location();
    point3 target = light.get_target();
    vec3 up = vec3{light_pos * -1}.normalize() * mat4::rotation(mat4::X, 90);

    lightV_matrix = lookAt(light_pos, target, up);
    lightP_matrix = pMat;

    mat4 shadowMVP;

//  glUniformMatrix4fv(pmat_loc, 1, GL_TRUE, pMat.getFloatArray());

    int shadow_loc = glGetUniformLocation(pass1_shader.getID(), "shadowMVP");

//  for (int i = 0; i < objects.size(); ++i)
//  {
//      Object obj = objects[i];
//      mat4 mMat = obj.get_position().as_translation() * obj.get_rotation();
//      shadowMVP = mMat * lightV_matrix * lightP_matrix;
////        mat4 mvMat = vMat*mMat;
//      glUniformMatrix4fv(shadow_loc, 1, GL_TRUE, shadowMVP.getFloatArray());
//      glBindVertexArray(VAO);
//      glBindBuffer(GL_ARRAY_BUFFER, VBO[i]);
//      glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
//      glEnableVertexAttribArray(0);
//      glDrawArrays(GL_TRIANGLES, 0, obj.get_num_vertices() / 3);
//
//  }

    if (!tobjects.empty())
    {

        for (int i = 0; i < tobjects.size(); ++i)
        {

            Object obj = tobjects[i];
            mat4 mMat = obj.get_position().as_translation() * obj.get_rotation() * obj.get_scale();
//          mMat.print();
//          mat4 mMat = obj.get_scale() * obj.get_rotation() * obj.get_position().as_translation();
//          shadowMVP = mMat * lightV_matrix * lightP_matrix;
//          shadowMVP.print();
            shadowMVP = lightP_matrix * lightV_matrix * mMat;
            glUniformMatrix4fv(shadow_loc, 1, GL_TRUE, shadowMVP.getFloatArray());
//          glBindTexture(GL_TEXTURE_2D, textures[i]);
            glBindVertexArray(VAO);
            glBindBuffer(GL_ARRAY_BUFFER, TVBO[i]);
            glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
            glEnableVertexAttribArray(0);
//          glBindBuffer(GL_ARRAY_BUFFER, TCBO[i]);
//          glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
//          glEnableVertexAttribArray(1);
            glDrawArrays(GL_TRIANGLES, 0, obj.get_num_vertices() / 3);

        }

    }

}

void Renderer::passTwo()
{

//  basic_shader.use();
//  pass1_shader.use();

    glClear(GL_DEPTH_BUFFER_BIT);

    int pmat_loc = glGetUniformLocation(basic_shader.getID(), "proj_matrix");
    int mv_loc = glGetUniformLocation(basic_shader.getID(), "mv_matrix");
//
    StateManager& sm = StateManager::get();
//
//  std::vector<Object> objects = sm.get_objects();
    std::vector<Object> tobjects = sm.get_textured_objects();
    Camera camera = sm.get_camera();
    vMat = camera.get_transformation();

    mat4 shadowMVP;
//
//  glUniformMatrix4fv(pmat_loc, 1, GL_TRUE, pMat.getFloatArray());
//
//  for (int i = 0; i < objects.size(); ++i)
//  {
//      Object obj = objects[i];
//      mat4 mMat = obj.get_position().as_translation() * obj.get_rotation();
//      mat4 mvMat = vMat*mMat;
//      glUniformMatrix4fv(mv_loc, 1, GL_TRUE, mvMat.getFloatArray());
//      glBindVertexArray(VAO);
//      glBindBuffer(GL_ARRAY_BUFFER, VBO[i]);
//      glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
//      glEnableVertexAttribArray(0);
//      glDrawArrays(GL_TRIANGLES, 0, obj.get_num_vertices() / 3);
//
//  }

    if (!tobjects.empty())
    {

        textured_shader.use();

        pmat_loc = glGetUniformLocation(textured_shader.getID(), "proj_matrix");
        mv_loc = glGetUniformLocation(textured_shader.getID(), "mv_matrix");
        int sloc = glGetUniformLocation(textured_shader.getID(), "shadowMVP");

        glUniformMatrix4fv(pmat_loc, 1, GL_TRUE, pMat.getFloatArray());

        for (int i = 0; i < tobjects.size(); ++i)
        {

            Object obj = tobjects[i];
            mat4 mMat = obj.get_position().as_translation() * obj.get_rotation() * obj.get_scale();
//          mat4 mMat = obj.get_scale() * obj.get_rotation() * obj.get_position().as_translation();
            mat4 mvMat = vMat*mMat;
//          mat4 mvMat = mMat*vMat;
            installLights(textured_shader);
            glUniformMatrix4fv(mv_loc, 1, GL_TRUE, mvMat.getFloatArray());
            shadowMVP = mMat * lightV_matrix * lightP_matrix * b;
//          shadowMVP = b * lightP_matrix * lightV_matrix * mMat;
            glUniformMatrix4fv(sloc, 1, GL_TRUE, shadowMVP.getFloatArray());
            glActiveTexture(GL_TEXTURE2);
            glBindTexture(GL_TEXTURE_2D, textures[i]);
            glBindVertexArray(VAO);
            glBindBuffer(GL_ARRAY_BUFFER, TVBO[i]);
            glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
            glEnableVertexAttribArray(0);
            glBindBuffer(GL_ARRAY_BUFFER, TCBO[i]);
            glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
            glEnableVertexAttribArray(1);
            glBindBuffer(GL_ARRAY_BUFFER, NBO[i]);
            glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
            glEnableVertexAttribArray(2);
            glDrawArrays(GL_TRIANGLES, 0, obj.get_num_vertices() / 3);

        }

    }

}

void Renderer::installLights(Shader current_shader)
{

    StateManager& sm = StateManager::get();

    PositionalLight currentLight = sm.get_lights()[0];

    point3 lightP = currentLight.get_location();
    point3 lightPv = lightP * vMat;
//  float [] viewspaceLightPos = new float[] { (float) lightPv.getX(), (float) lightPv.getY(), (float) lightPv.getZ() };
    std::array<float, 3> viewspaceLightPos = lightPv.get_array();

    // set the current globalAmbient settings
    int globalAmbLoc = glGetUniformLocation(textured_shader.getID(), "globalAmbient");
    float globalAmbient[] = {.2f, .2f, .2f, 1.0f};
    glUniform4fv(globalAmbLoc, 1, globalAmbient);

    // get the locations of the light and material fields in the shader
    int ambLoc = glGetUniformLocation(current_shader.getID(), "light.ambient");
    int diffLoc = glGetUniformLocation(current_shader.getID(), "light.diffuse");
    int specLoc = glGetUniformLocation(current_shader.getID(), "light.specular");
    int posLoc = glGetUniformLocation(current_shader.getID(), "light.position");
    int MambLoc = glGetUniformLocation(current_shader.getID(), "material.ambient");
    int MdiffLoc = glGetUniformLocation(current_shader.getID(), "material.diffuse");
    int MspecLoc = glGetUniformLocation(current_shader.getID(), "material.specular");
    int MshiLoc = glGetUniformLocation(current_shader.getID(), "material.shininess");

    std::array<float, 4> amb = currentLight.get_ambient().get_array();
    std::array<float, 4> diff = currentLight.get_diffuse().get_array();
    std::array<float, 4> spec = currentLight.get_specular().get_array();
    //  set the uniform light and material values in the shader
    glUniform4fv(ambLoc, 1, &amb[0]);
    glUniform4fv(diffLoc, 1, &diff[0]);
    glUniform4fv(specLoc, 1, &spec[0]);
    glUniform3fv(posLoc, 1, &viewspaceLightPos[0]);

    // Values taken from graphicslib3d Material.SILVER
    float matAmb[] = {0.1923f, 0.1923f, 0.1923f, 1.0f};
    float matDiff[] = {0.5075f, 0.5075f, 0.5075f, 1.0f};
    float matSpec[] = {0.5083f, 0.5083f, 0.5083f, 1.0f};
    float matShine = 51.2;

    glUniform4fv(MambLoc, 1, matAmb);
    glUniform4fv(MdiffLoc, 1, matDiff);
    glUniform4fv(MspecLoc, 1, matSpec);
    glUniform1f(MshiLoc, matShine);

}

const bool Renderer::shouldLoop() const
{

    return !glfwWindowShouldClose(window);

}

My pass 1 vertex shader:

#version 450 core

layout (location=0) in vec3 vertPos;

uniform mat4 shadowMVP;

void main(void)
{
    gl_Position = shadowMVP * vec4(vertPos,1.0);
}

My pass 2 vertex shader:

#version 450 core

layout (location=0) in vec3 vertPos;
layout (location=1) in vec2 tex_coord;
layout (location=2) in vec3 vertNormal;

out vec3 vNormal, vLightDir, vVertPos, vHalfVec;
out vec4 shadow_coord;
out vec2 tc;

struct PositionalLight
{
    vec4 ambient, diffuse, specular;
    vec3 position;
};
struct Material
{
    vec4 ambient, diffuse, specular;
    float shininess;
};

uniform vec4 globalAmbient;
uniform PositionalLight light;
uniform Material material;
uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
uniform mat4 shadowMVP;
layout (binding=1) uniform sampler2DShadow shadowTex;
layout (binding=2) uniform sampler2D s;

void main(void)
{
    //output the vertex position to the rasterizer for interpolation
    vVertPos = (mv_matrix * vec4(vertPos,1.0)).xyz;

    //get a vector from the vertex to the light and output it to the rasterizer for interpolation
    vLightDir = light.position - vVertPos;

    //get a vertex normal vector in eye space and output it to the rasterizer for interpolation
    mat4 normalMat = transpose(inverse(mv_matrix));
    vNormal = (normalMat * vec4(vertNormal,1.0)).xyz;

    // calculate the half vector (L+V)
    vHalfVec = (vLightDir-vVertPos).xyz;

    shadow_coord = shadowMVP * vec4(vertPos,1.0);

    tc = tex_coord;

    gl_Position = proj_matrix * mv_matrix * vec4(vertPos,1.0);
}

My pass 2 fragment shader:

#version 450

in vec3 vNormal, vLightDir, vVertPos, vHalfVec;
in vec4 shadow_coord;
in vec2 tc;
out vec4 fragColor;

struct PositionalLight
{
    vec4 ambient, diffuse, specular;
    vec3 position;
};

struct Material
{
    vec4 ambient, diffuse, specular;
    float shininess;
};

uniform vec4 globalAmbient;
uniform PositionalLight light;
uniform Material material;
uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
uniform mat4 shadowMVP;
layout (binding=1) uniform sampler2DShadow shadowTex;
layout (binding=2) uniform sampler2D s;

void main(void)
{
    vec3 L = normalize(vLightDir);
    vec3 N = normalize(vNormal);
    vec3 V = normalize(-vVertPos);
    vec3 H = normalize(vHalfVec);
    float inShadow = textureProj(shadowTex, shadow_coord);

    vec4 texColor = texture(s, tc);

    fragColor = texColor*(globalAmbient + light.ambient + light.diffuse * max(dot(L,N), 0.0));
//    fragColor = vec4(0,0,0,0);
    if (inShadow != 0.0) {
        fragColor += light.diffuse * material.diffuse * max(dot(L, N), 0.0)
        + light.specular * material.specular
        * pow(max(dot(H, N), 0.0), material.shininess*3.0);
    }

}

When I open it up in renderdoc, the shadow texture appears to be all black, so I think it just isn't writing the texture properly, but I'm not sure. I appreciate any help.

Edit:

Render doc capture file: https://www.dropbox.com/s/zdxobai3ce86eod/capture.rdc?dl=0

\$\endgroup\$
  • \$\begingroup\$ Can you give us the renderdoc capture file, maybe we'll figure something out? \$\endgroup\$ – HolyBlackCat May 1 at 21:11
  • \$\begingroup\$ @HolyBlackCat Done \$\endgroup\$ – Kamakwazee May 1 at 23:07
  • 1
    \$\begingroup\$ Your shadow map appear to be full of 0. You are not clearing it properly before rendering to it. \$\endgroup\$ – gan_ May 2 at 14:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.