Skip to content

Commit 7eb3d38

Browse files
committed
Aggressively merge meshes
1 parent b78dc2f commit 7eb3d38

File tree

6 files changed

+138
-69
lines changed

6 files changed

+138
-69
lines changed

include/renderer/Mesh.hpp

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ struct Vertex {
1111
glm::vec3 m_position;
1212
glm::vec3 m_normal;
1313
glm::vec2 m_tex_coords;
14+
15+
// first byte diffuse
16+
// second byte opacity
17+
uint32_t texture_indices;
1418
};
1519

1620
struct AABB {
@@ -20,25 +24,28 @@ struct AABB {
2024
AABB merge(AABB const&);
2125
};
2226

27+
struct IntermediateMesh {
28+
std::vector<Vertex> vertices;
29+
std::vector<unsigned int> indices;
30+
std::vector<Texture const*> textures;
31+
AABB aabb;
32+
33+
bool merge(IntermediateMesh const&);
34+
};
35+
2336
class Mesh {
2437
public:
25-
std::vector<Vertex> m_vertices;
26-
std::vector<unsigned int> m_indices;
27-
Texture const* m_texture_diffuse;
28-
Texture const* m_texture_opacity;
38+
std::vector<Texture const*> textures;
2939
AABB aabb;
3040

31-
Mesh(std::vector<Vertex> vertices,
32-
std::vector<unsigned int> indices,
33-
Texture const* texture_diffuse,
34-
Texture const* texture_opacity,
35-
AABB);
41+
Mesh(IntermediateMesh);
3642

3743
void draw() const;
3844
void draw(ViewingMode) const;
3945
[[nodiscard]] bool is_fully_loaded() const;
40-
void setup_mesh();
46+
void setup_mesh(std::vector<Vertex> const& vertices, std::vector<unsigned int> const& indices);
4147

4248
private:
4349
unsigned int m_vao{0}, m_vbo{0}, m_ebo{0};
50+
unsigned int m_indices_size;
4451
};

include/renderer/Shader.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ struct UniformLocations {
5454
int projection{-1};
5555

5656
// Fragment
57-
int texture_diffuse{-1};
57+
int textures[10]{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
5858
int texture_opacity{-1};
5959
int light_direction{-1};
6060
int light_color{-1};

src/core/ModelLoader.cpp

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
#include <glad/glad.h>
1010
#include <glm/gtc/quaternion.hpp>
1111
#include <iostream>
12-
#include <map>
1312
#include <vector>
1413

1514
glm::vec3 ai_to_glm_vec(aiVector3D vector)
@@ -145,7 +144,7 @@ Texture const* load_mask_texture(aiMaterial* mat, std::filesystem::path director
145144
}
146145
}
147146

148-
Mesh process_mesh(aiMesh* mesh, aiScene const* scene, std::filesystem::path directory)
147+
IntermediateMesh process_mesh(aiMesh* mesh, aiScene const* scene, std::filesystem::path directory)
149148
{
150149
std::vector<Vertex> vertices;
151150
std::vector<unsigned int> indices;
@@ -176,6 +175,9 @@ Mesh process_mesh(aiMesh* mesh, aiScene const* scene, std::filesystem::path dire
176175
vertex.m_tex_coords = {0.0f, 0.0f};
177176
}
178177

178+
// diffuse: 0; opacity: 1
179+
vertex.texture_indices = 0x00010000;
180+
179181
vertices.push_back(vertex);
180182

181183
// if you want to add more attributes do it here
@@ -191,25 +193,26 @@ Mesh process_mesh(aiMesh* mesh, aiScene const* scene, std::filesystem::path dire
191193
// assign materials if any
192194
auto material = scene->mMaterials[mesh->mMaterialIndex];
193195

196+
std::vector<Texture const*> textures;
197+
194198
auto texture_diffuse = load_material_texture(material, aiTextureType_DIFFUSE, directory);
195199
if (!texture_diffuse) {
196200
texture_diffuse = Project::get_current()->fallback_texture();
197201
}
202+
textures.push_back(texture_diffuse);
198203

199-
// TODO: Find mask texture
200-
// Each texture has a <texture name>.meta file that includes a guid
201-
// And each material has a list of linked textures that include a base and mask texture guid
202204
auto texture_opacity = load_mask_texture(material, directory);
203205
if (!texture_opacity) {
204206
texture_opacity = Project::get_current()->white_texture();
205207
}
208+
textures.push_back(texture_opacity);
206209

207210
auto aabb = AABB{
208211
.min = ai_to_glm_vec(mesh->mAABB.mMin),
209212
.max = ai_to_glm_vec(mesh->mAABB.mMax),
210213
};
211214

212-
return Mesh{vertices, indices, texture_diffuse, texture_opacity, aabb};
215+
return IntermediateMesh{vertices, indices, textures, aabb};
213216
}
214217

215218
Node process_node(aiNode* node, aiScene const* scene, std::filesystem::path directory, NodeLocation parent_location)
@@ -230,13 +233,13 @@ Node process_node(aiNode* node, aiScene const* scene, std::filesystem::path dire
230233
auto location = NodeLocation::file(parent_location.file_path, parent_location.node_path / name);
231234
auto new_node = Node::create(name, new_transform, location);
232235

233-
std::map<std::pair<Texture const*, Texture const*>, Mesh> merged_meshes;
236+
std::vector<IntermediateMesh> merged_meshes;
234237

235238
// This messy code transforms the vertices and the positions in such a way that the mesh vertices are built around the object center.
236239
// This ensures that the gizmos aren't diplayed somewhere far away.
237-
// It also merges meshes with identical textures to improve performance.
240+
// It also merges meshes to improve performance.
238241

239-
// 1. Load all meshes and compute the node's AABB
242+
// 1. Load and merge all meshes and compute the node's AABB
240243
std::optional<AABB> aabb;
241244
for (unsigned int i = 0; i < node->mNumMeshes; ++i) {
242245
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
@@ -247,16 +250,8 @@ Node process_node(aiNode* node, aiScene const* scene, std::filesystem::path dire
247250
aabb = aabb->merge(new_mesh.aabb);
248251
}
249252

250-
auto key = std::make_pair(new_mesh.m_texture_diffuse, new_mesh.m_texture_opacity);
251-
if (merged_meshes.contains(key)) {
252-
auto& merged_mesh = merged_meshes.at(key);
253-
auto start_index = merged_mesh.m_vertices.size();
254-
for (auto index : new_mesh.m_indices) {
255-
merged_mesh.m_indices.push_back(start_index + index);
256-
}
257-
merged_mesh.m_vertices.insert(merged_mesh.m_vertices.end(), new_mesh.m_vertices.begin(), new_mesh.m_vertices.end());
258-
} else {
259-
merged_meshes.emplace(key, std::move(new_mesh));
253+
if (merged_meshes.size() == 0 || !merged_meshes.back().merge(new_mesh)) {
254+
merged_meshes.push_back(new_mesh);
260255
}
261256
}
262257

@@ -271,14 +266,13 @@ Node process_node(aiNode* node, aiScene const* scene, std::filesystem::path dire
271266
}
272267

273268
// 3. Move vertices, setup mesh buffers and add the meshes to the node
274-
for (auto& [_, mesh] : merged_meshes) {
275-
for (auto& vertex : mesh.m_vertices) {
269+
for (auto& mesh : merged_meshes) {
270+
for (auto& vertex : mesh.vertices) {
276271
vertex.m_position -= center;
277272
}
278273
mesh.aabb.min -= center;
279274
mesh.aabb.max -= center;
280-
mesh.setup_mesh();
281-
new_node.meshes.push_back(std::move(mesh));
275+
new_node.meshes.push_back(mesh);
282276
}
283277

284278
// 4. Load and move the child nodes

src/renderer/Camera.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,8 +202,9 @@ void Camera::draw_outline(Framebuffer const& framebuffer, InstancedNode const& n
202202
Shader::albedo.set_uniform(Shader::albedo.uniform_locations.gamma, 1.0f);
203203
glActiveTexture(GL_TEXTURE0);
204204
glBindTexture(GL_TEXTURE_2D, project->white_texture()->id);
205-
Shader::albedo.set_uniform(Shader::albedo.uniform_locations.texture_diffuse, 0);
206-
Shader::albedo.set_uniform(Shader::albedo.uniform_locations.texture_opacity, 0);
205+
for (std::size_t i = 0; i < sizeof(Shader::albedo.uniform_locations.textures) / sizeof(Shader::albedo.uniform_locations.textures[0]); ++i) {
206+
Shader::albedo.set_uniform(Shader::albedo.uniform_locations.textures[i], 0);
207+
}
207208

208209
node.traverse([&](auto transform_matrix, auto const& node_data) {
209210
Shader::albedo.set_uniform(Shader::albedo.uniform_locations.model, transform_matrix);

src/renderer/Mesh.cpp

Lines changed: 73 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,85 @@
11
#include "renderer/Mesh.hpp"
22

33
#include "core/Project.hpp"
4+
#include <iostream>
5+
#include <map>
46

5-
Mesh::Mesh(std::vector<Vertex> vertices, std::vector<unsigned int> indices, Texture const* texture_diffuse, Texture const* texture_opacity, AABB aabb)
6-
: m_vertices(vertices)
7-
, m_indices(indices)
8-
, m_texture_diffuse(texture_diffuse)
9-
, m_texture_opacity(texture_opacity)
10-
, aabb(aabb)
11-
{ }
7+
bool IntermediateMesh::merge(IntermediateMesh const& other)
8+
{
9+
std::size_t new_textures_count = 0;
10+
for (auto other_texture : other.textures) {
11+
auto found_it = std::find(textures.begin(), textures.end(), other_texture);
12+
if (found_it == textures.end()) {
13+
++new_textures_count;
14+
}
15+
}
16+
17+
if (textures.size() + new_textures_count > 10) {
18+
return false;
19+
}
20+
21+
std::map<std::size_t, std::size_t> texture_mapping;
22+
for (std::size_t i = 0; auto other_texture : other.textures) {
23+
auto found_it = std::find(textures.begin(), textures.end(), other_texture);
24+
if (found_it == textures.end()) {
25+
texture_mapping[i] = textures.size();
26+
textures.push_back(other_texture);
27+
} else {
28+
texture_mapping[i] = found_it - textures.begin();
29+
}
30+
++i;
31+
}
32+
33+
for (auto vertex : other.vertices) {
34+
auto diffuse_index = texture_mapping[vertex.texture_indices >> 24];
35+
auto opacity_index = texture_mapping[(vertex.texture_indices >> 16) & 0xff];
36+
vertex.texture_indices = (diffuse_index << 24) | (opacity_index << 16);
37+
vertices.push_back(vertex);
38+
}
39+
40+
auto index_offset = indices.size();
41+
for (auto index : other.indices) {
42+
indices.push_back(index + index_offset);
43+
}
44+
45+
aabb = aabb.merge(other.aabb);
46+
return true;
47+
}
48+
49+
Mesh::Mesh(IntermediateMesh mesh)
50+
{
51+
m_indices_size = mesh.indices.size();
52+
textures = mesh.textures;
53+
54+
setup_mesh(mesh.vertices, mesh.indices);
55+
}
1256

1357
void Mesh::draw() const
1458
{
1559
glBindVertexArray(m_vao);
16-
glDrawElements(GL_TRIANGLES, m_indices.size(), GL_UNSIGNED_INT, nullptr);
60+
glDrawElements(GL_TRIANGLES, m_indices_size, GL_UNSIGNED_INT, nullptr);
1761
}
1862

1963
void Mesh::draw(ViewingMode mode) const
2064
{
2165
auto const& shader = Shader::get_shader_for_mode(mode);
22-
auto diffuse_texture_id = mode == ViewingMode::SOLID ? Project::get_current()->fallback_texture()->id : m_texture_diffuse->id;
2366

24-
// set diffuse texture
25-
glActiveTexture(GL_TEXTURE0);
26-
shader.set_uniform(shader.uniform_locations.texture_diffuse, 0);
27-
glBindTexture(GL_TEXTURE_2D, diffuse_texture_id);
67+
for (std::size_t i = 0; auto const& texture : textures) {
68+
auto id = mode == ViewingMode::SOLID ? Project::get_current()->fallback_texture()->id : texture->id;
69+
70+
glActiveTexture(GL_TEXTURE0 + i);
71+
glBindTexture(GL_TEXTURE_2D, id);
72+
shader.set_uniform(shader.uniform_locations.textures[i], static_cast<int>(i));
2873

29-
// set opacity texture
30-
glActiveTexture(GL_TEXTURE1);
31-
shader.set_uniform(shader.uniform_locations.texture_opacity, 1);
32-
glBindTexture(GL_TEXTURE_2D, m_texture_opacity->id);
74+
++i;
75+
}
3376

3477
// set active
3578
glBindVertexArray(m_vao);
36-
glDrawElements(GL_TRIANGLES, static_cast<unsigned int>(m_indices.size()), GL_UNSIGNED_INT, nullptr);
79+
glDrawElements(GL_TRIANGLES, static_cast<unsigned int>(m_indices_size), GL_UNSIGNED_INT, nullptr);
3780
}
3881

39-
void Mesh::setup_mesh()
82+
void Mesh::setup_mesh(std::vector<Vertex> const& vertices, std::vector<unsigned int> const& indices)
4083
{
4184
if (m_vao != 0) {
4285
return;
@@ -48,10 +91,10 @@ void Mesh::setup_mesh()
4891

4992
glBindVertexArray(m_vao);
5093
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
51-
glBufferData(GL_ARRAY_BUFFER, m_vertices.size() * sizeof(Vertex), &m_vertices[0], GL_STATIC_DRAW);
94+
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW);
5295

5396
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ebo);
54-
glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_indices.size() * sizeof(unsigned int), &m_indices[0], GL_STATIC_DRAW);
97+
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);
5598

5699
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
57100
glEnableVertexAttribArray(0);
@@ -61,11 +104,19 @@ void Mesh::setup_mesh()
61104
// vertex texture coords
62105
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, m_tex_coords));
63106
glEnableVertexAttribArray(2);
107+
// texture index
108+
glVertexAttribIPointer(3, 1, GL_UNSIGNED_INT, sizeof(Vertex), (void*)offsetof(Vertex, texture_indices));
109+
glEnableVertexAttribArray(3);
64110
}
65111

66112
bool Mesh::is_fully_loaded() const
67113
{
68-
return m_texture_diffuse->is_loaded;
114+
for (auto const& texture : textures) {
115+
if (!texture->is_loaded) {
116+
return false;
117+
}
118+
}
119+
return true;
69120
}
70121

71122
AABB AABB::merge(AABB const& other)

0 commit comments

Comments
 (0)