-
Notifications
You must be signed in to change notification settings - Fork 184
/
ShaderLesson5.java
191 lines (142 loc) · 5.43 KB
/
ShaderLesson5.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
package mdesl.test.shadertut;
import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT;
import static org.lwjgl.opengl.GL11.glClear;
import static org.lwjgl.opengl.GL11.glClearColor;
import java.io.IOException;
import mdesl.graphics.SpriteBatch;
import mdesl.graphics.Texture;
import mdesl.graphics.glutils.FrameBuffer;
import mdesl.graphics.glutils.ShaderProgram;
import mdesl.test.Game;
import mdesl.test.SimpleGame;
import mdesl.test.Util;
import mdesl.util.MathUtil;
import org.lwjgl.LWJGLException;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.lwjgl.util.vector.Matrix4f;
public class ShaderLesson5 extends SimpleGame {
//should be at least as large as our display
public static final int FBO_SIZE = 1024;
public static void main(String[] args) throws LWJGLException {
Game game = new ShaderLesson5();
game.setDisplayMode(800, 600, false);
game.start();
}
//our texture to blur
Texture tex, tex2;
//we'll use a single batch for everything
SpriteBatch batch;
//our blur shader
ShaderProgram blurShader;
//our offscreen buffers
FrameBuffer blurTargetA, blurTargetB;
float radius = 3f;
final static float MAX_BLUR = 3f;
protected void create() throws LWJGLException {
super.create();
try {
//load our texture with linear filter
tex = new Texture(Util.getResource("res/slider.png"), Texture.LINEAR);
tex2 = new Texture(Util.getResource("res/tiles.png"), Texture.LINEAR);
} catch (IOException e) {
throw new RuntimeException("couldn't decode texture");
}
//our simple demo won't support display resizing
Display.setResizable(false);
//load our shader program and sprite batch
try {
//create our FBOs
blurTargetA = new FrameBuffer(FBO_SIZE, FBO_SIZE, Texture.LINEAR);
blurTargetB = new FrameBuffer(FBO_SIZE, FBO_SIZE, Texture.LINEAR);
//our basic pass-through vertex shader
final String VERT = Util.readFile(Util.getResourceAsStream("res/shadertut/lesson5.vert"));
//our fragment shader, which does the blur in one direction at a time
final String FRAG = Util.readFile(Util.getResourceAsStream("res/shadertut/lesson5.frag"));
//create our shader program
blurShader = new ShaderProgram(VERT, FRAG, SpriteBatch.ATTRIBUTES);
//Good idea to log any warnings if they exist
if (blurShader.getLog().length()!=0)
System.out.println(blurShader.getLog());
//always a good idea to set up default uniforms...
blurShader.use();
blurShader.setUniformf("dir", 0f, 0f); //direction of blur; nil for now
blurShader.setUniformf("resolution", FBO_SIZE); //size of FBO texture
blurShader.setUniformf("radius", radius); //radius of blur
batch = new SpriteBatch();
} catch (Exception e) {
//simple exception handling...
e.printStackTrace();
System.exit(0);
}
}
protected void drawEntities(SpriteBatch batch) {
batch.draw(tex, 50, 50);
batch.draw(tex2, tex.getWidth()+20, 100);
}
void renderScene() throws LWJGLException {
//Bind FBO target A
blurTargetA.begin();
//Clear FBO A with an opaque colour to minimize blending issues
glClearColor(0.5f, 0.5f, 0.5f, 1f);
glClear(GL_COLOR_BUFFER_BIT);
//Reset batch to default shader (without blur)
batch.setShader(SpriteBatch.getDefaultShader());
//send the new projection matrix (FBO size) to the default shader
batch.resize(blurTargetA.getWidth(), blurTargetA.getHeight());
//now we can start our batch
batch.begin();
//render our scene fully to FBO A
drawEntities(batch);
//flush the batch, i.e. render entities to GPU
batch.flush();
//After flushing, we can finish rendering to FBO target A
blurTargetA.end();
}
void horizontalBlur() throws LWJGLException {
//swap the shaders
//this will send the batch's (FBO-sized) projection matrix to our blur shader
batch.setShader(blurShader);
//ensure the direction is along the X-axis only
blurShader.setUniformf("dir", 1f, 0f);
//determine radius of blur based on mouse position
float mouseXAmt = Mouse.getX() / (float)Display.getWidth();
blurShader.setUniformf("radius", mouseXAmt * MAX_BLUR);
//start rendering to target B
blurTargetB.begin();
//no need to clear since targetA has an opaque background
//render target A (the scene) using our horizontal blur shader
//it will be placed into target B
batch.draw(blurTargetA, 0, 0);
//flush the batch before ending target B
batch.flush();
//finish rendering target B
blurTargetB.end();
}
void verticalBlur() throws LWJGLException {
//now we can render to the screen using the vertical blur shader
//send the screen-size projection matrix to the blurShader
batch.resize(Display.getWidth(), Display.getHeight());
//apply the blur only along Y-axis
blurShader.setUniformf("dir", 0f, 1f);
//update Y-axis blur radius based on mouse
float mouseYAmt = (Display.getHeight()-Mouse.getY()-1) / (float)Display.getHeight();
blurShader.setUniformf("radius", mouseYAmt * MAX_BLUR);
//draw the horizontally-blurred FBO B to the screen, applying the vertical blur as we go
batch.draw(blurTargetB, 0, 0);
batch.end();
}
protected void render() throws LWJGLException {
//render scene to FBO A
renderScene();
//render FBO A to FBO B, using horizontal blur
horizontalBlur();
//render FBO B to scene, using vertical blur
verticalBlur();
}
// called to resize the display
protected void resize() throws LWJGLException {
super.resize();
//we will call batch.resize() in render
}
}