使用不同的计算机渲染问题

apo*_*iat 1 c++ opengl

所以我正在做一个塔防游戏.我与他们共享了一个构建,因此我可以检查一切是否在其他主机上执行.

而实际发生的事情是,虽然一切都完美地呈现在我的身边(在我的mac/xcode + windows/visual studio 2012上),在我朋友的一边,似乎几何图形混乱了.我的屏幕上的每个对象都由VBO表示,我每次都会使用它来渲染到不同的位置.但似乎我的VBO具有从所有模型导入的所有几何体.(因此塔边有树.)

这是结果:

在此输入图像描述(我的电脑)在此输入图像描述(我朋友的电脑)

到目前为止,我已经设法将此问题调试到某一点.我可以告诉它不是我导入我的模型的方式,因为我在创建一个带有所有向量的debug.txt文件,然后我将它们作为VBO发送到gpu,在两台计算机上它们输出相同的值.所以我的矢量不会被内存问题或其他任何东西弄乱.所以我想也许这就是我设置或渲染我的VBO的方式

最令我印象深刻的是,为什么我的电脑上的东西不在朋友的电脑上.我知道的一个区别是我的电脑是一个开发者工作站(无论这意味着什么),而我朋友的电脑却没有.

这是我的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);



}
Run Code Online (Sandbox Code Playgroud)

绘制代码:

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);

}
Run Code Online (Sandbox Code Playgroud)

我没有想法,我希望有人可以指导我如何进一步调试这个.

And*_*man 5

OpenGL规范.没有指定当您发出具有比缓冲区存储更多顶点的绘制调用时应该发生的确切行为.这可能在一台机器上正常工作而不在另一台机器上工作的原因归结为实现.如果出现这种情况,每个供应商都可以自由地做任何他们想做的事情,因此渲染工件可能会出现在AMD硬件上,但根本不会出现在nVIDIA或Intel上.更糟糕的是,glDrawArrays (...)当要求绘制太多顶点时,调用实际上没有生成错误状态.您肯定需要在来自多个供应商的硬件上测试您的软件以捕获这些类型的错误; 谁在您的计算机中制造GPU,以及驱动程序版本,与操作系统和编译器一样重要.

然而,有办法捕捉这些愚蠢的错误.gDEBugger是一个,我将在下面讨论一个新的OpenGL扩展.我更喜欢使用新扩展,因为根据我的经验,除了弃用的API调用和错误(gDEBugger可以配置为监视)之外,扩展还可以警告您使用效率低下的数据结构以及各种其他可移植性和性能问题.

我想在我的软件中添加一些用于使用OpenGL调试输出的代码,因为这是一个错误行为的示例,它实际上不会产生您可以捕获的错误glGetError (...).有时候,你可以通过调试输出来捕获这些错误(但是,我只测试了它,而这不是其中一种情况).你需要一个OpenGL调试上下文才能工作(设置它的过程高度依赖于平台),但它是一个上下文标志,就像向前/向后兼容和核心(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
Run Code Online (Sandbox Code Playgroud)


启用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);
}
Run Code Online (Sandbox Code Playgroud)


一些重要的实用程序函数,用更有意义的文本替换枚举值


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];
}
Run Code Online (Sandbox Code Playgroud)


我的调试输出回调(有点凌乱,因为它在我的软件中以不同的颜色打印每个字段)


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 ();
}
Run Code Online (Sandbox Code Playgroud)



由于我无法让您的情况触发调试输出事件,我想我至少会展示一个我能够触发的事件的示例.这不是您可以捕获glGetError (...)的错误,或者根本就是错误.但它肯定是一个绘制调用问题,你可能完全忘记你的项目持续时间而不使用这个扩展名:)

OpenGL Error:
=============
 Object ID: 102
 Severity:  Medium
 Type:      Performance
 Source:    API
 Message:   glDrawElements uses element index type 'GL_UNSIGNED_BYTE' that is not optimal for the current hardware configuration; consider using 'GL_UNSIGNED_SHORT' instead.