Java-Gaming.org    
Featured games (79)
games approved by the League of Dukes
Games in Showcase (476)
Games in Android Showcase (106)
games submitted by our members
Games in WIP (532)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Help me understand 3D, OpenGL, GLSL, LWJGL and life in general  (Read 2189 times)
0 Members and 1 Guest are viewing this topic.
Offline codemonkey

Senior Newbie





« Posted 2011-11-01 17:34:01 »

Hey All,

I have been trying to port the Modern OpenGL Wikibook to LWJGL for a while now, and while I currently have a vague understanding of what is going on, I get stuck at times and then I realize, I don't really understand as much as I would like about the whole process, that makes me feel really dumb. So, instead of just asking another debugging question, I have decided to lay down my understanding of the complete process in this VERY long tread, to make sure that ACTUALLY I understand everything I think I do (apologies beforehand for the length of the post and THANKS a MILLION times if you read it all through).

Please bear in mind that I write all of this, while keeping in mind that it has to be done through the shaders (the new/openglES way) and not classic glBegin()-glEnd() pair

So, without further ado, here I go

EDIT: You can check out the entire code over at the github repo for a more reader-friendly version
Offline codemonkey

Senior Newbie





« Reply #1 - Posted 2011-11-01 17:34:37 »

1. Graphics programming is a little like photography, so you have to setup the scene, adjust the camera and then adjust the lens, so everything translates well into the picture. And then you just do this every frame. Those three stages roughly translate to the Model-View-Projection matrix and the way this works is as follows:

  • Setting up the world: This is where GLUT/LWJGL, etc come in, where you create an application window, and get a reference to the display window
  • Setting up the Scene[ie: The Model Matrix]: Here you setup the world. this happens usually as follows
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
//switch to modelview matrix
glMatrixMode(GL_MODELVIEW_MATRIX);
//clear all that came before by setting matrix to 1
glLoadIdentity();
glShadeModel(GL_SMOOTH);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // white
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
GL11.glDepthFunc(GL11.GL_LESS);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);


  • Setting up the Camera[ie: The View Matrix]: While still in the modelview matrix mode, we move the camera to where it sits in the world, where it should point and the UP vector, that determines the gravity of the world. This is done by the gluLookAt() helper function
1  
gluLookAt(0f, 2f, 0f, 0f, 0f, -4f, 0f, 1f, 0f);


  • Setting up the Lens[ie: The Projection Matrix]: We switch the mode now to projection matrix, then set the field of view (the view angle), aspect ratio of the pic, near & far clipping planes. This is done by gluPerspective() helper function. Anything with a Z axis values LESS than (cameraZ+zNEAR) or GREATER than (cameraZ+zFAR) will not be shown on screen; anything else will be.

    In our specific case, this means for objects to be shown, they'll have to lie between the zPlanes of (-0.1 & -10)

    Again, the code for this is simply:
