From 61ea376ff2aad4d28b9788b9f9d02de953f42650 Mon Sep 17 00:00:00 2001 From: Vincent Lejeune Date: Wed, 26 Feb 2014 18:36:41 +0100 Subject: [PATCH] Use cubemap for skyboxes --- src/graphics/irr_driver.cpp | 4 +++ src/graphics/irr_driver.hpp | 3 +++ src/graphics/render.cpp | 53 ++++++++++++++++++++++++++++++++++--- src/graphics/shaders.cpp | 28 ++++++++++++++++++++ src/graphics/shaders.hpp | 11 ++++++++ 5 files changed, 96 insertions(+), 3 deletions(-) diff --git a/src/graphics/irr_driver.cpp b/src/graphics/irr_driver.cpp index 16c1eca1763..446a502be18 100644 --- a/src/graphics/irr_driver.cpp +++ b/src/graphics/irr_driver.cpp @@ -1171,7 +1171,9 @@ scene::ISceneNode *IrrDriver::addSkyDome(video::ITexture *texture, scene::ISceneNode *IrrDriver::addSkyBox(const std::vector &texture) { + assert(texture.size() == 6); SkyboxTextures = texture; + SkyboxCubeMap = 0; return m_scene_manager->addSkyBoxSceneNode(texture[0], texture[1], texture[2], texture[3], texture[4], texture[5]); @@ -1180,6 +1182,8 @@ scene::ISceneNode *IrrDriver::addSkyBox(const std::vector void IrrDriver::suppressSkyBox() { SkyboxTextures.clear(); + glDeleteTextures(1, &SkyboxCubeMap); + SkyboxCubeMap = 0; } // ---------------------------------------------------------------------------- diff --git a/src/graphics/irr_driver.hpp b/src/graphics/irr_driver.hpp index c89a7949b70..a3a9fd0cb81 100644 --- a/src/graphics/irr_driver.hpp +++ b/src/graphics/irr_driver.hpp @@ -115,6 +115,8 @@ class IrrDriver : public IEventReceiver, public NoCopy core::matrix4 m_ViewMatrix, m_InvViewMatrix, m_ProjMatrix, m_InvProjMatrix, m_ProjViewMatrix, m_InvProjViewMatrix; std::vector SkyboxTextures; + GLuint SkyboxCubeMap; + /** Flag to indicate if a resolution change is pending (which will be * acted upon in the next update). None means no change, yes means @@ -225,6 +227,7 @@ class IrrDriver : public IEventReceiver, public NoCopy ~IrrDriver(); void initDevice(); void reset(); + void generateSkyboxCubemap(); void renderSkybox(); void setPhase(STKRenderingPass); STKRenderingPass getPhase() const; diff --git a/src/graphics/render.cpp b/src/graphics/render.cpp index c35e0426481..8a32d8a9442 100644 --- a/src/graphics/render.cpp +++ b/src/graphics/render.cpp @@ -918,6 +918,47 @@ static void createcubevao() glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * 6 * sizeof(int), indices, GL_STATIC_DRAW); } +#define MAX2(a, b) ((a) > (b) ? (a) : (b)) + +void IrrDriver::generateSkyboxCubemap() +{ + + glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); + + glGenTextures(1, &SkyboxCubeMap); + + GLint w = 0, h = 0; + for (unsigned i = 0; i < 6; i++) + { + w = MAX2(w, SkyboxTextures[i]->getOriginalSize().Width); + h = MAX2(h, SkyboxTextures[i]->getOriginalSize().Height); + } + + const unsigned texture_permutation[] = { 2, 3, 0, 1, 5, 4 }; + char *rgba = new char[w * h * 4]; + for (unsigned i = 0; i < 6; i++) + { + unsigned idx = texture_permutation[i]; + + video::IImage* image = getVideoDriver()->createImageFromData( + SkyboxTextures[idx]->getColorFormat(), + SkyboxTextures[idx]->getSize(), + SkyboxTextures[idx]->lock(), + false + ); + SkyboxTextures[idx]->unlock(); + + image->copyToScaling(rgba, w, h); + + glBindTexture(GL_TEXTURE_CUBE_MAP, SkyboxCubeMap); + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, (GLvoid*)rgba); + image->drop(); + } + delete[] rgba; + glBindTexture(GL_TEXTURE_CUBE_MAP, 0); +} + + void IrrDriver::renderSkybox() { if (SkyboxTextures.empty()) return; @@ -925,6 +966,8 @@ void IrrDriver::renderSkybox() scene::ICameraSceneNode *camera = m_scene_manager->getActiveCamera(); if (!cubevao) createcubevao(); + if (!SkyboxCubeMap) + generateSkyboxCubemap(); glBindVertexArray(cubevao); glDisable(GL_CULL_FACE); assert(SkyboxTextures.size() == 6); @@ -937,13 +980,17 @@ void IrrDriver::renderSkybox() core::matrix4 scale; scale.setScale(core::vector3df(viewDistance, viewDistance, viewDistance)); transform *= translate * scale; + core::matrix4 invtransform; + transform.getInverse(invtransform); for (unsigned i = 0; i < 6; i++) { glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, static_cast(SkyboxTextures[i])->getOpenGLTextureName()); - glUseProgram(MeshShader::ObjectUnlitShader::Program); - MeshShader::ObjectUnlitShader::setUniforms(transform, 0); + glBindTexture(GL_TEXTURE_CUBE_MAP, SkyboxCubeMap); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glUseProgram(MeshShader::SkyboxShader::Program); + MeshShader::SkyboxShader::setUniforms(transform, invtransform, core::vector2df(UserConfigParams::m_width, UserConfigParams::m_height), 0); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, (GLvoid*) (6 * i * sizeof(int))); } glBindVertexArray(0); diff --git a/src/graphics/shaders.cpp b/src/graphics/shaders.cpp index 2de8c64892a..911f1da4917 100644 --- a/src/graphics/shaders.cpp +++ b/src/graphics/shaders.cpp @@ -260,6 +260,7 @@ void Shaders::loadShaders() MeshShader::ShadowShader::init(); MeshShader::RefShadowShader::init(); MeshShader::GrassShadowShader::init(); + MeshShader::SkyboxShader::init(); ParticleShader::FlipParticleRender::init(); ParticleShader::HeightmapSimulationShader::init(); ParticleShader::SimpleParticleRender::init(); @@ -1028,6 +1029,33 @@ namespace MeshShader glUniform2f(uniform_dir2, dir2X, dir2Y); glUniform1i(uniform_tex, TU_tex); } + + GLuint SkyboxShader::Program; + GLuint SkyboxShader::attrib_position; + GLuint SkyboxShader::attrib_texcoord; + GLuint SkyboxShader::uniform_MVP; + GLuint SkyboxShader::uniform_tex; + GLuint SkyboxShader::uniform_screen; + GLuint SkyboxShader::uniform_InvProjView; + + void SkyboxShader::init() + { + Program = LoadProgram(file_manager->getAsset("shaders/object_pass2.vert").c_str(), file_manager->getAsset("shaders/sky.frag").c_str()); + attrib_position = glGetAttribLocation(Program, "Position"); + attrib_texcoord = glGetAttribLocation(Program, "Texcoord"); + uniform_MVP = glGetUniformLocation(Program, "ModelViewProjectionMatrix"); + uniform_InvProjView = glGetUniformLocation(Program, "InvProjView"); + uniform_tex = glGetUniformLocation(Program, "tex"); + uniform_screen = glGetUniformLocation(Program, "screen"); + } + + void SkyboxShader::setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &InvProjView, const core::vector2df &screen, unsigned TU_tex) + { + glUniformMatrix4fv(uniform_MVP, 1, GL_FALSE, ModelViewProjectionMatrix.pointer()); + glUniformMatrix4fv(uniform_InvProjView, 1, GL_FALSE, InvProjView.pointer()); + glUniform1i(uniform_tex, TU_tex); + glUniform2f(uniform_screen, screen.X, screen.Y); + } } diff --git a/src/graphics/shaders.hpp b/src/graphics/shaders.hpp index 104286338e0..7de3627cc48 100644 --- a/src/graphics/shaders.hpp +++ b/src/graphics/shaders.hpp @@ -280,6 +280,17 @@ class DisplaceShader static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &ModelViewMatrix, float dirX, float dirY, float dir2X, float dir2Y, unsigned TU_tex); }; +class SkyboxShader +{ +public: + static GLuint Program; + static GLuint attrib_position, attrib_texcoord; + static GLuint uniform_MVP, uniform_InvProjView, uniform_tex, uniform_screen; + + static void init(); + static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &InvProjView, const core::vector2df &screen, unsigned TU_tex); +}; + } namespace ParticleShader