Opengl 三角形未正确呈现

Opengl Triangles are not being rendered correctly

我正在尝试创建地形,但同样的错误不断出现。三角形在彼此不靠近的顶点之间形成链接,即 v1 到 v100,导致渲染时形成畸形三角形。

错误图片:

线框:

重现此代码:

    class Generator
    {
        TerrainMesh gen_emptyTerrainMesh  = TerrainMesh();

        /* Parameters for the class */

        int                 gen_size;

        /**
         \brief for loop from 0 to n, making x, y, z
         coordinates, n's default is 128
        
         \param arr Array to store the vertices in

        **/ 
        void gen(std::vector<vec3>* arr) const
        {
            float x = 0.0f, y = 0.0f, z = 0.0f;

            for (int j = 0; j < gen_size; j++)
            {
                for (int i = 0; i < gen_size; i++)
                {
                    

                    x = static_cast<float>(i);
                    // y += rand() % 10 - 1.0f;
                    z = static_cast<float>(j);

                    arr->push_back(vec3(x, y, z));

                    // DEBUG 
                    // printf("[BUILD INFO]: x: %F, y: %F, z: %F \n", x, y, z);
                }
            }
        }

        /**
         *\brief Using struct Triangle and vector convert x, y z
         * coordinates from vertices into quads made up of 2 triangles
         * stored sequentially. 
         *
         * 
         *  Triangle {
         *
         *      p:  n
         *
         *      p2: n + 1 \ n + 2 + size
         *
         *      p3: n + 2 + size \ n + 1 + size
         *
         *  }
         *
         * At the same time work out normals for each Triangle
         **/
        void toTriangle(const std::vector<vec3>* arr, std::vector<Triangle>* tri_arr) const
        {
            int crrPointer = 0;

            // Convert vector float to vector Triangle/Quad format
            for (int n = 0; n < arr->size(); n++)
            {
                if (n % gen_size == 0)
                    crrPointer += 1;

                if (crrPointer < (gen_size - 1) && n % (gen_size - 1) != 0) {
                    tri_arr->push_back(Triangle{arr->at(n), arr->at(n + 1), arr->at(n + 2 + gen_size)});
                    tri_arr->push_back(Triangle{arr->at(n), arr->at(n + 2 + gen_size), arr->at(n + 1 + gen_size), true});
                }
            }

            // Work out the normal for each triangle
            // needs to be done

        }

        static void toVectorArray(std::vector<float>* vertices, const std::vector<Triangle>* tri_arr)
        {
            for (auto &tri : *tri_arr)
            {
                vertices->push_back(tri.p.x);
                vertices->push_back(tri.p.y);
                vertices->push_back(tri.p.z);

                vertices->push_back(tri.normal.x);
                vertices->push_back(tri.normal.y);
                vertices->push_back(tri.normal.z);

                vertices->push_back(0.0);
                vertices->push_back(1.0);

                vertices->push_back(tri.p2.x);
                vertices->push_back(tri.p2.y);
                vertices->push_back(tri.p2.z);

                vertices->push_back(tri.normal.x);
                vertices->push_back(tri.normal.y);
                vertices->push_back(tri.normal.z);

                vertices->push_back(1.0);
                vertices->push_back(1.0);

                vertices->push_back(tri.p3.x);
                vertices->push_back(tri.p3.y);
                vertices->push_back(tri.p3.z);

                vertices->push_back(tri.normal.x);
                vertices->push_back(tri.normal.y);
                vertices->push_back(tri.normal.z);

                if (!tri.isP4)
                {
                    vertices->push_back(1.0);
                    vertices->push_back(0.0);
                } else
                {
                    vertices->push_back(0.0);
                    vertices->push_back(0.0);
                }

            }
        }
        // DEBUG

        //----------------------------------------------------------------------------
        static std::string getTime()
        {
            time_t result = time(nullptr);

            char str[26];
            ctime_s(str, sizeof str, &result);


            // Remove the "\n" source: 
            if (str[strlen(str) - 1] == '\n') str[strlen(str) - 1] = '[=10=]';

            return str;
        }
        //----------------------------------------------------------------------------
    public:
        Generator(std::vector<float>* p_vecArray, int p_size = 128): gen_size(p_size)
        {
            std::vector<vec3> tempVec;
            std::vector<Triangle> triangles;


            // Make the vertices, gen_size * gen_size
            gen(&tempVec);

            // Turn them into Triangles so its easier
            // to work out normals and texture coordinates
            toTriangle(&tempVec, &triangles);

            std::cout << p_vecArray->size() << "\n";

            // turn the triangles into
            // x, y, z, nx, ny, nz, texX, texY
            // for each vertex
            toVectorArray(p_vecArray, &triangles);

            std::cout << p_vecArray->size() << "\n";
            // printTriangles(&triangles);
            
        }
    };

三角形结构

struct Triangle
{
    vec3 p;
    vec3 p2;
    vec3 p3;

    bool isP4 = false;

    vec3 normal = {0, 0, 0};
};

我尝试使用四边形而不是三角形来查看是否有帮助,但无济于事。 我认为错误与它们如何被转换成三角形或它们在 vertices 向量中的顺序有关,在线检查以查看是否是这种情况,但没有发现任何有意义的建议顺序在 opengl 中很重要。

TL;DR: 所以通过听@TedKleinBergman,我能够推断出问题所在,即顶点顺序错误以及我之前绑定它们的方式不准确,因此不知疲倦地找出正确的顺序。


长版:

所以我回到生成顶点的代码并稍微更改它以适应纹理坐标。

/**
\brief for loop from 0 to n, making x, y, z
coordinates, n's default is 128
        
\param arr Array to store the vertices in

**/
void gen(std::vector<vec4>* arr) const
{
    float x = 0.0f, y = 0.0f, z = 0.0f;

    int p = 1;

    for (int j = 0; j <= gen_size; j++)
    {
        for (int i = 0; i <= gen_size; i++)
        {
            x = static_cast<float>(i);
            // y += rand() % 10 - 1.0f;
            z = static_cast<float>(j);

            if (p < 4)
            {
                if (p == 3)
                {
                    arr->push_back(vec4({ x, y, z }, txc_p));
                    // printf("4, value x: %F z: %F\n", x, z);
                    p++;
                } else if (p == 2)
                {
                    arr->push_back(vec4({ x, y, z }, txc_p2));
                    // printf("3, value x: %F z: %F\n", x, z);
                    p++;
                } else if (p == 1)
                {
                    arr->push_back(vec4({ x, y, z }, txc_p3));
                    // printf("2, value x: %F z: %F\n", x, z);
                    p++;
                } else if (p == 4)
                {
                    arr->push_back(vec4({ x, y, z }, txc_p4));
                    // printf("1, value x: %F z: %F\n", x, z);
                    p++;
                }
            } else
            {
                p = 2;
                arr->push_back(vec4({ x, y, z }, txc_p));
                // printf("null, value x: %F z: %F\n", x, z);
            }
        }
    }
}

有帮助的主要变化是将函数 toTriangleToArray 更改为一个函数,并将三角形顶点视为向量(我花了很长时间才弄清楚)并使用四边形(方形)标记每个顶点并查看差异。这应该导致 ij 的 v1 和 v4 之间存在 +- 1 差异。其余代码应该是 self-explanatory,但我现在看到的问题是优化和照明(当然,我会尝试自己修复)。

所以请注意这段代码没有达到应有的优化程度,我可能做了一些很容易修复的蠢事,如果是这样请发表评论!


void OrderPair(std::vector<vec4> v, std::vector<float>* tempV) const
{
    /*
     *
     *    Counter-Clockwise order; is default
     *
     *  Left Triangle
     *  v2 --- v1
     *   |     /
     *   |    /
     *   |   /      ORDER: v1 -> v2 -> v3
     *   |  /
     *   | /
     *   v3
     *
     *   Right Triangle
     *         v1
     *        / |
     *       /  |
     *      /   |   ORDER: v1 -> v3 -> v4
     *     /    |
     *    /     |
     *   v3 --- v4
     *
     *
     */

    std::vector<Triangle> triangles;


    for (int index = 1; index < v.size(); index += 1)
    {
        int YPointer = 0;
        if (index % gen_size == 0)
        {
            YPointer++;
            continue;
        }

        if (YPointer <= (gen_size - 1))
        {
            vec4 n = v.at(index);

            vec3 p = n.xyz;
            vec3 p2 = { n.xyz.x - 1, n.xyz.y,       n.xyz.z, };
            vec3 p3 = { n.xyz.x - 1, n.xyz.y, n.xyz.z + 1 };
            vec3 p4 = { n.xyz.x,        n.xyz.y, n.xyz.z + 1 };

            // Left Triangle
            auto tri1 = Triangle(p, p2, p3);

            vec3 u = p2 - p;
            vec3 v = p3 - p;

            tri1.normal.x = (u.x * v.z) - (u.z * v.y);
            tri1.normal.y = (u.z * v.x) - (u.x * v.z);
            tri1.normal.z = (u.x * v.y) - (u.y * v.x);

            // Right Triangle
            auto tri2 = Triangle(p, p3, p4, false, true);

            u = p3 - p;
            v = p4 - p;

            tri2.normal.x = (u.x * v.z) - (u.z * v.y);
            tri2.normal.y = (u.z * v.x) - (u.x * v.z);
            tri2.normal.z = (u.x * v.y) - (u.y * v.x);

            triangles.push_back(tri1);
            triangles.push_back(tri2);
        }

    }

    for (auto [p, p2, p3, isP2, isP4, normal] : triangles)
    {
        // Vertex 1;
        tempV->push_back(p.x);
        tempV->push_back(p.y);
        tempV->push_back(p.z);

        tempV->push_back(normal.x);
        tempV->push_back(normal.y);
        tempV->push_back(normal.z);

        tempV->push_back(txc_p.x);
        tempV->push_back(txc_p.y);

        // Vertex 2;
        tempV->push_back(p2.x);
        tempV->push_back(p2.y);
        tempV->push_back(p2.z);

        tempV->push_back(normal.x);
        tempV->push_back(normal.y);
        tempV->push_back(normal.z);
        if (isP2)
        {
            tempV->push_back(txc_p2.x);
            tempV->push_back(txc_p2.y);
        }
        else
        {
            tempV->push_back(txc_p3.x);
            tempV->push_back(txc_p3.y);
        }

        // Vertex 3;
        tempV->push_back(p3.x);
        tempV->push_back(p3.y);
        tempV->push_back(p3.z);

        tempV->push_back(normal.x);
        tempV->push_back(normal.y);
        tempV->push_back(normal.z);

        if (isP4)
        {
            tempV->push_back(txc_p4.x);
            tempV->push_back(txc_p4.y);
        }
        else
        {
            tempV->push_back(txc_p3.x);
            tempV->push_back(txc_p3.y);
        }

    }

}
Generator(std::vector<float>* p_vecArray, int p_size = 2): gen_size(p_size)
{
    std::vector<vec4> tempVec;
    
    // Make the vertices, gen_size * gen_size
    gen(&tempVec);
    // printArray(&tempVec);

    OrderPair(tempVec, p_vecArray);
    // printArray(p_vecArray);
    // printTriangles(&triangles);
            
}

结果:

使用 gen_size 作为 128

线框图: