使用vector存储顶点属性时仅渲染单个矩形的问题求助
问题分析
你现在的核心问题是:当把多个矩形的顶点合并到一个vector后,绘制时仍然只使用了对应单个矩形的索引数量(6个),所以只会渲染第一个矩形。
原来循环调用descriptRender时,每次只传单个矩形的顶点,用6个索引刚好绘制这个矩形;现在合并所有顶点后,索引数组和绘制调用的参数都没有适配多矩形的情况。
具体问题点
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);这里的第二个参数固定为6,只会绘制6个索引对应的三角形,也就是第一个矩形的两个三角形,后面的顶点根本没被用到。- 传入的
indices数组是针对单个矩形的,没有为后续的矩形生成偏移后的索引(比如第二个矩形的顶点索引应该从4开始,而不是0)。
修复方案
方案1:动态生成适配多矩形的索引数组
在render函数里,根据积累的顶点数量生成对应的索引数组,每个矩形对应6个偏移后的索引:
void engine::render(sectors* walls, int size, player player, trig math, unsigned VAO, unsigned VBO, unsigned EBO, unsigned shaderProgram) { float wx[4]; float wy[4]; float wz[4]; int SW2 = 400; int SH2 = 300; float ps = math.SIN[player.a]; float pc = math.COS[player.a]; std::vector<float> points; std::vector<unsigned int> indices; int vertexCount = 0; // 记录当前已添加的顶点数(每个顶点对应2个float) for (int i = 0; i < size; i++) { int x1 = walls[i].x1 - player.x; int y1 = walls[i].y1 - player.y; int x2 = walls[i].x2 - player.x; int y2 = walls[i].y2 - player.y; // 旋转计算 wx[0] = x1 * pc - y1 * ps; wy[0] = y1 * pc + x1 * ps; wz[0] = 0 - player.z; wz[2] = walls[i].z - player.z; wx[1] = x2 * pc - y2 * ps; wy[1] = y2 * pc + x2 * ps; wz[1] = 0 - player.z; wz[3] = walls[i].z - player.z; if (wy[0] > 0 && wy[1] > 0) { // 添加当前矩形的4个顶点 points.push_back(wx[0] / wy[0]); points.push_back(wz[0] / wy[0]); points.push_back(wx[1] / wy[1]); points.push_back(wz[1] / wy[1]); points.push_back(wx[0] / wy[0]); points.push_back(wz[2] / wy[0]); points.push_back(wx[1] / wy[1]); points.push_back(wz[3] / wy[1]); // 为当前矩形生成偏移后的索引 indices.push_back(vertexCount + 0); indices.push_back(vertexCount + 1); indices.push_back(vertexCount + 2); indices.push_back(vertexCount + 1); indices.push_back(vertexCount + 3); indices.push_back(vertexCount + 2); vertexCount += 4; } } if (!points.empty()) { descriptRender(points, indices.data(), indices.size(), VAO, VBO, EBO, shaderProgram); } }
然后修改descriptRender函数,适配动态的索引数量:
void engine::descriptRender(std::vector<float> points, unsigned int* indices, unsigned int indexCount, unsigned int VAO, unsigned int VBO, unsigned int EBO, unsigned int shaderProgram) { glUseProgram(shaderProgram); glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, points.size() * sizeof(float), points.data(), GL_STREAM_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * sizeof(unsigned int), indices, GL_STREAM_DRAW); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, 0); glBindVertexArray(0); glUseProgram(0); std::cout << points.size() << std::endl; }
方案2:改用glDrawArrays简化绘制(无需索引)
如果你的顶点顺序符合GL_TRIANGLE_STRIP的要求(比如每个矩形的4个顶点按左下-右下-左上-右上排列),可以直接用无索引绘制,省去索引数组的维护:
修改descriptRender函数:
void engine::descriptRender(std::vector<float> points, unsigned int VAO, unsigned int VBO, unsigned int shaderProgram) { glUseProgram(shaderProgram); glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, points.size() * sizeof(float), points.data(), GL_STREAM_DRAW); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); // 总顶点数为points.size()/2,每个矩形4个顶点用TRIANGLE_STRIP绘制 glDrawArrays(GL_TRIANGLE_STRIP, 0, points.size() / 2); glBindVertexArray(0); glUseProgram(0); std::cout << points.size() << std::endl; }
同时render函数不需要处理索引,直接调用修改后的descriptRender即可。
额外建议
- 尽量不要每次渲染都调用
glBufferData,可以改用glBufferSubData更新部分数据,提升性能。 - 顶点属性指针和启用操作可以只在初始化VAO时执行一次,VAO会保存这些状态,无需每次渲染重复设置。
内容的提问来源于stack exchange,提问作者prarthik krishnan
相关产品推荐
相关产品推荐

