gpt4 book ai didi

c++ - openGL 中的对象有限制吗?

转载 作者:行者123 更新时间:2023-12-02 18:52:56 26 4
gpt4 key购买 nike

我想在 Visual C++ 中使用 OpenGL 绘制 2000 个球体。以下代码绘制了 1000 个球体,结果看起来不错。

但是当我增加 2000 个球体的数量时(请参阅下面的部分代码并用 ** 突出显示),它失败了。出现以下错误消息。

“freeglut:fgInitGL2:fghGenBuffers 为 NULL”

你能帮我解决这个问题吗?

    for (int j = 0; j < 10; j++) {
for (int k = 0; k < 10; k++) {
**for (int l = 0; l < 20; l++) { \\ for (int l = 0; l < 10; l++)**
glPushMatrix();
glTranslatef(j, k, l);
gluSphere(myQuad, 0.5, 100, 100);
glPopMatrix();
}
}
}

这是一个完整的测试代码。

#include <GL/glew.h>
#include <GL/glut.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <fstream>
#include <string>
#include <cstring>
#include <cmath>
#include <iostream>

int selectedObject = 1;
bool drawThatAxis = 0;
bool lightEffect = 1;

float fovy = 60.0, aspect = 1.0, zNear = 1.0, zFar = 100.0;

float depth = 8;
float phi = 0, theta = 0;
float downX, downY;
bool leftButton = false, middleButton = false;

GLfloat white[3] = { 1.0, 1.0, 1.0 };

void displayCallback(void);

GLdouble width, height;
int wd;

int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH);
glutInitWindowSize(800,600);

wd = glutCreateWindow("3D Molecules");

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);
glClearColor(0.0, 0.0, 0.0, 0.0);

GLuint id;
id = glGenLists(1);

GLUquadric* myQuad;
myQuad = gluNewQuadric();

glNewList(id, GL_COMPILE);

for (int j = 0; j < 10; j++) {
for (int k = 0; k < 10; k++) {
for (int l = 0; l < 10; l++) {
glPushMatrix();
glTranslatef(j, k, l);
gluSphere(myQuad, 0.5, 100, 100);
glPopMatrix();
}
}
}

glEndList();

glutDisplayFunc(displayCallback);
glutMainLoop();
return 0;
}
void displayCallback(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(fovy, aspect, zNear, zFar);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

gluLookAt(0, 0, 40, 0, 0, 0, 0, 1, 0);

glTranslatef(0.0, 0.0, -depth);
glRotatef(-theta, 1.0, 0.0, 0.0);
glRotatef(phi, 0.0, 1.0, 0.0);

if (lightEffect) {
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
}
else
{
glDisable(GL_LIGHTING);
glDisable(GL_LIGHT0);
}

switch (selectedObject)
{
case (1):
glCallList(1);
break;
default:
break;
}

glFlush();
}

最佳答案

Is there a limit of object in openGL?

OpenGL 没有定义像“最大对象数”这样的限制。应用程序能够绘制尽可能多的对象,只要它们适合CPU 内存,但通常在应用程序达到内存限制之前,绘制速度会变得非常慢。即使当所有纹理和顶点数据无法放入 GPU 内存 时,OpenGL 仍然不会失败并通过在每一帧上不断上传 CPU->GPU 内存来继续绘制。

因此,如果我们回到 OpenGL 限制的问题上 - 实际上,存在内存限制,正如您可能从另一个 similar question 中看到的那样.您的代码实际上并未使用 glGetError() 检查任何 OpenGL 错误,因此您关于 fghGenBuffers() 是根本原因的结论具有误导性。我预计 GL_OUT_OF_MEMORY 错误会出现在您的案例中。现代 OpenGL 还定义了更复杂的错误报告机制 - ARB_debug_output .

显示列表 是 OpenGL 世界中一种非常古老的机制,旨在通过将一系列 OpenGL 命令“记住”到某些内部驱动程序管理的缓存中来优化大量数据的绘制。在广泛采用 Vertex Buffer Objects 之前通常使用此机制,它已被添加到 OpenGL 1.5 作为控制顶点数据内存的更直接和有效的方式,并且在 Vulkan 之前和 GL_NV_command_list重新发明了命令缓冲区作为用于缓存一系列 GPU 命令的更可靠的接口(interface)。

显示列表机制的一个大设计问题是不可预测的内存管理和供应商之间极其不同的实现(从非常差到极度优化)。现代图形驱动程序在编译显示列表时尝试将顶点数据隐式上传到 GPU 内存,但它们实际所做的仍然是隐藏的。

古老的 GLU 库是代码中的另一个谜团,因为很难估计 gluSphere() 使用的内存。悲观的计算表明:

size_t aNbSpheres = 10 * 10 * 20;
size_t aNbSlices, aNbStacks = 100;
size_t aNbTriangles = aNbSlices * aNbSlices * 2;
size_t aNbNodes = aNbSpheres * aNbTriangles * 3; // non-indexed array
size_t aNodeSize = (3 * sizeof(GLfloat)) * 2; // position + normal
size_t aMemSize = aNbNodes * aNodeSize;
size_t aMemSizeMiB = aMemSize / 1024 / 1024;

仅仅 2000 个球体的顶点数据就可能使用大约 2.746 GiB 的内存!如果您的应用程序是在 32 位模式下构建的,那么它会达到 32 位地址空间内存限制也就不足为奇了。但即使在 64 位应用程序的情况下,OpenGL 驱动程序实现也可能会遇到一些内部限制,这将由相同的 GL_OUT_OF_MEMORY 错误报告。

无论内存限制如何,您的代码都会尝试绘制大约 40M 的三角形。这对于快速的现代 GPU 硬件来说并非不可能,但在低端嵌入式图形上可能真的很慢。

那么接下来可以做什么?

  • 学习 OpenGL 调试实践 - 使用 glGetError() 和/或 ARB_debug_output 定位此问题和其他问题的位置和根本原因。
  • 减少 gluSphere() 曲面 segmentation 参数。
  • 生成单个球体的显示列表并绘制多次。 实例化 显着减少了内存消耗。然而,与一次绘制所有球体相比,这可能是一种较慢的替代方法(但 2000 次绘制调用对于现代 CPU 来说并不大)。
  • 用直接生成的顶点数据替换过时的 GLU 库 - 球面 segmentation 并不难实现,网络上有很多示例。
  • 学习 Vertex Buffer Objects并使用它们代替过时的显示列表。
  • 学习 GLSL 和现代 OpenGL,以便您可以实现 hardware instancing最有效地绘制球体。

从另一方面看,fghGenBuffers 错误看起来很奇怪,因为 glGenBuffers() 应该出现在每个现代 OpenGL 实现中。通过 glGetString(GL_VENDOR)/glGetString(GL_RENDERER)/glGetString(GL_VERSION) 打印驱动程序信息,以查看您的系统是否安装了正确的 GPU 驱动程序并且没有使用 OpenGL 1.1 的过时 Microsoft 软件实现。

关于c++ - openGL 中的对象有限制吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66523211/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com