1

i am trying to build a tessellated rectangle based from the answer to this question.

How to build data for a tessellated rectangle

My final result has only the half rectangle drawn and the geometry looks broken.

This is how it looks. enter image description here

This is my code which i have tried to port to VAO and VBO.

Generating the Data.

std::vector<float> verticesRect;
std::vector<unsigned int> indicesRect;
nSegments = 16; mSegments = 16;
void Rectangle2::Generate()
{
    const int n8 = nSegments * 8;           // size of VBO gfx data
    const int sz0 = mSegments * n8;         // size of VBO gfx data
    const int sz1 = (mSegments - 1) * (nSegments - 1) * 6;// size of indices
    verticesRect.clear();
    indicesRect.clear();
    int a,i, j, k, b;
    GLfloat x, y, z, dx, dy, l;
    glm::vec3 u, v, nor;
    dx = 2.0 * (width / float(nSegments - 1));
    dy = 2.0 * (height / float(mSegments - 1));
    for (a = 0,y = -height, j = 0; j < mSegments; j++, y += dy)
        for (x = -width, i = 0; i < nSegments; i++, x += dx)
        {
            z = 20.0 * sin((x * x) + (y * y));
            verticesRect.push_back(x); a++;
            verticesRect.push_back(y); a++;
            verticesRect.push_back(z); a++;
            // Normal ( will be recomputed later)
            verticesRect.push_back(0.0); a++;
            verticesRect.push_back(0.0); a++;
            verticesRect.push_back(1.0); a++;
            // TexCoord
            verticesRect.push_back((x + width) / (width + width)); a++;
            verticesRect.push_back((y + height) / (height + height)); a++;
        }
    
    // triangulation indices
    for(a = 0, j = 1; j < mSegments; j++ )
        for (i = 1; i < nSegments; i++)
        {
            b = ((nSegments * j) + i) * 8;
            // First triangle per quad
            indicesRect.push_back(b - 8); a++;
            indicesRect.push_back(b - 8 - n8); a++;
            indicesRect.push_back(b); a++;
            // Second triangle per quad
            indicesRect.push_back(b - 8 - n8); a++;
            indicesRect.push_back(b - n8); a++;
            indicesRect.push_back(b); a++;

            // recompute inner normals
            for (k = 0; k < 3; k++) {
                u[k] = verticesRect[indicesRect[a - 6] + k] - verticesRect[indicesRect[a - 4] + k];
                v[k] = verticesRect[indicesRect[a - 5] + k] - verticesRect[indicesRect[a - 4] + k];
            }
            glm::vec3 cross1 = crossProduct(u, v);
            cross1 = glm::normalize(cross1);

            for (k = 0; k < 3; k++) {
                u[k] = verticesRect[indicesRect[a - 3] + k] - verticesRect[indicesRect[a - 1] + k];
                v[k] = verticesRect[indicesRect[a - 2] + k] - verticesRect[indicesRect[a - 1] + k];

            }
            glm::vec3 cross2 = crossProduct(u, v);
            cross2 = glm::normalize(cross2);
            
            for (k = 0; k < 3; k++) {
                verticesRect[indicesRect[a - 1] + 3 + k] = 0.5 * (cross1[k] + cross2[k]);

            }
        }                   
        
}

Creating the VAO and VBO

void Rectangle2::init()
{
    Generate();
    glGenVertexArrays(1, &m_VAO);
    glGenBuffers(1, &m_VBO);
    glGenBuffers(1, &m_EBO);
    glBindVertexArray(m_VAO);
    glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
    glBufferData(GL_ARRAY_BUFFER, verticesRect.size() * sizeof(float), &verticesRect[0], GL_STATIC_DRAW);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * indicesRect.size(), &indicesRect[0], GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(2);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
    isInited = true;
}

Drawing the Object.

glBindVertexArray(m_VAO);
    glDrawElements(GL_TRIANGLES, indicesRect.size() - 1, GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);
Summit
  • 2,112
  • 2
  • 12
  • 36
  • 3
    first try to turn off `GL_CULL_FACE` just to make sure its not just winding rule for every odd triangle. What is the input (geometry)? – Spektre Jul 12 '22 at 07:37
  • @Spektre the input Geometry is GL_TRIANGLES.I tried disabling GL_CULL_FACE but still problem persists. – Summit Jul 12 '22 at 07:46
  • @Spektre it should be just open curved plane. – Summit Jul 12 '22 at 08:21
  • @Spektre this is how the vectors look like , std::vector verticesRect; std::vector indicesRect; , They are addresed from 0, yes all my elements are same type. – Summit Jul 12 '22 at 08:50
  • @Spektre Thank you very much for your time , would really appreciate whenever you have time to look into this issue , or i can build a project in GLFW GLEW and send it to you. – Summit Jul 12 '22 at 08:58
  • 1
    I found the problem see my answer ... you just add that lines of code I marked with `// !!!` comment – Spektre Jul 12 '22 at 10:02

