Проблемы с добавлением экземпляров в работающую спрайт-систему

Я пытаюсь внедрить инстансинг в мой 2d Game Engine, чтобы он мог поддерживать системы частиц без потери производительности. Мой класс ISprite является производным от класса Sprite. Я просто просмотрел и удалил всю функциональность, влияющую на отдельные спрайты, и заменил ее с учетом плана создания экземпляров. К сожалению, ничего не рисует на экране.

Вот соответствующая информация:

Вершинный шейдер

#version 330 core

layout (location = 0) in vec3 position;
layout (location = 1) in vec2 texCoords;
layout (location = 2) in vec4 colorSource;
layout (location = 3) in mat4 transform;

out vec2 TexCoords;
out vec4 Color;

uniform mat4 uniformView;
uniform mat4 uniformProjection;

void main()
{
gl_Position = uniformProjection * uniformView * transform * vec4(position, 1.0f);
TexCoords = texCoords;
Color = colorSource;
}

Фрагмент шейдера

#version 330 core
in vec2 TexCoords;
in vec4 Color;

out vec4 color;

uniform sampler2D Texture;
uniform vec4 uniformColor;

void main()
{
vec4 texColor = texture(Texture, TexCoords) * Color;
if(texColor.a < 0.1)
discard;

color = texColor;
}

нагрузка — Готовит все спрайты для рисования, вызываемого один раз.

void ISprite::Load(Shader spriteShader)
{
spriteShader.Use();

GLfloat vertices[] = {
//X    Y     Z
0.5f, -0.5f, 0.0f,
-0.5f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.5f, 0.5f, 0.0f,
-0.5f, 0.5f, 0.0f
};

glGenVertexArrays(1, &vertexArray);
glGenBuffers(1, &positionBuffer);
glGenBuffers(1, &texCoordsBuffer);
glGenBuffers(1, &colorBuffer);
glGenBuffers(1, &matrixBuffer);

glBindVertexArray(vertexArray);

//The vertex data will never change, so send that data now.
glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

//For vertex Position
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(GLfloat), (GLvoid*)0);

//For texture coordinates
glBindBuffer(GL_ARRAY_BUFFER, texCoordsBuffer);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2*sizeof(GLfloat), (GLvoid*)0);

//For Color
glBindBuffer(GL_ARRAY_BUFFER, colorBuffer);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (GLvoid*)0);

//For Transformation Matrix
glBindBuffer(GL_ARRAY_BUFFER, matrixBuffer);
for (int i = 0; i < 4; ++i)
{
glEnableVertexAttribArray(3 + i);
glVertexAttribPointer(3 + i, 4, GL_FLOAT, GL_FALSE,
4 * 4 * sizeof(GLfloat), (GLvoid*)(4 * i * sizeof(GLfloat)));
}

glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
glBindBuffer(GL_ARRAY_BUFFER, texCoordsBuffer);
glBindBuffer(GL_ARRAY_BUFFER, colorBuffer);
glBindBuffer(GL_ARRAY_BUFFER, matrixBuffer);
glBindVertexArray(0);

glVertexAttribDivisor(positionBuffer, 0);
glVertexAttribDivisor(texCoordsBuffer, 1);
glVertexAttribDivisor(colorBuffer, 1);
glVertexAttribDivisor(matrixBuffer, 1);
glVertexAttribDivisor(matrixBuffer + 1, 1);
glVertexAttribDivisor(matrixBuffer + 2, 1);
glVertexAttribDivisor(matrixBuffer + 3, 1);

ISprite::shader = &spriteShader;
}

Подготовить жеребьевку — вызывается каждым спрайтом, каждым кадром. Отправляет данные в статические векторы

void ISprite::prepareDraw(void)
{
//Adds their personal data to vectors shared by class
glm::mat4 transform = calculateTransorm();

for (int i = 0; i < 4; ++i)
{
for (int j = 0; j < 4; ++j)
ISprite::transformMatrices.push_back(transform[i][j]);
}

texture.updateAnimation();
for (int i = 0; i < 12; ++i)
ISprite::textureCoordinatesAll.push_back(texture.textureCoordinates[i]);

ISprite::colorValues.push_back(color.x);
ISprite::colorValues.push_back(color.y);
ISprite::colorValues.push_back(color.z);
ISprite::colorValues.push_back(color.w);
}

Рисовать спрайты — вызывается один раз каждый кадр, на самом деле рисует спрайты

void ISprite::drawSprites(Texture testTexture)
{
shader->Use();

for (std::vector<ISprite*>::iterator it = Isprites.begin(); it != Isprites.end(); ++it)
(*it)->prepareDraw();

glBindVertexArray(vertexArray);
glBindTexture(GL_TEXTURE_2D, testTexture.ID);

//Bind texture here if you want textures to work. if not, a single texture atlas will be bound
glBindBuffer(GL_ARRAY_BUFFER, texCoordsBuffer);
glBufferData(GL_ARRAY_BUFFER, textureCoordinatesAll.size() * sizeof(GLfloat),
textureCoordinatesAll.data(), GL_STREAM_DRAW);

glBindBuffer(GL_ARRAY_BUFFER, colorBuffer);
glBufferData(GL_ARRAY_BUFFER, colorValues.size() * sizeof(GLfloat),
colorValues.data(), GL_STREAM_DRAW);

glBindBuffer(GL_ARRAY_BUFFER, matrixBuffer);
glBufferData(GL_ARRAY_BUFFER, transformMatrices.size() * sizeof(GLfloat),
transformMatrices.data(), GL_STREAM_DRAW);

glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 6, Isprites.size());

textureCoordinatesAll.clear();
colorValues.clear();
transformMatrices.clear();
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindVertexArray(0);
}

0

Решение

Там может быть много причин, почему ничего не отображается. Проблемы с преобразованиями, координатами вне диапазона и т. Д. Но одна вещь, связанная с созданием экземпляров, определенно выглядит неправильно в размещенном коде:

glBindVertexArray(0);

glVertexAttribDivisor(positionBuffer, 0);
glVertexAttribDivisor(texCoordsBuffer, 1);
glVertexAttribDivisor(colorBuffer, 1);
...

Первый аргумент glVertexAttribDivisor() это местоположение атрибута вершины, а не имя буфера. Кроме того, состояние, установленное этим вызовом, является частью состояния VAO, поэтому вы должны выполнять эти вызовы, пока VAO все еще связан.

Так что звонки должны выглядеть так:

glVertexAttribDivisor(0, 0);
glVertexAttribDivisor(1, 0);
glVertexAttribDivisor(2, 1);
...

glBindVertexArray(0);

где первые аргументы glVertexAttribDivisor() сопоставьте значения местоположения, которые вы также используете в качестве первого аргумента glVertexAttribPointer() а также glEnableVertexAttribArray(),

Значение делителя для координат текстуры (атрибут 1), скорее всего, должно быть 0, поскольку вы хотите, чтобы координаты текстуры были установлены для каждой вершины, как и позиции. Для цветов и других оставшихся атрибутов 1 — правильное значение, чтобы они применялись для каждого экземпляра.

Кроме того, как я упоминал в комментарии, вы также можете захотеть использовать точечные спрайты. Хотя они не дают такой же гибкости, какую можно получить при рисовании отдельных квадов, их часто можно использовать для спрайтов. С точечными спрайтами вам нужна только одна вершина на спрайт, и координаты текстуры генерируются автоматически. Мой ответ здесь дает общее представление о том, как используются точечные спрайты, включая способы применения к ним текстур: Визуализируйте большие круглые точки в современном OpenGL.

0

Другие решения


По вопросам рекламы [email protected]