mirror of
https://github.com/Anuken/Mindustry.git
synced 2025-01-09 22:59:13 +07:00
Bloom
This commit is contained in:
parent
ab716e96e2
commit
f8526e1ac7
23
core/assets/bloomshaders/alpha_bloom.fragment.glsl
Normal file
23
core/assets/bloomshaders/alpha_bloom.fragment.glsl
Normal file
@ -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;
|
||||
}
|
26
core/assets/bloomshaders/alpha_gaussian.fragment.glsl
Normal file
26
core/assets/bloomshaders/alpha_gaussian.fragment.glsl
Normal file
@ -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);
|
||||
}
|
15
core/assets/bloomshaders/alpha_threshold.fragment.glsl
Normal file
15
core/assets/bloomshaders/alpha_threshold.fragment.glsl
Normal file
@ -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;
|
||||
}
|
23
core/assets/bloomshaders/bloom.fragment.glsl
Normal file
23
core/assets/bloomshaders/bloom.fragment.glsl
Normal file
@ -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;
|
||||
}
|
31
core/assets/bloomshaders/blurspace.vertex.glsl
Normal file
31
core/assets/bloomshaders/blurspace.vertex.glsl
Normal file
@ -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;
|
||||
}
|
26
core/assets/bloomshaders/gaussian.fragment.glsl
Normal file
26
core/assets/bloomshaders/gaussian.fragment.glsl
Normal file
@ -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;
|
||||
}
|
17
core/assets/bloomshaders/maskedtreshold.fragment.glsl
Normal file
17
core/assets/bloomshaders/maskedtreshold.fragment.glsl
Normal file
@ -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);
|
||||
}
|
13
core/assets/bloomshaders/screenspace.vertex.glsl
Normal file
13
core/assets/bloomshaders/screenspace.vertex.glsl
Normal file
@ -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;
|
||||
}
|
15
core/assets/bloomshaders/threshold.fragment.glsl
Normal file
15
core/assets/bloomshaders/threshold.fragment.glsl
Normal file
@ -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;
|
||||
}
|
@ -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<? extends BaseUnit> 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<? extends BaseUnit> 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 <T extends DrawTrait> void drawAndInterpolate(EntityGroup<T> group){
|
||||
drawAndInterpolate(group, t -> true, DrawTrait::draw);
|
||||
public <T extends DrawTrait> void draw(EntityGroup<T> group){
|
||||
draw(group, t -> true, DrawTrait::draw);
|
||||
}
|
||||
|
||||
public <T extends DrawTrait> void drawAndInterpolate(EntityGroup<T> group, Predicate<T> toDraw){
|
||||
drawAndInterpolate(group, toDraw, DrawTrait::draw);
|
||||
public <T extends DrawTrait> void draw(EntityGroup<T> group, Predicate<T> toDraw){
|
||||
draw(group, toDraw, DrawTrait::draw);
|
||||
}
|
||||
|
||||
public <T extends DrawTrait> void drawAndInterpolate(EntityGroup<T> group, Predicate<T> toDraw, Consumer<T> drawer){
|
||||
public <T extends DrawTrait> void draw(EntityGroup<T> group, Predicate<T> toDraw, Consumer<T> drawer){
|
||||
Entities.draw(group, toDraw, drawer);
|
||||
}
|
||||
|
||||
|
417
core/src/io/anuke/mindustry/graphics/Bloom.java
Normal file
417
core/src/io/anuke/mindustry/graphics/Bloom.java
Normal file
@ -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
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* Initialize bloom class that capsulate original scene capturate,
|
||||
* tresholding, gaussian blurring and blending.
|
||||
* <p>
|
||||
* * @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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user