Skip to content

Commit

Permalink
Add: GenerateMeshIndices option
Browse files Browse the repository at this point in the history
This also adds a default material into the gl_viewer example for meshes without a material.
  • Loading branch information
spnda committed Oct 27, 2023
1 parent 8c5f198 commit 20e4afd
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 3 deletions.
15 changes: 12 additions & 3 deletions examples/gl_viewer/gl_viewer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,8 @@ bool loadGltf(Viewer* viewer, std::string_view cPath) {
fastgltf::Options::AllowDouble |
fastgltf::Options::LoadGLBBuffers |
fastgltf::Options::LoadExternalBuffers |
fastgltf::Options::LoadExternalImages;
fastgltf::Options::LoadExternalImages |
fastgltf::Options::GenerateMeshIndices;

fastgltf::GltfDataBuffer data;
data.loadFromFile(path);
Expand Down Expand Up @@ -372,15 +373,17 @@ bool loadMesh(Viewer* viewer, fastgltf::Mesh& mesh) {
primitive.primitiveType = fastgltf::to_underlying(it->type);
primitive.vertexArray = vao;
if (it->materialIndex.has_value()) {
primitive.materialUniformsIndex = it->materialIndex.value();
primitive.materialUniformsIndex = it->materialIndex.value() + 1; // Adjust for default material
auto& material = viewer->asset.materials[it->materialIndex.value()];
if (material.pbrData.baseColorTexture.has_value()) {
auto& texture = viewer->asset.textures[material.pbrData.baseColorTexture->textureIndex];
if (!texture.imageIndex.has_value())
return false;
primitive.albedoTexture = viewer->textures[texture.imageIndex.value()].texture;
}
}
} else {
primitive.materialUniformsIndex = 0;
}

{
// Position
Expand Down Expand Up @@ -648,6 +651,12 @@ int main(int argc, char* argv[]) {
return -1;
}

// Add a default material
auto& defaultMaterial = viewer.materials.emplace_back();
defaultMaterial.baseColorFactor = glm::vec4(1.0f);
defaultMaterial.alphaCutoff = 0.0f;
defaultMaterial.flags = 0;

// We load images first.
auto& asset = viewer.asset;
for (auto& image : asset.images) {
Expand Down
9 changes: 9 additions & 0 deletions include/fastgltf/parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,13 @@ namespace fastgltf {
* to LoadExternalBuffers.
*/
LoadExternalImages = 1 << 7,

/**
* Lets fastgltf generate indices for all mesh primitives without indices. This currently
* does not de-duplicate the vertices. This is entirely for compatibility and simplifying the
* loading process.
*/
GenerateMeshIndices = 1 << 8,
};
// clang-format on

Expand Down Expand Up @@ -652,6 +659,8 @@ namespace fastgltf {
[[nodiscard]] auto decodeDataUri(URIView& uri) const noexcept -> Expected<DataSource>;
[[nodiscard]] auto loadFileFromUri(URIView& uri) const noexcept -> Expected<DataSource>;

Error generateMeshIndices(Asset& asset) const;

Error parseAccessors(simdjson::dom::array& array, Asset& asset);
Error parseAnimations(simdjson::dom::array& array, Asset& asset);
Error parseBuffers(simdjson::dom::array& array, Asset& asset);
Expand Down
49 changes: 49 additions & 0 deletions src/fastgltf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -722,6 +722,51 @@ fg::MimeType fg::Parser::getMimeTypeFromString(std::string_view mime) {
}
}

fg::Error fg::Parser::generateMeshIndices(fastgltf::Asset& asset) const {
for (auto& mesh : asset.meshes) {
for (auto& primitive : mesh.primitives) {
if (primitive.indicesAccessor.has_value())
continue;

auto* positionAttribute = primitive.findAttribute("POSITION");
if (positionAttribute == primitive.attributes.end()) {
return Error::InvalidGltf;
}
auto& positionAccessor = asset.accessors[positionAttribute->second];

sources::Vector generatedIndices;
generatedIndices.bytes.resize(positionAccessor.count * getElementByteSize(positionAccessor.type, positionAccessor.componentType));
fastgltf::span<std::uint32_t> indices { reinterpret_cast<std::uint32_t*>(generatedIndices.bytes.data()),
generatedIndices.bytes.size() / sizeof(std::uint32_t) };
for (std::size_t i = 0; i < positionAccessor.count; ++i) {
indices[i] = i;
}

auto bufferIdx = asset.buffers.size();

auto bufferViewIdx = asset.bufferViews.size();
auto& bufferView = asset.bufferViews.emplace_back();
bufferView.byteLength = generatedIndices.bytes.size();
bufferView.bufferIndex = bufferIdx;
bufferView.byteOffset = 0;

auto accessorIdx = asset.accessors.size();
auto& accessor = asset.accessors.emplace_back();
accessor.byteOffset = 0;
accessor.count = positionAccessor.count;
accessor.type = AccessorType::Scalar;
accessor.componentType = ComponentType::UnsignedInt;
accessor.normalized = false;
accessor.bufferViewIndex = bufferViewIdx;

auto& buffer = asset.buffers.emplace_back();
buffer.byteLength = generatedIndices.bytes.size();
buffer.data = std::move(generatedIndices);
primitive.indicesAccessor = accessorIdx;
}
}
}

fg::Error fg::validate(const fastgltf::Asset& asset) {
auto isExtensionUsed = [&used = asset.extensionsUsed](std::string_view extension) {
for (const auto& extensionUsed : used) {
Expand Down Expand Up @@ -1155,6 +1200,10 @@ fg::Expected<fg::Asset> fg::Parser::parse(simdjson::dom::object root, Category c

asset.availableCategories = readCategories;

if (hasBit(options, Options::GenerateMeshIndices)) {
generateMeshIndices(asset);
}

return Expected(std::move(asset));
}

Expand Down

0 comments on commit 20e4afd

Please sign in to comment.