1

だから私はタワーディフェンスゲームを手短にしています。ビルドを共有したので、別のホストですべてが正常に動作するかどうかを確認できます。

そして、実際に何が起こるかというと、私の側ではすべてが完全にレンダリングされますが (私の mac/xcode + windows/visual studio 2012 の両方で)、私の友人の側では、ジオメトリが台無しになっているように見えます。画面上の各オブジェクトは、毎回異なる場所にレンダリングするために使用する VBO で表されます。しかし、私の VBO には、すべてのモデルからインポートされたすべてのジオメトリがあるようです。(したがって、側面に木があるタワー。)

結果は次のとおりです。

ここに画像の説明を入力(私のパソコン)ここに画像の説明を入力(友達のパソコン)

今のところ、この問題を特定の時点までデバッグすることができました。VBOとしてgpuに送信する前にすべてのベクトルを含むdebug.txtファイルを作成していて、両方のコンピューターで同じ値を出力しているため、モデルをインポートする方法ではないことがわかります。だから私は彼らのベクトルがメモリの問題やそのようなものによって台無しにされていません. だから私は多分それが私のVBOを設定またはレンダリングしている方法だと思っています

しかし、最も印象に残っているのは、友人のコンピューターでは機能しないのに、自分のコンピューターでは機能する理由です。私が確かに知っている違いの 1 つは、私のコンピューターは (これが何を意味するにせよ) 開発者ステーションであり、友人のコンピューターはそうではないということです。

これは私の VBO 読み込み関数と VBO 描画関数です。glfw を使用してウィンドウとコンテキストを作成し、glew ヘッダーを含めて新しい opengl 関数のいくつかを有効にします。

void               G4::Renderer::LoadObject(
                                           G4::TILE_TYPES   aType,
                                           std::vector<float> &v_data,
                                           std::vector<float> &n_data,
                                           std::vector<float> &t_data,
                                           float scale,
                                           bool has_texture,
                                           unsigned int texture_id
                                           )
{

    unsigned int vertices_id, vertices_size, normals_id, texturecoordinates_id;

    vertices_size   = static_cast<unsigned int>(v_data.size());

    glGenBuffers(1, &vertices_id);
    glGenBuffers(1, &normals_id);

    //::->Vertex array buffer upload.
    glBindBuffer(GL_ARRAY_BUFFER, vertices_id);
    glBufferData(GL_ARRAY_BUFFER, sizeof(float)*v_data.size(), &v_data.front(), GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    //::->Normal Array buffer upload.
    glBindBuffer(GL_ARRAY_BUFFER, normals_id);
    glBufferData(GL_ARRAY_BUFFER, sizeof(float)*n_data.size(), &n_data.front(), GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);



    if (has_texture)
    {
        glGenBuffers(1, &texturecoordinates_id);

        glBindBuffer(GL_ARRAY_BUFFER, texturecoordinates_id);
        glBufferData(GL_ARRAY_BUFFER, sizeof(float)*t_data.size(), &(t_data[0]), GL_STATIC_DRAW);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
    }


    this->vbos[aType].Update(vertices_id, vertices_size, normals_id, texture_id, texturecoordinates_id, scale, has_texture);



}

ドローコード:

void G4::Renderer::DrawUnit(G4::VBO aVBO, bool drawWithColor, float r, float g, float b, float a)
{
    bool model_has_texture = aVBO.HasTexture();

    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_NORMAL_ARRAY);

    if (model_has_texture && !drawWithColor)  {
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
        glEnable(GL_TEXTURE_2D);
    }

    if (drawWithColor)
    {
        glColor4f(r, g, b, a);
    }

    glScalef(aVBO.GetScaleValue(), aVBO.GetScaleValue(), aVBO.GetScaleValue());

    glBindBuffer(GL_ARRAY_BUFFER, aVBO.GetVerticesID());
    glVertexPointer(3, GL_FLOAT, 0, 0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glBindBuffer(GL_ARRAY_BUFFER, aVBO.GetNormalsID());
    glNormalPointer(GL_FLOAT, 0, 0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);


    if (model_has_texture && !drawWithColor)
    {
        glBindTexture(GL_TEXTURE_2D, aVBO.GetTextureID());
        glBindBuffer(GL_ARRAY_BUFFER, aVBO.GetTextureCoordsID());
        glTexCoordPointer(2, GL_FLOAT, 0, 0);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
    }

    glDrawArrays(GL_TRIANGLES, 0, aVBO.GetVerticesSize());

    if (model_has_texture && !drawWithColor)  {
        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
        glDisable(GL_TEXTURE_2D);

    } 

    glDisableClientState(GL_NORMAL_ARRAY);
    glDisableClientState(GL_VERTEX_ARRAY);

}

私はアイデアがありません。誰かがこれをさらにデバッグする方法を教えてくれることを願っています。

4

2 に答える 2

6

OpenGL 仕様。は、バッファ ストアよりも多くの頂点を指定してドロー コールを発行したときに発生する正確な動作を指定していません。これがあるマシンでは正しく機能し、別のマシンでは正しく機能しない理由は、実装に帰着します。この状況が発生した場合、各ベンダーは好きなことを自由に行うことができるため、AMD ハードウェアではレンダリング アーティファクトが表示される可能性がありますが、nVIDIA または Intel ではまったく表示されません。さらに悪いことに、glDrawArrays (...)あまりにも多くの頂点を描画するように要求されたときに、 の呼び出しによってエラー状態が生成されることは実際にはありません。この種のエラーを検出するには、複数のベンダーから供給されたハードウェアでソフトウェアをテストする必要があります。コンピューターの GPU の製造元とドライバーのバージョンは、オペレーティング システムやコンパイラーと同じくらい重要です。

それでも、これらのばかげた間違いを見つける方法はあります。gDEBugger はその 1 つです。また、以下で説明する新しい OpenGL 拡張機能もあります。私の経験では、非推奨の API 呼び出しとエラー (gDEBugger を監視するように構成できます) に加えて、拡張機能は、非効率的に調整されたデータ構造の使用や、その他のさまざまな移植性とパフォーマンスの問題について警告することもできるため、新しい拡張機能を使用することを好みます。

ソフトウェアで OpenGL デバッグ出力を使用するために使用するコードを追加したいと考えましたglGetError (...)。場合によっては、デバッグ出力でこれらの間違いを見つけることができます (ただし、テストしたばかりで、これはそのような状況の 1 つではありません)。これを機能させるには OpenGL Debug Context が必要ですが (これを設定するプロセスはプラットフォームに大きく依存します)、これは前方/後方互換性とコアのようなコンテキスト フラグです (glfw はこれを簡単にするはずです)。

x86 プラットフォーム用の自動ブレークポイント マクロ


// Breakpoints that should ALWAYS trigger (EVEN IN RELEASE BUILDS) [x86]!
#ifdef _MSC_VER
# define eTB_CriticalBreakPoint() if (IsDebuggerPresent ()) __debugbreak ();
#else
# define eTB_CriticalBreakPoint() asm (" int $3");
#endif


OpenGL デバッグ出力を有効にする (デバッグ コンテキストと比較的最近のドライバー、OpenGL 4.x 時代が必要です)


// SUPER VERBOSE DEBUGGING!
if (glDebugMessageControlARB != NULL) {
  glEnable                  (GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
  glDebugMessageControlARB  (GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
  glDebugMessageCallbackARB ((GLDEBUGPROCARB)ETB_GL_ERROR_CALLBACK, NULL);
}


列挙型の値をより意味のあるテキストに置き換えるためのいくつかの重要なユーティリティ関数


const char*
ETB_GL_DEBUG_SOURCE_STR (GLenum source)
{
  static const char* sources [] = {
    "API",   "Window System", "Shader Compiler", "Third Party", "Application",
    "Other", "Unknown"
  };

  int str_idx =
    min ( source - GL_DEBUG_SOURCE_API,
            sizeof (sources) / sizeof (const char *) );

  return sources [str_idx];
}

const char*
ETB_GL_DEBUG_TYPE_STR (GLenum type)
{
  static const char* types [] = {
    "Error",       "Deprecated Behavior", "Undefined Behavior", "Portability",
    "Performance", "Other",               "Unknown"
  };

  int str_idx =
    min ( type - GL_DEBUG_TYPE_ERROR,
            sizeof (types) / sizeof (const char *) );

  return types [str_idx];
}

const char*
ETB_GL_DEBUG_SEVERITY_STR (GLenum severity)
{
  static const char* severities [] = {
    "High", "Medium", "Low", "Unknown"
  };

  int str_idx =
    min ( severity - GL_DEBUG_SEVERITY_HIGH,
            sizeof (severities) / sizeof (const char *) );

  return severities [str_idx];
}

DWORD
ETB_GL_DEBUG_SEVERITY_COLOR (GLenum severity)
{
  static DWORD severities [] = {
    0xff0000ff, // High (Red)
    0xff00ffff, // Med  (Yellow)
    0xff00ff00, // Low  (Green)
    0xffffffff  // ???  (White)
  };

  int col_idx =
    min ( severity - GL_DEBUG_SEVERITY_HIGH,
            sizeof (severities) / sizeof (DWORD) );

  return severities [col_idx];
}


私のデバッグ出力コールバック(私のソフトウェアでは各フィールドが異なる色で印刷されるため、やや面倒です)


void
ETB_GL_ERROR_CALLBACK (GLenum        source,
                       GLenum        type,
                       GLuint        id,
                       GLenum        severity,
                       GLsizei       length,
                       const GLchar* message,
                       GLvoid*       userParam)
{
  eTB_ColorPrintf (0xff00ffff, "OpenGL Error:\n");
  eTB_ColorPrintf (0xff808080, "=============\n");

  eTB_ColorPrintf (0xff6060ff, " Object ID: ");
  eTB_ColorPrintf (0xff0080ff, "%d\n", id);

  eTB_ColorPrintf (0xff60ff60, " Severity:  ");
  eTB_ColorPrintf ( ETB_GL_DEBUG_SEVERITY_COLOR   (severity),
                      "%s\n",
                        ETB_GL_DEBUG_SEVERITY_STR (severity) );

  eTB_ColorPrintf (0xffddff80, " Type:      ");
  eTB_ColorPrintf (0xffccaa80, "%s\n", ETB_GL_DEBUG_TYPE_STR     (type));

  eTB_ColorPrintf (0xffddff80, " Source:    ");
  eTB_ColorPrintf (0xffccaa80, "%s\n", ETB_GL_DEBUG_SOURCE_STR   (source));

  eTB_ColorPrintf (0xffff6060, " Message:   ");
  eTB_ColorPrintf (0xff0000ff, "%s\n\n", message);

  // Force the console to flush its contents before executing a breakpoint
  eTB_FlushConsole ();

  // Trigger a breakpoint in gDEBugger...
  glFinish ();

  // Trigger a breakpoint in traditional debuggers...
  eTB_CriticalBreakPoint ();
}



あなたの状況でデバッグ出力イベントを実際にトリガーすることができなかったので、少なくともトリガーできたイベントの例を示すことにしました。これは でキャッチできるエラーではなく、その意味でのエラーでもありませんglGetError (...)。しかし、この拡張機能を使用しないと、プロジェクトの期間中に完全に気付かない可能性があるのは、ドロー コールの問題であることは確かです :)

OpenGL エラー:
=============
 オブジェクト ID: 102
 重大度: 中
 タイプ: パフォーマンス
 ソース: API
 メッセージ: glDrawElements は、現在のハードウェア構成に最適ではない要素インデックス タイプ 'GL_UNSIGNED_BYTE' を使用しています。代わりに「GL_UNSIGNED_SHORT」の使用を検討してください。
于 2013-08-05T20:35:59.960 に答える
4

友人とのデバッグセッションと多くの試行錯誤の後、問題を見つけることができました。これを理解するのに丸2日かかりましたが、本当にばかげた間違いでした.

glDrawArrays(GL_TRIANGLES, 0, aVBO.GetVerticesSize());

上記のコードは、頂点のサイズを (ポイントとして) 取得するのではなく、そこに格納されている float の総数として取得します。したがって、すべてに 3 が掛けられます。/3 を追加すると解決しました。

したがって、合計ポイントに vbo の 3 倍を掛けると、GPU に保存されている他の vbo からデータを「盗んだ」と仮定します。(したがって、ツリーモデルは私のタワーにスタックされます)。

私がまだ理解できないのは、それについての答えが欲しいのですが、私のコンピューターではすべてが正常にレンダリングされたのに、他のコンピューターではレンダリングされなかった理由です。最初の質問で述べたように、ヒントは、私のコンピューターは実際には開発者ステーションですが、友人はそうではないということです。この効果が再現されない理由を説明してくれる親切な人なら誰でも、私の問題の解決策として彼の答えを喜んで受け入れます.

ありがとうございました

于 2013-08-05T19:29:49.543 に答える