Jump to content

  • Log In with Google      Sign In   
  • Create Account

Phil123

Member Since 08 Jul 2012
Offline Last Active Yesterday, 10:29 PM

Topics I've Started

Stencil Shadow Volume Problems

24 December 2014 - 12:08 PM

Hey everyone,

 

I've been working on implementing stencil shadow volumes in OpenGL, and I've ran into some complications.  What I want to do is simply draw my shadow volumes to the stencil buffer, and then I'll shade the scene a bit brighter (depending on the lighting calculations of course) in any areas that the shadow volumes don't consume.  The problem I'm experiencing is that the values in my stencil buffer always equal 0, and as such, my entire scene (instead of select parts) gets brighter.

 

 

Here's the high level overview of what's going on:

 

1. I render the scene's objects' positions, normals, and colours to individual textures using a framebuffer object (FBO).

2. I render the ambient lighting for the scene to the default window's FBO.  This pass only writes to the colour buffer.

3. I render the shadow volumes (which I create in a geometry shader) to the default window's FBO.  This pass only writes to the stencil buffer.

4. I render the scene (using the stored values in the framebuffer object textures) and apply lighting.  This pass only writes to the colour buffer (for the default window's FBO) and uses additive blending to add any previous lighting that has been applied.

5. I would do #3 and #4 for each light in the scene.  For now, I only have one light so I'm only making one pass through for #3 and #4.

 

Here's what it currently looks like: http://puu.sh/dHXcN/efef32c2d6.jpg

Here's what it looks like with shadow volumes drawing: http://puu.sh/dHXhR/b664d05370.png

 

Note that the light is directly above the model at (0, 5, 0), and the model itself is at (0, 0, 0), so the shadow volumes extend downward.  The light is treated as an infinite point light for prototyping purposes.

 

I'm not sure what I'm doing wrong with the stencil buffer, but all of its values end up being 0 despite the Z-Fail tests that are configured before the shadow volume creation pass.  I've read a few articles and various snippets of code to aid in the implementation of this technique, but to no success.  It's possible the triangle winding order is flipped (clockwise instead of counterclockwise) for the shadow volumes - though even that seems like a bit of a stretch as there has to be something else wrong with this code (despite the simplicity of this technique).  At this point, I'm hoping it's some small stupid thing I missed.

 

Here's the source code (some of it has been omitted for clarity).  For my sanity, certain things are explicitly set at the beginning of each section.


    ///////////////////////////////////////////////////////////////////////////////////////////////

    // Render To FBO

    ///////////////////////////////////////////////////////////////////////////////////////////////

    glDisable(GL_BLEND);

    glEnable(GL_DEPTH_TEST);

    glDisable(GL_STENCIL_TEST);



    // GL_BLEND Changes - N/A

    glDepthMask(GL_TRUE);

    // GL_STENCIL Changes - N/A



    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, GBufferObj.FBO);

    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);



    std::array<GLenum, EGBufferTexture::COUNT> DrawBuffers = {

        GL_COLOR_ATTACHMENT0,

        GL_COLOR_ATTACHMENT1,

        GL_COLOR_ATTACHMENT2

    };



    glDrawBuffers(DrawBuffers.size(), &DrawBuffers[0]);



    Shaders[EShader_Test::GBUFF_PASS].Use();
 
// Uniform locations are asserted here in order to ensure everything is working properly. (Removed for clarity).
// Uniform values are set for the shader here.  (Removed for clarity).
 
    glActiveTexture(GL_TEXTURE0);



    for (size_t I = 0; I < Models.size(); ++I) {

        glUniformMatrix4fv(Shaders[EShader_Test::GBUFF_PASS].GetUniform("uModel"), 1, GL_FALSE, glm::value_ptr(Matrices[I]));



        for (auto& Mesh : Models[I]->GetMeshes()) {

            glBindVertexArray(Mesh.GetVAO());

            glBindTexture(GL_TEXTURE_2D, Mesh.GetMap(EGLMeshMap::DIFFUSE)->GetID());

            glDrawElements(GL_TRIANGLES, Mesh.GetIndexCount(), GL_UNSIGNED_INT, nullptr);

            glBindVertexArray(0);

        }

    }



    ///////////////////////////////////////////////////////////////////////////////////////////////

    // Render Ambient Lighting

    ///////////////////////////////////////////////////////////////////////////////////////////////

    glEnable(GL_BLEND);

    glDisable(GL_DEPTH_TEST);

    glDisable(GL_STENCIL_TEST);



    glBlendFunc(GL_ONE, GL_ONE);

    // GL_DEPTH Changes - N/A

    // GL_STENCIL Changes - N/A



    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    glBindFramebuffer(GL_READ_FRAMEBUFFER, GBufferObj.FBO);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);



    const glm::vec3 CameraPos = PersCam->GetPosition();



    Shaders[EShader_Test::SCREEN_AMBIENT].Use();
 
