diff --git a/data/shaders/rh.frag b/data/shaders/rh.frag new file mode 100644 index 000000000..9db5d458b --- /dev/null +++ b/data/shaders/rh.frag @@ -0,0 +1,96 @@ +// From http://graphics.cs.aueb.gr/graphics/research_illumination.html +// "Real-Time Diffuse Global Illumination Using Radiance Hints" +// paper and shader code + +uniform float R_wcs = 10.; // Rmax: maximum sampling distance (in WCS units) +uniform vec3 extents; +uniform mat4 RHMatrix; +uniform mat4 RSMMatrix; +uniform sampler2D dtex; +uniform sampler2D ctex; +uniform sampler2D ntex; + +flat in int slice; +layout (location = 0) out vec4 SHRed; +layout (location = 1) out vec4 SHGreen; +layout (location = 2) out vec4 SHBlue; + +vec3 resolution = vec3(32, 16, 32); +#define SAMPLES 16 + +vec4 SHBasis (const in vec3 dir) +{ + float L00 = 0.282095; + float L1_1 = 0.488603 * dir.y; + float L10 = 0.488603 * dir.z; + float L11 = 0.488603 * dir.x; + return vec4 (L11, L1_1, L10, L00); +} + +vec4 DirToSh(vec3 dir, float flux) +{ + return SHBasis (dir) * flux; +} + +void main(void) +{ + + vec3 normalizedRHCenter = 2. * vec3(gl_FragCoord.xy, slice) / resolution - 1.; + vec3 RHcenter = (RHMatrix * vec4(normalizedRHCenter * extents, 1.)).xyz; + + vec4 ShadowProjectedRH = RSMMatrix * vec4(RHcenter, 1.); + + vec3 RHCellSize = extents / resolution; + vec2 RHuv = .5 * ShadowProjectedRH.xy / ShadowProjectedRH.w + .5; + float RHdepth = .5 * ShadowProjectedRH.z / ShadowProjectedRH.w + .5; + + vec4 SHr = vec4(0.); + vec4 SHg = vec4(0.); + vec4 SHb = vec4(0.); + + int x = int(gl_FragCoord.x), y = int(gl_FragCoord.y); + float phi = 30. * (x ^ y) + 10. * x * y; + + for (int i = 0; i < SAMPLES; i++) + { + // produce a new sample location on the RSM texture + float alpha = (i + .5) / SAMPLES; + float theta = 2. * 3.14 * 7. * alpha; + float h = alpha; + vec2 offset = h * vec2(cos(theta), sin(theta)); + vec2 uv = RHuv + offset * 0.01; + + // Get world position and normal from the RSM sample + float depth = texture2D(dtex, uv).z; + vec4 RSMPos = inverse(RSMMatrix) * (2. * vec4(uv, depth, 1.) - 1.); + RSMPos /= RSMPos.w; + vec3 RSMAlbedo = texture(ctex, uv).xyz; + vec3 normal = normalize(2. * texture(ntex, uv).xyz - 1.); + + // Sampled location inside the RH cell + vec3 offset3d = vec3(uv, 0); + vec3 SamplePos = RHcenter + .5 * offset3d.xzy * RHCellSize; + + // Normalize distance to RSM sample + float dist = distance(SamplePos, RSMPos.xyz) / R_wcs; + // Determine the incident direction. + // Avoid very close samples (and numerical instability problems) + vec3 RSM_to_RH_dir = (dist <= 0.00) ? vec3(0.) : normalize(SamplePos - RSMPos.xyz); + float dotprod = max(dot(RSM_to_RH_dir, normal.xyz), 0.); + float factor = dotprod / (0.1 + dist * dist); + + vec3 color = RSMAlbedo.rgb * factor; + + SHr += DirToSh(RSM_to_RH_dir, color.r); + SHg += DirToSh(RSM_to_RH_dir, color.g); + SHb += DirToSh(RSM_to_RH_dir, color.b); + } + + SHr /= 3.14159 * SAMPLES; + SHg /= 3.14159 * SAMPLES; + SHb /= 3.14159 * SAMPLES; + + SHRed = SHr; + SHGreen = SHg; + SHBlue = SHb; +} \ No newline at end of file diff --git a/data/shaders/rhpassthrough.geom b/data/shaders/rhpassthrough.geom new file mode 100644 index 000000000..998b6f887 --- /dev/null +++ b/data/shaders/rhpassthrough.geom @@ -0,0 +1,20 @@ +layout(triangles) in; +layout(triangle_strip, max_vertices=3) out; + +in int layer[3]; +in vec2 uv_in[3]; +flat out int slice; +out vec2 uv; + +void main(void) +{ + gl_Layer = layer[0]; + for(int i=0; i<3; i++) + { + slice = layer[0]; + uv = uv_in[i]; + gl_Position = gl_in[i].gl_Position; + EmitVertex(); + } + EndPrimitive(); +} diff --git a/data/shaders/slicedscreenquad.vert b/data/shaders/slicedscreenquad.vert new file mode 100644 index 000000000..4922972f9 --- /dev/null +++ b/data/shaders/slicedscreenquad.vert @@ -0,0 +1,24 @@ +in vec2 Position; +in vec2 Texcoord; + +#ifndef VSLayer +out int layer; +out vec2 uv_in; +#else +out vec2 uv; +flat out int slice; +#endif + + + +void main() { +#ifdef VSLayer + gl_Layer = gl_InstanceID; + uv = Texcoord; + slice = gl_InstanceID; +#else + layer = gl_InstanceID; + uv_in = Texcoord; +#endif + gl_Position = vec4(Position, 0., 1.); +} diff --git a/src/graphics/irr_driver.hpp b/src/graphics/irr_driver.hpp index d9652f857..058d2fa6b 100644 --- a/src/graphics/irr_driver.hpp +++ b/src/graphics/irr_driver.hpp @@ -203,6 +203,8 @@ private: /** RTTs. */ RTT *m_rtts; std::vector sun_ortho_matrix; + core::vector3df rh_extend; + core::matrix4 rh_matrix; core::matrix4 rsm_matrix; /** Additional details to be shown in case that a texture is not found. diff --git a/src/graphics/render.cpp b/src/graphics/render.cpp index 5c5e8c78c..71381abf9 100644 --- a/src/graphics/render.cpp +++ b/src/graphics/render.cpp @@ -720,6 +720,11 @@ void IrrDriver::computeCameraMatrix(scene::ICameraSceneNode * const camnode, siz } if (!(tick % 100)) rsm_matrix = sun_ortho_matrix[3]; + rh_extend = core::vector3df(128, 64, 128); + core::vector3df campos = camnode->getAbsolutePosition(); + core::vector3df translation(8 * floor(campos.X / 8), 8 * floor(campos.Y / 8), 8 * floor(campos.Z / 8)); + rh_matrix.setTranslation(translation); + assert(sun_ortho_matrix.size() == 4); camnode->setNearValue(oldnear); camnode->setFarValue(oldfar); @@ -872,6 +877,16 @@ static void renderPointLights(unsigned count) void IrrDriver::renderLights(scene::ICameraSceneNode * const camnode, float dt) { + //RH + glDisable(GL_BLEND); + m_rtts->getRH().Bind(); + glUseProgram(FullScreenShader::RadianceHintsConstructionShader::Program); + glBindVertexArray(FullScreenShader::RadianceHintsConstructionShader::vao); + setTexture(0, m_rtts->getRSM().getRTT()[0], GL_LINEAR, GL_LINEAR); + setTexture(1, m_rtts->getRSM().getRTT()[1], GL_LINEAR, GL_LINEAR); + setTexture(2, m_rtts->getRSM().getDepthTexture(), GL_LINEAR, GL_LINEAR); + FullScreenShader::RadianceHintsConstructionShader::setUniforms(rsm_matrix, rh_matrix, rh_extend, 0, 1, 2); + glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, 32); for (unsigned i = 0; i < sun_ortho_matrix.size(); i++) sun_ortho_matrix[i] *= getInvViewMatrix(); diff --git a/src/graphics/shaders.cpp b/src/graphics/shaders.cpp index d8bd2a9dd..2e1e6a9a3 100644 --- a/src/graphics/shaders.cpp +++ b/src/graphics/shaders.cpp @@ -281,6 +281,7 @@ void Shaders::loadShaders() FullScreenShader::DiffuseEnvMapShader::init(); FullScreenShader::ShadowedSunLightShader::init(); FullScreenShader::ShadowedSunLightDebugShader::init(); + FullScreenShader::RadianceHintsConstructionShader::init(); FullScreenShader::MotionBlurShader::init(); FullScreenShader::GodFadeShader::init(); FullScreenShader::GodRayShader::init(); @@ -2304,6 +2305,52 @@ namespace FullScreenShader glUniform1i(uniform_shadowtex, TU_shadowtex); } + GLuint RadianceHintsConstructionShader::Program; + GLuint RadianceHintsConstructionShader::uniform_ctex; + GLuint RadianceHintsConstructionShader::uniform_ntex; + GLuint RadianceHintsConstructionShader::uniform_dtex; + GLuint RadianceHintsConstructionShader::uniform_extents; + GLuint RadianceHintsConstructionShader::uniform_RHMatrix; + GLuint RadianceHintsConstructionShader::uniform_RSMMatrix; + GLuint RadianceHintsConstructionShader::vao; + + void RadianceHintsConstructionShader::init() + { + if (irr_driver->hasVSLayerExtension()) + { + Program = LoadProgram( + GL_VERTEX_SHADER, file_manager->getAsset("shaders/slicedscreenquad.vert").c_str(), + GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/rh.frag").c_str()); + } + else + { + Program = LoadProgram( + GL_VERTEX_SHADER, file_manager->getAsset("shaders/slicedscreenquad.vert").c_str(), + GL_GEOMETRY_SHADER, file_manager->getAsset("shaders/rhpassthrough.geom").c_str(), + GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/rh.frag").c_str()); + } + + uniform_ctex = glGetUniformLocation(Program, "ctex"); + uniform_ntex = glGetUniformLocation(Program, "ntex"); + uniform_dtex = glGetUniformLocation(Program, "dtex"); + uniform_extents = glGetUniformLocation(Program, "extents"); + uniform_RHMatrix = glGetUniformLocation(Program, "RHMatrix"); + uniform_RSMMatrix = glGetUniformLocation(Program, "RSMMatrix"); + vao = createVAO(Program); + GLuint uniform_ViewProjectionMatrixesUBO = glGetUniformBlockIndex(Program, "MatrixesData"); + glUniformBlockBinding(Program, uniform_ViewProjectionMatrixesUBO, 0); + } + + void RadianceHintsConstructionShader::setUniforms(const core::matrix4 &RSMMatrix, const core::matrix4 &RHMatrix, const core::vector3df &extents, unsigned TU_ctex, unsigned TU_ntex, unsigned TU_dtex) + { + glUniformMatrix4fv(uniform_RSMMatrix, 1, GL_FALSE, RSMMatrix.pointer()); + glUniformMatrix4fv(uniform_RHMatrix, 1, GL_FALSE, RHMatrix.pointer()); + glUniform1i(uniform_ctex, TU_ctex); + glUniform1i(uniform_ntex, TU_ntex); + glUniform1i(uniform_dtex, TU_dtex); + glUniform3f(uniform_extents, extents.X, extents.Y, extents.Z); + } + GLuint Gaussian17TapHShader::Program; GLuint Gaussian17TapHShader::uniform_tex; GLuint Gaussian17TapHShader::uniform_pixel; diff --git a/src/graphics/shaders.hpp b/src/graphics/shaders.hpp index 4597e8d7f..d8e5fc594 100644 --- a/src/graphics/shaders.hpp +++ b/src/graphics/shaders.hpp @@ -609,6 +609,17 @@ public: static void setUniforms(const core::vector3df &direction, float r, float g, float b, unsigned TU_ntex, unsigned TU_dtex, unsigned TU_shadowtex); }; +class RadianceHintsConstructionShader +{ +public: + static GLuint Program; + static GLuint uniform_ctex, uniform_ntex, uniform_dtex, uniform_extents, uniform_RHMatrix, uniform_RSMMatrix; + static GLuint vao; + + static void init(); + static void setUniforms(const core::matrix4 &RSMMatrix, const core::matrix4 &RHMatrix, const core::vector3df &extents, unsigned TU_ctex, unsigned TU_ntex, unsigned TU_dtex); +}; + class Gaussian17TapHShader { public: