如何修复地形纹理?
How to fix texturing a terrain?
我编写了一个由三角形组成的平坦地形,但似乎出现了一些镜像。我想让它模仿草,但有些地方很模糊。我需要在 glTexParameteri 中添加一些参数吗?或者可能是与绘图代码相关的错误?
读取纹理的函数:
GLuint Terrain::write_model_texture(const char* filename)
{
GLuint tex;
// Activate texture 0
glActiveTexture(GL_TEXTURE0);
// Read into computers memory
std::vector<unsigned char> image;
unsigned width, height;
// Read the image
unsigned error = lodepng::decode(image, width, height, filename);
// Import to graphics card memory
glGenTextures(1, &tex); //Initialize one handle
glBindTexture(GL_TEXTURE_2D, tex); //Activate handle
// Copy image to graphics cards memory represented by the active handle
glTexImage2D(GL_TEXTURE_2D, 0, 4, width, height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, (unsigned char*)image.data());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
return tex;
}
还有绘制三角形的代码:
this->P = glm::mat4(1.0f);
this->V = glm::mat4(1.0f);
this->M = glm::mat4(1.0f);
P = in.P;
V = in.V;
//M = glm::rotate(M, glm::radians(90.0f), glm::vec3(1.0f, 0.0f, 0.0f));
M = glm::translate(M, glm::vec3(-5.0f, -5.0f, 0.0f));
//M = glm::scale(M, glm::vec3(10.0f, 10.0f, 10.0f));
for (int row = 0; row < terrain_height; row++)
{
int col;
// adding a row of vertices
for (col = 0; col < terrain_width; col++) {
// x, y, z, 1
//std::cout << random_num << std::endl;
terrain_verts.emplace_back(col, row, 0, 1);
terrain_norms.emplace_back(0.0f, 0.0f, 1.0f, 0);
}
// adding a row of indices
for (col = 0; col < terrain_width; col++)
{
terrain_indices.emplace_back(col + row * terrain_width);
terrain_indices.emplace_back(col + row * terrain_width + 1);
terrain_indices.emplace_back(col + terrain_width * (row + 1) - 1);
}
for (col = terrain_width - 1; col >= 0; col--)
{
terrain_indices.emplace_back(col + row * terrain_width);
terrain_indices.emplace_back(col + terrain_width * (row + 1) - 1);
terrain_indices.emplace_back(col + terrain_width * (row + 1));
}
// adding a row of texture coordinates
if (row % 2 == 0)
{
for (col = 0; col < terrain_width; col += 2)
{
terrain_texture_coordinates.emplace_back(0, 0);
terrain_texture_coordinates.emplace_back(1, 0);
}
}
else
{
for (col = 0; col < terrain_width; col += 2)
{
terrain_texture_coordinates.emplace_back(0, 1);
terrain_texture_coordinates.emplace_back(1, 1);
}
}
}
spTextured->use();
glUniformMatrix4fv(spTextured->u("P"), 1, false, glm::value_ptr(P));
glUniformMatrix4fv(spTextured->u("V"), 1, false, glm::value_ptr(V));
glEnableVertexAttribArray(spTextured->a("vertex"));
glEnableVertexAttribArray(spTextured->a("texCoord"));
glEnableVertexAttribArray(spTextured->a("normal"));
glUniformMatrix4fv(spTextured->u("M"), 1, false, glm::value_ptr(M));
glVertexAttribPointer(spTextured->a("vertex"), 4, GL_FLOAT, false, 0, terrain_verts.data());
glVertexAttribPointer(spTextured->a("texCoord"), 2, GL_FLOAT, false, 0, terrain_texture_coordinates.data());
glVertexAttribPointer(spTextured->a("normal"), 4, GL_FLOAT, false, 0, terrain_norms.data());
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex);
glUniform1i(spTextured->u("tex"), 0);
glDrawElements(GL_TRIANGLES, terrain_indices_count(), GL_UNSIGNED_INT, terrain_indices.data());
glDisableVertexAttribArray(spTextured->a("vertex"));
glDisableVertexAttribArray(spTextured->a("color"));
glDisableVertexAttribArray(spTextured->a("normal"));
你的指数没有任何意义:
for (col = 0; col < terrain_width; col++)
{
terrain_indices.emplace_back(col + row * terrain_width);
terrain_indices.emplace_back(col + row * terrain_width + 1);
terrain_indices.emplace_back(col + terrain_width * (row + 1) - 1);
}
for (col = terrain_width - 1; col >= 0; col--)
{
terrain_indices.emplace_back(col + row * terrain_width);
terrain_indices.emplace_back(col + terrain_width * (row + 1) - 1);
terrain_indices.emplace_back(col + terrain_width * (row + 1));
}
如果您查看数据网格:
row = 0: 0 --- 1 --- 2 --- 3
| | | |
| | | |
row = 1: 4 --- 5 --- 6 ----7
^ ^ ^ ^
col=0 1 2 3
对于第 0 行第 0 列,您生成两个具有以下顶点的三角形:
0, 1, 3
是面积为零的变形三角形
0, 3, 4
完全穿过您的网格:
对于行=0、列=1 等内部单元格,您得到:
1, 2, 4
跨越 2 个网格单元
1, 4, 5
至少属于一个网格单元(虽然不是它应该的那个)
您实际上可以在屏幕截图中看到这些图案,您只需要考虑到您绘制了很多奇怪的重叠三角形。
你的 tex 坐标也不会那样工作。您可以像这样为交替行生成 tex 坐标:
row = 0: (0,0) --- (1,0)
| |
| |
row = 1: (0,1) --- (1,1)
| |
| |
row = 2: (0,0) --- (1,0)
如果您以这种方式映射纹理坐标,则第 1 行和第 2 行之间的单元格的图像将垂直镜像到第 0 行和第 1 行之间的单元格。您不能共享下方网格单元格的行顶点和以这种方式在其上方,您将必须使用不同的纹理坐标复制行顶点才能使其工作。
但是,这不是必需的,因为您可以使用 GL_REPEAT
纹理环绕模式,只需使用 [0,1]
范围之外的纹理坐标,例如:
row = 0: (0,0) --- (1,0) --- (2,0)
| | |
| | |
row = 1: (0,1) --- (1,1) --- (2,1)
| | |
| | |
row = 2: (0,2) --- (1,2) --- (2,2)
我编写了一个由三角形组成的平坦地形,但似乎出现了一些镜像。我想让它模仿草,但有些地方很模糊。我需要在 glTexParameteri 中添加一些参数吗?或者可能是与绘图代码相关的错误?
读取纹理的函数:
GLuint Terrain::write_model_texture(const char* filename)
{
GLuint tex;
// Activate texture 0
glActiveTexture(GL_TEXTURE0);
// Read into computers memory
std::vector<unsigned char> image;
unsigned width, height;
// Read the image
unsigned error = lodepng::decode(image, width, height, filename);
// Import to graphics card memory
glGenTextures(1, &tex); //Initialize one handle
glBindTexture(GL_TEXTURE_2D, tex); //Activate handle
// Copy image to graphics cards memory represented by the active handle
glTexImage2D(GL_TEXTURE_2D, 0, 4, width, height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, (unsigned char*)image.data());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
return tex;
}
还有绘制三角形的代码:
this->P = glm::mat4(1.0f);
this->V = glm::mat4(1.0f);
this->M = glm::mat4(1.0f);
P = in.P;
V = in.V;
//M = glm::rotate(M, glm::radians(90.0f), glm::vec3(1.0f, 0.0f, 0.0f));
M = glm::translate(M, glm::vec3(-5.0f, -5.0f, 0.0f));
//M = glm::scale(M, glm::vec3(10.0f, 10.0f, 10.0f));
for (int row = 0; row < terrain_height; row++)
{
int col;
// adding a row of vertices
for (col = 0; col < terrain_width; col++) {
// x, y, z, 1
//std::cout << random_num << std::endl;
terrain_verts.emplace_back(col, row, 0, 1);
terrain_norms.emplace_back(0.0f, 0.0f, 1.0f, 0);
}
// adding a row of indices
for (col = 0; col < terrain_width; col++)
{
terrain_indices.emplace_back(col + row * terrain_width);
terrain_indices.emplace_back(col + row * terrain_width + 1);
terrain_indices.emplace_back(col + terrain_width * (row + 1) - 1);
}
for (col = terrain_width - 1; col >= 0; col--)
{
terrain_indices.emplace_back(col + row * terrain_width);
terrain_indices.emplace_back(col + terrain_width * (row + 1) - 1);
terrain_indices.emplace_back(col + terrain_width * (row + 1));
}
// adding a row of texture coordinates
if (row % 2 == 0)
{
for (col = 0; col < terrain_width; col += 2)
{
terrain_texture_coordinates.emplace_back(0, 0);
terrain_texture_coordinates.emplace_back(1, 0);
}
}
else
{
for (col = 0; col < terrain_width; col += 2)
{
terrain_texture_coordinates.emplace_back(0, 1);
terrain_texture_coordinates.emplace_back(1, 1);
}
}
}
spTextured->use();
glUniformMatrix4fv(spTextured->u("P"), 1, false, glm::value_ptr(P));
glUniformMatrix4fv(spTextured->u("V"), 1, false, glm::value_ptr(V));
glEnableVertexAttribArray(spTextured->a("vertex"));
glEnableVertexAttribArray(spTextured->a("texCoord"));
glEnableVertexAttribArray(spTextured->a("normal"));
glUniformMatrix4fv(spTextured->u("M"), 1, false, glm::value_ptr(M));
glVertexAttribPointer(spTextured->a("vertex"), 4, GL_FLOAT, false, 0, terrain_verts.data());
glVertexAttribPointer(spTextured->a("texCoord"), 2, GL_FLOAT, false, 0, terrain_texture_coordinates.data());
glVertexAttribPointer(spTextured->a("normal"), 4, GL_FLOAT, false, 0, terrain_norms.data());
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex);
glUniform1i(spTextured->u("tex"), 0);
glDrawElements(GL_TRIANGLES, terrain_indices_count(), GL_UNSIGNED_INT, terrain_indices.data());
glDisableVertexAttribArray(spTextured->a("vertex"));
glDisableVertexAttribArray(spTextured->a("color"));
glDisableVertexAttribArray(spTextured->a("normal"));
你的指数没有任何意义:
for (col = 0; col < terrain_width; col++) { terrain_indices.emplace_back(col + row * terrain_width); terrain_indices.emplace_back(col + row * terrain_width + 1); terrain_indices.emplace_back(col + terrain_width * (row + 1) - 1); } for (col = terrain_width - 1; col >= 0; col--) { terrain_indices.emplace_back(col + row * terrain_width); terrain_indices.emplace_back(col + terrain_width * (row + 1) - 1); terrain_indices.emplace_back(col + terrain_width * (row + 1)); }
如果您查看数据网格:
row = 0: 0 --- 1 --- 2 --- 3
| | | |
| | | |
row = 1: 4 --- 5 --- 6 ----7
^ ^ ^ ^
col=0 1 2 3
对于第 0 行第 0 列,您生成两个具有以下顶点的三角形:
0, 1, 3
是面积为零的变形三角形0, 3, 4
完全穿过您的网格:
对于行=0、列=1 等内部单元格,您得到:
1, 2, 4
跨越 2 个网格单元1, 4, 5
至少属于一个网格单元(虽然不是它应该的那个)
您实际上可以在屏幕截图中看到这些图案,您只需要考虑到您绘制了很多奇怪的重叠三角形。
你的 tex 坐标也不会那样工作。您可以像这样为交替行生成 tex 坐标:
row = 0: (0,0) --- (1,0)
| |
| |
row = 1: (0,1) --- (1,1)
| |
| |
row = 2: (0,0) --- (1,0)
如果您以这种方式映射纹理坐标,则第 1 行和第 2 行之间的单元格的图像将垂直镜像到第 0 行和第 1 行之间的单元格。您不能共享下方网格单元格的行顶点和以这种方式在其上方,您将必须使用不同的纹理坐标复制行顶点才能使其工作。
但是,这不是必需的,因为您可以使用 GL_REPEAT
纹理环绕模式,只需使用 [0,1]
范围之外的纹理坐标,例如:
row = 0: (0,0) --- (1,0) --- (2,0)
| | |
| | |
row = 1: (0,1) --- (1,1) --- (2,1)
| | |
| | |
row = 2: (0,2) --- (1,2) --- (2,2)