Cześć! Chciałbym móc przycinać np. kwadraty, które wychodzą z jednej klasy sprite batch. Próbowałem zrobić to w ten sposób:

struct VertexData
{
	glm::vec2 position = glm::vec2(0.0f);
	glm::vec4 color = glm::vec4(0.0f);
};

struct DrawCmd
{
	glm::vec4 clipRect = glm::vec4(0.0f);
	GLuint elemCount = 0;
};

class SpriteBatch
{
public:
	SpriteBatch();

	void AddDrawCmd();
	void UpdateClipRect();
	void PushClipRect(glm::vec4 clip);
	void PopClipRect();

	void Prepare();
	void Draw(glm::vec2 pos, glm::vec2 size, glm::vec4 color);
	void Flush();

	GLuint vao, vbo, ebo;

	std::vector<VertexData> vertex;
	std::vector<GLuint> element;
	std::vector<glm::vec4> clipRect;
	std::vector<DrawCmd> drawCmd; // 1 komenda = 1 polecenie rysowania GPU
};
SpriteBatch::SpriteBatch()
{
	glGenVertexArrays(1, &vao);
	glBindVertexArray(vao);

	glGenBuffers(1, &vbo);
	glBindBuffer(GL_ARRAY_BUFFER, vbo);

	glEnableVertexAttribArray(0);
	glEnableVertexAttribArray(1);

	glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(VertexData), (const void*)offsetof(VertexData, position));
	glVertexAttribPointer(1, 4, GL_FLOAT, GL_TRUE, sizeof(VertexData), (const void*)offsetof(VertexData, color));

	glGenBuffers(1, &ebo);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
}

void SpriteBatch::AddDrawCmd()
{
	DrawCmd draw;
	draw.clipRect = clipRect.size() ? clipRect.back() : glm::vec4(0.0f, 0.0f, 1280.0f, 720.0f);
	drawCmd.push_back(draw);
}

void SpriteBatch::UpdateClipRect()
{
	const glm::vec4 currentClip = clipRect.size() ? clipRect.back() : glm::vec4(0.0f, 0.0f, 1280.0f, 720.0f);
	DrawCmd* currentDraw = drawCmd.size() > 0 ? &drawCmd.back() : nullptr;

	// 1. Jeśli nie ma żadnego polecenia rysowania
	// 2. liczba elementów nie jest równa 0
	// 1. Musimy dodać polecenie rysowania żeby nie było błędu związanego z dostaniem się do tego polecenia
	// 2. Musimy dodać polecenie rysowania żeby używać nowego clip rect
	if (!currentDraw || currentDraw->elemCount != 0) {
		AddDrawCmd();
		return;
	}

	DrawCmd* prevDraw = drawCmd.size() > 1 ? currentDraw - 1 : nullptr;
	// Jeśli liczba elementów jest 0, to znaczy nie mamy co rysować, usuwamy polecenie rysowania, bo nie używamy go
	// Musimy sprawdzić czy jeśli usuniemy polecenie rysowania to czy nie będzie błędu, bo nie chcemy usuwać polecenia jeśli jest tylko jedno
	if (currentDraw->elemCount == 0 && prevDraw) {
		drawCmd.pop_back();
	} else { currentDraw->clipRect = currentClip; }
}

void SpriteBatch::PushClipRect(glm::vec4 clip)
{
	clipRect.push_back(clip);
	UpdateClipRect();
}

void SpriteBatch::PopClipRect()
{
	clipRect.pop_back();
	UpdateClipRect();
}

void SpriteBatch::Prepare()
{
	vertex.clear();
	element.clear();
	clipRect.clear();
	drawCmd.clear();
}

void SpriteBatch::Draw(glm::vec2 pos, glm::vec2 size, glm::vec4 color)
{
	GLuint index = vertex.size();

	VertexData vertexData;
	vertexData.position = glm::vec2(pos.x, pos.y);
	vertexData.color = color;
	vertex.push_back(vertexData);

	vertexData.position = glm::vec2(pos.x, pos.y + size.y);
	vertexData.color = color;
	vertex.push_back(vertexData);

	vertexData.position = glm::vec2(pos.x + size.x, pos.y + size.y);
	vertexData.color = color;
	vertex.push_back(vertexData);

	vertexData.position = glm::vec2(pos.x + size.x, pos.y);
	vertexData.color = color;
	vertex.push_back(vertexData);

	element.push_back(index);
	element.push_back(index + 1);
	element.push_back(index + 2);
	element.push_back(index + 2);
	element.push_back(index + 3);
	element.push_back(index);

	DrawCmd& draw = drawCmd.back();
	draw.elemCount += element.size();
}

void SpriteBatch::Flush()
{
	shader.UseProgram();
	glEnable(GL_SCISSOR_TEST);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	const int windowW = 1280;
	const int windowH = 720;

	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	glBufferData(GL_ARRAY_BUFFER, vertex.size() * sizeof(VertexData), vertex.data(), GL_DYNAMIC_DRAW);

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, element.size() * sizeof(GLuint), element.data(), GL_DYNAMIC_DRAW);

	for (GLuint i = 0; i < drawCmd.size(); ++i) {
		const DrawCmd drawCall = drawCmd[i];
		glm::vec4 clip = drawCall.clipRect;
		if (clip.x < windowW && clip.y < windowH && clip.z >= 0.0f && clip.w >= 0.0f) {
			glScissor(static_cast<int>(clip.x), static_cast<int>(windowH - clip.w), static_cast<int>(clip.z - clip.x), static_cast<int>(clip.w - clip.y));

			glBindVertexArray(vao);
			glDrawElements(GL_TRIANGLES, drawCall.elemCount, GL_UNSIGNED_INT, nullptr);
			glBindVertexArray(0);
		}
	}

	glDisable(GL_SCISSOR_TEST);
	glDisable(GL_BLEND);
}

int main()
{
	OpenWindow("Name", 1280.0f, 720.0f);
        
        SpriteBatch sb;
        bool done = false;
        while(!done)
        {
		glClear(GL_COLOR_BUFFER_BIT);

		sb.Prepare();

		sb.PushClipRect(glm::vec4(0.0f, 150.0f, 1280.0f, 720.0f));
		sb.Draw(glm::vec2(100.0f, 100.0f), glm::vec2(100.0f, 100.0f), glm::vec4(0.0f, 255.0f, 0.0f, 255.0f));
		sb.PopClipRect();

		sb.PushClipRect(glm::vec4(150.0f, 300.0f, 1280.0f, 720.0f));
		sb.Draw(glm::vec2(100.0f, 250.0f), glm::vec2(100.0f, 100.0f), glm::vec4(0.0f, 255.0f, 0.0f, 255.0f));
		sb.PopClipRect();

		tr.Flush();

		SwapBuffers();
	}
}

Chciałbym żeby pierwszy kwadrat był przycięty o 50 jednostek z góry i rzeczywiście tak się dzieje,
następnie chciałbym żeby drugi kwadrat był przycięty z lewej strony, więc dodaje nowe polecenie rysowania, nowy clip rect i powinno działać...
No niekoniecznie :/

Na jeden i drugi kwadrat oddziałuje pierwszy clip rect glm::vec4(0.0f, 150.0f, 1280.0f, 720.0f). Prostym inputem z klawiatury zmieniając pozycję Y drugiego kwadratu sprawdziłem, to, że pierwszy clip rect też oddziałuje na drugi.

Dlaczego tylko pierwszy clip rect jest w działaniu?
W jaki sposób mogę to poprawić?