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);
}
}
}
}
有帮助的主要变化是将函数 toTriangle
和 ToArray
更改为一个函数,并将三角形顶点视为向量(我花了很长时间才弄清楚)并使用四边形(方形)标记每个顶点并查看差异。这应该导致 i
和 j
的 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
线框图:
我正在尝试创建地形,但同样的错误不断出现。三角形在彼此不靠近的顶点之间形成链接,即 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);
}
}
}
}
有帮助的主要变化是将函数 toTriangle
和 ToArray
更改为一个函数,并将三角形顶点视为向量(我花了很长时间才弄清楚)并使用四边形(方形)标记每个顶点并查看差异。这应该导致 i
和 j
的 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
线框图: