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

时间:2013-08-05 18:19:45

标签: c++ opengl

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

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

结果如下:

enter image description here(我的电脑)enter image description here(我朋友的电脑)

到目前为止,我已经设法将此问题调试到某一点。我可以告诉它不是我导入我的模型的方式,因为我在创建一个带有所有向量的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);



}

绘制代码:

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

}

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

2 个答案:

答案 0 :(得分:5)

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

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

我想在我的软件中添加一些用于使用OpenGL调试输出的代码,因为这是一个错误行为的示例,它实际上不会产生您可以使用glGetError (...)捕获的错误。有时候,你可以通过Debug Output来捕获这些错误(但是,我只测试了它,而这不是其中一种情况)。你需要一个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


启用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 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.

答案 1 :(得分:4)

在与我的朋友进行进一步的调试和多次试训后,我设法找到了问题。这让我花了两天时间才弄明白,这真是一个愚蠢的错误。

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

上面的代码没有得到顶点大小(作为点),而是作为存储在那里的浮点数的总数。所以一切都乘以3.添加/ 3解决了它。

所以我假设因为总点数乘以存储在gpu上的其他vbos的vbo“stole”数据的3倍。 (因此树模型堆栈到我的塔)。

虽然我无法弄清楚,并希望得到一个答案,这就是为什么在我的电脑上一切都很好但不在其他电脑上。正如我在原始问题中所说,我的计算机实际上是一个开发者站,而我的朋友则不是。 任何善意解释为什么这种影响不能在我身上复制的人我都乐意接受他的答案来解决我的问题。

谢谢