feat: Implement proper self illumination (blur-based)
This commit is contained in:
parent
17ab14d99d
commit
d04096ed58
7 changed files with 197 additions and 60 deletions
|
@ -546,11 +546,11 @@ void Control::render3D(const glm::ivec2 &offset) const {
|
|||
shaders.activate(ShaderProgram::GUIGUI, locals);
|
||||
}
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
framebuffer->bindTexture();
|
||||
framebuffer->bindColorBuffer(0);
|
||||
|
||||
DefaultQuad.render(GL_TRIANGLES);
|
||||
|
||||
framebuffer->unbindTexture();
|
||||
framebuffer->unbindColorBuffer();
|
||||
}
|
||||
|
||||
void Control::stretch(float x, float y) {
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace reone {
|
|||
|
||||
namespace render {
|
||||
|
||||
Framebuffer::Framebuffer(int w, int h) : _width(w), _height(h) {
|
||||
Framebuffer::Framebuffer(int w, int h, int colorBufferCount) : _width(w), _height(h), _colorBufferCount(colorBufferCount) {
|
||||
}
|
||||
|
||||
Framebuffer::~Framebuffer() {
|
||||
|
@ -37,24 +37,30 @@ Framebuffer::~Framebuffer() {
|
|||
void Framebuffer::init() {
|
||||
if (_inited) return;
|
||||
|
||||
glGenTextures(1, &_texture);
|
||||
glBindTexture(GL_TEXTURE_2D, _texture);
|
||||
_colorBuffers.resize(_colorBufferCount);
|
||||
glGenTextures(_colorBufferCount, &_colorBuffers[0]);
|
||||
|
||||
for (int i = 0; i < _colorBufferCount; ++i) {
|
||||
glBindTexture(GL_TEXTURE_2D, _colorBuffers[i]);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _width, _height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
glGenRenderbuffers(1, &_renderbuffer);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, _renderbuffer);
|
||||
}
|
||||
glGenRenderbuffers(1, &_depthBuffer);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, _depthBuffer);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, _width, _height);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
|
||||
glGenFramebuffers(1, &_framebuffer);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, _framebuffer);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texture, 0);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _renderbuffer);
|
||||
|
||||
for (int i = 0; i < _colorBufferCount; ++i) {
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, _colorBuffers[i], 0);
|
||||
}
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _depthBuffer);
|
||||
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
||||
throw runtime_error("Control: framebuffer is not complete");
|
||||
|
@ -68,8 +74,10 @@ void Framebuffer::deinit() {
|
|||
if (!_inited) return;
|
||||
|
||||
glDeleteFramebuffers(1, &_framebuffer);
|
||||
glDeleteTextures(1, &_texture);
|
||||
glDeleteRenderbuffers(1, &_renderbuffer);
|
||||
glDeleteTextures(_colorBufferCount, &_colorBuffers[0]);
|
||||
glDeleteRenderbuffers(1, &_depthBuffer);
|
||||
|
||||
_inited = false;
|
||||
}
|
||||
|
||||
void Framebuffer::bind() const {
|
||||
|
@ -80,12 +88,12 @@ void Framebuffer::unbind() const {
|
|||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
void Framebuffer::bindTexture() const {
|
||||
glBindTexture(GL_TEXTURE_2D, _texture);
|
||||
void Framebuffer::bindColorBuffer(int n) const {
|
||||
glBindTexture(GL_TEXTURE_2D, _colorBuffers[n]);
|
||||
}
|
||||
|
||||
void Framebuffer::unbindTexture() const {
|
||||
glBindTexture(GL_TEXTURE_2D, _texture);
|
||||
void Framebuffer::unbindColorBuffer() const {
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
int Framebuffer::width() const {
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace reone {
|
||||
|
||||
|
@ -25,15 +26,15 @@ namespace render {
|
|||
|
||||
class Framebuffer {
|
||||
public:
|
||||
Framebuffer(int w, int h);
|
||||
Framebuffer(int w, int h, int colorBufferCount = 1);
|
||||
~Framebuffer();
|
||||
|
||||
void init();
|
||||
void deinit();
|
||||
void bind() const;
|
||||
void unbind() const;
|
||||
void bindTexture() const;
|
||||
void unbindTexture() const;
|
||||
void bindColorBuffer(int n) const;
|
||||
void unbindColorBuffer() const;
|
||||
|
||||
int width() const;
|
||||
int height() const;
|
||||
|
@ -41,10 +42,11 @@ public:
|
|||
private:
|
||||
int _width { 0 };
|
||||
int _height { 0 };
|
||||
int _colorBufferCount { 0 };
|
||||
bool _inited { false };
|
||||
uint32_t _framebuffer { 0 };
|
||||
uint32_t _texture { 0 };
|
||||
uint32_t _renderbuffer { 0 };
|
||||
std::vector<uint32_t> _colorBuffers;
|
||||
uint32_t _depthBuffer { 0 };
|
||||
};
|
||||
|
||||
} // namespace render
|
||||
|
|
|
@ -33,12 +33,19 @@ namespace reone {
|
|||
namespace render {
|
||||
|
||||
static const int kMaxLightCount = 8;
|
||||
static const int kBlurPassCount = 1;
|
||||
|
||||
SceneGraph::SceneGraph(const GraphicsOptions &opts) : _opts(opts), _framebuffer(opts.width, opts.height) {
|
||||
SceneGraph::SceneGraph(const GraphicsOptions &opts) :
|
||||
_opts(opts),
|
||||
_geometryFramebuffer(opts.width, opts.height, 2),
|
||||
_vBlurFramebuffer(opts.width, opts.height),
|
||||
_hBlurFramebuffer(opts.width, opts.height) {
|
||||
}
|
||||
|
||||
void SceneGraph::init() {
|
||||
_framebuffer.init();
|
||||
_geometryFramebuffer.init();
|
||||
_vBlurFramebuffer.init();
|
||||
_hBlurFramebuffer.init();
|
||||
}
|
||||
|
||||
void SceneGraph::clear() {
|
||||
|
@ -95,7 +102,11 @@ void SceneGraph::render() const {
|
|||
|
||||
ShaderManager &shaders = Shaders;
|
||||
{
|
||||
_framebuffer.bind();
|
||||
// Render geometry
|
||||
_geometryFramebuffer.bind();
|
||||
|
||||
static const GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
|
||||
glDrawBuffers(2, buffers);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
@ -117,28 +128,98 @@ void SceneGraph::render() const {
|
|||
mesh->render();
|
||||
}
|
||||
|
||||
_framebuffer.unbind();
|
||||
_geometryFramebuffer.unbind();
|
||||
}
|
||||
{
|
||||
float w = static_cast<float>(_opts.width);
|
||||
float h = static_cast<float>(_opts.height);
|
||||
|
||||
GlobalUniforms globals;
|
||||
globals.projection = glm::ortho(0.0f, static_cast<float>(_opts.width), static_cast<float>(_opts.height), 0.0f);
|
||||
globals.projection = glm::ortho(0.0f, w, h, 0.0f);
|
||||
|
||||
shaders.setGlobalUniforms(globals);
|
||||
|
||||
for (int i = 0; i < kBlurPassCount; ++i) {
|
||||
{
|
||||
// Apply horizontal blur
|
||||
_hBlurFramebuffer.bind();
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
glm::mat4 transform(1.0f);
|
||||
transform = glm::scale(transform, glm::vec3(_framebuffer.width(), _framebuffer.height(), 1.0f));
|
||||
transform = glm::scale(transform, glm::vec3(w, h, 1.0f));
|
||||
|
||||
LocalUniforms locals;
|
||||
locals.model = move(transform);
|
||||
locals.features.blurEnabled = true;
|
||||
locals.blur.resolution = glm::vec2(w, h);
|
||||
locals.blur.direction = glm::vec2(1.0f, 0.0f);
|
||||
|
||||
shaders.activate(ShaderProgram::GUIGUI, locals);
|
||||
shaders.activate(ShaderProgram::GUIBlur, locals);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
_framebuffer.bindTexture();
|
||||
if (i == 0) {
|
||||
_geometryFramebuffer.bindColorBuffer(1);
|
||||
} else {
|
||||
_vBlurFramebuffer.bindColorBuffer(0);
|
||||
}
|
||||
|
||||
DefaultQuad.render(GL_TRIANGLES);
|
||||
|
||||
_framebuffer.unbindTexture();
|
||||
_geometryFramebuffer.unbindColorBuffer();
|
||||
_hBlurFramebuffer.unbind();
|
||||
}
|
||||
{
|
||||
// Apply vertical blur
|
||||
_vBlurFramebuffer.bind();
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
glm::mat4 transform(1.0f);
|
||||
transform = glm::scale(transform, glm::vec3(w, h, 1.0f));
|
||||
|
||||
LocalUniforms locals;
|
||||
locals.model = move(transform);
|
||||
locals.features.blurEnabled = true;
|
||||
locals.blur.resolution = glm::vec2(_opts.width, _opts.height);
|
||||
locals.blur.direction = glm::vec2(0.0f, 1.0f);
|
||||
|
||||
shaders.activate(ShaderProgram::GUIBlur, locals);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
_hBlurFramebuffer.bindColorBuffer(0);
|
||||
|
||||
DefaultQuad.render(GL_TRIANGLES);
|
||||
|
||||
_hBlurFramebuffer.unbindColorBuffer();
|
||||
_vBlurFramebuffer.unbind();
|
||||
}
|
||||
}
|
||||
{
|
||||
glm::mat4 transform(1.0f);
|
||||
transform = glm::scale(transform, glm::vec3(w, h, 1.0f));
|
||||
|
||||
LocalUniforms locals;
|
||||
locals.model = move(transform);
|
||||
locals.features.bloomEnabled = true;
|
||||
locals.textures.bloom = 1;
|
||||
|
||||
shaders.activate(ShaderProgram::GUIBloom, locals);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
_geometryFramebuffer.bindColorBuffer(0);
|
||||
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
_vBlurFramebuffer.bindColorBuffer(0);
|
||||
|
||||
DefaultQuad.render(GL_TRIANGLES);
|
||||
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
_vBlurFramebuffer.unbindColorBuffer();
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
_geometryFramebuffer.unbindColorBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -61,7 +61,9 @@ private:
|
|||
std::shared_ptr<CameraSceneNode> _activeCamera;
|
||||
glm::vec3 _ambientLightColor { 1.0f };
|
||||
uint32_t _textureId { 0 };
|
||||
Framebuffer _framebuffer;
|
||||
Framebuffer _geometryFramebuffer;
|
||||
Framebuffer _vBlurFramebuffer;
|
||||
Framebuffer _hBlurFramebuffer;
|
||||
|
||||
SceneGraph(const SceneGraph &) = delete;
|
||||
SceneGraph &operator=(const SceneGraph &) = delete;
|
||||
|
|
|
@ -116,10 +116,12 @@ static const GLchar kWhiteFragmentShader[] = R"END(
|
|||
|
||||
uniform float uAlpha;
|
||||
|
||||
out vec4 fragColor;
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
layout(location = 1) out vec4 fragColorBright;
|
||||
|
||||
void main() {
|
||||
fragColor = vec4(1.0, 1.0, 1.0, uAlpha);
|
||||
fragColorBright = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
)END";
|
||||
|
||||
|
@ -132,11 +134,13 @@ uniform float uAlpha;
|
|||
|
||||
in vec2 fragTexCoords;
|
||||
|
||||
out vec4 fragColor;
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
layout(location = 1) out vec4 fragColorBright;
|
||||
|
||||
void main() {
|
||||
vec4 textureSample = texture(uTexture, fragTexCoords);
|
||||
fragColor = vec4(uColor * textureSample.rgb, uAlpha * textureSample.a);
|
||||
fragColorBright = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
)END";
|
||||
|
||||
|
@ -179,7 +183,8 @@ in vec3 fragNormal;
|
|||
in vec2 fragTexCoords;
|
||||
in vec2 fragLightmapCoords;
|
||||
|
||||
out vec4 fragColor;
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
layout(location = 1) out vec4 fragColorBright;
|
||||
|
||||
void applyLightmap(inout vec3 color) {
|
||||
vec4 lightmapSample = texture(uLightmap, fragLightmapCoords);
|
||||
|
@ -219,13 +224,6 @@ void applyLighting(vec3 normal, inout vec3 color) {
|
|||
}
|
||||
}
|
||||
|
||||
void applySelfIllum(inout vec3 color) {
|
||||
vec4 diffuseSample = texture(uDiffuse, fragTexCoords);
|
||||
float luminosity = dot(diffuseSample.rgb, RGB_TO_LUMINOSITY);
|
||||
|
||||
color += 0.5 * smoothstep(0.5, 1.0, luminosity) * uSelfIllumColor;
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec4 diffuseSample = texture(uDiffuse, fragTexCoords);
|
||||
vec3 surfaceColor = diffuseSample.rgb;
|
||||
|
@ -246,15 +244,19 @@ void main() {
|
|||
} else {
|
||||
lightColor = vec3(1.0);
|
||||
}
|
||||
if (uSelfIllumEnabled) {
|
||||
applySelfIllum(lightColor);
|
||||
}
|
||||
float finalAlpha = uAlpha;
|
||||
|
||||
if (!uEnvmapEnabled && !uBumpyShinyEnabled) {
|
||||
finalAlpha *= diffuseSample.a;
|
||||
}
|
||||
fragColor = vec4(lightColor * surfaceColor, finalAlpha);
|
||||
|
||||
if (uSelfIllumEnabled) {
|
||||
vec3 color = uSelfIllumColor * diffuseSample.rgb;
|
||||
fragColorBright = vec4(smoothstep(0.75, 1.0, color), 1.0);
|
||||
} else {
|
||||
fragColorBright = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
)END";
|
||||
|
||||
|
@ -269,17 +271,37 @@ out vec4 fragColor;
|
|||
|
||||
void main() {
|
||||
vec2 uv = vec2(gl_FragCoord.xy / uResolution);
|
||||
vec2 off1 = vec2(1.3333333333333333) * uDirection;
|
||||
|
||||
vec4 color = vec4(0.0);
|
||||
color += texture2D(uTexture, uv) * 0.29411764705882354;
|
||||
color += texture2D(uTexture, uv + (off1 / uResolution)) * 0.35294117647058826;
|
||||
color += texture2D(uTexture, uv - (off1 / uResolution)) * 0.35294117647058826;
|
||||
vec2 off1 = vec2(1.3846153846) * uDirection;
|
||||
vec2 off2 = vec2(3.2307692308) * uDirection;
|
||||
color += texture2D(uTexture, uv) * 0.2270270270;
|
||||
color += texture2D(uTexture, uv + (off1 / uResolution)) * 0.3162162162;
|
||||
color += texture2D(uTexture, uv - (off1 / uResolution)) * 0.3162162162;
|
||||
color += texture2D(uTexture, uv + (off2 / uResolution)) * 0.0702702703;
|
||||
color += texture2D(uTexture, uv - (off2 / uResolution)) * 0.0702702703;
|
||||
|
||||
fragColor = color;
|
||||
}
|
||||
)END";
|
||||
|
||||
static const GLchar kBloomFragmentShader[] = R"END(
|
||||
#version 330
|
||||
|
||||
uniform sampler2D uGeometry;
|
||||
uniform sampler2D uBloom;
|
||||
|
||||
in vec2 fragTexCoords;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
void main() {
|
||||
vec3 geometryColor = texture(uGeometry, fragTexCoords).rgb;
|
||||
vec3 bloomColor = texture(uBloom, fragTexCoords).rgb;
|
||||
|
||||
fragColor = vec4(geometryColor + bloomColor, 1.0);
|
||||
}
|
||||
)END";
|
||||
|
||||
ShaderManager &ShaderManager::instance() {
|
||||
static ShaderManager instance;
|
||||
return instance;
|
||||
|
@ -291,9 +313,12 @@ void ShaderManager::initGL() {
|
|||
initShader(ShaderName::FragmentWhite, GL_FRAGMENT_SHADER, kWhiteFragmentShader);
|
||||
initShader(ShaderName::FragmentGUI, GL_FRAGMENT_SHADER, kGUIFragmentShader);
|
||||
initShader(ShaderName::FragmentModel, GL_FRAGMENT_SHADER, kModelFragmentShader);
|
||||
initShader(ShaderName::FragmentGaussianBlur, GL_FRAGMENT_SHADER, kGaussianBlurFragmentShader);
|
||||
initShader(ShaderName::FragmentBlur, GL_FRAGMENT_SHADER, kGaussianBlurFragmentShader);
|
||||
initShader(ShaderName::FragmentBloom, GL_FRAGMENT_SHADER, kBloomFragmentShader);
|
||||
|
||||
initProgram(ShaderProgram::GUIGUI, ShaderName::VertexGUI, ShaderName::FragmentGUI);
|
||||
initProgram(ShaderProgram::GUIBlur, ShaderName::VertexGUI, ShaderName::FragmentBlur);
|
||||
initProgram(ShaderProgram::GUIBloom, ShaderName::VertexGUI, ShaderName::FragmentBloom);
|
||||
initProgram(ShaderProgram::ModelWhite, ShaderName::VertexModel, ShaderName::FragmentWhite);
|
||||
initProgram(ShaderProgram::ModelModel, ShaderName::VertexModel, ShaderName::FragmentModel);
|
||||
}
|
||||
|
@ -432,6 +457,13 @@ void ShaderManager::setLocalUniforms(const LocalUniforms &locals) {
|
|||
if (locals.features.selfIllumEnabled) {
|
||||
setUniform("uSelfIllumColor", locals.selfIllumColor);
|
||||
}
|
||||
if (locals.features.blurEnabled) {
|
||||
setUniform("uResolution", locals.blur.resolution);
|
||||
setUniform("uDirection", locals.blur.direction);
|
||||
}
|
||||
if (locals.features.bloomEnabled) {
|
||||
setUniform("uBloom", locals.textures.bloom);
|
||||
}
|
||||
}
|
||||
|
||||
void ShaderManager::setUniform(const string &name, const glm::mat4 &m) {
|
||||
|
|
|
@ -31,6 +31,8 @@ namespace render {
|
|||
enum class ShaderProgram {
|
||||
None,
|
||||
GUIGUI,
|
||||
GUIBlur,
|
||||
GUIBloom,
|
||||
ModelWhite,
|
||||
ModelModel
|
||||
};
|
||||
|
@ -49,6 +51,8 @@ struct FeatureUniforms {
|
|||
bool skeletalEnabled { false };
|
||||
bool lightingEnabled { false };
|
||||
bool selfIllumEnabled { false };
|
||||
bool blurEnabled { false };
|
||||
bool bloomEnabled { false };
|
||||
};
|
||||
|
||||
struct TextureUniforms {
|
||||
|
@ -56,6 +60,7 @@ struct TextureUniforms {
|
|||
int envmap { 0 };
|
||||
int bumpyShiny { 0 };
|
||||
int bumpmap { 0 };
|
||||
int bloom { 0 };
|
||||
};
|
||||
|
||||
struct SkeletalUniforms {
|
||||
|
@ -75,11 +80,17 @@ struct LightingUniforms {
|
|||
std::vector<ShaderLight> lights;
|
||||
};
|
||||
|
||||
struct GaussianBlurUniforms {
|
||||
glm::vec2 resolution { 0.0f };
|
||||
glm::vec2 direction { 0.0f };
|
||||
};
|
||||
|
||||
struct LocalUniforms {
|
||||
FeatureUniforms features;
|
||||
TextureUniforms textures;
|
||||
SkeletalUniforms skeletal;
|
||||
LightingUniforms lighting;
|
||||
GaussianBlurUniforms blur;
|
||||
|
||||
glm::mat4 model { 1.0f };
|
||||
glm::vec3 color { 1.0f };
|
||||
|
@ -105,7 +116,8 @@ private:
|
|||
FragmentWhite,
|
||||
FragmentGUI,
|
||||
FragmentModel,
|
||||
FragmentGaussianBlur
|
||||
FragmentBlur,
|
||||
FragmentBloom
|
||||
};
|
||||
|
||||
std::unordered_map<ShaderName, uint32_t> _shaders;
|
||||
|
|
Loading…
Reference in a new issue