Skip to content

Commit

Permalink
- Add mesh optimization
Browse files Browse the repository at this point in the history
- Increase indices to UINT32
- Check if GPU supports base vertex
  • Loading branch information
edunad committed Sep 24, 2024
1 parent 1cb399a commit f438164
Show file tree
Hide file tree
Showing 22 changed files with 201 additions and 118 deletions.
1 change: 0 additions & 1 deletion .clang-tidy
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,3 @@ Checks: clang-diagnostic-*
-cppcoreguidelines-pro-type-union-access
WarningsAsErrors: "*"
HeaderFilterRegex: ""
AnalyzeTemporaryDtors: false
6 changes: 3 additions & 3 deletions RAWBOX - Dependencies.drawio
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<mxfile host="65bd71144e" scale="1" border="0" disableSvgWarning="true">
<diagram name="Page-1" id="9xXpQoKFAjOWmioz_WNq">
<mxGraphModel dx="1196" dy="659" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="583" background="none" math="0" shadow="0">
<mxGraphModel dx="2464" dy="912" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="583" background="none" math="0" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
Expand Down Expand Up @@ -122,7 +122,7 @@
<mxCell id="10" style="edgeStyle=none;rounded=0;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fillColor=#1ba1e2;strokeColor=#006EAF;sketch=1;curveFitting=1;jiggle=2;" parent="1" source="5" target="vDj8au7zf55BE4AIelzE-11" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="5" value="ASSIMP" style="whiteSpace=wrap;html=1;backgroundOutline=0;rounded=0;fillStyle=solid;sketch=1;curveFitting=1;jiggle=2;fillColor=#18141D;fontColor=#F0F0F0;strokeColor=#F0F0F0;" parent="1" vertex="1">
<mxCell id="5" value="GLTF" style="whiteSpace=wrap;html=1;backgroundOutline=0;rounded=0;fillStyle=solid;sketch=1;curveFitting=1;jiggle=2;fillColor=#18141D;fontColor=#F0F0F0;strokeColor=#F0F0F0;" parent="1" vertex="1">
<mxGeometry x="103" y="473" width="60" height="30" as="geometry"/>
</mxCell>
<mxCell id="11" style="edgeStyle=none;rounded=0;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fillColor=#1ba1e2;strokeColor=#006EAF;sketch=1;curveFitting=1;jiggle=2;" parent="1" source="7" target="vDj8au7zf55BE4AIelzE-11" edge="1">
Expand Down Expand Up @@ -225,7 +225,7 @@
<mxCell id="48" value="STEAMWORKS" style="rounded=0;whiteSpace=wrap;html=1;backgroundOutline=0;fillStyle=solid;shadow=1;sketch=1;curveFitting=1;jiggle=2;fillColor=#18141D;fontColor=#F0F0F0;strokeColor=#F0F0F0;" parent="1" vertex="1">
<mxGeometry x="60" y="80" width="120" height="29" as="geometry"/>
</mxCell>
<mxCell id="51" style="edgeStyle=none;sketch=1;hachureGap=4;jiggle=2;curveFitting=1;html=1;fontFamily=Architects Daughter;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DArchitects%2BDaughter;fontSize=16;rounded=0;fillColor=#1ba1e2;strokeColor=#006EAF;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" target="vDj8au7zf55BE4AIelzE-11">
<mxCell id="51" style="edgeStyle=none;sketch=1;hachureGap=4;jiggle=2;curveFitting=1;html=1;fontFamily=Architects Daughter;fontSource=https%3A%2F%2Ffonts.googleapis.com%2Fcss%3Ffamily%3DArchitects%2BDaughter;fontSize=16;rounded=0;fillColor=#1ba1e2;strokeColor=#006EAF;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" target="vDj8au7zf55BE4AIelzE-11" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="166" y="403.5981308411215" as="sourcePoint"/>
<mxPoint x="270" y="500" as="targetPoint"/>
Expand Down
Binary file modified RAWBOX - Dependencies.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
33 changes: 19 additions & 14 deletions README.md

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions rawrbox.gltf/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ CPMAddPackage(
if(fastgltf_ADDED)
set_lib_runtime_mt(fastgltf)
endif()

CPMAddPackage("gh:zeux/[email protected]")
# ----

# Grab source files
Expand All @@ -43,6 +45,7 @@ target_link_libraries(${output_target}
${RAWRBOX_EXTRA_LIBS}

fastgltf
meshoptimizer
)

set_lib_runtime_mt(${output_target})
Expand Down
11 changes: 8 additions & 3 deletions rawrbox.gltf/include/rawrbox/gltf/importer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ namespace rawrbox {
} // namespace Debug

namespace Optimizer {
const uint32_t SKELETON_ANIMATIONS = 1 << 30;
const uint32_t MESH = 1 << 30;
const uint32_t SKELETON_ANIMATIONS = 1 << 31;
} // namespace Optimizer

}; // namespace ModelLoadFlags
Expand Down Expand Up @@ -95,7 +96,7 @@ namespace rawrbox {
rawrbox::GLTFMesh* parent = nullptr;

std::vector<rawrbox::VertexNormBoneData> vertices = {};
std::vector<uint16_t> indices = {};
std::vector<uint32_t> indices = {};

rawrbox::Color color = rawrbox::Colors::White();
GLTFMesh(std::string _name) : name(std::move(_name)) {};
Expand Down Expand Up @@ -151,7 +152,7 @@ namespace rawrbox {
virtual void loadMeshes(const fastgltf::Asset& scene, const fastgltf::Node& node, rawrbox::GLTFMesh* parentMesh = nullptr);

virtual std::vector<rawrbox::VertexNormBoneData> extractVertex(const fastgltf::Asset& scene, const fastgltf::Primitive& primitive);
virtual std::vector<uint16_t> extractIndices(const fastgltf::Asset& scene, const fastgltf::Primitive& primitive);
virtual std::vector<uint32_t> extractIndices(const fastgltf::Asset& scene, const fastgltf::Primitive& primitive);
// ----------

// UTILS ---
Expand All @@ -177,6 +178,10 @@ namespace rawrbox {
}
// ------

// OPTIMIZATION ---
virtual void optimizeMesh(std::vector<rawrbox::VertexNormBoneData>& verts, std::vector<uint32_t>& indices);
virtual void simplifyMesh(std::vector<rawrbox::VertexNormBoneData>& verts, std::vector<uint32_t>& indices, float complexity_threshold = 0.9F);
// -----------
public:
std::filesystem::path filePath;
uint32_t loadFlags = 0;
Expand Down
4 changes: 2 additions & 2 deletions rawrbox.gltf/include/rawrbox/gltf/utils/model.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ namespace rawrbox {

mesh.baseVertex = 0;
mesh.baseIndex = 0;
mesh.totalVertex = static_cast<uint16_t>(mesh.vertices.size());
mesh.totalIndex = static_cast<uint16_t>(mesh.indices.size());
mesh.totalVertex = static_cast<uint32_t>(mesh.vertices.size());
mesh.totalIndex = static_cast<uint32_t>(mesh.indices.size());

// Bones
if (gltfMesh.skeleton != nullptr) {
Expand Down
85 changes: 73 additions & 12 deletions rawrbox.gltf/src/importer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <fastgltf/types.hpp>
#include <magic_enum.hpp>

#include <meshoptimizer.h>
#include <ozz/animation/offline/animation_builder.h>
#include <ozz/animation/offline/animation_optimizer.h>
#include <ozz/animation/offline/raw_track.h>
Expand Down Expand Up @@ -86,7 +87,9 @@ namespace rawrbox {
this->postLoadFixSceneNames(scene);
// ---------------

// TODO: PRINT METADATA
// OPTIMIZATION --

// ----------

// LOAD MATERIALS ---
if ((this->loadFlags & rawrbox::ModelLoadFlags::IMPORT_TEXTURES) > 0) {
Expand Down Expand Up @@ -188,9 +191,9 @@ namespace rawrbox {
} else if (gltfTexture.imageIndex.has_value()) {
imgIndex = {gltfTexture.imageIndex.value(), rawrbox::GLTFImageType::OTHER};
} else if (gltfTexture.webpImageIndex.has_value()) {
imgIndex = {gltfTexture.imageIndex.value(), rawrbox::GLTFImageType::WEBP};
imgIndex = {gltfTexture.webpImageIndex.value(), rawrbox::GLTFImageType::WEBP};
} else if (gltfTexture.ddsImageIndex.has_value()) {
// imgIndex = {gltfTexture.imageIndex.value(), rawrbox::GLTFImageType::DDS}; // TODO: SUPPORT DDS
// imgIndex = {gltfTexture.ddsImageIndex.value(), rawrbox::GLTFImageType::DDS}; // TODO: SUPPORT DDS
continue;
}

Expand Down Expand Up @@ -725,9 +728,21 @@ namespace rawrbox {
// ----------------

std::vector<rawrbox::VertexNormBoneData> verts = this->extractVertex(scene, primitive);
gltfMesh->vertices.insert(gltfMesh->vertices.end(), verts.begin(), verts.end());
std::vector<uint32_t> indices = this->extractIndices(scene, primitive);

if ((this->loadFlags & rawrbox::ModelLoadFlags::Optimizer::MESH) > 0) {
auto startVert = verts.size();
auto startInd = indices.size();

this->optimizeMesh(verts, indices);
this->simplifyMesh(verts, indices);

if (startVert != verts.size() || startInd != indices.size()) {
this->_logger->info("Optimized mesh '{}'\n\tVertices -> {} to {}\n\tIndices -> {} to {}", fmt::styled(gltfMesh->name, fmt::fg(fmt::color::cyan)), startVert, verts.size(), startInd, indices.size());
}
}

std::vector<uint16_t> indices = this->extractIndices(scene, primitive);
gltfMesh->vertices.insert(gltfMesh->vertices.end(), verts.begin(), verts.end());
gltfMesh->indices.insert(gltfMesh->indices.end(), indices.begin(), indices.end());
}
/// -------
Expand Down Expand Up @@ -832,17 +847,14 @@ namespace rawrbox {
return verts;
}

std::vector<uint16_t> GLTFImporter::extractIndices(const fastgltf::Asset& scene, const fastgltf::Primitive& primitive) {
auto indices = std::vector<uint16_t>();
std::vector<uint32_t> GLTFImporter::extractIndices(const fastgltf::Asset& scene, const fastgltf::Primitive& primitive) {
auto indices = std::vector<uint32_t>();

const auto& accessor = scene.accessors[primitive.indicesAccessor.value()];
indices.resize(accessor.count);

// INDICES ----
// TODO: SUPPORT UINT32 FOR INDICES
if (accessor.componentType == fastgltf::ComponentType::UnsignedByte || accessor.componentType == fastgltf::ComponentType::UnsignedShort) {
fastgltf::iterateAccessorWithIndex<uint16_t>(scene, accessor, [&](uint16_t indice, size_t idx) { indices[idx] = indice; });
}
fastgltf::iterateAccessorWithIndex<uint32_t>(scene, accessor, [&](uint32_t indice, size_t idx) { indices[idx] = indice; });
// -----------

return indices;
Expand Down Expand Up @@ -897,10 +909,59 @@ namespace rawrbox {
}
// ----------

// OPTIMIZATION ---
void GLTFImporter::optimizeMesh(std::vector<rawrbox::VertexNormBoneData>& verts, std::vector<uint32_t>& indices) {
size_t indiceSize = indices.size();
std::vector<uint32_t> remap(indiceSize);

// Calculate vertex map ---
size_t newVerticeCount = meshopt_generateVertexRemap(&remap[0], &indices[0], indiceSize, &verts[0], indiceSize, sizeof(rawrbox::VertexNormBoneData));
// ------

// Optimize index & vertex buffers ---
std::vector<uint32_t> resultIndices(indiceSize);
std::vector<rawrbox::VertexNormBoneData> resultVertices(newVerticeCount);

meshopt_remapIndexBuffer(&resultIndices[0], &indices[0], indiceSize, &remap[0]);
meshopt_remapVertexBuffer(&resultVertices[0], &verts[0], indiceSize, sizeof(rawrbox::VertexNormBoneData), &remap[0]);
// -------------

// Vertex cache
meshopt_optimizeVertexCache(&resultIndices[0], &resultIndices[0], indiceSize, newVerticeCount);

// Overdraw
meshopt_optimizeOverdraw(&resultIndices[0], &resultIndices[0], indiceSize, &resultVertices[0].position.x, newVerticeCount, sizeof(rawrbox::VertexNormBoneData), 1.05f);

// Vertex fetch
meshopt_optimizeVertexFetch(&resultVertices[0], &resultIndices[0], indiceSize, &resultVertices[0], newVerticeCount, sizeof(rawrbox::VertexNormBoneData));

verts.swap(resultVertices);
indices.swap(resultIndices);
}

void GLTFImporter::simplifyMesh(std::vector<rawrbox::VertexNormBoneData>& verts, std::vector<uint32_t>& indices, float complexity_threshold) {
const size_t index_count = indices.size();
const size_t vertex_count = verts.size();

const size_t target_index_count = index_count * complexity_threshold;
constexpr float target_error = 1e-2f;
constexpr unsigned int options = 0;

std::vector<uint32_t> lod_indices(index_count);
float lod_error = 0.0f;

lod_indices.resize(meshopt_simplify(lod_indices.data(), indices.data(), index_count,
reinterpret_cast<const float*>(verts.data()),
vertex_count, sizeof(rawrbox::VertexNormBoneData), target_index_count,
target_error, options, &lod_error));

indices.swap(lod_indices);
}

// -----------
// -------------

// PUBLIC -------

GLTFImporter::GLTFImporter(uint32_t loadFlags) : loadFlags(loadFlags) {}
GLTFImporter::~GLTFImporter() {
this->_logger.reset();
Expand Down
1 change: 1 addition & 0 deletions rawrbox.imgui/src/manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ namespace rawrbox {
ImGuiIO& IO = ImGui::GetIO();
IO.BackendRendererName = "RawrBox-IMGUI";
IO.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
IO.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset;

switch (renderer.getRenderType()) {
case Diligent::RENDER_DEVICE_TYPE_D3D12:
Expand Down
16 changes: 6 additions & 10 deletions rawrbox.render/include/rawrbox/render/models/base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ namespace rawrbox {
if (!shape.second->isActive() || shape.second->mesh == nullptr) continue;

auto& verts = shape.second->mesh->vertices;

auto& blendPos = shape.second->pos;
auto& blendNormals = shape.second->normals;

Expand Down Expand Up @@ -129,10 +128,10 @@ namespace rawrbox {
auto vertSize = static_cast<uint64_t>(this->_mesh->vertices.size());
auto indcSize = static_cast<uint64_t>(this->_mesh->indices.size());

auto empty = vertSize == 0 || indcSize == 0;
const bool empty = vertSize == 0 || indcSize == 0;

uint64_t sizeVB = sizeof(typename M::vertexBufferType) * vertSize;
uint64_t sizeIB = sizeof(uint16_t) * indcSize;
uint64_t sizeIB = sizeof(uint32_t) * indcSize;

bool resizable = this->_uploadType == rawrbox::UploadType::RESIZABLE_DYNAMIC;

Expand All @@ -142,7 +141,7 @@ namespace rawrbox {
if (resizeVertex) {
RAWRBOX_DESTROY(this->_vbh);

this->_mesh->vertices.reserve(vertSize + this->BUFFER_INCREASE_OFFSET);
this->_mesh->vertices.reserve(vertSize + RB_RENDER_BUFFER_INCREASE_OFFSET);
this->createVertexBuffer();

this->_logger->info("Resizing vertex buffer ({} -> {})", vertSize, this->_mesh->vertices.capacity());
Expand All @@ -151,7 +150,7 @@ namespace rawrbox {
if (resizeIndex) {
RAWRBOX_DESTROY(this->_ibh);

this->_mesh->indices.reserve(indcSize + this->BUFFER_INCREASE_OFFSET);
this->_mesh->indices.reserve(indcSize + RB_RENDER_BUFFER_INCREASE_OFFSET);
this->createIndexBuffer();

this->_logger->info("Resizing index buffer ({} -> {})", indcSize, this->_mesh->indices.capacity());
Expand All @@ -170,7 +169,7 @@ namespace rawrbox {
rawrbox::BarrierUtils::barrier(barriers);

if (!resizeVertex) context->UpdateBuffer(this->_vbh, 0, vertSize * sizeof(typename M::vertexBufferType), empty ? nullptr : this->_mesh->vertices.data(), Diligent::RESOURCE_STATE_TRANSITION_MODE_VERIFY);
if (!resizeIndex) context->UpdateBuffer(this->_ibh, 0, indcSize * sizeof(uint16_t), empty ? nullptr : this->_mesh->indices.data(), Diligent::RESOURCE_STATE_TRANSITION_MODE_VERIFY);
if (!resizeIndex) context->UpdateBuffer(this->_ibh, 0, indcSize * sizeof(uint32_t), empty ? nullptr : this->_mesh->indices.data(), Diligent::RESOURCE_STATE_TRANSITION_MODE_VERIFY);

barriers.clear();
if (!resizeVertex) barriers.emplace_back(this->_vbh, Diligent::RESOURCE_STATE_COPY_DEST, Diligent::RESOURCE_STATE_VERTEX_BUFFER, Diligent::STATE_TRANSITION_FLAG_UPDATE_STATE);
Expand All @@ -192,7 +191,7 @@ namespace rawrbox {
IndcBuffDesc.Name = "RawrBox::Buffer::Indices";
IndcBuffDesc.BindFlags = Diligent::BIND_INDEX_BUFFER;
IndcBuffDesc.Usage = this->isDynamic() ? Diligent::USAGE_DEFAULT : Diligent::USAGE_IMMUTABLE; // TODO: Diligent::USAGE_SPARSE;
IndcBuffDesc.Size = static_cast<uint32_t>(sizeof(uint16_t)) * indcSize;
IndcBuffDesc.Size = static_cast<uint32_t>(sizeof(uint32_t)) * indcSize;

Diligent::BufferData IBData;
IBData.pData = this->_mesh->indices.data();
Expand Down Expand Up @@ -227,9 +226,6 @@ namespace rawrbox {
}

public:
// To prevent the vertex / index buffer from resizing too often, increase this value to offset the scaling based on your model needs
uint64_t BUFFER_INCREASE_OFFSET = 256;

ModelBase(size_t vertices = 0, size_t indices = 0) {
this->_mesh = std::make_unique<rawrbox::Mesh<typename M::vertexBufferType>>(vertices, indices);
this->_material = std::make_unique<M>();
Expand Down
2 changes: 1 addition & 1 deletion rawrbox.render/include/rawrbox/render/models/instanced.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ namespace rawrbox {
// -----------

Diligent::DrawIndexedAttribs DrawAttrs;
DrawAttrs.IndexType = Diligent::VT_UINT16;
DrawAttrs.IndexType = Diligent::VT_UINT32;
DrawAttrs.FirstIndexLocation = this->_mesh->baseIndex;
DrawAttrs.BaseVertex = this->_mesh->baseVertex;
DrawAttrs.NumIndices = this->_mesh->totalIndex;
Expand Down
18 changes: 9 additions & 9 deletions rawrbox.render/include/rawrbox/render/models/mesh.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,13 @@ namespace rawrbox {
std::string name = "mesh";

// OFFSETS ---
uint16_t baseVertex = 0;
uint16_t baseIndex = 0;
uint16_t totalVertex = 0;
uint16_t totalIndex = 0;
uint32_t baseVertex = 0;
uint32_t baseIndex = 0;
uint32_t totalVertex = 0;
uint32_t totalIndex = 0;

std::vector<T> vertices = {};
std::vector<uint16_t> indices = {};
std::vector<uint32_t> indices = {};
// -------

// TEXTURES ---
Expand Down Expand Up @@ -158,7 +158,7 @@ namespace rawrbox {
[[nodiscard]] virtual bool isTransparent() const { return this->_transparent; }

[[nodiscard]] virtual const std::vector<T>& getVertices() const { return this->vertices; }
[[nodiscard]] virtual const std::vector<uint16_t>& getIndices() const { return this->indices; }
[[nodiscard]] virtual const std::vector<uint32_t>& getIndices() const { return this->indices; }

[[nodiscard]] virtual const rawrbox::BBOX& getBBOX() const { return this->bbox; }

Expand Down Expand Up @@ -278,11 +278,11 @@ namespace rawrbox {
}

virtual void merge(const rawrbox::Mesh<T>& other) {
std::transform(other.indices.begin(), other.indices.end(), std::back_inserter(this->indices), [this](const uint16_t& val) { return static_cast<uint16_t>(this->totalVertex + val); });
std::transform(other.indices.begin(), other.indices.end(), std::back_inserter(this->indices), [this](const uint32_t& val) { return this->totalVertex + val; });
this->vertices.insert(this->vertices.end(), other.vertices.begin(), other.vertices.end());

this->totalVertex = static_cast<uint16_t>(this->vertices.size());
this->totalIndex = static_cast<uint16_t>(this->indices.size());
this->totalVertex = static_cast<uint32_t>(this->vertices.size());
this->totalIndex = static_cast<uint32_t>(this->indices.size());

this->bbox.combine(other.bbox);
}
Expand Down
6 changes: 3 additions & 3 deletions rawrbox.render/include/rawrbox/render/models/model.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,8 @@ namespace rawrbox {
if (mesh == nullptr || mesh->empty()) continue;

// Fix start index ----
mesh->baseIndex = static_cast<uint16_t>(this->_mesh->indices.size());
mesh->baseVertex = static_cast<uint16_t>(this->_mesh->vertices.size());
mesh->baseIndex = static_cast<uint32_t>(this->_mesh->indices.size());
mesh->baseVertex = static_cast<uint32_t>(this->_mesh->vertices.size());
// --------------------

// Append vertices
Expand Down Expand Up @@ -483,7 +483,7 @@ namespace rawrbox {

// DRAW -------
Diligent::DrawIndexedAttribs DrawAttrs;
DrawAttrs.IndexType = Diligent::VT_UINT16;
DrawAttrs.IndexType = Diligent::VT_UINT32;
DrawAttrs.FirstIndexLocation = mesh->baseIndex;
DrawAttrs.BaseVertex = mesh->baseVertex;
DrawAttrs.NumIndices = mesh->totalIndex;
Expand Down
Loading

0 comments on commit f438164

Please sign in to comment.