// Uniform locations are asserted here in order to ensure everything is working properly. (Removed for clarity).
// Uniform values are set for the shader here.  (Removed for clarity).


    glActiveTexture(GL_TEXTURE0);

    glBindTexture(GL_TEXTURE_2D, GBufferObj.Textures[EGBufferTexture::POSITION]);

    glActiveTexture(GL_TEXTURE1);

    glBindTexture(GL_TEXTURE_2D, GBufferObj.Textures[EGBufferTexture::DIFFUSE]);

    glActiveTexture(GL_TEXTURE2);

    glBindTexture(GL_TEXTURE_2D, GBufferObj.Textures[EGBufferTexture::NORMAL]);



    glBindVertexArray(ScreenVAO);

    glDrawArrays(GL_QUADS, 0, 4);

    glBindVertexArray(0);



    ///////////////////////////////////////////////////////////////////////////////////////////////

    // Render Shadow Volume (1st Light)

    ///////////////////////////////////////////////////////////////////////////////////////////////

    glDisable(GL_BLEND);

    glEnable(GL_DEPTH_TEST);

    glEnable(GL_STENCIL_TEST);



    // GL_BLEND Changes - N/A

    glDepthMask(GL_FALSE);

    glStencilFunc(GL_ALWAYS, 0x00, 0xFF);

    glStencilOpSeparate(GL_BACK, GL_KEEP, GL_INCR_WRAP, GL_KEEP);

    glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_DECR_WRAP, GL_KEEP);

    glStencilMask(0xFF);



    Shaders[EShader_Test::SHADOW_VOLUME].Use();
 
// Uniform locations are asserted here in order to ensure everything is working properly. (Removed for clarity).
// Uniform values are set for the shader here.  (Removed for clarity).


    glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);



    for (size_t I = 0; I < Models.size(); ++I) {

        glUniformMatrix4fv(Shaders[EShader_Test::SHADOW_VOLUME].GetUniform("uModel"), 1, GL_FALSE, glm::value_ptr(Matrices[I]));



        for (auto& Mesh : Models[I]->GetMeshes()) {

            glBindVertexArray(Mesh.GetVAO());

            glDrawElements(GL_TRIANGLES, Mesh.GetIndexCount(), GL_UNSIGNED_INT, nullptr);

            glBindVertexArray(0);

        }

    }



    glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);



    ///////////////////////////////////////////////////////////////////////////////////////////////

    // Render With Lighting & Stencil Read (1st Light)

    ///////////////////////////////////////////////////////////////////////////////////////////////

    glEnable(GL_BLEND);

    glDisable(GL_DEPTH_TEST);

    glEnable(GL_STENCIL_TEST);



    glBlendFunc(GL_ONE, GL_ONE);

    // GL_DEPTH Changes - N/A

    glStencilFunc(GL_EQUAL, 0x00, 0xFF);

    glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

    glStencilMask(0x00);



    Shaders[EShader_Test::SCREEN].Use();
 
// Uniform locations are asserted here in order to ensure everything is working properly. (Removed for clarity).
// Uniform values are set for the shader here.  (Removed for clarity).



    glActiveTexture(GL_TEXTURE0);

    glBindTexture(GL_TEXTURE_2D, GBufferObj.Textures[EGBufferTexture::POSITION]);

    glActiveTexture(GL_TEXTURE1);

    glBindTexture(GL_TEXTURE_2D, GBufferObj.Textures[EGBufferTexture::DIFFUSE]);

    glActiveTexture(GL_TEXTURE2);

    glBindTexture(GL_TEXTURE_2D, GBufferObj.Textures[EGBufferTexture::NORMAL]);



    glBindVertexArray(ScreenVAO);

    glUniform3f(Shaders[EShader_Test::SCREEN_AMBIENT].GetUniform("uLightPos"), 0.0f, 5.0f, 0.0f);

    glDrawArrays(GL_QUADS, 0, 4);

    glBindVertexArray(0);



    ///////////////////////////////////////////////////////////////////////////////////////////////

    // Swap Buffers

    ///////////////////////////////////////////////////////////////////////////////////////////////

    Window->GL_SwapWindow();

Particle Systems & Handling Transparency

27 November 2014 - 12:14 PM

Hey everyone,

 

I've been studying OpenGL/Graphics for a short while now and I'm in the process of working on a simple rendering pipeline for my (basic) game engine.  From what I understand (and please correct me if my understanding is not entirely accurate), the high level overview of a simple rendering pipeline might look like this:

 

- Add all non-transparent objects to a queue, and sort them front to back based on their distance from the camera (as fragments are discarded if they fail the depth test).

- Or instead do some sorting based on which shader and textures various objects use to minimize OpenGL state changes.  (I'm not entirely sure which sorting method to use for the best performance but this isn't the main issue here).

- Add transparent objects to a 2nd queue, and sort them back to front based on their distance from the camera (so the proper effects show up on screen as a result of the transparency).

- Cull any objects (as they are added to the queues) that won't be seen anyway so there aren't any wasted draw calls. (As far as I know, primitives are discarded if they aren't within screen space anyways but at that point you've already spent some processing time calling draw and running the vertex shader so it ends up being worth it).

- Render all of the non-transparent objects in the queue, and then render all of the transparent objects in the other queue.

 

I understand there are some issues with drawing transparent objects, and that's what's led me to post this today.  My question is as follows:

 

- How do you handle rendering multiple particle systems that are working with different textures?  It seems like a clean (object oriented) solution to have one particle system responsible for a single type of particle, but then sorting the particles properly becomes a problem when you introduce multiple particle systems.  If you had every single particle in one container, then it seems like you have even more problems because different particle systems may have different data requirements.

 

I'm sure there's a simple and elegant solution here that I can't see due to my lack of experience with graphics programming.  Any ideas/suggestions?


Getting ASSIMP Working/Building

19 August 2014 - 10:22 AM

I've been trying to get ASSIMP working in my OpenGL4 project (Visual Studio 2013 as the IDE) and despite attempts at various methods it just doesn't want to cooperate.  The first method I tried was downloading the Windows binary files http://sourceforge.net/projects/assimp/files/assimp-3.1/ and setting it up the way I've set up numerous other libraries for use in my project http://puu.sh/aZ7Ak/a76c24e558.png http://puu.sh/aZ7B7/9ff180171f.png .

 

This resulted in an odd error that would pop up when running the project that's attempting to use ASSIMP functions and data structures. http://puu.sh/aZ7m6/18ee88b7b4.jpg .  Not only is assimp.exe on my computer, but the only files that should be required (to my knowledge...unless ASSIMP is different somehow) are the .dll, .h (and sometimes some implementation files), and .lib files (which I put into respectively into the bin, include, and lib folders referenced in that screenshot above).

 

Since that didn't work, I then tried to build it myself using CMake (as researching that issue didn't turn up enough relevant information to fix the error).  I downloaded the zip file that they have for use in CMake (again, via http://sourceforge.net/projects/assimp/files/assimp-3.1/ )  I've used CMake before so I thought this wouldn't be a problem but the build fails, so I went to their website and explicitly followed their instructions http://assimp.sourceforge.net/lib_html/cmake_build.html but the build still fails.  One thing of note is that they mention "Point it to the location of the assimp source code. The UI should now look like the screenshot above" but this doesn't occur for me. http://puu.sh/aZ8Gj/0c97c99d42.png .  Regardless of what I do (I have even tried specifying those values myself), I end up with the same error http://puu.sh/aZ8Yh/dc12f15480.jpg .

 

The text error message seems to indicate a problem with their CMakeLists.txt file itself (CMake Error at CMakeLists.txt:725 (INSTALL): install TARGETS given no ARCHIVE DESTINATION for static library target "assimp") though I'm not entirely sure.

 

Any suggestions?


Industrial Strength Hash Table

12 March 2014 - 12:26 PM

I've been enjoying the coding horrors forum for a while, so I decided to post a snippet of code that I found in a large c++ project that I'm (unfortunately) a part of.  Normally I wouldn't poke fun at code like this, but I couldn't resist this one.

 

Enjoy.

#pragma once

#include "Includes.h"



template<class T>

class Dictionary

{

private:

    std::vector<std::string> keys;

    std::vector<T> values;

public:

    Dictionary()

    {

        keys = new std::vector<std::string>{};

        values = new std::vector<T>{};

    }



    ~Dictionary()

    {

        delete[] keys;

        delete[] values;

    };



    std::vector* Values() { return &values; };

    std::vector* Keys() { return &keys; };



    size_t size() { return keys.size(); }



    void Add(std::string _key, T value)

    {

        keys.push_back(_key);

        values.push_back(value);

    };

    void Remove(std::string _key)

    {

        for (size_t i = 0; i < keys.size(); i++)

        {

            if (keys.at(i) == _key)

            {

                keys.erase(keys.begin() + i);

                values.erase(values.begin() + i);

                break;

            }

        }

    };

    T Get(std::string _key)

    {

        for (size_t i = 0; i < keys.size(); i++)

        {

            if (keys.at(i) == _key)

            {

                return values.at(i);

            }

        }

        return nullptr;

    };

};


XNA Access Violation Exception

30 April 2013 - 09:38 PM

System.AccessViolationException was unhandled
  Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
  Source=Microsoft.Xna.Framework
  StackTrace:
       at Microsoft.Xna.Framework.Audio.AudioCallbackDispatcher.IsEventRegistered(EventType type)
       at Microsoft.Xna.Framework.Audio.AudioCallbackDispatcher.UnregisterEvent(EventType type)
       at Microsoft.Xna.Framework.Audio.KernelMicrophone.ShutdownCaptureEngine()
       at Microsoft.Xna.Framework.Audio.MicrophoneUnsafeNativeMethods.ShutdownCaptureEngine()
       at Microsoft.Xna.Framework.Audio.AudioRendererShutdownHandler.AppExitingEventHandler(Object sender, EventArgs args)
  InnerException:
 

Every now and then, I get a System.AccessViolationException when closing the program and all the information I'm given is above.  I suppose it isn't really an issue as if the program crashes when I'm closing it, so it probably isn't the absolute end of the world (compared to it crashing during run time).  But I still would prefer for this to not happen.  Unfortunately, I don't know what's directly causing it, and I'm not sure it'd be helpful to post my audio manager classes either since the problem seems to be within the framework itself.

 

Any ideas?


PARTNERS