1 Answers1

2

The problem is with indices... You ported my old code which uses direct indices but you use VBO instead which uses logical indices ... so the remedy is just divide all indices by 8 (stride size) at the end of Generate function (or reindex the whole genere to use logical indices instead but thats more coding ...) Here full C++/VCL working code to cross reference:

//---------------------------------------------------------------------------
#include <vcl.h>            // VCL stuff (ignore)
#include <math.h>
#pragma hdrstop             // VCL stuff (ignore)
#include "Unit1.h"          // VCL stuff (header of this window)
#include "gl_simple.h"      // my GL init (source included)
//---------------------------------------------------------------------------
#pragma package(smart_init) // VCL stuff (ignore)
#pragma resource "*.dfm"    // VCL stuff (ignore)
TForm1 *Form1;              // VCL stuff (this window)
//---------------------------------------------------------------------------
const int m=16,n=16;        // points per grid axis
const int n8=n*8;           // size of VBO gfx data
const int sz0=m*n8;         // size of VBO gfx data
const int sz1=(m-1)*(n-1)*6;// size of indices
GLfloat dat[sz0];
GLuint idx[sz1];
//---------------------------------------------------------------------------
GLfloat divide(GLfloat a,GLfloat b){ if (fabs(b)<1e-10) return 0.0; else return a/b; }
void  normalize(GLfloat *c,GLfloat *a)  // c = a/|a|
    {
    GLfloat l=divide(1.0,sqrt((a[0]*a[0])+(a[1]*a[1])+(a[2]*a[2])));
    c[0]=a[0]*l;
    c[1]=a[1]*l;
    c[2]=a[2]*l;
    }
void  cross(GLfloat *c,GLfloat *a,GLfloat *b) // c = cross(a,b)
    {
    GLfloat   q[3];
    q[0]=(a[1]*b[2])-(a[2]*b[1]);
    q[1]=(a[2]*b[0])-(a[0]*b[2]);
    q[2]=(a[0]*b[1])-(a[1]*b[0]);
    for(int i=0;i<3;i++) c[i]=q[i];
    }
void genere(GLfloat w,GLfloat h)
    {
    int i,j,k,a,b;
    GLfloat x,y,z,dx,dy,l;
    GLfloat u[3],v[3],nor[3];
    // gfx data
    dx=2.0*w/GLfloat(n-1);
    dy=2.0*h/GLfloat(m-1);
    for (a=0,y=-h,j=0;j<m;j++,y+=dy)
     for (    x=-w,i=0;i<n;i++,x+=dx)
        {
        // Vertex
//      z= 0.3*sin((x*x)+(y*y));
        z=20.0*sin((x*x)+(y*y));
        dat[a]=x; a++;
        dat[a]=y; a++;
        dat[a]=z; a++;
        // Normal (will be recomputed latter)
        dat[a]=0.0; a++;
        dat[a]=0.0; a++;
        dat[a]=1.0; a++;
        // TexCoord
        dat[a]=(x+w)/(w+w); a++;
        dat[a]=(y+h)/(h+h); a++;
        }
    // triangulation indices
    for (a=0,j=1;j<m;j++)
     for (    i=1;i<n;i++)
        {
        // b = location of point[i,j] in dat[]
        b=((n*j)+i)*8;
        // first triangle per quad
        idx[a]=b-8;    a++;
        idx[a]=b-8-n8; a++;
        idx[a]=b;      a++;
        // second triangle per quad
        idx[a]=b-8-n8; a++;
        idx[a]=b-n8;   a++;
        idx[a]=b;      a++;
        // recompute inner normals
        for (k=0;k<3;k++)
            {
            u[k]=dat[idx[a-6]+k]-dat[idx[a-4]+k];
            v[k]=dat[idx[a-5]+k]-dat[idx[a-4]+k];
            }
        cross(nor,u,v); normalize(nor,nor);
        for (k=0;k<3;k++)
            {
            u[k]=dat[idx[a-3]+k]-dat[idx[a-1]+k];
            v[k]=dat[idx[a-2]+k]-dat[idx[a-1]+k];
            }
        cross(u,u,v); normalize(u,u);
        for (k=0;k<3;k++) dat[idx[a-1]+3+k]=0.5*(nor[k]+u[k]);
        }
    // copy edge normals
    for (j=0,i=1;i<n;i++)
        {
        // b = location of point[i,j] in dat[]
        b=((n*j)+i)*8;
        // copy
        for (k=0;k<3;k++) dat[b+3+k]=dat[b+3+k+n8];
        }
    for (i=0,j=1;j<m;j++)
        {
        // b = location of point[i,j] in dat[]
        b=((n*j)+i)*8;
        // copy
        for (k=0;k<3;k++) dat[b+3+k]=dat[b+3+k+8];
        }
    for (i=0;i<sz1;i++) idx[i]/=8; // !!! this is what you need to add !!!
    }
