From f8526e1ac797dfd1e2ca1e89eb1daebbfc085c4a Mon Sep 17 00:00:00 2001 From: Anuken Date: Mon, 24 Jun 2019 19:39:57 -0400 Subject: [PATCH] Bloom --- .../bloomshaders/alpha_bloom.fragment.glsl | 23 + .../bloomshaders/alpha_gaussian.fragment.glsl | 26 ++ .../alpha_threshold.fragment.glsl | 15 + core/assets/bloomshaders/bloom.fragment.glsl | 23 + .../assets/bloomshaders/blurspace.vertex.glsl | 31 ++ .../bloomshaders/gaussian.fragment.glsl | 26 ++ .../bloomshaders/maskedtreshold.fragment.glsl | 17 + .../bloomshaders/screenspace.vertex.glsl | 13 + .../bloomshaders/threshold.fragment.glsl | 15 + .../src/io/anuke/mindustry/core/Renderer.java | 60 ++- .../io/anuke/mindustry/graphics/Bloom.java | 417 ++++++++++++++++++ .../anuke/mindustry/graphics/Pixelator.java | 2 +- 12 files changed, 645 insertions(+), 23 deletions(-) create mode 100644 core/assets/bloomshaders/alpha_bloom.fragment.glsl create mode 100644 core/assets/bloomshaders/alpha_gaussian.fragment.glsl create mode 100644 core/assets/bloomshaders/alpha_threshold.fragment.glsl create mode 100644 core/assets/bloomshaders/bloom.fragment.glsl create mode 100644 core/assets/bloomshaders/blurspace.vertex.glsl create mode 100644 core/assets/bloomshaders/gaussian.fragment.glsl create mode 100644 core/assets/bloomshaders/maskedtreshold.fragment.glsl create mode 100644 core/assets/bloomshaders/screenspace.vertex.glsl create mode 100644 core/assets/bloomshaders/threshold.fragment.glsl create mode 100644 core/src/io/anuke/mindustry/graphics/Bloom.java diff --git a/core/assets/bloomshaders/alpha_bloom.fragment.glsl b/core/assets/bloomshaders/alpha_bloom.fragment.glsl new file mode 100644 index 0000000000..00444c1dca --- /dev/null +++ b/core/assets/bloomshaders/alpha_bloom.fragment.glsl @@ -0,0 +1,23 @@ +#ifdef GL_ES +#define LOWP lowp +#define MED mediump +precision lowp float; +#else +#define LOWP +#define MED +#endif +uniform sampler2D u_texture0; +uniform sampler2D u_texture1; +uniform float BloomIntensity; +uniform float OriginalIntensity; + +varying MED vec2 v_texCoords; + +void main() +{ + + vec4 original = texture2D(u_texture0, v_texCoords) * OriginalIntensity; + vec4 bloom = texture2D(u_texture1, v_texCoords) * BloomIntensity; + original = original * (vec4(1.0) - bloom); + gl_FragColor = original + bloom; +} \ No newline at end of file diff --git a/core/assets/bloomshaders/alpha_gaussian.fragment.glsl b/core/assets/bloomshaders/alpha_gaussian.fragment.glsl new file mode 100644 index 0000000000..e060efc278 --- /dev/null +++ b/core/assets/bloomshaders/alpha_gaussian.fragment.glsl @@ -0,0 +1,26 @@ +#ifdef GL_ES +#define LOWP lowp +#define MED mediump +precision lowp float; +#else +#define LOWP +#define MED +#endif + +uniform sampler2D u_texture; +varying MED vec2 v_texCoords0; +varying MED vec2 v_texCoords1; +varying MED vec2 v_texCoords2; +varying MED vec2 v_texCoords3; +varying MED vec2 v_texCoords4; +const float center = 0.2270270270; +const float close = 0.3162162162; +const float far = 0.0702702703; +void main() +{ + gl_FragColor = far * texture2D(u_texture, v_texCoords0) + + close * texture2D(u_texture, v_texCoords1) + + center * texture2D(u_texture, v_texCoords2) + + close * texture2D(u_texture, v_texCoords3) + + far * texture2D(u_texture, v_texCoords4); +} diff --git a/core/assets/bloomshaders/alpha_threshold.fragment.glsl b/core/assets/bloomshaders/alpha_threshold.fragment.glsl new file mode 100644 index 0000000000..698e4e712f --- /dev/null +++ b/core/assets/bloomshaders/alpha_threshold.fragment.glsl @@ -0,0 +1,15 @@ +#ifdef GL_ES +#define LOWP lowp +#define MED mediump +precision lowp float; +#else +#define LOWP +#define MED +#endif +uniform sampler2D u_texture0; +uniform vec2 threshold; +varying MED vec2 v_texCoords; +void main() +{ + gl_FragColor = (texture2D(u_texture0, v_texCoords) - vec4(threshold.r)) * threshold.g; +} \ No newline at end of file diff --git a/core/assets/bloomshaders/bloom.fragment.glsl b/core/assets/bloomshaders/bloom.fragment.glsl new file mode 100644 index 0000000000..93bbfe3737 --- /dev/null +++ b/core/assets/bloomshaders/bloom.fragment.glsl @@ -0,0 +1,23 @@ +#ifdef GL_ES +#define LOWP lowp +#define MED mediump +precision lowp float; +#else +#define LOWP +#define MED +#endif +uniform sampler2D u_texture0; +uniform sampler2D u_texture1; +uniform float BloomIntensity; +uniform float OriginalIntensity; + +varying MED vec2 v_texCoords; + +void main() +{ + + vec3 original = texture2D(u_texture0, v_texCoords).rgb; + vec3 bloom = texture2D(u_texture1, v_texCoords).rgb * BloomIntensity; + original = OriginalIntensity * (original - original * bloom); + gl_FragColor.rgb = original + bloom; +} \ No newline at end of file diff --git a/core/assets/bloomshaders/blurspace.vertex.glsl b/core/assets/bloomshaders/blurspace.vertex.glsl new file mode 100644 index 0000000000..1d7135d9ab --- /dev/null +++ b/core/assets/bloomshaders/blurspace.vertex.glsl @@ -0,0 +1,31 @@ +#ifdef GL_ES +#define MED mediump +#else +#define MED +#endif + +attribute vec4 a_position; +attribute vec2 a_texCoord0; +uniform vec2 dir; +uniform vec2 size; +varying MED vec2 v_texCoords0; +varying MED vec2 v_texCoords1; +varying MED vec2 v_texCoords2; +varying MED vec2 v_texCoords3; +varying MED vec2 v_texCoords4; +const vec2 futher = vec2(3.2307692308, 3.2307692308); +const vec2 closer = vec2(1.3846153846, 1.3846153846); +void main() +{ + vec2 sizeAndDir = dir / size; + vec2 f = futher*sizeAndDir; + vec2 c = closer*sizeAndDir; + + v_texCoords0 = a_texCoord0 - f; + v_texCoords1 = a_texCoord0 - c; + v_texCoords2 = a_texCoord0; + v_texCoords3 = a_texCoord0 + c; + v_texCoords4 = a_texCoord0 + f; + + gl_Position = a_position; +} \ No newline at end of file diff --git a/core/assets/bloomshaders/gaussian.fragment.glsl b/core/assets/bloomshaders/gaussian.fragment.glsl new file mode 100644 index 0000000000..5373349f85 --- /dev/null +++ b/core/assets/bloomshaders/gaussian.fragment.glsl @@ -0,0 +1,26 @@ +#ifdef GL_ES +#define LOWP lowp +#define MED mediump +precision lowp float; +#else +#define LOWP +#define MED +#endif + +uniform sampler2D u_texture; +varying MED vec2 v_texCoords0; +varying MED vec2 v_texCoords1; +varying MED vec2 v_texCoords2; +varying MED vec2 v_texCoords3; +varying MED vec2 v_texCoords4; +const float center = 0.2270270270; +const float close = 0.3162162162; +const float far = 0.0702702703; +void main() +{ + gl_FragColor.rgb = far * texture2D(u_texture, v_texCoords0).rgb + + close * texture2D(u_texture, v_texCoords1).rgb + + center * texture2D(u_texture, v_texCoords2).rgb + + close * texture2D(u_texture, v_texCoords3).rgb + + far * texture2D(u_texture, v_texCoords4).rgb; +} diff --git a/core/assets/bloomshaders/maskedtreshold.fragment.glsl b/core/assets/bloomshaders/maskedtreshold.fragment.glsl new file mode 100644 index 0000000000..a65064e380 --- /dev/null +++ b/core/assets/bloomshaders/maskedtreshold.fragment.glsl @@ -0,0 +1,17 @@ +#ifdef GL_ES +#define LOWP lowp +#define MED mediump +precision lowp float; +#else +#define LOWP +#define MED +#endif +uniform sampler2D u_texture0; +uniform vec2 threshold; +varying MED vec2 v_texCoords; +void main() +{ + vec4 tex = texture2D(u_texture0, v_texCoords); + vec3 colors = (tex.rgb - threshold.r) * threshold.g * tex.a; + gl_FragColor = vec4(colors, tex.a); +} \ No newline at end of file diff --git a/core/assets/bloomshaders/screenspace.vertex.glsl b/core/assets/bloomshaders/screenspace.vertex.glsl new file mode 100644 index 0000000000..8e521c9a75 --- /dev/null +++ b/core/assets/bloomshaders/screenspace.vertex.glsl @@ -0,0 +1,13 @@ +#ifdef GL_ES +#define MED mediump +#else +#define MED +#endif +attribute vec4 a_position; +attribute vec2 a_texCoord0; +varying MED vec2 v_texCoords; +void main() +{ + v_texCoords = a_texCoord0; + gl_Position = a_position; +} \ No newline at end of file diff --git a/core/assets/bloomshaders/threshold.fragment.glsl b/core/assets/bloomshaders/threshold.fragment.glsl new file mode 100644 index 0000000000..52de3f18ed --- /dev/null +++ b/core/assets/bloomshaders/threshold.fragment.glsl @@ -0,0 +1,15 @@ +#ifdef GL_ES +#define LOWP lowp +#define MED mediump +precision lowp float; +#else +#define LOWP +#define MED +#endif +uniform sampler2D u_texture0; +uniform vec2 threshold; +varying MED vec2 v_texCoords; +void main() +{ + gl_FragColor.rgb = (texture2D(u_texture0, v_texCoords).rgb - vec3(threshold.x)) * threshold.y; +} \ No newline at end of file diff --git a/core/src/io/anuke/mindustry/core/Renderer.java b/core/src/io/anuke/mindustry/core/Renderer.java index fef6d6bcaa..75398e713e 100644 --- a/core/src/io/anuke/mindustry/core/Renderer.java +++ b/core/src/io/anuke/mindustry/core/Renderer.java @@ -35,6 +35,7 @@ public class Renderer implements ApplicationListener{ public final Pixelator pixelator = new Pixelator(); public FrameBuffer shieldBuffer = new FrameBuffer(2, 2); + private Bloom bloom; private Color clearColor; private float targetscale = io.anuke.arc.scene.ui.layout.Unit.dp.scl(4); private float camerascale = targetscale; @@ -43,6 +44,7 @@ public class Renderer implements ApplicationListener{ public Renderer(){ camera = new Camera(); + bloom = new Bloom(true); Lines.setCircleVertices(20); Shaders.init(); @@ -130,9 +132,16 @@ public class Renderer implements ApplicationListener{ minimap.dispose(); shieldBuffer.dispose(); blocks.dispose(); + bloom.dispose(); Events.fire(new DisposeEvent()); } + @Override + public void resize(int width, int height){ + bloom.dispose(); + bloom = new Bloom(true); + } + void updateShake(float scale){ if(shaketime > 0){ float intensity = shakeIntensity * (settings.getInt("screenshake", 4) / 4f) * scale; @@ -163,9 +172,9 @@ public class Renderer implements ApplicationListener{ blocks.floor.drawFloor(); - drawAndInterpolate(groundEffectGroup, e -> e instanceof BelowLiquidTrait); - drawAndInterpolate(puddleGroup); - drawAndInterpolate(groundEffectGroup, e -> !(e instanceof BelowLiquidTrait)); + draw(groundEffectGroup, e -> e instanceof BelowLiquidTrait); + draw(puddleGroup); + draw(groundEffectGroup, e -> !(e instanceof BelowLiquidTrait)); blocks.processBlocks(); @@ -196,11 +205,18 @@ public class Renderer implements ApplicationListener{ drawAllTeams(true); - drawAndInterpolate(bulletGroup); - drawAndInterpolate(effectGroup); + Draw.flush(); + bloom.setClearColor(0f, 0f, 0f, 0f); + bloom.capture(); + + draw(bulletGroup); + draw(effectGroup); + + Draw.flush(); + bloom.render(); overlays.drawBottom(); - drawAndInterpolate(playerGroup, p -> true, Player::drawBuildRequests); + draw(playerGroup, p -> true, Player::drawBuildRequests); if(Entities.countInBounds(shieldGroup) > 0){ if(settings.getBool("animatedshields")){ @@ -223,7 +239,7 @@ public class Renderer implements ApplicationListener{ overlays.drawTop(); - drawAndInterpolate(playerGroup, p -> !p.isDead() && !p.isLocal, Player::drawName); + draw(playerGroup, p -> !p.isDead() && !p.isLocal, Player::drawName); Draw.color(); Draw.flush(); @@ -240,12 +256,12 @@ public class Renderer implements ApplicationListener{ for(EntityGroup group : unitGroups){ if(!group.isEmpty()){ - drawAndInterpolate(group, unit -> !unit.isDead(), draw::accept); + draw(group, unit -> !unit.isDead(), draw::accept); } } if(!playerGroup.isEmpty()){ - drawAndInterpolate(playerGroup, unit -> !unit.isDead(), draw::accept); + draw(playerGroup, unit -> !unit.isDead(), draw::accept); } Draw.color(); @@ -257,12 +273,12 @@ public class Renderer implements ApplicationListener{ for(EntityGroup group : unitGroups){ if(!group.isEmpty()){ - drawAndInterpolate(group, unit -> unit.isFlying() && !unit.isDead(), baseUnit -> baseUnit.drawShadow(trnsX, trnsY)); + draw(group, unit -> unit.isFlying() && !unit.isDead(), baseUnit -> baseUnit.drawShadow(trnsX, trnsY)); } } if(!playerGroup.isEmpty()){ - drawAndInterpolate(playerGroup, unit -> unit.isFlying() && !unit.isDead(), player -> player.drawShadow(trnsX, trnsY)); + draw(playerGroup, unit -> unit.isFlying() && !unit.isDead(), player -> player.drawShadow(trnsX, trnsY)); } Draw.color(); @@ -275,27 +291,27 @@ public class Renderer implements ApplicationListener{ if(group.count(p -> p.isFlying() == flying) + playerGroup.count(p -> p.isFlying() == flying && p.getTeam() == team) == 0 && flying) continue; - drawAndInterpolate(unitGroups[team.ordinal()], u -> u.isFlying() == flying && !u.isDead(), Unit::drawUnder); - drawAndInterpolate(playerGroup, p -> p.isFlying() == flying && p.getTeam() == team && !p.isDead(), Unit::drawUnder); + draw(unitGroups[team.ordinal()], u -> u.isFlying() == flying && !u.isDead(), Unit::drawUnder); + draw(playerGroup, p -> p.isFlying() == flying && p.getTeam() == team && !p.isDead(), Unit::drawUnder); - drawAndInterpolate(unitGroups[team.ordinal()], u -> u.isFlying() == flying && !u.isDead(), Unit::drawAll); - drawAndInterpolate(playerGroup, p -> p.isFlying() == flying && p.getTeam() == team, Unit::drawAll); + draw(unitGroups[team.ordinal()], u -> u.isFlying() == flying && !u.isDead(), Unit::drawAll); + draw(playerGroup, p -> p.isFlying() == flying && p.getTeam() == team, Unit::drawAll); blocks.drawTeamBlocks(Layer.turret, team); - drawAndInterpolate(unitGroups[team.ordinal()], u -> u.isFlying() == flying && !u.isDead(), Unit::drawOver); - drawAndInterpolate(playerGroup, p -> p.isFlying() == flying && p.getTeam() == team, Unit::drawOver); + draw(unitGroups[team.ordinal()], u -> u.isFlying() == flying && !u.isDead(), Unit::drawOver); + draw(playerGroup, p -> p.isFlying() == flying && p.getTeam() == team, Unit::drawOver); } } - public void drawAndInterpolate(EntityGroup group){ - drawAndInterpolate(group, t -> true, DrawTrait::draw); + public void draw(EntityGroup group){ + draw(group, t -> true, DrawTrait::draw); } - public void drawAndInterpolate(EntityGroup group, Predicate toDraw){ - drawAndInterpolate(group, toDraw, DrawTrait::draw); + public void draw(EntityGroup group, Predicate toDraw){ + draw(group, toDraw, DrawTrait::draw); } - public void drawAndInterpolate(EntityGroup group, Predicate toDraw, Consumer drawer){ + public void draw(EntityGroup group, Predicate toDraw, Consumer drawer){ Entities.draw(group, toDraw, drawer); } diff --git a/core/src/io/anuke/mindustry/graphics/Bloom.java b/core/src/io/anuke/mindustry/graphics/Bloom.java new file mode 100644 index 0000000000..734992d8c0 --- /dev/null +++ b/core/src/io/anuke/mindustry/graphics/Bloom.java @@ -0,0 +1,417 @@ +package io.anuke.mindustry.graphics; + +import io.anuke.arc.Core; +import io.anuke.arc.graphics.*; +import io.anuke.arc.graphics.Pixmap.Format; +import io.anuke.arc.graphics.VertexAttributes.Usage; +import io.anuke.arc.graphics.glutils.FrameBuffer; +import io.anuke.arc.graphics.glutils.Shader; + +/** + * Bloomlib allow easy but efficient way to add bloom effect as post process + * effect + * + * @author kalle_h + */ +public class Bloom{ + + /** + * To use implement bloom more like a glow. Texture alpha channel can be + * used as mask which part are glowing and which are not. see more info at: + * http://www.gamasutra.com/view/feature/2107/realtime_glow.php + *

+ * NOTE: need to be set before bloom instance is created. After that this + * does nothing. + */ + public static boolean useAlphaChannelAsMask = false; + + /** how many blur pass */ + public int blurPasses = 1; + + private Shader tresholdShader; + private Shader bloomShader; + + private Mesh fullScreenQuad; + + private Texture pingPongTex1; + private Texture pingPongTex2; + private Texture original; + + private FrameBuffer frameBuffer; + private FrameBuffer pingPongBuffer1; + private FrameBuffer pingPongBuffer2; + + private Shader blurShader; + + private float bloomIntensity; + private float originalIntensity; + private float threshold; + private int w; + private int h; + private boolean blending = false; + private boolean capturing = false; + private float r = 0f; + private float g = 0f; + private float b = 0f; + private float a = 1f; + private boolean disposeFBO = true; + + /** + * IMPORTANT NOTE CALL THIS WHEN RESUMING + */ + public void resume(){ + bloomShader.begin(); + { + bloomShader.setUniformi("u_texture0", 0); + bloomShader.setUniformi("u_texture1", 1); + } + bloomShader.end(); + + setSize(w, h); + setThreshold(threshold); + setBloomIntesity(bloomIntensity); + setOriginalIntesity(originalIntensity); + + original = frameBuffer.getTexture(); + pingPongTex1 = pingPongBuffer1.getTexture(); + pingPongTex2 = pingPongBuffer2.getTexture(); + } + + /** + * Initialize bloom class that capsulate original scene capturate, + * tresholding, gaussian blurring and blending. Default values: depth = true + * blending = false 32bits = true + */ + public Bloom(){ + initialize(Core.graphics.getWidth() / 4, Core.graphics.getHeight() / 4, + null, false, false, true); + } + + public Bloom(boolean useBlending){ + initialize(Core.graphics.getWidth() / 4, Core.graphics.getHeight() / 4, + null, false, useBlending, true); + } + + /** + * Initialize bloom class that capsulate original scene capturate, + * tresholding, gaussian blurring and blending. + * + * @param FBO_W + * @param FBO_H how big fbo is used for bloom texture, smaller = more blur and + * lot faster but aliasing can be problem + * @param hasDepth do rendering need depth buffer + * @param useBlending does fbo need alpha channel and is blending enabled when final + * image is rendered. This allow to combine background graphics + * and only do blooming on certain objects param use32bitFBO does + * fbo use higher precision than 16bits. + */ + public Bloom(int FBO_W, int FBO_H, boolean hasDepth, boolean useBlending, + boolean use32bitFBO){ + initialize(FBO_W, FBO_H, null, hasDepth, useBlending, use32bitFBO); + + } + + /** + * EXPERT FUNCTIONALITY. no error checking. Use this only if you know what + * you are doing. Remember that bloom.capture() clear the screen so use + * continue instead if that is a problem. + *

+ * Initialize bloom class that capsulate original scene capturate, + * tresholding, gaussian blurring and blending. + *

+ * * @param sceneIsCapturedHere diposing is user responsibility. + * + * @param FBO_W + * @param FBO_H how big fbo is used for bloom texture, smaller = more blur and + * lot faster but aliasing can be problem + * @param useBlending does fbo need alpha channel and is blending enabled when final + * image is rendered. This allow to combine background graphics + * and only do blooming on certain objects param use32bitFBO does + * fbo use higher precision than 16bits. + */ + public Bloom(int FBO_W, int FBO_H, FrameBuffer sceneIsCapturedHere, + boolean useBlending, boolean use32bitFBO){ + + initialize(FBO_W, FBO_H, sceneIsCapturedHere, false, useBlending, + use32bitFBO); + disposeFBO = false; + } + + private void initialize(int FBO_W, int FBO_H, FrameBuffer fbo, + boolean hasDepth, boolean useBlending, boolean use32bitFBO){ + blending = useBlending; + Format format = null; + + if(use32bitFBO){ + if(useBlending){ + format = Format.RGBA8888; + }else{ + format = Format.RGB888; + } + + }else{ + if(useBlending){ + format = Format.RGBA4444; + }else{ + format = Format.RGB565; + } + } + if(fbo == null){ + frameBuffer = new FrameBuffer(format, Core.graphics.getWidth(), + Core.graphics.getHeight(), hasDepth); + }else{ + frameBuffer = fbo; + } + + pingPongBuffer1 = new FrameBuffer(format, FBO_W, FBO_H, false); + + pingPongBuffer2 = new FrameBuffer(format, FBO_W, FBO_H, false); + + original = frameBuffer.getTexture(); + pingPongTex1 = pingPongBuffer1.getTexture(); + pingPongTex2 = pingPongBuffer2.getTexture(); + + fullScreenQuad = createFullScreenQuad(); + final String alpha = useBlending ? "alpha_" : ""; + + bloomShader = createShader("screenspace", alpha + "bloom"); + + if(useAlphaChannelAsMask){ + tresholdShader = createShader("screenspace", "maskedtreshold"); + }else{ + tresholdShader = createShader("screenspace", alpha + "threshold"); + } + + blurShader = createShader("blurspace", alpha + "gaussian"); + + setSize(FBO_W, FBO_H); + setBloomIntesity(2.5f); + setOriginalIntesity(0.8f); + setThreshold(0.5f); + + bloomShader.begin(); + { + bloomShader.setUniformi("u_texture0", 0); + bloomShader.setUniformi("u_texture1", 1); + } + bloomShader.end(); + } + + /** + * Set clearing color for capturing buffer + * + * @param r + * @param g + * @param b + * @param a + */ + public void setClearColor(float r, float g, float b, float a){ + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } + + /** + * Call this before rendering scene. + */ + public void capture(){ + if(!capturing){ + capturing = true; + frameBuffer.begin(); + Core.gl.glClearColor(r, g, b, a); + Core.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + + } + } + + /** + * Pause capturing to fbo. + */ + public void capturePause(){ + if(capturing){ + capturing = false; + frameBuffer.end(); + } + } + + /** Start capturing again after pause, no clearing is done to framebuffer */ + public void captureContinue(){ + if(!capturing){ + capturing = true; + frameBuffer.begin(); + } + } + + /** + * Call this after scene. Renders the bloomed scene. + */ + public void render(){ + if(capturing){ + capturing = false; + frameBuffer.end(); + } + + Core.gl.glDisable(GL20.GL_BLEND); + Core.gl.glDisable(GL20.GL_DEPTH_TEST); + Core.gl.glDepthMask(false); + + gaussianBlur(); + + if(blending){ + Core.gl.glEnable(GL20.GL_BLEND); + Core.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA); + } + + pingPongTex1.bind(1); + original.bind(0); + bloomShader.begin(); + { + fullScreenQuad.render(bloomShader, GL20.GL_TRIANGLE_FAN); + } + bloomShader.end(); + + } + + private void gaussianBlur(){ + + // cut bright areas of the picture and blit to smaller fbo + + original.bind(0); + pingPongBuffer1.begin(); + { + tresholdShader.begin(); + { + // tresholdShader.setUniformi("u_texture0", 0); + fullScreenQuad.render(tresholdShader, GL20.GL_TRIANGLE_FAN, 0, + 4); + } + tresholdShader.end(); + } + pingPongBuffer1.end(); + + for(int i = 0; i < blurPasses; i++){ + + pingPongTex1.bind(0); + + // horizontal + pingPongBuffer2.begin(); + { + blurShader.begin(); + { + blurShader.setUniformf("dir", 1f, 0f); + fullScreenQuad.render(blurShader, GL20.GL_TRIANGLE_FAN, 0, + 4); + } + blurShader.end(); + } + pingPongBuffer2.end(); + + pingPongTex2.bind(0); + // vertical + pingPongBuffer1.begin(); + { + blurShader.begin(); + { + blurShader.setUniformf("dir", 0f, 1f); + + fullScreenQuad.render(blurShader, GL20.GL_TRIANGLE_FAN, 0, + 4); + } + blurShader.end(); + } + pingPongBuffer1.end(); + } + } + + /** + * set intensity for bloom. higher mean more brightening for spots that are + * over threshold + * + * @param intensity multiplier for blurred texture in combining phase. must be + * positive. + */ + public void setBloomIntesity(float intensity){ + bloomIntensity = intensity; + bloomShader.begin(); + { + bloomShader.setUniformf("BloomIntensity", intensity); + } + bloomShader.end(); + } + + /** + * set intensity for original scene. under 1 mean darkening and over 1 means + * lightening + * + * @param intensity multiplier for captured texture in combining phase. must be + * positive. + */ + public void setOriginalIntesity(float intensity){ + originalIntensity = intensity; + bloomShader.begin(); + { + bloomShader.setUniformf("OriginalIntensity", intensity); + } + bloomShader.end(); + } + + /** + * Treshold for bright parts. everything under threshold is clamped to 0 + * + * @param threshold must be in range 0..1 + */ + public void setThreshold(float threshold){ + this.threshold = threshold; + tresholdShader.begin(); + { + tresholdShader.setUniformf("threshold", threshold, + 1f / (1 - threshold)); + } + tresholdShader.end(); + } + + private void setSize(int FBO_W, int FBO_H){ + w = FBO_W; + h = FBO_H; + blurShader.begin(); + blurShader.setUniformf("size", FBO_W, FBO_H); + blurShader.end(); + } + + /** + * Call this when application is exiting. + */ + public void dispose(){ + if(disposeFBO) + frameBuffer.dispose(); + + fullScreenQuad.dispose(); + + pingPongBuffer1.dispose(); + pingPongBuffer2.dispose(); + + blurShader.dispose(); + bloomShader.dispose(); + tresholdShader.dispose(); + + } + + private static Mesh createFullScreenQuad(){ + float[] verts = {-1, -1, 0, 0, 1, -1, 1, 0, 1, 1, 1, 1, -1, 1, 0, 1}; + Mesh tmpMesh = new Mesh(true, 4, 0, new VertexAttribute( + Usage.Position, 2, "a_position"), new VertexAttribute( + Usage.TextureCoordinates, 2, "a_texCoord0")); + + tmpMesh.setVertices(verts); + return tmpMesh; + + } + + private static Shader createShader(String vertexName, String fragmentName){ + String vertexShader = Core.files.internal("bloomshaders/" + vertexName + ".vertex.glsl").readString(); + String fragmentShader = Core.files.internal("bloomshaders/" + fragmentName + ".fragment.glsl").readString(); + return new Shader(vertexShader, fragmentShader); + } + +} diff --git a/core/src/io/anuke/mindustry/graphics/Pixelator.java b/core/src/io/anuke/mindustry/graphics/Pixelator.java index e8a9e0d2f3..8cc252eebd 100644 --- a/core/src/io/anuke/mindustry/graphics/Pixelator.java +++ b/core/src/io/anuke/mindustry/graphics/Pixelator.java @@ -55,7 +55,7 @@ public class Pixelator implements Disposable{ Draw.rect(Draw.wrap(buffer.getTexture()), Core.camera.position.x, Core.camera.position.y, Core.camera.width, -Core.camera.height); Draw.blend(); - renderer.drawAndInterpolate(playerGroup, p -> !p.isDead() && !p.isLocal, Player::drawName); + renderer.draw(playerGroup, p -> !p.isDead() && !p.isLocal, Player::drawName); Core.camera.position.set(px, py); Core.settings.put("animatedwater", hadWater);