opengl 如何构建镶嵌矩形

envsm3lx  于 2022-11-04  发布在  其他
关注(0)|答案(1)|浏览(162)

我正试图根据这个问题的答案来构建一个镶嵌矩形。
How to build data for a tessellated rectangle
我的最终结果只绘制了半个矩形,并且几何体看起来是断开的。
这就是它的样子。
这是我的代码,我试图移植到 VAO 和VBO。
生成数据。

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]);

            }
        }                   

}

创建 VAO 和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;
}

绘制对象。

glBindVertexArray(m_VAO);
    glDrawElements(GL_TRIANGLES, indicesRect.size() - 1, GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);
7gcisfzg

7gcisfzg1#

问题出在索引上...您移植了使用直接索引的my old code,但您使用的是使用逻辑索引的VBO...因此,补救方法是在Generate函数末尾将所有索引除以8(步长大小)(或重新索引整个genere以使用逻辑索引,但这需要更多的编码...)以下是完整的C++/VCL工作代码,以供交叉引用:

//---------------------------------------------------------------------------

# 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();
    }
//---------------------------------------------------------------------------

和预览:

使用固定函数和nVidia Default attribute locations(太懒了,没有为此制作着色器)...

相关问题