Создание собственного формата вершин совсем немного. Все это делается в glVertexAttribPointer
звонках. Прежде всего, вы используете 4 в качестве параметра шага, но ваша структура вершины имеет ширину 8 байтов, поэтому от начала одной вершины до следующей имеется 8 байтов, поэтому шаг должен быть 8 (конечно, в обоих вызовах ). Смещения верны, но вы должны установить для нормализованного флага значение true для цветов, поскольку вы наверняка хотите, чтобы они находились в диапазоне [0,1] (я не знаю, должно ли это быть в случае с позициями вершин). ).
Далее, при использовании пользовательских атрибутов вершин в шейдерах, вы не включаете устаревшие массивы фиксированных функций (вещи gl...ClienState
). Вместо этого вы должны использовать
GL.EnableVertexAttribArray(Shaders.PositionDataID);
GL.EnableVertexAttribArray(Shaders.ColorDataID);
и соответствующие glDisableVertexAttribArray
звонки.
А что означает count/4
в вызове glDrawArrays
. Имейте в виду, что последний параметр указывает количество вершин, а не примитивов (в вашем случае это квадроциклы). Но, возможно, так и было задумано.
Помимо этих реальных ошибок, вы не должны использовать такой формат копируемой вершины, что вам придется самостоятельно декодировать его в шейдере. Вот для чего нужны параметры шага и смещения glVertexAttribPointer
. Например, переопределите ваши данные вершины немного:
public struct SmallBlockVertex
{
public byte PositionX;
public byte PositionY;
public byte PositionZ;
public byte ColorR;
public byte ColorG;
public byte ColorB;
public byte TextureX;
public byte TextureY;
}
и тогда вы можете просто использовать
GL.VertexAttribPointer(Shaders.PositionDataID, 3, VertexAttribPointerType.UnsignedByte, false, 8, 0);
GL.VertexAttribPointer(Shaders.ColorDataID, 3, VertexAttribPointerType.UnsignedByte, true, 8, 3);
GL.VertexAttribPointer(Shaders.TexCoordDataID, 2, VertexAttribPointerType.UnsignedByte, true, 8, 6);
А в шейдере у вас есть
attribute vec3 pos_data;
attribute vec3 col_data;
attribute vec2 tex_data;
и вам не нужно извлекать координату текстуры из позиции и окрашивать самостоятельно.
И вам следует подумать, действительно ли ваши требования к пространству требуют использования байтов для позиций вершин, поскольку это крайне ограничивает точность ваших данных о положении. Возможно, шорты или поплавки половинной точности будут хорошим компромиссом.
А также не обязательно вызывать glBindBuffer
в методе рендеринга, поскольку это необходимо только для glVertexAttribPointer
и сохраняется в VAO, который активируется glBindVertexArray
. Вы также обычно не должны вызывать glFlush
, так как в любом случае ОС делает это при замене буферов (при условии, что вы используете двойную буферизацию).
И, наконец, что не менее важно, убедитесь, что ваше оборудование также поддерживает все функции, которые вы используете (например, VBO и VAO).
РЕДАКТИРОВАТЬ: На самом деле включенные флаги массивов также хранятся в VAO, так что вы можете вызвать
GL.EnableVertexAttribArray(Shaders.PositionDataID);
GL.EnableVertexAttribArray(Shaders.ColorDataID);
в методе SetData
(после создания и привязки VAO, конечно), и они затем включаются, когда вы связываете VAO с помощью glBindVertexArray
в функции рендеринга. О, я только что увидел еще одну ошибку. Когда вы связываете VAO в функции рендеринга, включенные флаги массивов атрибутов перезаписываются состоянием из VAO, и, поскольку вы не включили их после создания VAO, они по-прежнему отключены. Поэтому вам нужно будет сделать это, как сказано, включить массивы в методе SetData
. На самом деле в вашем случае вам может повезти, и VAO все еще привязан, когда вы включаете массивы в функции рендеринга (как вы не вызывали glBindVertexArray(0)
), но вы не должны на это рассчитывать.