//---------------------------------------------------------------------------
GLuint m_VAO=0,m_VBO=0,m_EBO=0;
void genere_VBO()
    {
    GLuint i;
    glGenVertexArrays(1,&m_VAO);
    glBindVertexArray(m_VAO);

    glGenBuffers(1,&m_VBO);
    glBindBuffer(GL_ARRAY_BUFFER,m_VBO);
    glBufferData(GL_ARRAY_BUFFER,sizeof(dat),dat,GL_STATIC_DRAW);
    i=0; glEnableVertexAttribArray(i);  // vertex
    glVertexAttribPointer(i,3,GL_FLOAT,GL_FALSE,8*sizeof(dat[0]),(void*)(0*sizeof(dat[0])));
    i=2; glEnableVertexAttribArray(i); // normal
    glVertexAttribPointer(i,3,GL_FLOAT,GL_FALSE,8*sizeof(dat[0]),(void*)(3*sizeof(dat[0])));
    i=8; glEnableVertexAttribArray(i); // texcoord0
    glVertexAttribPointer(i,2,GL_FLOAT,GL_FALSE,8*sizeof(dat[0]),(void*)(6*sizeof(dat[0])));

    glGenBuffers(1,&m_EBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,m_EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(idx),idx,GL_STATIC_DRAW);

    glBindVertexArray(0);
    glBindBuffer(GL_ARRAY_BUFFER,0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(2);
    glDisableVertexAttribArray(8);
    }
//---------------------------------------------------------------------------
void gl_draw()
    {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glDisable(GL_CULL_FACE);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_COLOR_MATERIAL);
    glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);


    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    float light[4]={-0.3,-0.7,0.0,0.0};
    glLightfv(GL_LIGHT0,GL_POSITION,light);

    glTranslatef(0.0,+6.0,-30.0);
    glRotatef(135.0,1.0,0.0,0.0);
    static float ang=0;
    glRotatef(ang,0.0,0.0,1.0); ang=fmod(ang+1.5,360.0);
/*
    // old api render (just for debug ignore this)
    int i,j;
    glColor3f(0.1,0.5,0.7);
    glBegin(GL_TRIANGLES);
    for (i=0;i<sz1;i++)
        {
        j=idx[i]*8; // !!! I added *8 as indices are logical now)
        glNormal3fv(dat+j+3);
        glTexCoord3fv(dat+j+6);
        glVertex3fv(dat+j);
        }
    glEnd();
*/
    // new api render
    glColor3f(0.1,0.5,0.7);
    glBindVertexArray(m_VAO);
    glDrawElements(GL_TRIANGLES,sizeof(idx)/sizeof(idx[0]),GL_UNSIGNED_INT,0);  // indices (choose just one line not both !!!)
    glBindVertexArray(0);

    glFlush();
    SwapBuffers(hdc);
    }
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner)
    {
    // this is called on window startup
    gl_init(Handle);                // init OpenGL 1.0
    genere(1.0,1.0);
    genere_VBO();
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
    {
    // this is called before window exits
    gl_exit();                      // exit OpenGL
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::FormResize(TObject *Sender)
    {
    // this is called on each window resize (and also after startup)
    gl_resize(ClientWidth,ClientHeight);
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::FormPaint(TObject *Sender)
    {
    // this is called whnewer app needs repaint
    gl_draw();
    }
//---------------------------------------------------------------------------
void __fastcall TForm1::tim_redrawTimer(TObject *Sender)
    {
    gl_draw();
    }
//---------------------------------------------------------------------------

And preview:

preview

using fixed function and nVidia Default attribute locations (was too lazy to make shaders for this)...

Spektre
  • 49,595
  • 11
  • 110
  • 380