最近、3D レンダリングのために C++ で OpenGL を使い始めましたが、奇妙なことに、いくつかのマシンでしか動作しないようです。頂点配列オブジェクトを使用してOpenGL 3.0以上(現時点では3.0に設定されています)を使用しています(どのように呼び出されたかはわかりませんが、glBegin、glEndなどを削除したAPIリビジョン)。
別のマシンでテストする前に、私は常に GPU ドライバーを尋ねます。それらのほとんどは OpenGL 4.2 をサポートしています。そうでない場合は、少なくとも 3.0 をサポートしていることを確認します。しかし、一部のマシンでは、アプリケーションが単にクラッシュするか、何もレンダリングされず、OpenGL はエラーをスローしません (フレームごとに少なくとも 1 回はエラーをチェックします)。ただし、自分のマシンでは完全に正常に動作し、場合によっては、動作しないマシンよりも古いマシンもあります。
私は OpenGL 自体と GLEW のみを使用し始めましたが、使いやすさと他のいくつかの機能のために SFML と GLEW に切り替えましたが、OpenGL 自体の動作は変わりませんでした。ある時点で取り組んでいたエンジンを書き直して、すべての GL 呼び出しをカプセル化し、頂点配列オブジェクトやその他の機能を組み込みました。実際、アプリケーションが使用するすべての API 呼び出しのリストを提供できます。明らかに、テスト アプリケーションでそれらすべてを使用しているわけではありませんが、これらはエンジンで使用するすべての呼び出しです (これはレンダリングできる最低限度であるため、そうです、エンジンはほぼ完成していません)。
- glAttachShader
- glBindAttribLocation
- glBindBuffer
- glBindVertexArray
- glBufferData
- glBufferSubData
- glClear
- glClearColor
- glClearDepth
- glCompileShader
- glCreateProgram
- glCreateShader
- glCullFace
- glDeleteBuffers
- glDeleteProgram
- glDeleteShader
- glDeleteVertexArrays
- glDepthFunc
- glDepthMask
- glDepthRange
- glDisableVertexAttribArray
- glDrawElements
- glEnable
- 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 クラス程度を検索したい場合を除き、簡単な例を挙げることはできません。
EDIT、オブジェクトをレンダリングする小さなコード
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();
}
EDIT、実際にオブジェクトをレンダリングするために上記のすべてのメソッドを呼び出すメッシュ
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;
}