From 391053e368f56f8c7234880a8037293ea93cf276 Mon Sep 17 00:00:00 2001 From: Vincent Lejeune Date: Sat, 1 Mar 2014 20:08:17 +0100 Subject: [PATCH 1/2] IBL: Implement IBL --- data/shaders/diffuseenvmap.frag | 49 +++++ src/graphics/irr_driver.cpp | 3 + src/graphics/irr_driver.hpp | 5 +- src/graphics/post_processing.cpp | 21 ++ src/graphics/post_processing.hpp | 1 + src/graphics/render.cpp | 367 ++++++++++++++++++++++++++++++- src/graphics/shaders.cpp | 26 +++ src/graphics/shaders.hpp | 11 + 8 files changed, 475 insertions(+), 8 deletions(-) create mode 100644 data/shaders/diffuseenvmap.frag diff --git a/data/shaders/diffuseenvmap.frag b/data/shaders/diffuseenvmap.frag new file mode 100644 index 000000000..1e0777fcd --- /dev/null +++ b/data/shaders/diffuseenvmap.frag @@ -0,0 +1,49 @@ +uniform float blueLmn[9]; +uniform float greenLmn[9]; +uniform float redLmn[9]; +uniform sampler2D ntex; + +#if __VERSION__ >= 130 +in vec2 uv; +out vec4 Diff; +out vec4 Spec; +#else +varying vec2 uv; +#define Diff gl_FragData[0] +#define Spec gl_FragData[1] +#endif + +vec3 DecodeNormal(vec2 n) +{ + float z = dot(n, n) * 2. - 1.; + vec2 xy = normalize(n) * sqrt(1. - z * z); + return vec3(xy,z); +} + +mat4 getMatrix(float L[9]) +{ + float c1 = 0.429043, c2 = 0.511664, c3 = 0.743125, c4 = 0.886227, c5 = 0.247708; + + return mat4( + c1 * L[8] /*L22*/, c1 * L[4] /*L2-2*/, c1 * L[7] /*L21*/, c2 * L[3] /*L11*/, + c1 * L[4], - c1 * L[8], c1 * L[5] /*L2-1*/, c2 * L[1] /*L1-1*/, + c1 * L[7], c1 * L[5], c3 * L[6] /*L20*/, c2 * L[2] /*L10*/, + c2 * L[3], c2 * L[1], c2 * L[2], c4 * L[0] /*L00*/ - c5 * L[6] + ); +} + +void main(void) +{ + vec3 normal = normalize(DecodeNormal(2. * texture(ntex, uv).xy - 1.)); + vec4 extendednormal = vec4(normal, 1.); + mat4 rmat = getMatrix(redLmn); + mat4 gmat = getMatrix(greenLmn); + mat4 bmat = getMatrix(blueLmn); + + float r = dot(extendednormal, rmat * extendednormal); + float g = dot(extendednormal, gmat * extendednormal); + float b = dot(extendednormal, bmat * extendednormal); + + Diff = 0.25 * vec4(r, g, b, .1); + Spec = vec4(0.); +} diff --git a/src/graphics/irr_driver.cpp b/src/graphics/irr_driver.cpp index b31eb9a20..97c104339 100644 --- a/src/graphics/irr_driver.cpp +++ b/src/graphics/irr_driver.cpp @@ -1173,6 +1173,7 @@ scene::ISceneNode *IrrDriver::addSkyBox(const std::vector assert(texture.size() == 6); SkyboxTextures = texture; SkyboxCubeMap = 0; + ConvolutedSkyboxCubeMap = 0; return m_scene_manager->addSkyBoxSceneNode(texture[0], texture[1], texture[2], texture[3], texture[4], texture[5]); @@ -1182,7 +1183,9 @@ void IrrDriver::suppressSkyBox() { SkyboxTextures.clear(); glDeleteTextures(1, &SkyboxCubeMap); + glDeleteTextures(1, &ConvolutedSkyboxCubeMap); SkyboxCubeMap = 0; + ConvolutedSkyboxCubeMap = 0; } // ---------------------------------------------------------------------------- diff --git a/src/graphics/irr_driver.hpp b/src/graphics/irr_driver.hpp index a3a9fd0cb..a6fe0a0b8 100644 --- a/src/graphics/irr_driver.hpp +++ b/src/graphics/irr_driver.hpp @@ -115,7 +115,10 @@ private: core::matrix4 m_ViewMatrix, m_InvViewMatrix, m_ProjMatrix, m_InvProjMatrix, m_ProjViewMatrix, m_InvProjViewMatrix; std::vector SkyboxTextures; - GLuint SkyboxCubeMap; + GLuint SkyboxCubeMap, ConvolutedSkyboxCubeMap; + float blueSHCoeff[9]; + float greenSHCoeff[9]; + float redSHCoeff[9]; /** Flag to indicate if a resolution change is pending (which will be diff --git a/src/graphics/post_processing.cpp b/src/graphics/post_processing.cpp index d5d8fbe3a..b03fc3ff9 100644 --- a/src/graphics/post_processing.cpp +++ b/src/graphics/post_processing.cpp @@ -302,6 +302,27 @@ void PostProcessing::renderPointlight(const std::vector &positions, const glDisable(GL_BLEND); } +void PostProcessing::renderDiffuseEnvMap(const float *bSHCoeff, const float *gSHCoeff, const float *rSHCoeff) +{ + glDisable(GL_DEPTH_TEST); + glEnable(GL_BLEND); + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_ONE, GL_ONE); + + glUseProgram(FullScreenShader::DiffuseEnvMapShader::Program); + glBindVertexArray(FullScreenShader::DiffuseEnvMapShader::vao); + + setTexture(0, getTextureGLuint(irr_driver->getRTT(RTT_NORMAL_AND_DEPTH)), GL_NEAREST, GL_NEAREST); + FullScreenShader::DiffuseEnvMapShader::setUniforms(bSHCoeff, gSHCoeff, rSHCoeff, 0); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glEnable(GL_DEPTH_TEST); + glDisable(GL_BLEND); +} + void PostProcessing::renderSunlight() { SunLightProvider * const cb = (SunLightProvider *) irr_driver->getCallback(ES_SUNLIGHT); diff --git a/src/graphics/post_processing.hpp b/src/graphics/post_processing.hpp index b1d29de03..260a2ee26 100644 --- a/src/graphics/post_processing.hpp +++ b/src/graphics/post_processing.hpp @@ -79,6 +79,7 @@ public: void renderFog(const core::matrix4 &ipvmat); void renderSSAO(const core::matrix4 &invprojm, const core::matrix4 &projm); + void renderDiffuseEnvMap(const float *bSHCoeff, const float *gSHCoeff, const float *rSHCoeff); /** Blur the in texture */ void renderGaussian3Blur(video::ITexture *in, video::ITexture *temprtt, float inv_width, float inv_height); diff --git a/src/graphics/render.cpp b/src/graphics/render.cpp index 4f2b36645..3cf7934a1 100644 --- a/src/graphics/render.cpp +++ b/src/graphics/render.cpp @@ -741,6 +741,8 @@ void IrrDriver::renderLights(const core::aabbox3df& cambox, video::SOverrideMaterial &overridemat, int cam, float dt) { + if (SkyboxCubeMap) + irr_driver->getSceneManager()->setAmbientLight(SColor(0, 0, 0, 0)); for (unsigned i = 0; i < sun_ortho_matrix.size(); i++) sun_ortho_matrix[i] *= getInvViewMatrix(); core::array rtts; @@ -831,6 +833,8 @@ void IrrDriver::renderLights(const core::aabbox3df& cambox, accumulatedLightEnergy.push_back(0.); } m_post_processing->renderPointlight(accumulatedLightPos, accumulatedLightColor, accumulatedLightEnergy); + if (SkyboxCubeMap) + m_post_processing->renderDiffuseEnvMap(blueSHCoeff, greenSHCoeff, redSHCoeff); // Handle SSAO m_video_driver->setRenderTarget(irr_driver->getRTT(RTT_SSAO), true, false, SColor(255, 255, 255, 255)); @@ -916,13 +920,351 @@ static void createcubevao() } #define MAX2(a, b) ((a) > (b) ? (a) : (b)) +#define MIN2(a, b) ((a) > (b) ? (b) : (a)) + +static void getXYZ(GLenum face, float i, float j, float &x, float &y, float &z) +{ + switch (face) + { + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + x = 1.; + y = -i; + z = -j; + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + x = -1.; + y = -i; + z = j; + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + x = j; + y = 1.; + z = i; + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + x = j; + y = -1; + z = -i; + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + x = j; + y = -i; + z = 1; + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + x = -j; + y = -i; + z = -1; + break; + } + + float norm = sqrt(x * x + y * y + z * z); + x /= norm, y /= norm, z /= norm; + return; +} + +static void getYml(GLenum face, size_t width, size_t height, + float *Y00, + float *Y1minus1, float *Y10, float *Y11, + float *Y2minus2, float *Y2minus1, float *Y20, float *Y21, float *Y22) +{ + for (unsigned i = 0; i < width; i++) + { + for (unsigned j = 0; j < height; j++) + { + float x, y, z; + float fi = i, fj = j; + fi /= width, fj /= height; + fi = 2 * fi - 1, fj = 2 * fj - 1; + getXYZ(face, fi, fj, x, y, z); + + // constant part of Ylm + float c00 = 0.282095; + float c1minus1 = 0.488603; + float c10 = 0.488603; + float c11 = 0.488603; + float c2minus2 = 1.092548; + float c2minus1 = 1.092548; + float c21 = 1.092548; + float c20 = 0.315392; + float c22 = 0.546274; + + size_t idx = i * height + j; + + Y00[idx] = c00; + Y1minus1[idx] = c1minus1 * y; + Y10[idx] = c10 * z; + Y11[idx] = c11 * x; + Y2minus2[idx] = c2minus2 * x * y; + Y2minus1[idx] = c2minus1 * y * z; + Y21[idx] = c21 * x * z; + Y20[idx] = c20 * (3 * z * z - 1); + Y22[idx] = c22 * (x * x - y * y); + } + } +} + +static float getTexelValue(unsigned i, unsigned j, size_t width, size_t height, float *Coeff, float *Y00, float *Y1minus1, float *Y10, float *Y11, + float *Y2minus2, float * Y2minus1, float * Y20, float *Y21, float *Y22) +{ + float d = sqrt(i * i + j * j + 1); + float solidangle = 1.; + size_t idx = i * height + j; + float reconstructedVal = Y00[idx] * Coeff[0]; + reconstructedVal += Y1minus1[i * height + j] * Coeff[1] + Y10[i * height + j] * Coeff[2] + Y11[i * height + j] * Coeff[3]; + reconstructedVal += Y2minus2[idx] * Coeff[4] + Y2minus1[idx] * Coeff[5] + Y20[idx] * Coeff[6] + Y21[idx] * Coeff[7] + Y22[idx] * Coeff[8]; + reconstructedVal /= solidangle; + return MAX2(255 * reconstructedVal, 0.); +} + +static void unprojectSH(float *output[], size_t width, size_t height, + float *Y00[], + float *Y1minus1[], float *Y10[], float *Y11[], + float *Y2minus2[], float *Y2minus1[], float * Y20[],float *Y21[], float *Y22[], + float *blueSHCoeff, float *greenSHCoeff, float *redSHCoeff) +{ + for (unsigned face = 0; face < 6; face++) + { + for (unsigned i = 0; i < width; i++) + { + for (unsigned j = 0; j < height; j++) + { + float fi = i, fj = j; + fi /= width, fj /= height; + fi = 2 * fi - 1, fj = 2 * fj - 1; + + output[face][4 * height * i + 4 * j + 2] = getTexelValue(i, j, width, height, + redSHCoeff, + Y00[face], Y1minus1[face], Y10[face], Y11[face], Y2minus2[face], Y2minus1[face], Y20[face], Y21[face], Y22[face]); + output[face][4 * height * i + 4 * j + 1] = getTexelValue(i, j, width, height, + greenSHCoeff, + Y00[face], Y1minus1[face], Y10[face], Y11[face], Y2minus2[face], Y2minus1[face], Y20[face], Y21[face], Y22[face]); + output[face][4 * height * i + 4 * j] = getTexelValue(i, j, width, height, + blueSHCoeff, + Y00[face], Y1minus1[face], Y10[face], Y11[face], Y2minus2[face], Y2minus1[face], Y20[face], Y21[face], Y22[face]); + } + } + } +} + +static void projectSH(float *color[], size_t width, size_t height, + float *Y00[], + float *Y1minus1[], float *Y10[], float *Y11[], + float *Y2minus2[], float *Y2minus1[], float * Y20[], float *Y21[], float *Y22[], + float *blueSHCoeff, float *greenSHCoeff, float *redSHCoeff + ) +{ + for (unsigned i = 0; i < 9; i++) + { + blueSHCoeff[i] = 0; + greenSHCoeff[i] = 0; + redSHCoeff[i] = 0; + } + float wh = width * height; + for (unsigned face = 0; face < 6; face++) + { + for (unsigned i = 0; i < width; i++) + { + for (unsigned j = 0; j < height; j++) + { + size_t idx = i * height + j; + float fi = i, fj = j; + fi /= width, fj /= height; + fi = 2 * fi - 1, fj = 2 * fj - 1; + + + float d = sqrt(fi * fi + fj * fj + 1); + + // Constant obtained by projecting unprojected ref values + float solidangle = 2.75 / (wh * pow(d, 1.5)); + float b = color[face][4 * height * i + 4 * j] / 255.; + float g = color[face][4 * height * i + 4 * j + 1] / 255.; + float r = color[face][4 * height * i + 4 * j + 2] / 255.; + + assert(b >= 0.); + + blueSHCoeff[0] += b * Y00[face][idx] * solidangle; + blueSHCoeff[1] += b * Y1minus1[face][idx] * solidangle; + blueSHCoeff[2] += b * Y10[face][idx] * solidangle; + blueSHCoeff[3] += b * Y11[face][idx] * solidangle; + blueSHCoeff[4] += b * Y2minus2[face][idx] * solidangle; + blueSHCoeff[5] += b * Y2minus1[face][idx] * solidangle; + blueSHCoeff[6] += b * Y20[face][idx] * solidangle; + blueSHCoeff[7] += b * Y21[face][idx] * solidangle; + blueSHCoeff[8] += b * Y22[face][idx] * solidangle; + + greenSHCoeff[0] += g * Y00[face][idx] * solidangle; + greenSHCoeff[1] += g * Y1minus1[face][idx] * solidangle; + greenSHCoeff[2] += g * Y10[face][idx] * solidangle; + greenSHCoeff[3] += g * Y11[face][idx] * solidangle; + greenSHCoeff[4] += g * Y2minus2[face][idx] * solidangle; + greenSHCoeff[5] += g * Y2minus1[face][idx] * solidangle; + greenSHCoeff[6] += g * Y20[face][idx] * solidangle; + greenSHCoeff[7] += g * Y21[face][idx] * solidangle; + greenSHCoeff[8] += g * Y22[face][idx] * solidangle; + + + redSHCoeff[0] += r * Y00[face][idx] * solidangle; + redSHCoeff[1] += r * Y1minus1[face][idx] * solidangle; + redSHCoeff[2] += r * Y10[face][idx] * solidangle; + redSHCoeff[3] += r * Y11[face][idx] * solidangle; + redSHCoeff[4] += r * Y2minus2[face][idx] * solidangle; + redSHCoeff[5] += r * Y2minus1[face][idx] * solidangle; + redSHCoeff[6] += r * Y20[face][idx] * solidangle; + redSHCoeff[7] += r * Y21[face][idx] * solidangle; + redSHCoeff[8] += r * Y22[face][idx] * solidangle; + } + } + } +} + +static void displayCoeff(float *SHCoeff) +{ + printf("L00:%f\n", SHCoeff[0]); + printf("L1-1:%f, L10:%f, L11:%f\n", SHCoeff[1], SHCoeff[2], SHCoeff[3]); + printf("L2-2:%f, L2-1:%f, L20:%f, L21:%f, L22:%f\n", SHCoeff[4], SHCoeff[5], SHCoeff[6], SHCoeff[7], SHCoeff[8]); +} + +// Only for 9 coefficients +static void testSH(char *color[6], size_t width, size_t height, + float *blueSHCoeff, float *greenSHCoeff, float *redSHCoeff) +{ + float *Y00[6]; + float *Y1minus1[6]; + float *Y10[6]; + float *Y11[6]; + float *Y2minus2[6]; + float *Y2minus1[6]; + float *Y20[6]; + float *Y21[6]; + float *Y22[6]; + + float *testoutput[6]; + for (unsigned i = 0; i < 6; i++) + { + testoutput[i] = new float[width * height * 4]; + for (unsigned j = 0; j < width * height; j++) + { + testoutput[i][4 * j] = 0xFF & color[i][4 * j]; + testoutput[i][4 * j + 1] = 0xFF & color[i][4 * j + 1]; + testoutput[i][4 * j + 2] = 0xFF & color[i][4 * j + 2]; + } + } + + for (unsigned face = 0; face < 6; face++) + { + Y00[face] = new float[width * height]; + Y1minus1[face] = new float[width * height]; + Y10[face] = new float[width * height]; + Y11[face] = new float[width * height]; + Y2minus2[face] = new float[width * height]; + Y2minus1[face] = new float[width * height]; + Y20[face] = new float[width * height]; + Y21[face] = new float[width * height]; + Y22[face] = new float[width * height]; + + getYml(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, width, height, Y00[face], Y1minus1[face], Y10[face], Y11[face], Y2minus2[face], Y2minus1[face], Y20[face], Y21[face], Y22[face]); + } + +/* blueSHCoeff[0] = 0.54, + blueSHCoeff[1] = .6, blueSHCoeff[2] = -.27, blueSHCoeff[3] = .01, + blueSHCoeff[4] = -.12, blueSHCoeff[5] = -.47, blueSHCoeff[6] = -.15, blueSHCoeff[7] = .14, blueSHCoeff[8] = -.3; + greenSHCoeff[0] = .44, + greenSHCoeff[1] = .35, greenSHCoeff[2] = -.18, greenSHCoeff[3] = -.06, + greenSHCoeff[4] = -.05, greenSHCoeff[5] = -.22, greenSHCoeff[6] = -.09, greenSHCoeff[7] = .21, greenSHCoeff[8] = -.05; + redSHCoeff[0] = .79, + redSHCoeff[1] = .39, redSHCoeff[2] = -.34, redSHCoeff[3] = -.29, + redSHCoeff[4] = -.11, redSHCoeff[5] = -.26, redSHCoeff[6] = -.16, redSHCoeff[7] = .56, redSHCoeff[8] = .21; + + printf("Blue:\n"); + displayCoeff(blueSHCoeff); + printf("Green:\n"); + displayCoeff(greenSHCoeff); + printf("Red:\n"); + displayCoeff(redSHCoeff);*/ + + projectSH(testoutput, width, height, + Y00, + Y1minus1, Y10, Y11, + Y2minus2, Y2minus1, Y20, Y21, Y22, + blueSHCoeff, greenSHCoeff, redSHCoeff + ); + + printf("Blue:\n"); + displayCoeff(blueSHCoeff); + printf("Green:\n"); + displayCoeff(greenSHCoeff); + printf("Red:\n"); + displayCoeff(redSHCoeff); + + + + // Convolute in frequency space +/* float A0 = 3.141593; + float A1 = 2.094395; + float A2 = 0.785398; + blueSHCoeff[0] *= A0; + greenSHCoeff[0] *= A0; + redSHCoeff[0] *= A0; + for (unsigned i = 0; i < 3; i++) + { + blueSHCoeff[1 + i] *= A1; + greenSHCoeff[1 + i] *= A1; + redSHCoeff[1 + i] *= A1; + } + for (unsigned i = 0; i < 5; i++) + { + blueSHCoeff[4 + i] *= A2; + greenSHCoeff[4 + i] *= A2; + redSHCoeff[4 + i] *= A2; + } + + + unprojectSH(testoutput, width, height, + Y00, + Y1minus1, Y10, Y11, + Y2minus2, Y2minus1, Y20, Y21, Y22, + blueSHCoeff, greenSHCoeff, redSHCoeff + );*/ + + +/* printf("Blue:\n"); + displayCoeff(blueSHCoeff); + printf("Green:\n"); + displayCoeff(greenSHCoeff); + printf("Red:\n"); + displayCoeff(redSHCoeff); + + printf("\nAfter projection\n\n");*/ + + + + for (unsigned i = 0; i < 6; i++) + { + for (unsigned j = 0; j < width * height; j++) + { + color[i][4 * j] = MIN2(testoutput[i][4 * j], 255); + color[i][4 * j + 1] = MIN2(testoutput[i][4 * j + 1], 255); + color[i][4 * j + 2] = MIN2(testoutput[i][4 * j + 2], 255); + } + } + + for (unsigned face = 0; face < 6; face++) + { + delete[] testoutput[face]; + delete[] Y00[face]; + delete[] Y1minus1[face]; + delete[] Y10[face]; + delete[] Y11[face]; + } +} void IrrDriver::generateSkyboxCubemap() { - glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); glGenTextures(1, &SkyboxCubeMap); + glGenTextures(1, &ConvolutedSkyboxCubeMap); GLint w = 0, h = 0; for (unsigned i = 0; i < 6; i++) @@ -932,7 +1274,9 @@ void IrrDriver::generateSkyboxCubemap() } const unsigned texture_permutation[] = { 2, 3, 0, 1, 5, 4 }; - char *rgba = new char[w * h * 4]; + char *rgba[6]; + for (unsigned i = 0; i < 6; i++) + rgba[i] = new char[w * h * 4]; for (unsigned i = 0; i < 6; i++) { unsigned idx = texture_permutation[i]; @@ -945,13 +1289,22 @@ void IrrDriver::generateSkyboxCubemap() ); SkyboxTextures[idx]->unlock(); - image->copyToScaling(rgba, w, h); + image->copyToScaling(rgba[i], w, h); + image->drop(); 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(); + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, (GLvoid*)rgba[i]); } - delete[] rgba; + + testSH(rgba, w, h, blueSHCoeff, greenSHCoeff, redSHCoeff); + + for (unsigned i = 0; i < 6; i++) + { + glBindTexture(GL_TEXTURE_CUBE_MAP, ConvolutedSkyboxCubeMap); + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, (GLvoid*)rgba[i]); + } + for (unsigned i = 0; i < 6; i++) + delete[] rgba[i]; glBindTexture(GL_TEXTURE_CUBE_MAP, 0); } @@ -981,7 +1334,7 @@ void IrrDriver::renderSkybox() transform.getInverse(invtransform); glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_CUBE_MAP, SkyboxCubeMap); + glBindTexture(GL_TEXTURE_CUBE_MAP, ConvolutedSkyboxCubeMap); 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); diff --git a/src/graphics/shaders.cpp b/src/graphics/shaders.cpp index 261a0c294..78ffea464 100644 --- a/src/graphics/shaders.cpp +++ b/src/graphics/shaders.cpp @@ -230,6 +230,7 @@ void Shaders::loadShaders() FullScreenShader::PointLightShader::init(); FullScreenShader::SSAOShader::init(); FullScreenShader::SunLightShader::init(); + FullScreenShader::DiffuseEnvMapShader::init(); FullScreenShader::ShadowedSunLightShader::init(); FullScreenShader::MotionBlurShader::init(); FullScreenShader::GodFadeShader::init(); @@ -1400,6 +1401,31 @@ namespace FullScreenShader glUniform1i(uniform_dtex, TU_dtex); } + GLuint DiffuseEnvMapShader::Program; + GLuint DiffuseEnvMapShader::uniform_ntex; + GLuint DiffuseEnvMapShader::uniform_blueLmn; + GLuint DiffuseEnvMapShader::uniform_greenLmn; + GLuint DiffuseEnvMapShader::uniform_redLmn; + GLuint DiffuseEnvMapShader::vao; + + void DiffuseEnvMapShader::init() + { + Program = LoadProgram(file_manager->getAsset("shaders/screenquad.vert").c_str(), file_manager->getAsset("shaders/diffuseenvmap.frag").c_str()); + uniform_ntex = glGetUniformLocation(Program, "ntex"); + uniform_blueLmn = glGetUniformLocation(Program, "blueLmn[0]"); + uniform_greenLmn = glGetUniformLocation(Program, "greenLmn[0]"); + uniform_redLmn = glGetUniformLocation(Program, "redLmn[0]"); + vao = createVAO(Program); + } + + void DiffuseEnvMapShader::setUniforms(const float *blueSHCoeff, const float *greenSHCoeff, const float *redSHCoeff, unsigned TU_ntex) + { + glUniform1i(uniform_ntex, TU_ntex); + glUniform1fv(uniform_blueLmn, 9, blueSHCoeff); + glUniform1fv(uniform_greenLmn, 9, greenSHCoeff); + glUniform1fv(uniform_redLmn, 9, redSHCoeff); + } + GLuint ShadowedSunLightShader::Program; GLuint ShadowedSunLightShader::uniform_ntex; GLuint ShadowedSunLightShader::uniform_dtex; diff --git a/src/graphics/shaders.hpp b/src/graphics/shaders.hpp index ce91d8922..c0d8869a3 100644 --- a/src/graphics/shaders.hpp +++ b/src/graphics/shaders.hpp @@ -408,6 +408,17 @@ public: static void setUniforms(const core::vector3df &direction, const core::matrix4 &InvProjMatrix, float r, float g, float b, unsigned TU_ntex, unsigned TU_dtex); }; +class DiffuseEnvMapShader +{ +public: + static GLuint Program; + static GLuint uniform_ntex, uniform_blueLmn, uniform_greenLmn, uniform_redLmn; + static GLuint vao; + + static void init(); + static void setUniforms(const float *blueSHCoeff, const float *greenSHCoeff, const float *redSHCoeff, unsigned TU_ntex); +}; + class ShadowedSunLightShader { public: From 8600d3bc6104224c4efa7d214d2d5683ac44cc45 Mon Sep 17 00:00:00 2001 From: Vincent Lejeune Date: Mon, 3 Mar 2014 00:47:13 +0100 Subject: [PATCH 2/2] IBL: Spheremap now reflects skybox --- data/shaders/objectpass_spheremap.frag | 22 +++++++++------------- src/graphics/irr_driver.hpp | 3 ++- src/graphics/shaders.cpp | 8 +++++++- src/graphics/shaders.hpp | 4 ++-- src/graphics/stkmesh.cpp | 20 ++++++++++++++++++-- 5 files changed, 38 insertions(+), 19 deletions(-) diff --git a/data/shaders/objectpass_spheremap.frag b/data/shaders/objectpass_spheremap.frag index c3a4c086a..8a02ae7ab 100644 --- a/data/shaders/objectpass_spheremap.frag +++ b/data/shaders/objectpass_spheremap.frag @@ -1,4 +1,6 @@ -uniform sampler2D tex; +uniform samplerCube tex; +uniform mat4 invproj; +uniform vec2 screen; #if __VERSION__ >= 130 in vec3 nor; @@ -10,18 +12,12 @@ varying vec3 nor; void main() { - // Calculate the spherical UV - const vec3 forward = vec3(0.0, 0.0, 1.0); + vec3 fpos = gl_FragCoord.xyz / vec3(screen, 1.); + vec4 xpos = 2.0 * vec4(fpos, 1.0) - 1.0; + xpos = invproj * xpos; - // get the angle between the forward vector and the horizontal portion of the normal - vec3 normal_x = normalize(vec3(nor.x, 0.0, nor.z)); - float sin_theta_x = length(cross( forward, normal_x )) * nor.x / abs(nor.x); + xpos.xyz /= xpos.w; + vec4 detail0 = texture(tex, reflect(xpos.xyz, nor)); - // get the angle between the forward vector and the vertical portion of the normal - vec3 normal_y = normalize(vec3(0.0, nor.y, nor.z)); - float sin_theta_y = length(cross( forward, normal_y )) * nor.y / abs(nor.y); - - vec4 detail0 = texture(tex, 0.5 * vec2(sin_theta_x, sin_theta_y) + 0.5); - - FragColor = vec4(detail0.xyz, 1.); + FragColor = vec4(detail0.xyz, 1.); } diff --git a/src/graphics/irr_driver.hpp b/src/graphics/irr_driver.hpp index a6fe0a0b8..9155451bf 100644 --- a/src/graphics/irr_driver.hpp +++ b/src/graphics/irr_driver.hpp @@ -115,7 +115,7 @@ private: core::matrix4 m_ViewMatrix, m_InvViewMatrix, m_ProjMatrix, m_InvProjMatrix, m_ProjViewMatrix, m_InvProjViewMatrix; std::vector SkyboxTextures; - GLuint SkyboxCubeMap, ConvolutedSkyboxCubeMap; + float blueSHCoeff[9]; float greenSHCoeff[9]; float redSHCoeff[9]; @@ -130,6 +130,7 @@ private: RES_CHANGE_CANCEL} m_resolution_changing; public: + GLuint SkyboxCubeMap, ConvolutedSkyboxCubeMap; /** A simple class to store video resolutions. */ class VideoMode { diff --git a/src/graphics/shaders.cpp b/src/graphics/shaders.cpp index 78ffea464..579c72b73 100644 --- a/src/graphics/shaders.cpp +++ b/src/graphics/shaders.cpp @@ -678,6 +678,8 @@ namespace MeshShader GLuint SphereMapShader::uniform_MVP; GLuint SphereMapShader::uniform_TIMV; GLuint SphereMapShader::uniform_tex; + GLuint SphereMapShader::uniform_invproj; + GLuint SphereMapShader::uniform_screen; void SphereMapShader::init() { @@ -687,12 +689,16 @@ namespace MeshShader uniform_MVP = glGetUniformLocation(Program, "ModelViewProjectionMatrix"); uniform_TIMV = glGetUniformLocation(Program, "TransposeInverseModelView"); uniform_tex = glGetUniformLocation(Program, "tex"); + uniform_invproj = glGetUniformLocation(Program, "invproj"); + uniform_screen = glGetUniformLocation(Program, "screen"); } - void SphereMapShader::setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView, unsigned TU_tex) + void SphereMapShader::setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView, const core::matrix4 &InvProj, const core::vector2df& screen, unsigned TU_tex) { glUniformMatrix4fv(uniform_MVP, 1, GL_FALSE, ModelViewProjectionMatrix.pointer()); glUniformMatrix4fv(uniform_TIMV, 1, GL_FALSE, TransposeInverseModelView.pointer()); + glUniformMatrix4fv(uniform_invproj, 1, GL_FALSE, InvProj.pointer()); + glUniform2f(uniform_screen, screen.X, screen.Y); glUniform1i(uniform_tex, TU_tex); } diff --git a/src/graphics/shaders.hpp b/src/graphics/shaders.hpp index c0d8869a3..84d28ab68 100644 --- a/src/graphics/shaders.hpp +++ b/src/graphics/shaders.hpp @@ -152,10 +152,10 @@ class SphereMapShader public: static GLuint Program; static GLuint attrib_position, attrib_normal; - static GLuint uniform_MVP, uniform_TIMV, uniform_tex; + static GLuint uniform_MVP, uniform_TIMV, uniform_tex, uniform_invproj, uniform_screen; static void init(); - static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView, unsigned TU_tex); + static void setUniforms(const core::matrix4 &ModelViewProjectionMatrix, const core::matrix4 &TransposeInverseModelView, const core::matrix4 &InvProj, const core::vector2df& screen, unsigned TU_tex); }; class SplattingShader diff --git a/src/graphics/stkmesh.cpp b/src/graphics/stkmesh.cpp index 944753676..6078bdb4d 100644 --- a/src/graphics/stkmesh.cpp +++ b/src/graphics/stkmesh.cpp @@ -226,13 +226,29 @@ void drawSphereMap(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionM GLenum itype = mesh.IndexType; size_t count = mesh.IndexCount; - setTexture(0, mesh.textures[0], GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR, true); + glActiveTexture(GL_TEXTURE0); + if (!irr_driver->SkyboxCubeMap) + { + GLint swizzleMask[] = { GL_ONE, GL_ONE, GL_ONE, GL_ONE }; + glTexParameteriv(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); + } + else + { + glBindBuffer(GL_TEXTURE_CUBE_MAP, irr_driver->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::SphereMapShader::Program); - MeshShader::SphereMapShader::setUniforms(ModelViewProjectionMatrix, TransposeInverseModelView, 0); + MeshShader::SphereMapShader::setUniforms(ModelViewProjectionMatrix, TransposeInverseModelView, irr_driver->getInvProjMatrix(), core::vector2df(UserConfigParams::m_width, UserConfigParams::m_height), 0); glBindVertexArray(mesh.vao_second_pass); glDrawElements(ptype, count, itype, 0); + if (!irr_driver->SkyboxCubeMap) + { + GLint swizzleMask[] = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA }; + glTexParameteriv(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); + } } void drawSplatting(const GLMesh &mesh, const core::matrix4 &ModelViewProjectionMatrix)