Rendering issue with different computers

Refresh

December 2018

Views

1.2k time

1

So i am making a short of tower defense game. I shared a build with them so i can check if everything performs as it should on another host.

And what actually happens is that while everything renders perfectly on my side (both on my mac/xcode + windows/visual studio 2012), on my friend's side it seems like the geometry is messed up. Each object on my screen is represented by a VBO which i use every time to render to different locations. But it seems like my VBOs have all the geometry imported from all models. (Hence the Tower with the tree on the side.)

Here's the result:

enter image description here(My computer)enter image description here(My friend's computer)

As by now i've managed to debug this issue up to a certain point. I can tell it's not the way i'm importing my models because i'm creating a debug.txt file with all the vectors before i send them to gpu as VBOs and on both computers they output the same values. So i their vectors are not getting messed up by memory issues or anything like that. So i am thinking maybe it is the way i am setting up or rendering my VBOs

What strikes me the most though is why things work on my computer while they are not on my friends computer. One difference i know for sure is that my computer is a developer station(whatever this means) while my friend's computer is not.

This is my VBO loading function and my VBO drawing function: I use glfw to create my window and context and include glew headers to enable some of the newer opengl functions.

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



}

Draw code:

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

}

I'm out of ideas i hope someone can direct me on how to debug this any further.

2 answers

5

OpenGL спецификации. не указывает точное поведение , которое должно произойти , когда вы выдаете вызов отрисовки с большим числом вершин , чем ваши буферные магазинах. Причиной этого может корректно работать на одной машине , а не на другой сводится к реализации. Каждый производитель волен делать все , что они хотят , если возникает такая ситуация, поэтому делают артефакты могут отображаться на оборудовании AMD , но не у всех на NVidia или Intel. В довершении, там на самом деле нет состояния ошибки генерируется при вызове , glDrawArrays (...)когда он попросил сделать слишком много вершин. Вы , безусловно , необходимо проверить свое программное обеспечение на оборудовании соерседа от нескольких поставщиков , чтобы поймать такого рода ошибки; который производит GPU в вашем компьютере, а версия драйвера, так же важна , как операционная система и компилятор.

Тем не менее, есть способы, чтобы поймать эти глупые ошибки. gDEBugger это один, и есть также новое расширение OpenGL я расскажу ниже. Я предпочитаю использовать новое расширение, потому что в моем опыте, в дополнении к устаревшим вызовам API и ошибкам (которые gDEBugger могут быть сконфигурированы для мониторинга), расширение может также предупредить Вас за использование нерационально выровненные структур данных и различные другие вопросов переносимости и эффективности.

Я хотел бы добавить некоторый код , я использую , чтобы использовать OpenGL Debug Output в моем программном обеспечении, так как это является примером неправедного поведения , которое фактически не генерировать ошибку, вы можете поймать с 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 Debug Output (требует отладки контекста и относительно недавний драйвер, 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);
}


Некоторая важные функции полезности для замены enumerant значения с более осмысленным текстом


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];
}


Моя Debug Output Callback (несколько сумбурно, потому что он печатает каждое поле в разных цветах в моем программном обеспечении)


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» вместо этого.
3

После дальнейших сеансов отладки с моими друзьями и многое пробным мне удалось найти проблему. Это взял меня два твердых дней, чтобы выяснить, и на самом деле это была просто глупая ошибка.

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

Приведенный выше код не получает размер вершины (в виде точек), а как общее число поплавков, хранящихся там. Так что все умножается на 3. Добавление / 3 решил.

Таким образом, я предполагаю, так как общее количество очков, где умноженные на 3 раза VBO «украл» данные из других РВО, хранящихся на GPU. (Таким образом, модель дерева стек моей башни).

Что я не могу понять, все же, хотя и хотел бы получить ответ на том, почему на моем компьютере все оказывается хорошо, но не на других компьютерах. Как я изложить в моем оригинальном вопросе намек будет то, что мой компьютер на самом деле разработчик станция в то время как мой друг не так. Тот, кто достаточно любезен, чтобы объяснить, почему этот эффект не воспроизводится на меня, я с удовольствием приму его ответ как решение моей проблемы.

Спасибо