Advertisement
Guest User

Untitled

a guest
Oct 16th, 2012
2,192
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. package atmos;
  2.  
  3. import java.text.DecimalFormat;
  4. import java.text.MessageFormat;
  5. import java.util.Random;
  6.  
  7. import com.badlogic.gdx.ApplicationListener;
  8. import com.badlogic.gdx.Gdx;
  9. import com.badlogic.gdx.Input.Keys;
  10. import com.badlogic.gdx.InputAdapter;
  11. import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
  12. import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
  13. import com.badlogic.gdx.graphics.Color;
  14. import com.badlogic.gdx.graphics.GL10;
  15. import com.badlogic.gdx.graphics.OrthographicCamera;
  16. import com.badlogic.gdx.graphics.Pixmap;
  17. import com.badlogic.gdx.graphics.Pixmap.Format;
  18. import com.badlogic.gdx.graphics.Texture;
  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. import com.badlogic.gdx.math.Vector2;
  24. import com.badlogic.gdx.math.Vector3;
  25.  
  26. /**
  27.  * Simple illumination model with shaders in LibGDX.
  28.  * @author davedes
  29.  */
  30. public class Illumination2D implements ApplicationListener {   
  31.  
  32.     Texture texture, texture_n;
  33.    
  34.     boolean flipY;
  35.     Texture normalBase;
  36.     OrthographicCamera cam;
  37.     SpriteBatch fxBatch, batch;
  38.    
  39.     Matrix4 transform = new Matrix4();
  40.  
  41.     Random rnd = new Random();
  42.  
  43.     // position of our light
  44.     final Vector3 DEFAULT_LIGHT_POS = new Vector3(0f, 0f, 0.07f);
  45.     // the color of our light
  46.     final Vector3 DEFAULT_LIGHT_COLOR = new Vector3(1f, 0.7f, 0.6f);
  47.     // the ambient color (color to use when unlit)
  48.     final Vector3 DEFAULT_AMBIENT_COLOR = new Vector3(0.3f, 0.3f, 1f);
  49.     // the attenuation factor: x=constant, y=linear, z=quadratic
  50.     final Vector3 DEFAULT_ATTENUATION = new Vector3(0.4f, 3f, 20f);
  51.     // the ambient intensity (brightness to use when unlit)
  52.     final float DEFAULT_AMBIENT_INTENSITY = 0.2f;
  53.     final float DEFAULT_STRENGTH = 1f;
  54.    
  55.     final Color NORMAL_VCOLOR = new Color(1f,1f,1f,DEFAULT_STRENGTH);
  56.    
  57.     // the position of our light in 3D space
  58.     Vector3 lightPos = new Vector3(DEFAULT_LIGHT_POS);
  59.     // the resolution of our game/graphics
  60.     Vector2 resolution = new Vector2();
  61.     // the current attenuation
  62.     Vector3 attenuation = new Vector3(DEFAULT_ATTENUATION);
  63.     // the current ambient intensity
  64.     float ambientIntensity = DEFAULT_AMBIENT_INTENSITY;
  65.     float strength = DEFAULT_STRENGTH;
  66.    
  67.     // whether to use attenuation/shadows
  68.     boolean useShadow = true;
  69.  
  70.     // whether to use lambert shading (with our normal map)
  71.     boolean useNormals = true;
  72.    
  73.     DecimalFormat DEC_FMT = new DecimalFormat("0.00000");
  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. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement