View difference between Paste ID: LDB9F59r and CYFjr9hT
SHOW: | | - or go back to the newest paste.
1-
------------------------
1+
package atmos;
2-
VERTEX PROGRAM:
2+
3-
------------------------
3+
import java.text.DecimalFormat;
4
import java.text.MessageFormat;
5-
attribute vec4 a_position;
5+
import java.util.Random;
6-
attribute vec4 a_color;
6+
7-
attribute vec2 a_texCoord0;
7+
import com.badlogic.gdx.ApplicationListener;
8-
uniform mat4 u_proj;
8+
import com.badlogic.gdx.Gdx;
9-
uniform mat4 u_trans;
9+
import com.badlogic.gdx.Input.Keys;
10-
uniform mat4 u_projTrans;
10+
import com.badlogic.gdx.InputAdapter;
11-
varying vec4 v_color;
11+
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
12-
varying vec2 v_texCoords;
12+
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
13
import com.badlogic.gdx.graphics.Color;
14-
void main()
14+
import com.badlogic.gdx.graphics.GL10;
15-
{
15+
import com.badlogic.gdx.graphics.OrthographicCamera;
16-
   v_color = a_color;
16+
import com.badlogic.gdx.graphics.Pixmap;
17-
   v_texCoords = a_texCoord0;
17+
import com.badlogic.gdx.graphics.Pixmap.Format;
18-
   gl_Position =  u_projTrans * a_position;
18+
import com.badlogic.gdx.graphics.Texture;
19-
}
19+
import com.badlogic.gdx.graphics.g2d.BitmapFont;
20
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
21
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
22
import com.badlogic.gdx.math.Matrix4;
23-
------------------------
23+
import com.badlogic.gdx.math.Vector2;
24-
FRAGMENT PROGRAM:
24+
import com.badlogic.gdx.math.Vector3;
25-
------------------------
25+
26
/**
27-
#ifdef GL_ES
27+
 * Simple illumination model with shaders in LibGDX.
28-
precision mediump float;
28+
 * @author davedes
29-
#endif
29+
 */
30
public class Illumination2D implements ApplicationListener {	
31-
varying vec4 v_color;
31+
32-
varying vec2 v_texCoords;
32+
	Texture texture, texture_n;
33-
uniform sampler2D u_texture;
33+
34-
uniform sampler2D u_normals;
34+
	boolean flipY;
35-
uniform vec3 light;
35+
	Texture normalBase;
36-
uniform vec3 ambientColor;
36+
	OrthographicCamera cam;
37-
uniform float ambientIntensity; 
37+
	SpriteBatch fxBatch, batch;
38-
uniform vec2 resolution;
38+
39-
uniform vec3 lightColor;
39+
	Matrix4 transform = new Matrix4();
40-
uniform bool useNormals;
40+
41-
uniform bool useShadow;
41+
	Random rnd = new Random();
42-
uniform vec3 attenuation;
42+
43-
uniform float strength;
43+
	// position of our light
44-
uniform bool yInvert;
44+
	final Vector3 DEFAULT_LIGHT_POS = new Vector3(0f, 0f, 0.07f);
45
	// the color of our light
46-
void main() {
46+
	final Vector3 DEFAULT_LIGHT_COLOR = new Vector3(1f, 0.7f, 0.6f);
47-
	//sample color & normals from our textures
47+
	// the ambient color (color to use when unlit)
48-
	vec4 color = texture2D(u_texture, v_texCoords.st);
48+
	final Vector3 DEFAULT_AMBIENT_COLOR = new Vector3(0.3f, 0.3f, 1f);
49-
	vec3 nColor = texture2D(u_normals, v_texCoords.st).rgb;
49+
	// the attenuation factor: x=constant, y=linear, z=quadratic
50
	final Vector3 DEFAULT_ATTENUATION = new Vector3(0.4f, 3f, 20f);
51-
	//some bump map programs will need the Y value flipped..
51+
	// the ambient intensity (brightness to use when unlit)
52-
	nColor.g = yInvert ? 1.0 - nColor.g : nColor.g;
52+
	final float DEFAULT_AMBIENT_INTENSITY = 0.2f;
53
	final float DEFAULT_STRENGTH = 1f;
54-
	//this is for debugging purposes, allowing us to lower the intensity of our bump map
54+
55-
	vec3 nBase = vec3(0.5, 0.5, 1.0);
55+
	final Color NORMAL_VCOLOR = new Color(1f,1f,1f,DEFAULT_STRENGTH);
56-
	nColor = mix(nBase, nColor, strength);
56+
57
	// the position of our light in 3D space
58-
	//normals need to be converted to [-1.0, 1.0] range and normalized
58+
	Vector3 lightPos = new Vector3(DEFAULT_LIGHT_POS);
59-
	vec3 normal = normalize(nColor * 2.0 - 1.0);
59+
	// the resolution of our game/graphics
60
	Vector2 resolution = new Vector2();
61-
	//here we do a simple distance calculation
61+
	// the current attenuation
62-
	vec3 deltaPos = vec3( (light.xy - gl_FragCoord.xy) / resolution.xy, light.z );
62+
	Vector3 attenuation = new Vector3(DEFAULT_ATTENUATION);
63
	// the current ambient intensity
64-
	vec3 lightDir = normalize(deltaPos);
64+
	float ambientIntensity = DEFAULT_AMBIENT_INTENSITY;
65-
	float lambert = useNormals ? clamp(dot(normal, lightDir), 0.0, 1.0) : 1.0;
65+
	float strength = DEFAULT_STRENGTH;
66
	
67-
	//now let's get a nice little falloff
67+
	// whether to use attenuation/shadows
68-
	float d = sqrt(dot(deltaPos, deltaPos));	
68+
	boolean useShadow = true;
69-
	float att = useShadow ? 1.0 / ( attenuation.x + (attenuation.y*d) + (attenuation.z*d*d) ) : 1.0;
69+
70
	// whether to use lambert shading (with our normal map)
71-
	vec3 result = (ambientColor * ambientIntensity) + (lightColor.rgb * lambert) * att;
71+
	boolean useNormals = true;
72-
	result *= color.rgb;
72+
73
	DecimalFormat DEC_FMT = new DecimalFormat("0.00000");
74-
	gl_FragColor = v_color * vec4(result, color.a);
74+
75
	ShaderProgram program;
76
77
	BitmapFont font;
78
	
79
	private int texWidth, texHeight;
80
	
81
	final String TEXT = "Use number keys to adjust parameters:\n" +
82
			"1: Randomize Ambient Color\n" +
83
			"2: Randomize Ambient Intensity {0}\n" +
84
			"3: Randomize Light Color\n" +
85
			"4/5: Increase/decrease constant attenuation: {1}\n" +
86
			"6/7: Increase/decrease linear attenuation: {2}\n" +
87
			"8/9: Increase/decrease quadratic attenuation: {3}\n" +
88
			"0: Reset parameters\n" +
89
			"RIGHT/LEFT: Increase/decrease normal map intensity: {4}\n" +
90
			"UP/DOWN: Increase/decrease lightDir.z: {5}\n\n" +
91
			"S toggles attenuation, N toggles normal shading\n" +
92
			"T to toggle textures";
93
	
94
	private Texture rock, rock_n, teapot, teapot_n;
95
	
96
	public void create() {
97
		// load our textures
98
		rock = new Texture(Gdx.files.internal("data/teapot.png"));
99
		rock_n = new Texture(Gdx.files.internal("data/teapot_n.png"));
100
		teapot = new Texture(Gdx.files.internal("data/rock.png"));
101
		teapot_n = new Texture(Gdx.files.internal("data/rock_n.png"));
102
		
103
		texture = teapot;
104
		texture_n = teapot_n;
105
		flipY = texture==rock;
106
		
107
		//we only use this to show what the strength-adjusted normal map looks like on screen
108
		Pixmap pix = new Pixmap(1, 1, Format.RGB565); 
109
		pix.setColor(0.5f, 0.5f, 1.0f, 1.0f); 
110
		pix.fill();
111
		normalBase = new Texture(pix);
112
		
113
		texWidth = texture.getWidth();
114
		texHeight = texture.getHeight();
115
		
116
		// a simple 2D orthographic camera
117
		cam = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
118
		cam.setToOrtho(false);
119
120
		// create our shader program...
121
		program = createShader();
122
123
		// now we create our sprite batch for our shader
124
		fxBatch = new SpriteBatch(100, program);
125
		// setShader is needed; perhaps this is a LibGDX bug?
126
		fxBatch.setShader(program);
127
		fxBatch.setProjectionMatrix(cam.combined);
128
		fxBatch.setTransformMatrix(transform);
129
130
		// usually we would just use a single batch for our application,
131
		// but for demonstration let's also show the un-affected image
132
		batch = new SpriteBatch(100);
133
		batch.setProjectionMatrix(cam.combined);
134
		batch.setTransformMatrix(transform);
135
136
		// quick little input for debugging -- press S to toggle shadows, N to
137
		// toggle normals
138
		Gdx.input.setInputProcessor(new InputAdapter() {
139
			public boolean keyDown(int key) {
140
				if (key == Keys.S) {
141
					useShadow = !useShadow;
142
					return true;
143
				} else if (key == Keys.N) {
144
					useNormals = !useNormals;
145
					return true;
146
				} else if (key == Keys.NUM_1) {
147
					program.begin();
148
					program.setUniformf("ambientColor", rndColor());
149
					program.end();
150
					return true;
151
				} else if (key == Keys.NUM_2) {
152
					ambientIntensity = rnd.nextFloat();
153
					return true;
154
				} else if (key == Keys.NUM_3) {
155
					program.begin();
156
					program.setUniformf("lightColor", rndColor());
157
					program.end();
158
					return true;
159
				} else if (key == Keys.NUM_0) {
160
					attenuation.set(DEFAULT_ATTENUATION);
161
					ambientIntensity = DEFAULT_AMBIENT_INTENSITY;
162
					lightPos.set(DEFAULT_LIGHT_POS);
163
					strength = DEFAULT_STRENGTH;
164
					program.begin();
165
					program.setUniformf("lightColor", DEFAULT_LIGHT_COLOR);
166
					program.setUniformf("ambientColor", DEFAULT_AMBIENT_COLOR);
167
					program.setUniformf("ambientIntensity", ambientIntensity);
168
					program.setUniformf("attenuation", attenuation);
169
					program.setUniformf("lightPos", lightPos);
170
					program.setUniformf("strength", strength);
171
					program.end();
172
				} else if (key == Keys.T) {
173
					texture = texture==teapot ? rock : teapot;
174
					texture_n = texture_n==teapot_n ? rock_n : teapot_n;
175
					flipY = texture==rock;
176
					texWidth = texture.getWidth();
177
					texHeight = texture.getHeight();
178
					program.begin();
179
					program.setUniformi("yInvert", flipY ? 1 : 0);
180
					program.end();
181
				}
182
				return false;
183
			}
184
		});
185
		
186
		font = new BitmapFont();
187
	}
188
	
189
	private Vector3 rndColor() {
190
		return new Vector3(rnd.nextFloat(), rnd.nextFloat(), rnd.nextFloat());
191
	}
192
193
	private ShaderProgram createShader() {
194
		// see the code here: http://pastebin.com/7fkh1ax8
195
		// simple illumination model using ambient, diffuse (lambert) and attenuation
196
		// see here: http://nccastaff.bournemouth.ac.uk/jmacey/CGF/slides/IlluminationModels4up.pdf
197
		String vert = "attribute vec4 " + ShaderProgram.POSITION_ATTRIBUTE + ";\n" //
198
				+ "attribute vec4 " + ShaderProgram.COLOR_ATTRIBUTE + ";\n" //
199
				+ "attribute vec2 " + ShaderProgram.TEXCOORD_ATTRIBUTE + "0;\n" //
200
				+ "uniform mat4 u_proj;\n" //
201
				+ "uniform mat4 u_trans;\n" //
202
				+ "uniform mat4 u_projTrans;\n" //
203
				+ "varying vec4 v_color;\n" //
204
				+ "varying vec2 v_texCoords;\n" //
205
				+ "\n" //
206
				+ "void main()\n" //
207
				+ "{\n" //
208
				+ "   v_color = " + ShaderProgram.COLOR_ATTRIBUTE + ";\n" //
209
				+ "   v_texCoords = " + ShaderProgram.TEXCOORD_ATTRIBUTE + "0;\n" //
210
				+ "   gl_Position =  u_projTrans * " + ShaderProgram.POSITION_ATTRIBUTE + ";\n" //
211
				+ "}\n";
212
		
213
		String frag = "#ifdef GL_ES\n" +
214
				"precision mediump float;\n" +
215
				"#endif\n" +
216
				"varying vec4 v_color;\n" +
217
				"varying vec2 v_texCoords;\n" +
218
				
219
				"uniform sampler2D u_texture;\n" +
220
				"uniform sampler2D u_normals;\n" +
221
				"uniform vec3 light;\n" + 
222
				"uniform vec3 ambientColor;\n" + 
223
				"uniform float ambientIntensity; \n" + 
224
				"uniform vec2 resolution;\n" + 
225
				"uniform vec3 lightColor;\n" + 
226
				"uniform bool useNormals;\n" + 
227
				"uniform bool useShadow;\n" + 
228
				"uniform vec3 attenuation;\n" + 
229
				"uniform float strength;\n" +
230
				"uniform bool yInvert;\n"+ 
231
				"\n" + 
232
				"void main() {\n" +
233
				"	//sample color & normals from our textures\n" +
234
				"	vec4 color = texture2D(u_texture, v_texCoords.st);\n" +
235
				"	vec3 nColor = texture2D(u_normals, v_texCoords.st).rgb;\n\n" +
236
				"	//some bump map programs will need the Y value flipped..\n" +
237
				"	nColor.g = yInvert ? 1.0 - nColor.g : nColor.g;\n\n" +
238
				"	//this is for debugging purposes, allowing us to lower the intensity of our bump map\n" +
239
				"	vec3 nBase = vec3(0.5, 0.5, 1.0);\n" +
240
				"	nColor = mix(nBase, nColor, strength);\n\n" +
241
				"	//normals need to be converted to [-1.0, 1.0] range and normalized\n" +
242
				"	vec3 normal = normalize(nColor * 2.0 - 1.0);\n\n" +
243
				"	//here we do a simple distance calculation\n" +
244
				"	vec3 deltaPos = vec3( (light.xy - gl_FragCoord.xy) / resolution.xy, light.z );\n\n" +
245
				"	vec3 lightDir = normalize(deltaPos);\n" + 
246
				"	float lambert = useNormals ? clamp(dot(normal, lightDir), 0.0, 1.0) : 1.0;\n" + 
247
				"	\n" + 
248
				"	//now let's get a nice little falloff\n" + 
249
				"	float d = sqrt(dot(deltaPos, deltaPos));"+ 
250
				"	\n" + 
251
				"	float att = useShadow ? 1.0 / ( attenuation.x + (attenuation.y*d) + (attenuation.z*d*d) ) : 1.0;\n" + 
252
				"	\n" + 
253
				"	vec3 result = (ambientColor * ambientIntensity) + (lightColor.rgb * lambert) * att;\n" + 
254
				"	result *= color.rgb;\n" + 
255
				"	\n" + 
256
				"	gl_FragColor = v_color * vec4(result, color.a);\n" + 
257
				"}";
258
		System.out.println("VERTEX PROGRAM:\n------------\n\n"+vert);
259
		System.out.println("FRAGMENT PROGRAM:\n------------\n\n"+frag);
260
		ShaderProgram program = new ShaderProgram(vert, frag);
261
		// u_proj and u_trans will not be active but SpriteBatch will still try to set them...
262
		program.pedantic = false;
263
		if (program.isCompiled() == false)
264
			throw new IllegalArgumentException("couldn't compile shader: "
265
					+ program.getLog());
266
267
		// set resolution vector
268
		resolution.set(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
269
270
		// we are only using this many uniforms for testing purposes...!!
271
		program.begin();
272
		program.setUniformi("u_texture", 0);
273
		program.setUniformi("u_normals", 1);
274
		program.setUniformf("light", lightPos);
275
		program.setUniformf("strength", strength);
276
		program.setUniformf("ambientIntensity", ambientIntensity);
277
		program.setUniformf("ambientColor", DEFAULT_AMBIENT_COLOR);
278
		program.setUniformf("resolution", resolution);
279
		program.setUniformf("lightColor", DEFAULT_LIGHT_COLOR);
280
		program.setUniformf("attenuation", attenuation);
281
		program.setUniformi("useShadow", useShadow ? 1 : 0);
282
		program.setUniformi("useNormals", useNormals ? 1 : 0);
283
		program.setUniformi("yInvert", flipY ? 1 : 0);
284
		program.end();
285
286
		return program;
287
	}
288
289
	public void dispose() {
290
		fxBatch.dispose();
291
		batch.dispose();
292
		texture.dispose();
293
		texture_n.dispose();
294
	}
295
	
296
	public void render() {
297
		Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
298
		
299
		// draw our sprites without any effects
300
		batch.begin();
301
		
302
		final int IMG_Y = texHeight/2; 
303
		
304
		//let's first simulate our resulting normal map by blending a blue square atop it
305
		//we also could have achieved this with glTexEnv in the fixed function pipeline
306
		NORMAL_VCOLOR.a = 1.0f - strength;
307
		batch.draw(texture_n, texWidth + 10, IMG_Y);
308
		batch.setColor(NORMAL_VCOLOR);
309
		batch.draw(normalBase, texWidth + 10, IMG_Y, texWidth, texHeight);
310
		batch.setColor(Color.WHITE);
311
		batch.draw(texture, 0, IMG_Y);
312
		//now let's simulate how our normal map will be sampled using strength
313
		//we can do this simply by blending a blue fill overtop
314
		
315
		String str = MessageFormat.format(TEXT, ambientIntensity,
316
				attenuation.x, attenuation.y, DEC_FMT.format(attenuation.z),
317
				strength, lightPos.z);
318
		font.drawMultiLine(batch, str, 10, Gdx.graphics.getHeight()-10);
319
		
320
		font.draw(batch, "Diffuse Color", 10, IMG_Y+texHeight + 30);
321
		font.draw(batch, "Normal Map", texWidth+20, IMG_Y+texHeight + 30);
322
		font.draw(batch, "Final Color", texWidth*2+30, IMG_Y+texHeight + 30);
323
		batch.end();
324
		
325
		// start our FX batch, which will bind our shader program
326
		fxBatch.begin();
327
		
328
		// get y-down light position based on mouse/touch
329
		lightPos.x = Gdx.input.getX();
330
		lightPos.y = Gdx.graphics.getHeight() - Gdx.input.getY();
331
		
332
		// handle attenuation input
333
		if (Gdx.input.isKeyPressed(Keys.NUM_4)) {
334
			attenuation.x += 0.025f;
335
		} else if (Gdx.input.isKeyPressed(Keys.NUM_5)) {
336
			attenuation.x -= 0.025f;
337
			if (attenuation.x < 0)
338
				attenuation.x = 0;
339
		} else if (Gdx.input.isKeyPressed(Keys.NUM_6)) {
340
			attenuation.y += 0.25f;
341
		} else if (Gdx.input.isKeyPressed(Keys.NUM_7)) {
342
			attenuation.y -= 0.25f;
343
			if (attenuation.y < 0)
344
				attenuation.y = 0;
345
		} else if (Gdx.input.isKeyPressed(Keys.NUM_8)) {
346
			attenuation.z += 0.25f;
347
		} else if (Gdx.input.isKeyPressed(Keys.NUM_9)) {
348
			attenuation.z -= 0.25f;
349
			if (attenuation.z < 0)
350
				attenuation.z = 0;
351
		} else if (Gdx.input.isKeyPressed(Keys.RIGHT)) {
352
			strength += 0.025f;
353
			if (strength > 1f)
354
				strength = 1f;
355
		} else if (Gdx.input.isKeyPressed(Keys.LEFT)) {
356
			strength -= 0.025f;
357
			if (strength < 0)
358
				strength = 0;
359
		} else if (Gdx.input.isKeyPressed(Keys.UP)) {
360
			lightPos.z += 0.0025f;
361
		} else if (Gdx.input.isKeyPressed(Keys.DOWN)) {
362
			lightPos.z -= 0.0025f;
363
		}
364
		
365
		// update our uniforms
366
		program.setUniformf("ambientIntensity", ambientIntensity);
367
		program.setUniformf("attenuation", attenuation);
368
		program.setUniformf("light", lightPos);
369
		program.setUniformi("useNormals", useNormals ? 1 : 0);
370
		program.setUniformi("useShadow", useShadow ? 1 : 0);
371
		program.setUniformf("strength", strength);
372
		
373
		// bind the normal first at texture1
374
		texture_n.bind(1);
375
		
376
		// bind the actual texture at texture0
377
		texture.bind(0);
378
		
379
		// we bind texture0 second since draw(texture) will end up binding it at
380
		// texture0...
381
		fxBatch.draw(texture, texWidth*2 + 20, IMG_Y);
382
		fxBatch.end();
383
	}
384
385
	public void resize(int width, int height) {
386
		cam.setToOrtho(false, width, height);
387
		resolution.set(width, height);
388
		program.setUniformf("resolution", resolution);
389
	}
390
391
	public void pause() {
392
	}
393
394
	public void resume() {
395
	}
396
397
	public static void main(String[] args) {
398
		LwjglApplicationConfiguration cfg = new LwjglApplicationConfiguration();
399
		cfg.title = "Lighting Test";
400
		cfg.useGL20 = true;
401
		cfg.width = 1024;
402
		cfg.height = 768;
403
		cfg.resizable = false;
404
405
		new LwjglApplication(new Illumination2D(), cfg);
406
	}
407
}