Dlaczego przy małej rozdzielczości ścianki kwadratu znikają i dlaczego kwadrat zmienia kształt przy zmienianiu rozdzielczości?

0

Witam, ostatnio zaciekawiłem się klasą renderowania 2d, którą oferuje imgui. Postanowiłem na bardzo podobnej zasadzie zrobić to w swojej aplikacji.

class TestRenderer
{
public:
	TestRenderer();
	~TestRenderer();

	void Create();

	void DrawRect(const Rect& rect, GLuint color, float thickness);

	void Present();

private:
	void MapBuffer(int numVertices, int numElements);

	void AddVertexData(GLuint index, const Vector2& position, GLuint color);
	void AddElementData(GLuint index, GLuint value);

	void AddRectElements();

	void CreatePolygon(const Vector2* vertices, const GLuint verticesCount, GLuint color, float thickness);

private:
	GLuint vao = 0,  // vertex array
		   vbo = 0,  // vertex buffer       
		   ebo = 0,  // index buffer
           currentVertexIndex = 0,
           * mappedElement = nullptr;

	Vertex* mappedVertex = nullptr;

	std::vector<Vertex> vertexBuffer;  // vertex data
	std::vector<GLuint> elementBuffer; // index data

	std::vector<Vector2> vertices; // vertices positions
};
void TestRenderer::Create()
{
        glGenBuffers(1, &vbo);
        glGenBuffers(1, &ebo);
     
        glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
}

void TestRenderer::Present()
{
	Mat4 projection = Mat4(1.0f);
	projection = glm::ortho(0.0f, 1280.0f, 720.0f, 0.0f);
	shader->UseProgram();
	shader->UniformMatrix4fv("projection", projection);

	GLuint elemCount = elementBuffer.size();

	vao = vao->Create();
	vao->BindVertexArray();

	glBindBuffers(GL_ARRAY_BUFFER, vbo);
	glEnableVertexAttribArray(0);
	glVertexAttribPointer(0, 2, GL_FLOAT, false, sizeof(Vertex), (const void*)offsetof(Vertex, position));

	glEnableVertexAttribArray(1);
	glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, true, sizeof(Vertex), (const void*)offsetof(Vertex, color));

	glBufferData(GL_ARRAY_BUFFER, vertexBuffer.size()  * sizeof(Vertex), vertexBuffer.data(), GL_DYNAMIC_DRAW);

	glBindBuffers(GL_ELEMENT_ARRAY_BUFFER, ebo);
	glBufferData(GL_ARRAY_BUFFER, elementBuffer.size()  * sizeof(GLuint), elementBuffer.data(), GL_DYNAMIC_DRAW);

	vertexBuffer.clear();
	elementBuffer.clear();

	const unsigned short* elementBufferOffset = 0;

	glDrawElements(GL_TRIANGLES, elemCount, GL_UNSIGNED_INT,  elementBufferOffset);

	elementBufferOffset += elemCount;

	glDeleteVertexArrays(1, &vao);
}

void TestRenderer::CreatePolygon(const Vector2* vertices, const GLuint verticesCount, GLuint color, float thickness)
{
	if (verticesCount < 2) {
		return;
	}

	// Do stworzenia na przykład niewypełnionego kwadrata potrzebujemy 4 wypełnionych prostokątów 
        // Więc, niewypełniony kwadrat jest zbudowany z 4 prostokątów, a każdy z nich zawiera 4 wierzchołki ( *4) i 6 indeksów ( * 6)
	MapBuffer(verticesCount * 4, verticesCount * 6);

	for (GLuint i = 0; i < verticesCount; ++i)
	{
		const int j = (i + 1) == verticesCount ? 0 : i + 1;

		const Vector2& position1 = vertices[i];
		const Vector2& position2 = vertices[j];

		Vector2 difference = position2 - position1;

		difference *= difference.Magnitude() > 0 ? 1.0f / difference.Magnitude() : 1.0f;

		const float dx = difference.x * (thickness * 0.5f);
		const float dy = difference.y * (thickness * 0.5f);

		AddVertexData(0, Vector2(position1.x + dy, position1.y - dx), color);
		AddVertexData(1, Vector2(position2.x + dy, position2.y - dx), color);
		AddVertexData(2, Vector2(position2.x - dy, position2.y + dx), color);
		AddVertexData(3, Vector2(position1.x - dy, position1.y + dx), color);
		
		AddRectElements();

		mappedVertex += 4;
		currentVertexIndex += 4;
	}

	this->vertices.clear();
}

