最近我开始在 C++ 中使用 OpenGL 进行一些 3D 渲染,但奇怪的是它似乎只在少数机器上工作。我正在使用 OpenGL 3.0 或更高版本(目前它设置为 3.0)使用顶点数组对象(不确定它是如何调用的,但 API 修订版删除了 glBegin、glEnd 等)。
在另一台机器上测试之前,我总是询问他们的 GPU 驱动程序,其中大多数支持 OpenGL 4.2,如果没有,我确保他们至少支持 3.0。然而在某些机器上,我的应用程序只是崩溃了,或者不渲染任何东西,OpenGL 不会抛出任何错误(我每帧至少检查一次错误)。不过,它在我自己的机器上运行得非常好,而且在某些情况下,我的机器甚至比一些它不工作的机器还要老。
我开始只使用 OpenGL 本身和 GLEW,但为了易于使用和其他一些我喜欢的功能切换到 SFML 和 GLEW,但 OpenGL 本身并没有改变它的行为。我确实重写了我正在开发的引擎,以封装所有 GL 调用并合并顶点数组对象和其他一些功能,事实上我可以给你一个应用程序使用的所有 API 调用的列表。显然它并没有在测试应用程序中使用所有这些,但这些都是我在引擎中使用的所有调用(这是能够渲染的最低限度,所以是的,引擎甚至还没有接近完成):
- glAttachShader
- glBindAttribLocation
- glBindBuffer
- glBindVertexArray
- glBufferData
- glBufferSubData
- gl清除
- glClearColor
- glClearDepth
- glCompileShader
- glCreate程序
- glCreateShader
- glCullFace
- glDeleteBuffers
- glDeleteProgram
- glDeleteShader
- glDeleteVertexArrays
- glDepthFunc
- glDepthMask
- glDepthRange
- glDisableVertexAttribArray
- glDrawElements
- gl启用
- glEnableVertexAttribArray
- glFrontFace
- glGenBuffers
- glGenVertexArrays
- glGetAttribLocation
- glGetBufferParameteriv
- glGetBufferSubData
- glGetError
- glGetIntegerv
- glGetProgramInfoLog
- glGetProgramiv
- glGetShaderInfoLog
- glGetShaderiv
- glGetShaderSource
- glGetUniformLocation
- glIs程序
- glIsShader
- glLink程序
- glMapBufferRange
- glPixelStorei
- glShaderSource
- glUniform(1i, 1ui, 1f, 2f, 3f, 4f, Matrix3fv, Matrix4fv)
- glUnmapBuffer
- glUseProgram
- glVertexAttrib(1i, 1ui, 1f, 2f, 3f, 4f)
- glVertexAttribPointer
总之,Shader 和 ShaderProgram 部分没什么特别的,我有一些方法来创建/编译它们,预先设置一些属性位置,最后设置属性/制服。缓冲区对象也没有什么特别之处,您可以写入、读取和映射缓冲区,目前我只使用 GL_ARRAY_BUFFER 和 GL_ELEMENT_ARRAY_BUFFER。最后我使用顶点数组对象来实际渲染对象,显然我设置了属性指针,并封装了绘图调用和程序使用,它总是使用索引绘图。
此外,我在谷歌和堆栈溢出本身上进行了广泛搜索以寻找答案。但是所有的问题都与 OpenGL 无法在任何地方工作有关,例如,一些 API 调用没有按顺序调用或根本没有调用。遗憾的是,这些答案都不适合我,它一直在我自己的机器和我可以直接访问的其他机器上工作,但是当我将应用程序发送给其他人在他们的机器上测试它时它从来没有工作过。
希望这足够具体 XD
编辑,从下面的帖子中复制
每个测试都是在 windows vista 或 7 上完成的。我对每个 API 调用都进行了 OpenGL 错误检查,但似乎没有一个发现任何错误。我无法在我自己的机器上重现它,但在其他机器上进行更多跟踪后,我发现它在渲染之前不会崩溃。设置工作正常,它可以完美地创建所有缓冲区和对象,但是一旦我尝试渲染网格(VAO),它就会崩溃而没有任何错误(除了 .exe 已经停止工作)。我怀疑命令 glUseProgram 或 glDrawElements
关于一个例子,除非你想搜索大约 10 个类,我不能给你一个简短的例子
编辑,一小段代码渲染一个对象
Mesh 类将这些结构添加到对象中,因此它知道要绘制什么:
// Define Geometry (draw command)
struct Geometry
{
// Primitives
PrimitiveType primitiveType;
// Indices
IndexType indexType;
unsigned int count; // elements
unsigned int offset; // bytes
};
哦,顺便说一句,“几何标记”只是一个字符串,在该字符串下可以“放置”多个绘制调用,几个定义:
// Define a list of primitives
typedef std::vector<Geometry> GeometryList;
// Define Geometry ordered by tag
typedef std::map<const std::string, GeometryList> GeometryMap;
对于每个“绘制”调用,它都会返回一个字符串,以便网格类可以绑定适当的材质。
//-----------------------------------------------------------------------
const std::string HardwareObject::nextGeometryTag()
{
// Loop back
GeometryMap::const_iterator end = _geometry.end();
if(_activeGeometry == end)
{
// Bind and go to begin
glBindVertexArray(_GL_VertexArray);
_activeGeometry = _geometry.begin();
}
// Check if new tag exists
else if(++_activeGeometry == end)
{
// Unbind and return empty tag
glBindVertexArray(0);
return "";
}
return _activeGeometry->first;
}
//-----------------------------------------------------------------------
bool HardwareObject::drawGeometryTag() const
{
// Validate current tag
if(_activeGeometry == _geometry.end()) return false;
// Draw each geometry call of tag
for(GeometryList::const_iterator it = _activeGeometry->second.begin(); it != _activeGeometry->second.end(); ++it)
glDrawElements(it->primitiveType, it->count, it->indexType, (void*)it->offset);
// GL Error
return !Console::GET().getError("HardwareObject Drawing");
}
//-----------------------------------------------------------------------
void HardwareObject::resetGeometryTag()
{
_activeGeometry = _geometry.end();
}
编辑,网格调用所有上述方法来实际渲染对象
lockVertexAttributes() 只是确保所有属性指针都绑定到正确的顶点缓冲区。HardwareProgram 的 bind 方法只是检查程序是否编译并调用 glUseProgram
//-----------------------------------------------------------------------
bool Mesh::render()
{
// Lock vertex attributes
if(!lockVertexAttributes()) return false;
// To avoid errors
_object.resetGeometryTag();
// Loop while there's a tag
for(std::string tag = _object.nextGeometryTag(); tag != ""; tag = _object.nextGeometryTag())
{
// Find material
MaterialMap::const_iterator it = _materials.find(tag);
if(it == _materials.end()) continue;
// Bind material (get program directly)
const HardwareProgram *prog = it->second->getProgram();
if(!prog) continue;
if(!prog->bind()) continue;
// Draw tag
_object.drawGeometryTag();
}
// Ok!
return true;
}