diff --git a/CMakeLists.txt b/CMakeLists.txt index d72a5b9..ead39d4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,8 +56,8 @@ ADD_DEFINITIONS(-DNO_SPACE_NAVIGATOR_SUPPORT) SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} -DSAXUM_DEBUG -g") SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} -DSAXUM_DEBUG -g") -SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -O2") -SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS} -O2") +SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -O2 -DNDEBUG") +SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS} -O2 -DNDEBUG") set(dir ${CMAKE_CURRENT_SOURCE_DIR}/binaries) set(EXECUTABLE_OUTPUT_PATH ${dir} CACHE PATH "Build directory" FORCE) diff --git a/data/shader/phong.fsh b/data/shader/phong.fsh index 88c5207..ee2a029 100644 --- a/data/shader/phong.fsh +++ b/data/shader/phong.fsh @@ -272,7 +272,7 @@ void main() for(int i = 0; ivalidate(); } - - // always generate and bind all cube maps, because otherwise the shader won't work depth_cubeMaps = std::vector(maxShadowSampleCount); for (unsigned int i = 0; iuse(); skydomeShader->setUniform("farPlane", farPlane); @@ -197,6 +193,7 @@ void Graphics::init(Level* level) { lightingShader->setUniform("fogColorRise", level->getFogColourRise()); lightingShader->setUniform("fogColorNight", level->getFogColourNight()); lightingShader->setUniform("ambientColor", level->getAmbientLight()); + if(level->getDirectionalLight()) { lightingShader->setUniform("directionalLightVector", level->getDirectionalLight()->getPosition()); @@ -210,10 +207,14 @@ void Graphics::init(Level* level) { depthCubeShader->setUniform("farPlane", farPlane); level->sortObjects(Material::getAllTextures()->size()); + #ifdef SAXUM_DEBUG std::cout << "There were " << Material::getAllTextures()->size() << " materials used in this level." << std::endl; #endif + + initShadowRenderQueue(); + updateLights(); } void Graphics::bindTextureUnits(){ @@ -338,6 +339,32 @@ void Graphics::render(double time) // At first render shadows std::vector depthViewProjectionMatrices = std::vector(framebuffer_directional.size()); if (renderShadows) { + // update priorities + for(unsigned int i = 0; i, int, int>> renderQueue = + std::vector, int, int>>(maxShadowRenderCount); + for(unsigned int i = 0; i std::get<1>(renderQueue.at(j))){ + if (juse(); // render depth textures for point lights glViewport(0, 0, cube_size, cube_size); depthCubeShader->use(); @@ -349,19 +376,30 @@ void Graphics::render(double time) framebuffer_cube->bind(); - for (unsigned int i_pointlight = 0; i_pointlightsize() && i_pointlight < maxShadowRenderCount; i_pointlight++) { - // render each side of the cube - for (int i_face = 0; i_face<6; i_face++) { - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i_face, depth_cubeMaps.at(i_pointlight)->getObjectName(), 0); - glClear(GL_DEPTH_BUFFER_BIT); - glm::mat4 viewMatrix = glm::lookAt(closestLights->at(i_pointlight)->getPosition(), - closestLights->at(i_pointlight)->getPosition() + looking_directions[i_face], upvectors[i_face]); - glm::mat4 depthViewProjectionMatrix_face = depthProjectionMatrix_pointlights * viewMatrix; - std::vector viewMatrixVector = std::vector(); - viewMatrixVector.push_back(viewMatrix); - level->render(depthCubeShader, false, closestLights->at(i_pointlight)->getPosition(), 1, &depthViewProjectionMatrix_face, &viewMatrixVector); - if (!framebuffer_cube->isFrameBufferObjectComplete()) { - printf("Framebuffer incomplete, unknown error occured during shadow generation!\n"); + for (unsigned int i_pointlight = 0; i_pointlight < renderQueue.size(); i_pointlight++) { + // check if queue points to a existing light + if (std::get<0>(renderQueue.at(i_pointlight))) { + // render each side of the cube + glm::vec3 position = glm::vec3(0.0f); + if (std::get<0>(renderQueue.at(i_pointlight))->isFlame()) { + position = std::get<0>(renderQueue.at(i_pointlight))->getPosition(); + position = glm::vec3(position.x + 0.75f*wind.x, position.y, position.z + 0.75f*wind.y); + } + else { + position = std::get<0>(renderQueue.at(i_pointlight))->getPosition(); + } + for (int i_face = 0; i_face<6; i_face++) { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i_face, + depth_cubeMaps.at(std::get<2>(renderQueue.at(i_pointlight)))->getObjectName(), 0); + glClear(GL_DEPTH_BUFFER_BIT); + glm::mat4 viewMatrix = glm::lookAt(position, position + looking_directions[i_face], upvectors[i_face]); + glm::mat4 depthViewProjectionMatrix_face = depthProjectionMatrix_pointlights * viewMatrix; + std::vector viewMatrixVector = std::vector(1); + viewMatrixVector.at(0) = viewMatrix; + level->render(depthCubeShader, false, std::get<0>(renderQueue.at(i_pointlight))->getPosition(), 1, &depthViewProjectionMatrix_face, &viewMatrixVector); + if (!framebuffer_cube->isFrameBufferObjectComplete()) { + printf("Framebuffer incomplete, unknown error occured during shadow generation!\n"); + } } } } @@ -594,47 +632,87 @@ void Graphics::render(double time) } void Graphics::updateLights() { + std::vector> oldClosestLights = std::vector>(*closestLights); closestLights = level->getClosestLights(); if (closestLights->size() > 0) { lightingShader->use(); lightingShader->setUniform("lightCount", (int) closestLights->size()); - lightingShader->setUniform("maxShadowRenderCount", std::min((int) closestLights->size(), (int)maxShadowRenderCount)); + lightingShader->setUniform("maxShadowRenderCount", min((int)closestLights->size(), maxShadowSampleCount)); + + // find new closest lights for the shadow render queue + unsigned int i = 0; + std::vector> compareClosestLights = std::vector>(*closestLights); + while(igetCameraCenter()->getPosition(), shadowRenderQueue.at(i).light->getPosition()); + shadowRenderQueue.at(i).priority = (int) 100*std::exp(5.0f - 0.1f * distance); + } // Build light position array - glm::vec3 lightSources[closestLights->size()]; - for(unsigned int i = 0; isize(); i++) { - lightSources[i] = closestLights->at(i)->getPosition(); + glm::vec3 lightSources[shadowRenderQueue.size()]; + for(unsigned int i = 0; igetPosition(); } glUniform3fv(lightingShader->getUniformLocation("lightSources"), sizeof(lightSources), (GLfloat*) lightSources); // Build light colour array - glm::vec3 lightColours[closestLights->size()]; - for(unsigned int i = 0; isize(); i++) { - lightColours[i] = closestLights->at(i)->getColour(); + glm::vec3 lightColours[shadowRenderQueue.size()]; + for(unsigned int i = 0; igetColour(); } glUniform3fv(lightingShader->getUniformLocation("lightColors"), sizeof(lightColours), (GLfloat*) lightColours); // Build light attenuation array - float lightIntensities[closestLights->size()]; - for(unsigned int i = 0; isize(); i++) { - lightIntensities[i] = closestLights->at(i)->getIntensity(); + float lightIntensities[shadowRenderQueue.size()]; + for(unsigned int i = 0; igetIntensity(); } glUniform1fv(lightingShader->getUniformLocation("lightIntensities"), sizeof(lightIntensities), (GLfloat*) lightIntensities); - } - // set directional Light - bool isFlame[closestLights->size()]; - closestFlames = std::vector(); - for (unsigned int i = 0; isize(); i++) { - if (closestLights->at(i)->isFlame()) { - closestFlames.push_back(closestLights->at(i)->getFlame()); - isFlame[i] = true; - } - else { - isFlame[i] = false; + + bool isFlame[shadowRenderQueue.size()]; + closestFlames = std::vector(); + for(unsigned int i = 0; iisFlame()) { + closestFlames.push_back(shadowRenderQueue.at(i).light->getFlame()); + isFlame[i] = true; + } + else { + isFlame[i] = false; + } } + glUniform1iv(lightingShader->getUniformLocation("isFlame"), sizeof(isFlame), (GLint*) isFlame); } - glUniform1iv(lightingShader->getUniformLocation("isFlame"), sizeof(isFlame), (GLint*) isFlame); } void Graphics::saveWindowSize(glm::uvec2 windowSize) { @@ -777,3 +855,38 @@ bool Graphics::getRenderWorld() { void Graphics::enqueueObjects(std::vector>* queue){ renderQueue.push_back(queue); } + +void Graphics::initShadowRenderQueue() { + closestLights = level->getClosestLights(); + int maxLights = min((int)closestLights->size(), maxShadowSampleCount); + shadowRenderQueue = std::vector(maxLights); + glViewport(0, 0, cube_size, cube_size); + glm::mat4 depthProjectionMatrix_pointlights = glm::perspective(1.571f, (float)cube_size/(float)cube_size, 0.1f, 50.0f); + glm::vec3 looking_directions[6] = {glm::vec3(1.0f, 0.0f, 0.0f), glm::vec3(-1.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f), + glm::vec3(0.0f, -1.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(0.0f, 0.0f, -1.0f)}; + glm::vec3 upvectors[6] = {glm::vec3(0.0f, -1.0f, 0.0f),glm::vec3(0.0f, -1.0f, 0.0f),glm::vec3(0.0f, 0.0f, -1.0f), + glm::vec3(0.0f, 0.0f, -1.0f),glm::vec3(0.0f, -1.0f, 0.0f),glm::vec3(0.0f, -1.0f, 0.0f)}; + + framebuffer_cube->bind(); + + for(unsigned int i = 0; iat(i); + shadowRenderQueue.at(i).currentPriority = 0; + // render depth textures for point lights + depthCubeShader->use(); + // render each side of the cube + for (int i_face = 0; i_face<6; i_face++) { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i_face, depth_cubeMaps.at(i)->getObjectName(), 0); + glClear(GL_DEPTH_BUFFER_BIT); + glm::mat4 viewMatrix = glm::lookAt(shadowRenderQueue.at(i).light->getPosition(), + shadowRenderQueue.at(i).light->getPosition() + looking_directions[i_face], upvectors[i_face]); + glm::mat4 depthViewProjectionMatrix_face = depthProjectionMatrix_pointlights * viewMatrix; + std::vector viewMatrixVector = std::vector(); + viewMatrixVector.push_back(viewMatrix); + level->render(depthCubeShader, false, shadowRenderQueue.at(i).light->getPosition(), 1, &depthViewProjectionMatrix_face, &viewMatrixVector); + if (!framebuffer_cube->isFrameBufferObjectComplete()) { + printf("Framebuffer incomplete, unknown error occured during shadow generation!\n"); + } + } + } +} diff --git a/game/graphics.hh b/game/graphics.hh index ec1c815..0e63f7b 100644 --- a/game/graphics.hh +++ b/game/graphics.hh @@ -11,6 +11,12 @@ using namespace ACGL::OpenGL; +struct ShadowRenderQueueSlot{ + shared_ptr light; + int priority; + int currentPriority; +}; + class Graphics { public: Graphics(glm::uvec2 windowSize, float nearPlane, float farPlane, int cube_size, @@ -89,6 +95,8 @@ class Graphics { SharedVertexArrayObject debug_vao; SharedShaderProgram debugShader; std::vector>*> renderQueue; + std::vector shadowRenderQueue; + void initShadowRenderQueue(); }; #endif diff --git a/game/level.cc b/game/level.cc index 6d51bc1..3497ce7 100644 --- a/game/level.cc +++ b/game/level.cc @@ -462,5 +462,7 @@ std::vector>* Level::getClosestLights() { closestLights = std::vector>(&closestLights[0], &closestLights[15]); } + // sort pointers for faster comparisons + std::sort(closestLights.begin(), closestLights.end()); return &closestLights; }