void TestRenderer::AddVertexData(GLuint index, const Vector2& position, GLuint color)
{
	mappedVertex[index].position = position;
	mappedVertex[index].color = color;
}

void TestRenderer::AddRectElements()
{
	AddElementData(0, currentVertexIndex);
	AddElementData(1, currentVertexIndex + 1);
	AddElementData(2, currentVertexIndex + 2);
	AddElementData(3, currentVertexIndex + 2);
	AddElementData(4, currentVertexIndex + 3);
	AddElementData(5, currentVertexIndex);

	mappedElement += 6;
}

void TestRenderer::AddElementData(GLuint index, GLuint value)
{
	mappedElement[index] = value;
}

void TestRenderer::MapBuffer(int numVertices, int numElements)
{
	currentVertexIndex = vertexBuffer.size();

	// Map vertex buffer
	int oldVertexSize = vertexBuffer.size();
	vertexBuffer.resize(oldVertexSize + numVertices);
	mappedVertex = vertexBuffer.data() + oldVertexSize;

	// Map element buffer
	int oldIndexSize = elementBuffer.size();
	elementBuffer.resize(oldIndexSize + numElements);
	mappedElement = elementBuffer.data() + oldIndexSize;
}

void TestRenderer::DrawRect(const Rect& rect, GLuint color, float thickness)
{
	// Add vertices
        Vector2 position = {rect.x, rect.y};
        Vector2 size = {rect.w, rect.h};

	vertices.push_back(position);
	vertices.push_back(Vector2(size.x, position.y));
	vertices.push_back(size);
	vertices.push_back(Vector2(position.x, size.y));
	// Create rect
	CreatePolygon(vertices.data(), vertices.size(), color, thickness);
}
#version 330 core

layout(location = 0) in vec3 a_position;
layout(location = 1) in vec4 a_color;

out vec4 v_color;

uniform mat4 projection;

void main()
{
	gl_Position = projection* vec4(a_position, 1.0);

	v_color = a_color;
}

#version 330 core

layout (location = 0) out vec4 color;

in vec4 v_color;

void main()
{
	color = v_color;
}
void main()
{
	//Stwórz okno (1280x720), zainicjuj glew, dodaj shadery
	TestRenderer tr;
	tr.Create();
	while(running)
	{
		ProcesEvent();

		//wyczyść kolor buffer bit

		tr.DrawRect(Rect(100.0f, 100.0f, 50.0f, 50.0f, 0xff0080ff, 1.0f);
		tr.Present();
	}
}

I o ile przy HD wszystko ładnie pięknie, to jak zmieniam szerokość i wysokość to kwadrat zmienia się razem z tym na na przykład prostokąt.

Myślałem, że imgui stosuje jakiegoś typu skalowanie, ale nie mogłem tego znaleźć.

Przy małym thickness niektóre boki kwadratu znikają i pokazują się dopiero jak zwiększę rozdzielczość.

Przy za małej rozdzielczości niektóre boki znikają.

W imgui cały czas wszystko jest na swoim miejscu.

Dlaczego tak się dzieje?

W jaki sposób mogę to zmienić, naprawić?

4

Dawno nie robiłem w OpenGL, nie orientuję się w GLM, ale sądzę, że powinieneś zainteresować się wywołaniem ortho:
projection = glm::ortho(0.0f, 1280.0f, 720.0f, 0.0f);
Twoja aplikacja cały czas renderuje wierzchołki na przestrzeni jaką określa ortho.
Więc jak zmienią się proporcje okna, to przestrzeń renderowania się rozciąga aby zająć cały obszar okna.

Najlepiej by było, żebyś wyłączył możliwość zmiany rozmiaru okna.

Jeśli jednak tego koniecznie potrzebujesz, to powinieneś po każdej zmianie wielkości okna, dostosowywać wartości ortho do nowych wymiarów. Np. jako szerokość ortho podając iloczyn wysokości ortho i nowych proporcji okna.

1

Masz rację! Dzięki wielkie!

1 użytkowników online, w tym zalogowanych: 0, gości: 1