1  
2  
3  
glMatrixMode(GL11.GL_PROJECTION_MATRIX);
glLoadIdentity();
gluPerspective(45.0f, (float)width/(float)height, 0.1f, 10f);
    Offline codemonkey

    Senior Newbie





    « Reply #2 - Posted 2011-11-01 17:55:56 »

    2. Once this is set up, it is time to place your models in the world. For sake of brevity, I will create a very simple model of a cube, that is coloured. To do this, we load up a VBO with the vertex data, another with colour data per vertex, and an indices buffer (one that tells OpenGL how to go through the vertices drawing the different faces).

    • A cube has 8 vertices, each interleaved with is own colour, and i'll place them around the origin at first
    1  
    2  
    3  
    4  
    5  
    6  
    7  
    8  
    9  
    10  
    11  
    float[] vertexAttributesData=new float[] {
       // front
      -1f, -1f, 1f, 1f, 0f, 0f,
       1f, -1f, 1f, 0f, 1f, 0f,
       1f, 1f, 1f, 0f, 0f, 1f,
       -1f, 1f, 1f, 1f, 1f, 1f,
       // back
      -1f, -1f, -1f, 1f, 0f, 0f,
       1f, -1f, -1f, 0f, 1f, 0f,
       1f, 1f, -1f, 0f, 0f, 1f,
       -1f, 1f, -1f, 1f, 1f, 1f,};


    • A cube has 6 faces, each created from 2 triangles, each again, created from 3 vertices. So, the indices matrix comes out like the following
    1  
    2  
    3  
    4  
    5  
    6  
    7  
    8  
    9  
    10  
    11  
    12  
    13  
    int[] indecesData=new int[] {
       // front
      0, 1, 2, 2, 3, 0,
       // top
      1, 5, 6, 6, 2, 1,
       // back
      7, 6, 5, 5, 4, 7,
       // bottom
      4, 0, 3, 3, 7, 4,
       // left
      4, 5, 1, 1, 0, 4,
       // right
      3, 2, 6, 6, 7, 3};


    • Next up, we setup the Vertex Shader & the Fragment Shader to transform the cube vertices and colour to the screen
      • The Vertex Shader: does no real transformation at this point, and so just produces the output by applying the ModelViewProjection Matrix to the coordinates and hence, turns out as follows:
    1  
    2  
    3  
    4  
    5  
    6  
    7  
    8  
    9  
    10  
    #version 120

    attribute vec3 coords;
    attribute vec3 color;
    varying vec3 fragmentColor;

    void main(void) {
       gl_Position=gl_ModelViewProjectionMatrix*vec4(coords,1.0);
       fragmentColor=color;
    }


    • The Fragment Shader: Also here does not do much, and hence just outputs the colours as specified in the model matrix, which makes it turn out to be simply
    1  
    2  
    3  
    4  
    5  
    6  
    7  
    #version 120

    varying vec3 fragmentColor;

    void main(void) {
       gl_FragColor=vec4(fragmentColor.x,fragmentColor.y,fragmentColor.z,1.0);
    }
        [/li]

        [li]Finally, the Drawing process of the cube is a simple passing in of arguments to the shaders and drawing according to the indices[/li][/list]
        1  
        2  
        3  
        4  
        5  
        6  
        7  
        8  
        9  
        10  
        11  
        12  
        13  
        14  
        15  
        16  
        17  
        18  
        19  
        20  
        21  
        22  
        public void draw() {
           // bind vertex data array
          glBindBufferARB(GL_ARRAY_BUFFER_ARB, vertexAttributesBuffer);

           // pass in info to vertex shader
          int dataOffset=0;
           glEnableVertexAttribArray(coordsAttributeIndex);
           glVertexAttribPointer(coordsAttributeIndex, numAxisPerVertex, GL_FLOAT, false, stride, 0);
           dataOffset+=numAxisPerVertex*bytesPerFloat;
           glEnableVertexAttribArray(colorAttributeIndex);
           glVertexAttribPointer(colorAttributeIndex, numColoursPerVertex, GL_FLOAT, false, stride, dataOffset);
           dataOffset+=numColoursPerVertex*bytesPerFloat;

           // draw the vertices using the indices
          glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, vertexIndicesBuffer);
           glDrawElements(GL_TRIANGLES, numIndeces, GL_UNSIGNED_INT, 0);

           // unbind the buffers & attribute arrays
          glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
           glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
           glDisableVertexAttribArray(colorAttributeIndex);
        }


          • FINALLY we can actually run and GET something drawn on the screen. What we get is the front face of the cube filling up the entire screen, because we placed the square vertices from -1 to 1, which fills up our entire area
          [/list]
          Games published by our own members! Check 'em out!
          Legends of Yore - The Casual Retro Roguelike
          Offline codemonkey

          Senior Newbie





          « Reply #3 - Posted 2011-11-01 18:03:56 »

          3. Now that we have the cube drawing correctly, lets push it back a little bit to make sure we can see something else in the screen. Let's push it back to the camera target point for example

          • Ok, the camera points at 0,0,-4 in the world, so we need to push back our cube by 4 in the z direction; meaning we need to translate it by a vector of (0,0,-4). We will pass in this translation matrix to the shader, and let the GPU do the math. Hence, our shader becomes:
          1  
          2  
          3  
          4  
          5  
          6  
          7  
          8  
          9  
          10  
          11  
          12  
          13  
          14  
          15  
          16  
          #version 120
           
          attribute vec3 coords;
          attribute vec3 color;
          uniform vec3 modelPosition;
          varying vec3 fragmentColor;
           
          void main(void) {
              mat4x4 positionMatrix=mat4x4(1.0);
              positionMatrix[3].x=modelPosition.x;
              positionMatrix[3].y=modelPosition.y;
              positionMatrix[3].z=modelPosition.z;

              gl_Position=gl_ModelViewProjectionMatrix*positionMatrix*vec4(coords,1.0);
              fragmentColor=color;
          }
          • the Fragment shader does not change much, except for adding in the uniform declaration for the model position, to follow GLSL specs

          Now HERE is where I'm stuck JGO. When I do this step, I get NOTHING drawn on the screen. What am I doing wrong? what am I missing?

          Again, if you have read through ALL this, then thank you a MILLION and sorry for any waste of your time
          Offline theagentd
          « Reply #4 - Posted 2011-11-01 19:11:35 »

          It could be anything, really. Strip out functions one after another until you get something on the screen.
           - Disable depth testing. Are you clearing the depth buffer properly? Do you even have a depth buffer?
           - Change your fragment shader to just draw white so you can see if it's just the color that isn't working.
           - Did you forget to flip the attribute and index buffer before submitting it?
           - (This is a tip) gl_FragColor=vec4(fragmentColor.x,fragmentColor.y,fragmentColor.z,1.0); is the same as just gl_FragColor = vec4(fragmentColor, 1.0);
           - If you aren't using lighting, why do you have glShadeModel(GL_SMOOTH);? This value is completely ignored with shaders and will just confuse people (if you're making a tutorial, that is).
           - Do you get any shader errors?
           - (Another tip) Blending + writing to the depth buffer = bad results. Transparent things drawn first will occlude underlying things. I recommend disabling blending, especially since you set the alpha to 1.0 in the fragment shader. Less confusing, and better performance, since OpenGL won't have to read the current color in the framebuffer to do the blending (even if it's multiplied by 0 in the end.
           - In your first code block, you aren't setting up the model view matrix. You're just loading the identity matrix, and then doing things completely unrelated to the model view matrix. Confusing + it might be the problem?
           - Are you sure you're looking the right way with gluLookAt()?

          All I can think of for now...

          Myomyomyo.
          Offline lhkbob

          JGO Knight


          Medals: 32



          « Reply #5 - Posted 2011-11-01 19:13:45 »

          You have a couple of problems in how you're setting up your matrices.

          1. In initGL(), at the end you set the mode to GL_PROJECTION_MATRIX, but you should use GL_PROJECTION.  Similarly, it's GL_MODELVIEW not GL_MODELVIEW_MATRIX.  The _MATRIX are used to query matrix values with glGetFloatfv
          2. At the end of initGL() you never change the mode back to GL_MODELVIEW, so in render(), when you call glLoadIdentity() you're wiping out your projection matrix
          3. The model and view matrices are a single matrix in OpenGL, so you'll need to use glPushMatrix and glPopMatrix, and glMultMatrix() to update the model without destroying the view you configured in initGL()

          1  
          2  
          3  
          4  
          5  
          6  
          7  
          8  
          9  
          10  
          11  
          12  
          13  
          14  
          15  
          initGL() {
             glMatrixMode(GL_MODELVIEW);
             glLoadIdentity();
             gluLookAt(...);
          }

          render() {
             glPushMatrix(); // save the view
            glTransform(...); // this is the transform of the object
            glRotate(...); // this is the rotation of the object

             renderCube();

             glPopMatrix(); // restore to just the view matrix
          }


          4. Always make sure to call glGetError() to see if you've made a bad call.  If it's returning a non-zero value, then you need to carefully walk through your code and place glGetError's after every call to see which exact call causes it to fail.

          LWJGL may have a utility that can check glGetError for you automatically.  I know JOGL does with their DebugGL wrappers.

          Offline codemonkey

          Senior Newbie





          « Reply #6 - Posted 2011-11-01 20:13:56 »

          Thanks for the awesome replies everyone I will look into them and get back to you

          if you're making a tutorial, that is

          no, i'm not, but the best way I can understand something, is if i try to explain to someone else, and this is what i was trying to do here Smiley
          Offline kappa
          « League of Dukes »

          JGO Kernel


          Medals: 74
          Projects: 15


          ★★★★★


          « Reply #7 - Posted 2011-11-01 20:31:57 »

          LWJGL may have a utility that can check glGetError for you automatically.  I know JOGL does with their DebugGL wrappers.
          Yup, use lwjgl-debug.jar instead of lwjgl.jar, this will output debug information.
          Pages: [1]
            ignore  |  Print  
           
           
          You cannot reply to this message, because it is very, very old.

           

          Add your game by posting it in the WIP section,
          or publish it in Showcase.

          The first screenshot will be displayed as a thumbnail.

          pw (16 views)
          2014-07-24 01:59:36

          Riven (16 views)
          2014-07-23 21:16:32

          Riven (14 views)
          2014-07-23 21:07:15

          Riven (16 views)
          2014-07-23 20:56:16

          ctomni231 (43 views)
          2014-07-18 06:55:21

          Zero Volt (40 views)
          2014-07-17 23:47:54

          danieldean (32 views)
          2014-07-17 23:41:23

          MustardPeter (36 views)
          2014-07-16 23:30:00

          Cero (51 views)
          2014-07-16 00:42:17

          Riven (50 views)
          2014-07-14 18:02:53
          HotSpot Options
          by dleskov
          2014-07-08 03:59:08

          Java and Game Development Tutorials
          by SwordsMiner
          2014-06-14 00:58:24

          Java and Game Development Tutorials
          by SwordsMiner
          2014-06-14 00:47:22

          How do I start Java Game Development?
          by ra4king
          2014-05-17 11:13:37

          HotSpot Options
          by Roquen
          2014-05-15 09:59:54

          HotSpot Options
          by Roquen
          2014-05-06 15:03:10

          Escape Analysis
          by Roquen
          2014-04-29 22:16:43

          Experimental Toys
          by Roquen
          2014-04-28 13:24:22
          java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
          Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!