Better bloom effect

This commit is contained in:
Tomoaki Kawada 2016-11-07 01:37:15 +09:00
parent 2358f30ce2
commit 2db1a22f81
4 changed files with 86 additions and 42 deletions

View File

@ -1,21 +1,21 @@
/* /*
Copyright (c) 2013 yvt Copyright (c) 2013 yvt
This file is part of OpenSpades. This file is part of OpenSpades.
OpenSpades is free software: you can redistribute it and/or modify OpenSpades is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
OpenSpades is distributed in the hope that it will be useful, OpenSpades is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>. along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
*/ */
@ -29,13 +29,13 @@ varying vec4 texCoord1;
varying vec4 texCoord2; varying vec4 texCoord2;
void main() { void main() {
vec2 pos = positionAttribute; vec2 pos = positionAttribute;
vec2 scrPos = pos * 2. - 1.; vec2 scrPos = pos * 2. - 1.;
gl_Position = vec4(scrPos, 0.5, 1.); gl_Position = vec4(scrPos, 0.5, 1.);
// generated by ./1dgaussGen.rb // generated by ./1dgaussGen.rb
// pixelShift is texture coord shift / texture pixel // pixelShift is texture coord shift / texture pixel
const float pixelShift = 1.; const float pixelShift = 1.;
@ -47,9 +47,9 @@ void main() {
const float scale3 = 0.321295592929097; const float scale3 = 0.321295592929097;
const float shift4 = pixelShift * 2.30654399138844; const float shift4 = pixelShift * 2.30654399138844;
const float scale4 = 0.178704407070903; const float scale4 = 0.178704407070903;
texCoord1 = pos.xyxy + unitShift.xyxy * vec4(vec2(shift1), vec2(shift2)); texCoord1 = pos.xyxy + unitShift.xyxy * vec4(vec2(shift1), vec2(shift2));
texCoord2 = pos.xyxy + unitShift.xyxy * vec4(vec2(shift3), vec2(shift4)); texCoord2 = pos.xyxy + unitShift.xyxy * vec4(vec2(shift3), vec2(shift4));
} }

View File

@ -1,21 +1,21 @@
/* /*
Copyright (c) 2013 yvt Copyright (c) 2013 yvt
This file is part of OpenSpades. This file is part of OpenSpades.
OpenSpades is free software: you can redistribute it and/or modify OpenSpades is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
OpenSpades is distributed in the hope that it will be useful, OpenSpades is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with OpenSpades. If not, see <http://www.gnu.org/licenses/>. along with OpenSpades. If not, see <http://www.gnu.org/licenses/>.
*/ */
@ -38,45 +38,45 @@ void main() {
vec3 dust2 = texture2D(dustTexture, dustTexCoord1.zw).xyz; vec3 dust2 = texture2D(dustTexture, dustTexCoord1.zw).xyz;
vec3 dust3 = texture2D(dustTexture, dustTexCoord2.xy).xyz; vec3 dust3 = texture2D(dustTexture, dustTexCoord2.xy).xyz;
vec3 dust4 = texture2D(dustTexture, dustTexCoord2.zw).xyz; vec3 dust4 = texture2D(dustTexture, dustTexCoord2.zw).xyz;
// linearize // linearize
dust1 *= dust1; dust1 *= dust1;
dust2 *= dust2; dust2 *= dust2;
dust3 *= dust3; dust3 *= dust3;
dust4 *= dust4; dust4 *= dust4;
// blurred texture (already linearized?) // blurred texture (already linearized?)
vec3 blur1 = texture2D(blurTexture1, texCoord).xyz; vec3 blur1 = texture2D(blurTexture1, texCoord).xyz;
vec3 blur2 = texture2D(blurTexture2, texCoord).xyz; vec3 blur2 = texture2D(blurTexture2, texCoord).xyz;
vec3 blur3 = texture2D(blurTexture3, texCoord).xyz; vec3 blur3 = texture2D(blurTexture3, texCoord).xyz;
vec3 blur4 = texture2D(blurTexture4, texCoord).xyz; vec3 blur4 = texture2D(blurTexture4, texCoord).xyz;
vec3 sum = dust1 * blur1; vec3 sum = dust1 * blur1;
sum += dust2 * blur2; sum += dust2 * blur2;
sum += dust3 * blur3; sum += dust3 * blur3;
sum += dust4 * blur4; sum += dust4 * blur4;
vec3 final = texture2D(inputTexture, texCoord).xyz; vec3 final = texture2D(inputTexture, texCoord).xyz;
#if !LINEAR_FRAMEBUFFER #if !LINEAR_FRAMEBUFFER
final *= final; final *= final;
#endif #endif
final *= 0.95; final *= 0.95;
final += sum * 0.4; final += sum * 0.8;
// add grain // add grain
float grain = texture2D(noiseTexture, noiseTexCoord.xy).x; float grain = texture2D(noiseTexture, noiseTexCoord.xy).x;
grain += texture2D(noiseTexture, noiseTexCoord.zw).x; grain += texture2D(noiseTexture, noiseTexCoord.zw).x;
grain = fract(grain) - 0.5; grain = fract(grain) - 0.5;
final += grain * 0.003; final += grain * 0.003;
// non-linearize // non-linearize
#if !LINEAR_FRAMEBUFFER #if !LINEAR_FRAMEBUFFER
final = sqrt(max(final, 0.)); final = sqrt(max(final, 0.));
#else #else
final = max(final, 0.); final = max(final, 0.);
#endif #endif
gl_FragColor = vec4(final, 1.); gl_FragColor = vec4(final, 1.);
} }

View File

@ -37,8 +37,9 @@ SPADES_SETTING(r_hdr, "");
namespace spades { namespace spades {
namespace draw { namespace draw {
GLLensDustFilter::GLLensDustFilter(GLRenderer *renderer): GLLensDustFilter::GLLensDustFilter(GLRenderer *renderer):
renderer(renderer){ renderer(renderer){
thru = renderer->RegisterProgram("Shaders/PostFilters/PassThroughConstAlpha.program"); thru = renderer->RegisterProgram("Shaders/PostFilters/PassThroughConstAlpha.program");
gauss1d = renderer->RegisterProgram("Shaders/PostFilters/Gauss1D.program");
dust = renderer->RegisterProgram("Shaders/PostFilters/LensDust.program"); dust = renderer->RegisterProgram("Shaders/PostFilters/LensDust.program");
dustImg = (GLImage *)renderer->RegisterImage("Textures/RealLens.jpg"); dustImg = (GLImage *)renderer->RegisterImage("Textures/RealLens.jpg");
@ -81,8 +82,9 @@ namespace spades {
static GLProgramAttribute blur_positionAttribute("positionAttribute"); static GLProgramAttribute blur_positionAttribute("positionAttribute");
static GLProgramUniform blur_textureUniform("texture"); static GLProgramUniform blur_textureUniform("texture");
static GLProgramUniform blur_colorUniform("colorUniform"); static GLProgramUniform blur_colorUniform("colorUniform");
static GLProgramUniform blur_texCoordRangeUniform("texCoordRange"); static GLProgramUniform blur_texCoordRangeUniform("texCoordRange");
static GLProgramUniform blur_texCoordOffsetUniform("texCoordOffset");
program->Use(); program->Use();
blur_positionAttribute(program); blur_positionAttribute(program);
@ -90,12 +92,17 @@ namespace spades {
blur_textureUniform.SetValue(0); blur_textureUniform.SetValue(0);
dev->ActiveTexture(0); dev->ActiveTexture(0);
dev->BindTexture(IGLDevice::Texture2D, tex.GetTexture()); dev->BindTexture(IGLDevice::Texture2D, tex.GetTexture());
blur_texCoordOffsetUniform(program);
blur_texCoordOffsetUniform.SetValue(1.f / w, 1.f / h, -1.f / w, -1.f / h);
blur_colorUniform(program); blur_colorUniform(program);
blur_colorUniform.SetValue(1.f,1.f,1.f,1.f); blur_colorUniform.SetValue(1.f,1.f,1.f,1.f);
blur_texCoordRangeUniform(program); blur_texCoordRangeUniform(program);
blur_texCoordRangeUniform.SetValue(0.f, 0.f, 1.f, 1.f); blur_texCoordRangeUniform.SetValue(0.f, 0.f,
(float)((w + 1) & ~1) / w,
(float)((h + 1) & ~1) / h);
qr.SetCoordAttributeIndex(blur_positionAttribute()); qr.SetCoordAttributeIndex(blur_positionAttribute());
if(linearize){ if(linearize){
@ -112,6 +119,39 @@ namespace spades {
qr.Draw(); qr.Draw();
return buf2; return buf2;
} }
GLColorBuffer GLLensDustFilter::GaussianBlur(GLColorBuffer tex, bool vertical) {
SPADES_MARK_FUNCTION();
GLProgram *program = gauss1d;
IGLDevice *dev = renderer->GetGLDevice();
GLQuadRenderer qr(dev);
int w = tex.GetWidth();
int h = tex.GetHeight();
static GLProgramAttribute blur_positionAttribute("positionAttribute");
static GLProgramUniform blur_textureUniform("texture");
static GLProgramUniform blur_unitShift("unitShift");
program->Use();
blur_positionAttribute(program);
blur_textureUniform(program);
blur_textureUniform.SetValue(0);
dev->ActiveTexture(0);
dev->BindTexture(IGLDevice::Texture2D, tex.GetTexture());
blur_unitShift(program);
blur_unitShift.SetValue(vertical ? 0.f : 1.f / w,
vertical ? 1.f / h : 0.f);
qr.SetCoordAttributeIndex(blur_positionAttribute());
dev->Enable(IGLDevice::Blend, false);
GLColorBuffer buf2 = renderer->GetFramebufferManager()->CreateBufferHandle(w, h, false);
dev->Viewport(0, 0, buf2.GetWidth(), buf2.GetHeight());
dev->BindFramebuffer(IGLDevice::Framebuffer, buf2.GetFramebuffer());
qr.Draw();
return buf2;
}
void GLLensDustFilter::UpdateNoise() { void GLLensDustFilter::UpdateNoise() {
SPADES_MARK_FUNCTION(); SPADES_MARK_FUNCTION();
@ -162,18 +202,18 @@ namespace spades {
thruTexCoordRange(thru); thruTexCoordRange(thru);
GLColorBuffer downSampled = DownSample(input, r_hdr ? false : true); GLColorBuffer downSampled = DownSample(input, r_hdr ? false : true);
downSampled = DownSample(downSampled); downSampled = GaussianBlur(downSampled, false);
downSampled = DownSample(downSampled); downSampled = GaussianBlur(downSampled, true);
thru->Use(); thru->Use();
thruColor.SetValue(1.f, 1.f, 1.f, 1.f); thruColor.SetValue(1.f, 1.f, 1.f, 1.f);
thruTexture.SetValue(0); thruTexture.SetValue(0);
dev->Enable(IGLDevice::Blend, false); dev->Enable(IGLDevice::Blend, false);
levels.reserve(8); levels.reserve(10);
// create downsample levels // create downsample levels
for(int i = 0; i < 8; i++){ for(int i = 0; i < 10; i++){
GLColorBuffer prevLevel; GLColorBuffer prevLevel;
if(i == 0){ if(i == 0){
prevLevel = downSampled; prevLevel = downSampled;
@ -187,7 +227,9 @@ namespace spades {
int newH = (prevH + 1) / 2; int newH = (prevH + 1) / 2;
if(newW <= 1 || newH <= 1) if(newW <= 1 || newH <= 1)
break; break;
GLColorBuffer newLevel = DownSample(prevLevel); GLColorBuffer newLevel = DownSample(prevLevel);
newLevel = GaussianBlur(newLevel, false);
newLevel = GaussianBlur(newLevel, true);
Level lv; Level lv;
lv.w = newW; lv.h = newH; lv.w = newW; lv.h = newH;
@ -205,12 +247,12 @@ namespace spades {
for(int i = (int)levels.size() - 1; i >= 1; i--){ for(int i = (int)levels.size() - 1; i >= 1; i--){
int cnt = (int)levels.size() - i; int cnt = (int)levels.size() - i;
float alpha = (float)cnt / (float)(cnt + 1); float alpha = (float)cnt / (float)(cnt + 1);
alpha = sqrtf(alpha); alpha = alpha;
GLColorBuffer curLevel = levels[i].buffer; GLColorBuffer curLevel = levels[i].buffer;
float sx = .7f / curLevel.GetWidth(); float sx = .25f / curLevel.GetWidth();
float sy = .7f / curLevel.GetHeight(); float sy = .25f / curLevel.GetHeight();
for(int j = 0; j < 4; j++) { for(int j = 0; j < 4; j++) {
if(i < (int)levels.size() - 1) { if(i < (int)levels.size() - 1) {

View File

@ -32,13 +32,15 @@ namespace spades {
class GLProgram; class GLProgram;
class GLImage; class GLImage;
class GLLensDustFilter { class GLLensDustFilter {
GLProgram *thru; GLProgram *thru;
GLProgram *dust; GLProgram *dust;
GLProgram *gauss1d;
GLImage *dustImg; GLImage *dustImg;
GLRenderer *renderer; GLRenderer *renderer;
IGLDevice::UInteger noiseTex; IGLDevice::UInteger noiseTex;
std::vector<uint32_t> noise; std::vector<uint32_t> noise;
GLColorBuffer DownSample(GLColorBuffer, bool linearize = false); GLColorBuffer DownSample(GLColorBuffer, bool linearize = false);
GLColorBuffer GaussianBlur(GLColorBuffer, bool vertical);
void UpdateNoise(); void UpdateNoise();
public: public:
GLLensDustFilter(GLRenderer *); GLLensDustFilter(GLRenderer *);