Results 1 to 9 of 9

Thread: Having trouble with glDrawElements and triangles

  1. #1

    Having trouble with glDrawElements and triangles

    Hi all,
    I have figured out how to use glDrawElements to render quads from an interleaved array of vertices to draw an internal video buffer of pixels at various sizes to the screen (see code below):

    Code:
    procedure TApplication.RenderScreen;type
      TVertex = packed record
        x,y,z : Single;
        col   : TRGBA;
      end;
    
    
    var
      col         : TRGBA;
      buff        : PVideoBuffer;
      palette     : TChip16Palette;
      sx,sy       : Integer;
      dx,dy       : Integer;
    
    
      Vertices    : array[0..(cVideoPixelCount * 4) - 1] of TVertex; // 4 x vertices per screen pixel (maximum possible per screen...)
      Indices     : array[0..(cVideoPixelCount * 4) - 1] of GLuint;  // 4 x vertices per screen pixel (maximum possible per screen...)
      VPointer    : PByte; // vertices pointer
      CPointer    : PByte; // color pointer
      VertexCount : Integer;
    begin
      palette := FChip16.Palette;
    
    
      col := palette[FChip16.BGColor];
      glClearColor(col.r/255,col.g/255,col.b/255,col.a/255);
    
    
      glClear(GL_COLOR_BUFFER_BIT);
    
    
      glDisable(GL_BLEND);
    
    
      // draw video buffer to screen
      buff := FChip16.VideoBuffer;
    
    
      // enable and specify pointers to vertex arrays
      glEnableClientState(GL_COLOR_ARRAY);
      glEnableClientState(GL_VERTEX_ARRAY);
    
    
      VPointer := @Vertices[0];
      CPointer := @Vertices[0];
      Inc(CPointer,3 * SizeOf(GLfloat));
    
    
      glVertexPointer(3, GL_FLOAT        , SizeOf(TVertex), VPointer);
      glColorPointer (4, GL_UNSIGNED_BYTE, SizeOf(TVertex), CPointer);
    
    
      VertexCount := 0;
      dy := 0;
      for sy := 0 to cVideoResY - 1 do
      begin
        dx := 0;
        for sx := 0 to cVideoResX - 1 do
        begin
          col := palette[buff^[sy,sx]];
    
    
          if buff^[sy,sx] <> cTransparentColor then
          begin
            Vertices[VertexCount].col := col;
            Vertices[VertexCount].x   := dx;
            Vertices[VertexCount].y   := dy;
            Indices[VertexCount]      := VertexCount;
            Inc(VertexCount);
    
    
            Vertices[VertexCount].col := col;
            Vertices[VertexCount].x   := dx+FScale;
            Vertices[VertexCount].y   := dy;
            Indices[VertexCount]      := VertexCount;
            Inc(VertexCount);
    
    
            Vertices[VertexCount].col := col;
            Vertices[VertexCount].x   := dx+FScale;
            Vertices[VertexCount].y   := dy+FScale;
            Indices[VertexCount]      := VertexCount;
            Inc(VertexCount);
    
    
            Vertices[VertexCount].col := col;
            Vertices[VertexCount].x   := dx;
            Vertices[VertexCount].y   := dy+FScale;
            Indices[VertexCount]      := VertexCount;
            Inc(VertexCount);
          end;
          Inc(dx,FScale);
        end;
        Inc(dy,FScale);
      end;
    
    
      // draw number of elements
      glDrawElements(GL_QUADS, VertexCount, GL_UNSIGNED_INT,@Indices);
    
    
      glDisableClientState(GL_VERTEX_ARRAY);  // disable vertex arrays
      glDisableClientState(GL_COLOR_ARRAY);
    end;
    Since I want to see if I can port this to Android, I need to use triangles instead of quads (is deprecated now...), but I just can't figure out how to place the vertices in the vertex array to draw triangles properly...

    My screen is orientated with (0,0) at top left, and using Clockwise winding for triangles, quads, etc.

    Any ideas?
    cheers,
    Paul

  2. #2
    Here is a great page that helped me a lot when porting from OpenGL to ES:

    http://pandorawiki.org/Porting_to_GLES_from_GL
    ZGameEditor - Develop 64kb games for Windows.
    Thrust for Vectrex - ROM-file and 6809 source code.

  3. #3
    Thanks for the link
    I figured out how to do the triangles ok now...it was only a small change - 6 vertices per pixel (2 triangles) instead of 4 (quad), slightly larger arrays, and GL_TRIANGLES of course
    Code:
    procedure TApplication.RenderScreen;type
      TVertex = packed record
        x,y,z : Single;
        col   : TRGBA;
      end;
    
    
    var
      col         : TRGBA;
      buff        : PVideoBuffer;
      palette     : TChip16Palette;
      sx,sy       : Integer;
      dx,dy       : Integer;
    
    
      Vertices    : array[0..(cVideoPixelCount * 6) - 1] of TVertex; // 6 x vertices per screen pixel (maximum possible per screen...)
      Indices     : array[0..(cVideoPixelCount * 6) - 1] of GLuint;  // 6 x vertices per screen pixel (maximum possible per screen...)
      VPointer    : PByte; // vertices pointer
      CPointer    : PByte; // color pointer
      VertexCount : Integer;
    begin
      palette := FChip16.Palette;
    
    
      col := palette[FChip16.BGColor];
      glClearColor(col.r/255,col.g/255,col.b/255,col.a/255);
    
    
      glClear(GL_COLOR_BUFFER_BIT);
    
    
      glDisable(GL_BLEND);
    
    
      // draw video buffer to screen
      buff := FChip16.VideoBuffer;
    
    
      // enable and specify pointers to vertex arrays
      glEnableClientState(GL_COLOR_ARRAY);
      glEnableClientState(GL_VERTEX_ARRAY);
    
    
      VPointer := @Vertices[0];
      CPointer := @Vertices[0];
      Inc(CPointer,3 * SizeOf(GLfloat));
    
    
      glVertexPointer(3, GL_FLOAT        , SizeOf(TVertex), VPointer);
      glColorPointer (4, GL_UNSIGNED_BYTE, SizeOf(TVertex), CPointer);
    
    
      VertexCount := 0;
      dy := 0;
      for sy := 0 to cVideoResY - 1 do
      begin
        dx := 0;
        for sx := 0 to cVideoResX - 1 do
        begin
          col := palette[buff^[sy,sx]];
    
    
          if buff^[sy,sx] <> cTransparentColor then
          begin
            Vertices[VertexCount].col := col;
            Vertices[VertexCount].x   := dx;
            Vertices[VertexCount].y   := dy;
            Indices[VertexCount]      := VertexCount;
            Inc(VertexCount);
    
    
            Vertices[VertexCount].col := col;
            Vertices[VertexCount].x   := dx+FScale;
            Vertices[VertexCount].y   := dy;
            Indices[VertexCount]      := VertexCount;
            Inc(VertexCount);
    
    
            Vertices[VertexCount].col := col;
            Vertices[VertexCount].x   := dx+FScale;
            Vertices[VertexCount].y   := dy+FScale;
            Indices[VertexCount]      := VertexCount;
            Inc(VertexCount);
    
    
            Vertices[VertexCount].col := col;
            Vertices[VertexCount].x   := dx+FScale;
            Vertices[VertexCount].y   := dy+FScale;
            Indices[VertexCount]      := VertexCount;
            Inc(VertexCount);
    
    
            Vertices[VertexCount].col := col;
            Vertices[VertexCount].x   := dx;
            Vertices[VertexCount].y   := dy+FScale;
            Indices[VertexCount]      := VertexCount;
            Inc(VertexCount);
    
    
            Vertices[VertexCount].col := col;
            Vertices[VertexCount].x   := dx;
            Vertices[VertexCount].y   := dy;
            Indices[VertexCount]      := VertexCount;
            Inc(VertexCount);
          end;
          Inc(dx,FScale);
        end;
        Inc(dy,FScale);
      end;
    
    
      // draw number of elements
      glDrawElements(GL_TRIANGLES, VertexCount, GL_UNSIGNED_INT,@Indices);
    
    
      glDisableClientState(GL_VERTEX_ARRAY);  // disable vertex arrays
      glDisableClientState(GL_COLOR_ARRAY);
    end;

  4. #4
    Why do you need 6 verticles? Wouldn't be 5 enough. Verticle which diagonally splits pixel in half can be shared by both triangles.

  5. #5
    Quote Originally Posted by SilverWarior View Post
    Why do you need 6 verticles? Wouldn't be 5 enough. Verticle which diagonally splits pixel in half can be shared by both triangles.
    I am pretty sure that with glDrawElements and triangles, that the vertices are separate in each triangle...
    If I was using triangle strip or fan then it would reuse vertices wouldn't it?

    If I am wrong please let me know!!
    Last edited by paul_nicholls; 23-07-2012 at 08:51 PM. Reason: typo...

  6. #6
    PGD Staff / News Reporter phibermon's Avatar
    Join Date
    Sep 2009
    Location
    England
    Posts
    524
    you'll find that most model formats intended to be rendered on a GPU will be stored as plain old triangles. (sometimes strips but fans only make sence with certain patches of geometry)

    It was the case many years ago that some game engines stored models as a combination of tris/strips/fans so you were passing less data to the GPU, but :

    A) Today in almost all practical 3D model cases, it's slower to make multiple calls to glDrawElements (splitting a model into tris/strips/fans) than it is to pass more data than is technically needed (just GL_TRIANGLES)

    B) For various reasons such as using multiple textures/materials on a single model, you'll need to clone any verticies that are shared but have different normals/UVs. Strips/Fans share verticies by definintion so when using an index buffer, you can't have different UVs/Normals per face, for the same vertex.

    --

    So you'll often find you'll need to 'unwrap' shared verticies/uvs/normals. For example a vertex may be shared between two faces but those faces may have different materials or require lighting in unique ways (so different normals for a vertex, per face. think smoothing groups in the wavefront .obj format)

    That's not to say there won't be shared vert/norm/uv sets. Basic rule of thumb is to identify any unique sets of vert/norm/uv and ensure that each unique combination has it's own index.

    My engine (JenJin) has several model plugins that load into a generic data structure, depending on how a particular model format is stored I can either unwrap shared verts/uvs/normals as I load or do another pass after the data is loaded. (only for importing model formats of course, you don't want to be hogging the CPU in a game release, store your objects in a binary format with a layout that lets you get the data to the GPU with the bare minimum of pre-processing)

    After unwrapping it's off to the GPU. It's normal to generate index buffers per material (I've not come across a method of drawing sub-sets of a shared index buffer with glDrawElements but if I'm being blind someone please enlighten me)

    Be sure to replicate any per vertex data in this process, for example if you're loading bone weights they'll need to cloned along with the vertex.

    --

    Long story short : use GL_TRIANGLES for almost everything, it's your only practical choice for models using multiple materials.

    Only use fans/strips for special geometry cases that use a single, continually mapped texture (a sky dome for example) but you'd have to be drawing a lot of this special case geometry to make it worth optimizing.
    Last edited by phibermon; 23-07-2012 at 10:45 PM.
    When the moon hits your eye like a big pizza pie - that's an extinction level impact event.

  7. #7

  8. #8
    Quote Originally Posted by phibermon View Post
    Basic rule of thumb is to identify any unique sets of vert/norm/uv and ensure that each unique combination has it's own index.
    That's actually last thing i was working on with nxPascal. It wasn't ready yet at the time of the contest and you could see the vertex-sharing-done-wrong with the planet textures Hopefully it's fixed now though, is rather nasty issue to deal with.

    edit: Actually what made it even more complicated, was that the shared vertices may have exact same texture coordinates and normals. But when you go near the margin where texture coordinates wrap from 1.0 back to 0.0 side, you see 1 texture draw itself in a bugged manner. It may all look good and fine in a modelling program which doesn't share vertices when rendering, but not when going to vertex index mode.
    Last edited by User137; 24-07-2012 at 10:02 PM.

  9. #9
    Quote Originally Posted by User137 View Post
    is rather nasty issue to deal with.
    wait and see how nasty it gets when you add tangents and binormals to the equation

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •