Problem displaying a triangle array/mesh

Solved, I copy here for other ppl, it was hard to find a simple example (just one array, no interleaved) that show the basics


//init 

...
            initVertexArray(gl);
            int[] bufferID = new int[1];
            gl.glGenBuffers(1, bufferID, 0);
            
            vertexPointBufferID = bufferID[0];
            
            gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, vertexPointBufferID);
            gl.glBufferData(GL2.GL_ARRAY_BUFFER, triangleNumber*3*3*4, vertexData, L2.GL_STATIC_DRAW);
            
            gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, 0);
...


// display
...
        gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, vertexPointBufferID);
        gl.glVertexPointer(3, GL2.GL_FLOAT, 0, 0);
        
        gl.glEnableClientState(GL2.GL_VERTEX_ARRAY);
        gl.glDrawArrays(GL2.GL_TRIANGLES, 0, triangleNumber*3);
        
        gl.glDisableClientState(GL2.GL_VERTEX_ARRAY);
...

private void initVertexArray(GL2 gl)    {
        vertexData = GLBuffers.newDirectFloatBuffer(triangleNumber*3*3);
      for(int i=0; i<triangleNumber; i++) {
          Triangle tmp = triangleArray.get(i);
          vertexData.put(new float[]{tmp.x1/12000.0f, tmp.y1/12000.0f, tmp.z1/12000.0f, 
                                     tmp.x2/12000.0f, tmp.y2/12000.0f, tmp.z2/12000.0f, 
                                     tmp.x3/12000.0f, tmp.y3/12000.0f, tmp.z3/12000.0f  });
      }
        vertexData.flip();

I hope this gets you started, even with more complex setups: introduction to vertex arrays and vertex buffer objects opengl

Very cool! thanks Riven :wink:

I didnt found anything about using a single normal vector per triangle with VBOs

…do you know if it is possible?

This is impossible. All attributes (colors, texcoords, normals, etc) are specified per vertex, not per triangle.

What a pity, I saw it was pretty easy with glBegin/End and I hoped it could somehow possible also with VBOs…

However, I am now exploring the advantages of an indexed VBOs (based on your previous tutorial link). It looks very cool because you can for sure make your vertex array much more compact (and since I am experiencing problem over 2M buffers…)

The only “problem” seems to be the index creation. I am formulating just very roughly (i guess) method, like scanning the whole array, looking for duplicate vertexs, removing one of them and then write in the index array the indexed vertex order…

do you have any good link also for this? :smiley:

You can make something like this:


class Vec3 {
   public float x,y,z;
   
   @Override
   public int hashCode() {
      int hash = 0;
      hash |= Float.floatToRawIntBits(this.x) * 1;
      hash |= Float.floatToRawIntBits(this.y) * 17;
      hash |= Float.floatToRawIntBits(this.z) * 37;
      return hash;
   }

   @Override
   public boolean equals(Object obj) {
      Vec3 that = (Vec3) obj;
      return this.x==that.x && this.y==that.y && this.z==that.z;
   }
}


class Vertex {
   public Vec3 pos;
   public Vec3 color;
   public Vec3 normal;

   @Override
   public int hashCode() {
      int hash = 0;
      hash |= this.pos.hashCode() * 1;
      hash |= this.color.hashCode() * 17;
      hash |= this.normal.hashCode() * 37;
      return hash;
   }

   @Override
   public boolean equals(Object obj) {
      Vertex that = (Vertex) obj;
      return this.pos.equals(that.pos) && this.color.equals(that.color) && this.normal.equals(that.normal);
   }
}


class Builder {
   private fianl Map<Vertex, Integer> vertexToIndex = new HashMap<Vertex, Index>();
   private final List<Vertex> vertexList = new ArrayList<Vertex>();

   public int add(Vec3 pos, Vec3 color, Vec3 normal) {
     Vertex v = new Vertex(pos, color, normal);
     Integer index = this.vertexToIndex.get(v);
     if(index == null) {
        this.vertexToIndex.put(v, index=Integer.valueOf(this.vertexToIndex.size()));
        this.vertexList.add(v);
     }
     return index.intValue();
   }

   public List<Vertex> getData() {
       return this.vertexList;
   }
}

I wrote this in the reply, so it might have compile errors.

Hashes obvious, cool! Thanks Riven :wink:

But I have a question: how can you interleave vertexs and normal vectors with an indexed array?

I mean, since every vertex has his own normal (at the moment I am just rewriting the normal vector for the i-th triangle three times, once for each vertex), at the end how you can establish which normal vector assign to a vertex that is shared by two or more triangles?

Impossible. An index refers to a set of pos/color/normal.

You don’t; each normal is duplicated, not shared. A vertex is specified in its entirety by the complete set of its data: coordinate, normal, texcoords, colour, etc. The whole lot is reference by a single index.

If you thought that wasn’t the case when using glBegin()/glEnd(), you are mistaken - it is an illusion. glVertex() commands inside a glBegin()/glEnd() actually copied the last specified colour/texture/normal for you behind the scenes.

Cas :slight_smile:

It’s probably worth noting that except for certain pathological edge cases (a box being the most common one) you very rarely want to share vertex positions but not normals. For any ‘normal’ model like your bunny it only really comes up at crease edges, and those will be a tiny fraction of your total vertices.

Also note that aggressive indexing like removing duplicates in models e.t.c. may REDUCE performance, due to the data not being linearly laid out. I found it better to just keep duplicates of vertices in many cases.

True, but you can optimize the layout of your data to fully utilize the vertex cache (non-trivial calculation). With a near-perfect solution you can calculate it in O(n).

This can be slightly faster in the general case, and much faster if you have a heavy vertex shader. If most of the vertices are unique, the level of indirection will indeed hurt performance.

In a small test I made, I had vertices that were each used in 4 to 8 different triangles (average around 7), and it was faster to make all of them unique even if that gave me several times more data to process. Granted, it was impossible to lay out the data in a really effective way.

Here is an example that illustrates perfectly my idea

http://math.hws.edu/graphicsnotes/c2/s4.html

They do an kind of “average” normal vector between two

However, I have the feeling that all of this belongs much more to what should be the tuning part :stuck_out_tongue: so I would leave for the moment all your precious links and comments for later (I am not ironic, seriously)

Focusing back on the core part, after the rapresentation of my model I would need to put a light within the cabin and see where the shadow hits the ground, in terms of space (supposing I surround my model with a circle on the ground, I would need to know how many and how much shadows there are, not only by a graphical view but also by values, i.e: the biggest shadow is 2m long on the circle perimeter in front right side)

Another guy mentioned that since it is (or look) impossible to directly obtain the output from a shader, a solution might be using FBO

I would like to know your considerations about this

I guess I found the right way, another guy suggested me the following:

[quote]One way to do this is to create a FBO (frame buffer object) that has the dimensions of your plane. You’d then set up rendering to go into that FBO instead of the usual application buffers (that are displayed on the screeen) and have your modelview/projection matrices perform the projection of triangles onto the plane. Clear the FBO to white, enable GL_MIN blending (glBlendEquation(GL_MIN)) and render the triangles in black. Then use glReadPixels() to read back the data to main memory or another buffer on the GPU (that buffer could use CUDA/GL interop to be shared with CUDA) depending on where you need to process the information. Black pixels are in shadow, white ones are not.
[/quote]
Then, I decided to opt for a render on a renderBuffer image, attached to my FBO through the Color_attachment (http://www.songho.ca/opengl/gl_fbo.html)

private void renderShadows(GL2 gl)    {
        //  creating the FBO
        int[] frameBufferID = new int[1];
        gl.glGenBuffers(1, frameBufferID, 0);
        
        // bounding the FBO
        gl.glBindFramebuffer(GL2.GL_FRAMEBUFFER, frameBufferID[0]);
        
        // creating the RenderBuffer Object
        int[] renderBufferID = new int[1];
        gl.glGenRenderbuffers(1, renderBufferID, 0);
        
        // bounding the RBO
        gl.glBindRenderbuffer(GL2.GL_RENDERBUFFER, renderBufferID[0]);
        
        // Allocate the RBO
        gl.glRenderbufferStorage(GL2.GL_RENDERBUFFER, GL2.GL_RGB, floorWidth, floorHeight);
        
        // Attaching the RB image (RBO) to the FBO
        gl.glFramebufferRenderbuffer(GL2.GL_FRAMEBUFFER, GL2.GL_COLOR_ATTACHMENT0,
                                                GL2.GL_RENDERBUFFER, renderBufferID[0]);
        
        if(gl.glCheckFramebufferStatus(GL2.GL_FRAMEBUFFER) == GL2.GL_FRAMEBUFFER_COMPLETE)
            System.out.println("GL_FRAMEBUFFER_COMPLETE!!");
        else
            System.out.println("..shit ^^");
    }

And so far it works… I get the confirm that the framebuffer is complete

But I need help, I will start by render a simple triangle, just for testing, but… what about clearing the FBO to white?? And moreover, what about the pixel format when I am going to read them with glReadPixels()?

I went a little forward

// save the current viewport and set the new
        gl.glPushAttrib(GL2.GL_VIEWPORT_BIT);
        gl.glViewport(0, 0, floorWidth, floorHeight);
        
        // bind the FBO
        gl.glBindFramebuffer(GL2.GL_DRAW_FRAMEBUFFER, frameBufferID[0]);
        
        int[] attachmentID = new int[1];
        attachmentID[0] = GL2.GL_COLOR_ATTACHMENT0;
        gl.glDrawBuffers(1, attachmentID, 0);
        
        // clear
        gl.glClear(GL2.GL_COLOR_BUFFER_BIT);
        
        gl.glBlendEquation(GL2.GL_MIN);
        
        gl.glColor3f(0.0f, 0.0f, 0.0f);
        
        // render
        gl.glBegin(GL2.GL_TRIANGLES);
            gl.glVertex3f(0.0f, 1.0f, 0.0f);
            gl.glVertex3f(1.0f, 0.0f, 0.0f);
            gl.glVertex3f(0.0f, 0.0f, 0.0f);
        gl.glEnd();
        
        gl.glBindFramebuffer(GL2.GL_FRAMEBUFFER, 0);
        gl.glReadBuffer(GL2.GL_BACK);
        gl.glDrawBuffer(GL2.GL_BACK);
        
        //  restore viewport
        gl.glPopAttrib();

I really would like to check by myself the FBO… how can I render it on the screen?

At the moment I am trying to render it using:

gl.glBindFramebuffer( GL2.GL_FRAMEBUFFER, frameBufferID[0] );
        gl.glDrawBuffer(GL2.GL_COLOR_ATTACHMENT0);
        gl.glViewport( 0, 0, floorWidth, floorHeight );
        //gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        gl.glClear( GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT );

but it doesnt work, it doesnt display anything >.>

You’re not drawing to the screen, so why would it display anything? >_>

How can I do to render on the screen the content of a framebuffer?