From a3c9115d1e01059b5535e973f1d603e7715ee1ff Mon Sep 17 00:00:00 2001 From: Haroon Qureshi Date: Tue, 7 Apr 2026 06:40:51 -0700 Subject: [PATCH] Use MeshData struct for creating Meshes. Consolidate all Vertex and Index buffer creation inside the Mesh class. Users now set data pointers in the MeshData from which the Mesh class will create the filament buffers. PiperOrigin-RevId: 895871213 Change-Id: Ie086fcb5c31adf90e54cba168b03501e21720726 --- .../filament/filament/buffer_util.cc | 117 +-- .../filament/filament/buffer_util.h | 123 --- .../filament/filament/builtins.cc | 819 +++++++----------- .../filament/filament/geom_util.cc | 95 +- .../filament/filament/gui_view.cc | 43 +- .../filament/filament/model_objects.cc | 30 +- .../filament/filament/model_util.cc | 358 +++----- .../filament/filament/model_util.h | 19 +- .../filament/filament/renderables.cc | 4 +- .../filament/filament/vertex_util.h | 54 -- 10 files changed, 579 insertions(+), 1083 deletions(-) diff --git a/src/experimental/filament/filament/buffer_util.cc b/src/experimental/filament/filament/buffer_util.cc index 17f62091..a1ac791a 100644 --- a/src/experimental/filament/filament/buffer_util.cc +++ b/src/experimental/filament/filament/buffer_util.cc @@ -25,7 +25,6 @@ #include #include #include -#include "third_party/filament/libs/filabridge/include/filament/MaterialEnums.h" #include #include #include @@ -89,6 +88,17 @@ int VertexAttributeTypeSize(const VertexAttribute& attrib) { } } +// Fills an index buffer with a basic incrementing sequence. +template +int FillSequence(std::byte* buffer, std::size_t num_bytes) { + const T num = num_bytes / sizeof(T); + T* ptr = reinterpret_cast(buffer); + for (T i = 0; i < num; ++i) { + ptr[i] = i; + } + return num; +} + // Initializes the MeshData to default values. void DefaultMeshData(MeshData* data) { std::memset(data, 0, sizeof(MeshData)); @@ -140,11 +150,7 @@ void Mesh::BuildVertexBuffer(const MeshData& data) { const VertexAttribute* positions = nullptr; const VertexAttribute* normals = nullptr; const VertexAttribute* tangents = nullptr; - - // Calculate the stride of the vertex buffer. - int stride = 0; for (int i = 0; i < data.nattributes; ++i) { - stride += VertexAttributeTypeSize(data.attributes[i]); if (data.attributes[i].usage == mjVERTEX_ATTRIBUTE_POSITION) { positions = &data.attributes[i]; } else if (data.attributes[i].usage == mjVERTEX_ATTRIBUTE_NORMAL) { @@ -153,7 +159,6 @@ void Mesh::BuildVertexBuffer(const MeshData& data) { tangents = &data.attributes[i]; } } - if (!positions) { mju_error("MeshData has no positions."); } @@ -171,47 +176,66 @@ void Mesh::BuildVertexBuffer(const MeshData& data) { // Build the vertex buffer. filament::VertexBuffer::Builder vb_builder; - vb_builder.bufferCount(data.interleaved ? 1 : data.nattributes); vb_builder.vertexCount(data.nvertices); - int offset = 0; - for (int i = 0; i < data.nattributes; ++i) { - const VertexAttribute& attrib = data.attributes[i]; - const filament::VertexAttribute usage = GetUsage(attrib); - const filament::VertexBuffer::AttributeType type = GetType(attrib); - if (data.interleaved) { - vb_builder.attribute(usage, 0, type, offset, stride); - } else { - vb_builder.attribute(usage, i, type); - } - if (usage == filament::VertexAttribute::COLOR) { - vb_builder.normalized(usage); - } - offset += VertexAttributeTypeSize(attrib); - } - vertex_buffer_ = vb_builder.build(*engine_); - if (data.interleaved) { - const VertexAttribute& attrib = data.attributes[0]; - const size_t nbytes = data.nvertices * stride; - filament::backend::BufferDescriptor desc(attrib.bytes, nbytes, callback, - this); - vertex_buffer_->setBufferAt(*engine_, 0, std::move(desc)); - } else { + // For an interleaved vertex buffer, we will create a single buffer which + // contains the data in the order specified by the attributes array, + // starting from the first attribute's payload. + vb_builder.bufferCount(1); + int total_vertex_size = 0; + for (int i = 0; i < data.nattributes; ++i) { + total_vertex_size += VertexAttributeTypeSize(data.attributes[i]); + } + const void* bytes = data.attributes[0].bytes; + const size_t nbytes = data.nvertices * total_vertex_size; + + // We assume the buffer is tightly packed with no padding between + // attributes. As such, the stride is equal to the total vertex size and + // each offset is the sum of the sizes of the preceding attributes. + int offset = 0; for (int i = 0; i < data.nattributes; ++i) { const VertexAttribute& attrib = data.attributes[i]; - const size_t nbytes = data.nvertices * VertexAttributeTypeSize(attrib); - if (attrib.usage == mjVERTEX_ATTRIBUTE_NORMAL) { - const float4* orientations = - BuildOrientationsFromNormals(data.nvertices, attrib); - filament::backend::BufferDescriptor desc(orientations, nbytes, callback, - this); - vertex_buffer_->setBufferAt(*engine_, i, std::move(desc)); - } else { - filament::backend::BufferDescriptor desc(attrib.bytes, nbytes, callback, - this); - vertex_buffer_->setBufferAt(*engine_, i, std::move(desc)); + const filament::VertexAttribute usage = GetUsage(attrib); + filament::VertexBuffer::AttributeType type = GetType(attrib); + vb_builder.attribute(usage, 0, type, offset, total_vertex_size); + if (usage == filament::VertexAttribute::COLOR) { + vb_builder.normalized(usage); } + offset += VertexAttributeTypeSize(attrib); + } + vertex_buffer_ = vb_builder.build(*engine_); + vertex_buffer_->setBufferAt(*engine_, 0, {bytes, nbytes, callback, this}); + } else { + // For a non-interleaved vertex buffer, we assign a separate buffer to each + // attribute. + vb_builder.bufferCount(data.nattributes); + for (int i = 0; i < data.nattributes; ++i) { + const VertexAttribute& attrib = data.attributes[i]; + const filament::VertexAttribute usage = GetUsage(attrib); + filament::VertexBuffer::AttributeType type = GetType(attrib); + if (attrib.usage == mjVERTEX_ATTRIBUTE_NORMAL) { + // We will replace normals with orientations. + type = filament::VertexBuffer::AttributeType::FLOAT4; + } + vb_builder.attribute(usage, i, type); + if (usage == filament::VertexAttribute::COLOR) { + vb_builder.normalized(usage); + } + } + vertex_buffer_ = vb_builder.build(*engine_); + + // Assign the individual data buffers. + for (int i = 0; i < data.nattributes; ++i) { + const VertexAttribute& attrib = data.attributes[i]; + const void* bytes = attrib.bytes; + size_t nbytes = data.nvertices * VertexAttributeTypeSize(attrib); + if (attrib.usage == mjVERTEX_ATTRIBUTE_NORMAL) { + // Replace normals with orientations. + nbytes = data.nvertices * sizeof(float4); + bytes = BuildOrientationsFromNormals(data.nvertices, attrib); + } + vertex_buffer_->setBufferAt(*engine_, i, {bytes, nbytes, callback, this}); } } } @@ -318,15 +342,4 @@ bool Mesh::HasBounds() const { filament::Box Mesh::GetBounds() const { return bounds_.value(); } - -filament::backend::BufferDescriptor CreateBufferDescriptor( - std::size_t num_bytes, const FillBufferFn& fill) { - std::byte* bytes = new std::byte[num_bytes]; - fill(bytes, num_bytes); - const auto callback = [](void* buffer, size_t size, void* user) { - auto* ptr = reinterpret_cast(user); - delete[] ptr; - }; - return filament::backend::BufferDescriptor(bytes, num_bytes, callback, bytes); -} } // namespace mujoco diff --git a/src/experimental/filament/filament/buffer_util.h b/src/experimental/filament/filament/buffer_util.h index d72afedb..4bc6dd70 100644 --- a/src/experimental/filament/filament/buffer_util.h +++ b/src/experimental/filament/filament/buffer_util.h @@ -16,14 +16,11 @@ #define MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_BUFFER_UTIL_H_ #include -#include #include #include #include -#include #include -#include #include #include #include @@ -139,18 +136,6 @@ class Mesh { // Creates a Mesh from the given MeshData. Mesh(filament::Engine* engine, const MeshData& data); - // Create a Mesh directly from filament objects. Internal use only. - Mesh(filament::Engine* engine, filament::IndexBuffer* index_buffer, - filament::VertexBuffer* vertex_buffer, - std::optional bounds = std::nullopt, - filament::RenderableManager::PrimitiveType type = - filament::RenderableManager::PrimitiveType::TRIANGLES) - : engine_(engine), - index_buffer_(index_buffer), - vertex_buffer_(vertex_buffer), - type_(type), - bounds_(bounds) {} - ~Mesh(); // Returns the filament IndexBuffer for the mesh. @@ -192,114 +177,6 @@ class Mesh { using MeshPtr = std::unique_ptr; -// Function that fills in the given buffer with actual data. -using FillBufferFn = std::function; - -// Creates and populates a BufferDescriptor (for vertex and index buffers). -filament::backend::BufferDescriptor CreateBufferDescriptor( - std::size_t num_bytes, const FillBufferFn& fill); - -// Creates a filament::VertexBuffer based on the VertexType. The fill function -// will be used to populate the buffer. -template -filament::VertexBuffer* CreateVertexBuffer(filament::Engine* engine, - std::size_t num_vertices, - const FillBufferFn& fill) { - int vertex_size = 0; - if constexpr (VertexType::kHasPosition) { - vertex_size += sizeof(VertexType::position); - } - if constexpr (VertexType::kHasPosition2d) { - vertex_size += sizeof(VertexType::position); - } - if constexpr (VertexType::kHasOrientation) { - vertex_size += sizeof(VertexType::orientation); - } - if constexpr (VertexType::kHasUv) { - vertex_size += sizeof(VertexType::uv); - } - if constexpr (VertexType::kHasColor) { - vertex_size += sizeof(VertexType::color); - } - - auto builder = filament::VertexBuffer::Builder(); - builder.bufferCount(1); - builder.vertexCount(num_vertices); - - int offset = 0; - if constexpr (VertexType::kHasPosition) { - builder.attribute(filament::VertexAttribute::POSITION, 0, - filament::VertexBuffer::AttributeType::FLOAT3, offset, - vertex_size); - offset += sizeof(VertexType::position); - } - if constexpr (VertexType::kHasPosition2d) { - builder.attribute(filament::VertexAttribute::POSITION, 0, - filament::VertexBuffer::AttributeType::FLOAT2, offset, - vertex_size); - offset += sizeof(VertexType::position); - } - if constexpr (VertexType::kHasOrientation) { - builder.attribute(filament::VertexAttribute::TANGENTS, 0, - filament::VertexBuffer::AttributeType::FLOAT4, offset, - vertex_size); - offset += sizeof(VertexType::orientation); - } - if constexpr (VertexType::kHasUv) { - builder.attribute(filament::VertexAttribute::UV0, 0, - filament::VertexBuffer::AttributeType::FLOAT2, offset, - vertex_size); - offset += sizeof(VertexType::uv); - } - if constexpr (VertexType::kHasColor) { - builder.attribute(filament::VertexAttribute::COLOR, 0, - filament::VertexBuffer::AttributeType::UBYTE4, offset, - vertex_size); - builder.normalized(filament::VertexAttribute::COLOR); - offset += sizeof(VertexType::color); - } - - auto vb = builder.build(*engine); - const std::size_t buffer_size = num_vertices * vertex_size; - vb->setBufferAt(*engine, 0, CreateBufferDescriptor(buffer_size, fill)); - return vb; -} - -// Creates a filament::IndexBuffer. The IndexType should be either uin16_t or -// uint32_t. The fill function will be used to populate the buffer. -template -filament::IndexBuffer* CreateIndexBuffer(filament::Engine* engine, - std::size_t num_indices, - const FillBufferFn& fill) { - static_assert(std::is_same::value || - std::is_same::value); - - constexpr auto type = std::is_same::value - ? filament::IndexBuffer::IndexType::USHORT - : filament::IndexBuffer::IndexType::UINT; - - auto builder = filament::IndexBuffer::Builder(); - builder.bufferType(type); - builder.indexCount(num_indices); - - auto ib = builder.build(*engine); - - const std::size_t buffer_size = num_indices * sizeof(IndexType); - ib->setBuffer(*engine, CreateBufferDescriptor(buffer_size, fill)); - return ib; -} - -// Fills an index buffer with a basic incrementing sequence. -template -int FillSequence(std::byte* buffer, std::size_t num_bytes) { - const T num = num_bytes / sizeof(T); - T* ptr = reinterpret_cast(buffer); - for (T i = 0; i < num; ++i) { - ptr[i] = i; - } - return num; -} - } // namespace mujoco #endif // MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_BUFFER_UTIL_H_ diff --git a/src/experimental/filament/filament/builtins.cc b/src/experimental/filament/filament/builtins.cc index 3e4732e4..21f6c7cc 100644 --- a/src/experimental/filament/filament/builtins.cc +++ b/src/experimental/filament/filament/builtins.cc @@ -19,13 +19,14 @@ #include #include #include +#include +#include #include #include #include #include #include -#include #include "experimental/filament/filament/buffer_util.h" #include "experimental/filament/filament/vertex_util.h" @@ -40,263 +41,227 @@ static constexpr size_t kNumVerticesPerQuad = 4; static constexpr size_t kNumIndicesPerTriangle = 3; static constexpr size_t kNumIndicesPerQuad = 6; -static int AppendQuadIndices(uint16_t* ptr, int idx, uint16_t a, uint16_t b, - uint16_t c, uint16_t d) { - ptr[idx++] = a; - ptr[idx++] = b; - ptr[idx++] = c; - ptr[idx++] = a; - ptr[idx++] = c; - ptr[idx++] = d; - return idx; +static void AppendQuadIndices(std::vector& vec, uint16_t a, + uint16_t b, uint16_t c, uint16_t d) { + vec.push_back(a); + vec.push_back(b); + vec.push_back(c); + vec.push_back(a); + vec.push_back(c); + vec.push_back(d); } -std::size_t NumVerticesPerSide(int num_quads_per_axis) { +static std::size_t NumVerticesPerSide(int num_quads_per_axis) { return (num_quads_per_axis + 1) * (num_quads_per_axis + 1); } -std::size_t NumIndicesPerSide(int num_quads_per_axis) { +static std::size_t NumIndicesPerSide(int num_quads_per_axis) { return kNumIndicesPerQuad * num_quads_per_axis * num_quads_per_axis; } -class LineBuilder { +class BuiltinBuilder : MeshData { public: - using VertexType = VertexNoUv; - using IndexType = uint16_t; - static constexpr filament::RenderableManager::PrimitiveType kPrimitiveType = - filament::RenderableManager::PrimitiveType::LINES; + BuiltinBuilder() { DefaultMeshData(this); } + virtual ~BuiltinBuilder() = default; - explicit LineBuilder() {} - - std::size_t NumVertices() const { - return 2; + template + static MeshPtr Create(filament::Engine* engine, Args&&... args) { + auto builder = new T(std::forward(args)...); + MeshData* mesh_data = builder->PrepareMeshData(); + mesh_data->release_callback = +[](void* user_data) { + delete static_cast(user_data); + }; + mesh_data->user_data = builder; + return std::make_unique(engine, *mesh_data); } - std::size_t NumIndices() const { - return 2; + MeshData* PrepareMeshData() { + // Update the `MeshData` fields. + nattributes = 2; + attributes[0].usage = mjVERTEX_ATTRIBUTE_POSITION; + attributes[0].type = mjVERTEX_ATTRIBUTE_TYPE_FLOAT3; + attributes[0].bytes = reinterpret_cast(positions_.data()); + attributes[1].usage = mjVERTEX_ATTRIBUTE_TANGENTS; + attributes[1].type = mjVERTEX_ATTRIBUTE_TYPE_FLOAT4; + attributes[1].bytes = reinterpret_cast(orientations_.data()); + nvertices = positions_.size(); + + indices = indices_.data(); + nindices = indices_.size(); + primitive_type = + primitive_type_ == filament::backend::PrimitiveType::TRIANGLES + ? mjPRIM_TYPE_TRIANGLES + : mjPRIM_TYPE_LINES; + index_type = mjINDEX_TYPE_USHORT; + bounds_min[0] = bounds_.getMin().x; + bounds_min[1] = bounds_.getMin().y; + bounds_min[2] = bounds_.getMin().z; + bounds_max[0] = bounds_.getMax().x; + bounds_max[1] = bounds_.getMax().y; + bounds_max[2] = bounds_.getMax().z; + return this; } - void GenerateVertices(VertexType* ptr, size_t num) const { - constexpr float4 kOrientation = {0, 0, 0, 1}; // Unused for lines. - ptr[0] = VertexType({0, 0, 0}, kOrientation); - ptr[1] = VertexType({0, 0, 1}, kOrientation); - } + protected: + std::vector positions_; + std::vector orientations_; + std::vector indices_; + filament::Box bounds_; + filament::RenderableManager::PrimitiveType primitive_type_ = + filament::RenderableManager::PrimitiveType::TRIANGLES; +}; - void GenerateIndices(IndexType* ptr, size_t num) const { - ptr[0] = 0; - ptr[1] = 1; - } +class LineBuilder : public BuiltinBuilder { + public: + LineBuilder() { + primitive_type_ = filament::RenderableManager::PrimitiveType::LINES; - filament::Box GetBounds() const { - return filament::Box().set({-0.001, -0.001, 0}, {0.001, 0.001, 1}); + positions_.reserve(2); + positions_.emplace_back(0, 0, 0); + positions_.emplace_back(0, 0, 1); + + orientations_.resize(positions_.size(), {0, 0, 0, 1}); + + indices_.reserve(2); + indices_.push_back(0); + indices_.push_back(1); + + bounds_.set({0, 0, 0}, {0, 0, 1}); } }; -class PlaneBuilder { +class PlaneBuilder : public BuiltinBuilder { public: - using VertexType = VertexNoUv; - using IndexType = uint16_t; - static constexpr filament::RenderableManager::PrimitiveType kPrimitiveType = - filament::RenderableManager::PrimitiveType::TRIANGLES; + explicit PlaneBuilder(int num_quads_per_axis) { + const int num_vertices = NumVerticesPerSide(num_quads_per_axis); + positions_.reserve(num_vertices); - explicit PlaneBuilder(int num_quads_per_axis) - : num_quads_per_axis_(num_quads_per_axis), - orientation_(CalculateOrientation({0, 0, 1})) {} - - std::size_t NumVertices() const { - return NumVerticesPerSide(num_quads_per_axis_); - } - - std::size_t NumIndices() const { - return NumIndicesPerSide(num_quads_per_axis_); - } - - void GenerateVertices(VertexType* ptr, size_t num) const { - const float delta = 2.0f / num_quads_per_axis_; - - int idx = 0; - for (int x = 0; x <= num_quads_per_axis_; ++x) { - for (int y = 0; y <= num_quads_per_axis_; ++y) { + const float delta = 2.0f / num_quads_per_axis; + for (int x = 0; x <= num_quads_per_axis; ++x) { + for (int y = 0; y <= num_quads_per_axis; ++y) { const float dx = delta * static_cast(x); const float dy = delta * static_cast(y); - ptr[idx++] = VertexType({dx - 1.0f, dy - 1.0f, 0}, orientation_); + positions_.emplace_back(dx - 1.0f, dy - 1.0f, 0); } } - } - void GenerateIndices(IndexType* ptr, size_t num) const { - int idx = 0; - for (int x = 0; x < num_quads_per_axis_; ++x) { - for (int y = 0; y < num_quads_per_axis_; ++y) { - const int base_idx = x * (num_quads_per_axis_ + 1) + y; + orientations_.resize(positions_.size(), CalculateOrientation({0, 0, 1})); + + const int num_indices = NumIndicesPerSide(num_quads_per_axis); + indices_.reserve(num_indices); + for (int x = 0; x < num_quads_per_axis; ++x) { + for (int y = 0; y < num_quads_per_axis; ++y) { + const int base_idx = x * (num_quads_per_axis + 1) + y; const int i0 = base_idx + 0; const int i1 = base_idx + 1; - const int i2 = base_idx + num_quads_per_axis_ + 2; - const int i3 = base_idx + num_quads_per_axis_ + 1; - idx = AppendQuadIndices(ptr, idx, i0, i1, i2, i3); + const int i2 = base_idx + num_quads_per_axis + 2; + const int i3 = base_idx + num_quads_per_axis + 1; + AppendQuadIndices(indices_, i0, i1, i2, i3); } } - } - filament::Box GetBounds() const { - return filament::Box().set({-1, -1, -0.001}, {1, 1, 0.001}); + bounds_.set({-1, -1, -0.001}, {1, 1, 0.001}); } - - private: - int num_quads_per_axis_; - float4 orientation_; }; -class TriangleBuilder { +class TriangleBuilder : public BuiltinBuilder { public: - using VertexType = VertexNoUv; - using IndexType = uint16_t; - static constexpr filament::RenderableManager::PrimitiveType kPrimitiveType = - filament::RenderableManager::PrimitiveType::TRIANGLES; + TriangleBuilder() { + positions_.reserve(3); + positions_.emplace_back(0, 0, 0); + positions_.emplace_back(1, 0, 0); + positions_.emplace_back(0, 1, 0); - TriangleBuilder() - : orientation_(CalculateOrientation({0, 0, 1})) {} + orientations_.resize(positions_.size(), CalculateOrientation({0, 0, 1})); - std::size_t NumVertices() const { - return 3; + indices_.reserve(3); + indices_.emplace_back(0); + indices_.emplace_back(1); + indices_.emplace_back(2); + + bounds_.set({-1, -1, -0.001}, {1, 1, 0.001}); } - - std::size_t NumIndices() const { - return 3; - } - - void GenerateVertices(VertexType* ptr, size_t num) const { - ptr[0] = VertexType({0, 0, 0}, orientation_); - ptr[1] = VertexType({1, 0, 0}, orientation_); - ptr[2] = VertexType({0, 1, 0}, orientation_); - } - - void GenerateIndices(IndexType* ptr, size_t num) const { - ptr[0] = 0; - ptr[1] = 1; - ptr[2] = 2; - } - - filament::Box GetBounds() const { - return filament::Box().set({-1, -1, -0.001}, {1, 1, 0.001}); - } - - private: - float4 orientation_; }; -class LineBoxBuilder { +class LineBoxBuilder : public BuiltinBuilder { public: - using VertexType = VertexNoUv; - using IndexType = uint16_t; - static constexpr filament::RenderableManager::PrimitiveType kPrimitiveType = - filament::RenderableManager::PrimitiveType::LINES; + explicit LineBoxBuilder() { + primitive_type_ = filament::RenderableManager::PrimitiveType::LINES; - explicit LineBoxBuilder() {} + positions_.reserve(8); + positions_.emplace_back(-1.0f, -1.0f, -1.0f); + positions_.emplace_back( 1.0f, -1.0f, -1.0f); + positions_.emplace_back(-1.0f, 1.0f, -1.0f); + positions_.emplace_back( 1.0f, 1.0f, -1.0f); + positions_.emplace_back(-1.0f, -1.0f, 1.0f); + positions_.emplace_back( 1.0f, -1.0f, 1.0f); + positions_.emplace_back(-1.0f, 1.0f, 1.0f); + positions_.emplace_back( 1.0f, 1.0f, 1.0f); - std::size_t NumVertices() const { - return 8; - } + orientations_.resize(positions_.size(), {0, 0, 0, 1}); - std::size_t NumIndices() const { - return 24; - } - - void GenerateVertices(VertexType* ptr, size_t num) const { - constexpr float4 kOrientation = {0, 0, 0, 1}; // Unused for lines. - ptr[0] = VertexType({-1.0f, -1.0f, -1.0f}, kOrientation); - ptr[1] = VertexType({ 1.0f, -1.0f, -1.0f}, kOrientation); - ptr[2] = VertexType({-1.0f, 1.0f, -1.0f}, kOrientation); - ptr[3] = VertexType({ 1.0f, 1.0f, -1.0f}, kOrientation); - ptr[4] = VertexType({-1.0f, -1.0f, 1.0f}, kOrientation); - ptr[5] = VertexType({ 1.0f, -1.0f, 1.0f}, kOrientation); - ptr[6] = VertexType({-1.0f, 1.0f, 1.0f}, kOrientation); - ptr[7] = VertexType({ 1.0f, 1.0f, 1.0f}, kOrientation); - } - - void GenerateIndices(IndexType* ptr, size_t num) const { - // Bottom square (where z == -1). - ptr[0] = 0; - ptr[1] = 1; - ptr[2] = 1; - ptr[3] = 3; - ptr[4] = 3; - ptr[5] = 2; - ptr[6] = 2; - ptr[7] = 0; + indices_.reserve(24); + indices_.push_back(0); + indices_.push_back(1); + indices_.push_back(1); + indices_.push_back(3); + indices_.push_back(3); + indices_.push_back(2); + indices_.push_back(2); + indices_.push_back(0); // Top square (where z == 1). - ptr[8] = 4; - ptr[9] = 5; - ptr[10] = 5; - ptr[11] = 7; - ptr[12] = 7; - ptr[13] = 6; - ptr[14] = 6; - ptr[15] = 4; + indices_.push_back(4); + indices_.push_back(5); + indices_.push_back(5); + indices_.push_back(7); + indices_.push_back(7); + indices_.push_back(6); + indices_.push_back(6); + indices_.push_back(4); // Connect edges from bottom to top. - ptr[16] = 2; - ptr[17] = 6; - ptr[18] = 3; - ptr[19] = 7; - ptr[20] = 0; - ptr[21] = 4; - ptr[22] = 1; - ptr[23] = 5; - } + indices_.push_back(2); + indices_.push_back(6); + indices_.push_back(3); + indices_.push_back(7); + indices_.push_back(0); + indices_.push_back(4); + indices_.push_back(1); + indices_.push_back(5); - filament::Box GetBounds() const { - return filament::Box().set({-1, -1, -1}, {1, 1, 1}); + bounds_.set({-1, -1, -1}, {1, 1, 1}); } }; -class BoxBuilder { +class BoxBuilder : public BuiltinBuilder { public: - using VertexType = VertexNoUv; - using IndexType = uint16_t; - static constexpr filament::RenderableManager::PrimitiveType kPrimitiveType = - filament::RenderableManager::PrimitiveType::TRIANGLES; - static constexpr int kNumSides = 6; explicit BoxBuilder(int num_quads_per_axis) : num_quads_per_axis_(num_quads_per_axis) { quad_size_ = 2.0f / static_cast(num_quads_per_axis_); - } - std::size_t NumVertices() const { - return NumVerticesPerSide(num_quads_per_axis_) * kNumSides; - } - - std::size_t NumIndices() const { - return NumIndicesPerSide(num_quads_per_axis_) * kNumSides; - } - - void GenerateVertices(VertexType* ptr, size_t num) const { - int idx = 0; - idx = GenerateVerticesForSide(ptr, idx, {0, 1, 0}, [](float2 pt) { - return float3{pt.x, 1.0f, pt.y}; - }); - idx = GenerateVerticesForSide(ptr, idx, {0, -1, 0}, [](float2 pt) { - return float3{pt.x, -1.0f, pt.y}; - }); - idx = GenerateVerticesForSide(ptr, idx, {1, 0, 0}, [](float2 pt) { - return float3{1.0f, pt.x, pt.y}; - }); - idx = GenerateVerticesForSide(ptr, idx, {-1, 0, 0}, [](float2 pt) { - return float3{-1.0f, pt.x, pt.y}; - }); - idx = GenerateVerticesForSide(ptr, idx, {0, 0, 1}, [](float2 pt) { - return float3{pt.x, pt.y, 1.0f}; - }); - idx = GenerateVerticesForSide(ptr, idx, {0, 0, -1}, [](float2 pt) { - return float3{pt.x, pt.y, -1.0f}; - }); - } - - void GenerateIndices(IndexType* ptr, size_t num) const { const int vertices_per_side = NumVerticesPerSide(num_quads_per_axis_); + const int indices_per_side = NumIndicesPerSide(num_quads_per_axis_); + const int num_vertices = vertices_per_side * kNumSides; + const int num_indices = indices_per_side * kNumSides; + + positions_.reserve(num_vertices); + orientations_.reserve(num_vertices); + indices_.reserve(num_indices); + + GenerateVerticesForSide({0, 1, 0}, + [](float2 pt) { return float3{pt.x, 1.0f, pt.y}; }); + GenerateVerticesForSide( + {0, -1, 0}, [](float2 pt) { return float3{pt.x, -1.0f, pt.y}; }); + GenerateVerticesForSide({1, 0, 0}, + [](float2 pt) { return float3{1.0f, pt.x, pt.y}; }); + GenerateVerticesForSide( + {-1, 0, 0}, [](float2 pt) { return float3{-1.0f, pt.x, pt.y}; }); + GenerateVerticesForSide({0, 0, 1}, + [](float2 pt) { return float3{pt.x, pt.y, 1.0f}; }); + GenerateVerticesForSide( + {0, 0, -1}, [](float2 pt) { return float3{pt.x, pt.y, -1.0f}; }); - int idx = 0; for (int i = 0; i < kNumSides; ++i) { for (int x = 0; x < num_quads_per_axis_; ++x) { for (int y = 0; y < num_quads_per_axis_; ++y) { @@ -306,279 +271,199 @@ class BoxBuilder { const int i1 = base_idx + 1; const int i2 = base_idx + num_quads_per_axis_ + 2; const int i3 = base_idx + num_quads_per_axis_ + 1; - idx = AppendQuadIndices(ptr, idx, i0, i1, i2, i3); + AppendQuadIndices(indices_, i0, i1, i2, i3); } } } - } - filament::Box GetBounds() const { - return filament::Box().set({-1, -1, -1}, {1, 1, 1}); + bounds_.set({-1, -1, -1}, {1, 1, 1}); } private: template - int GenerateVerticesForSide(VertexType* ptr, int idx, float3 normal, - const F& pt_gen) const { + void GenerateVerticesForSide(float3 normal, const F& pt_gen) { float4 orientation = CalculateOrientation(normal); for (int x = 0; x <= num_quads_per_axis_; ++x) { for (int y = 0; y <= num_quads_per_axis_; ++y) { const float dx = -1.0f + (quad_size_ * static_cast(x)); const float dy = -1.0f + (quad_size_ * static_cast(y)); const float3 position = pt_gen({dx, dy}); - ptr[idx++] = VertexType(position, orientation); + positions_.push_back(position); + orientations_.push_back(orientation); } } - return idx; } int num_quads_per_axis_; float quad_size_; }; -class TubeBuilder { +class TubeBuilder : public BuiltinBuilder { public: - using VertexType = VertexNoUv; - using IndexType = uint16_t; - static constexpr filament::RenderableManager::PrimitiveType kPrimitiveType = - filament::RenderableManager::PrimitiveType::TRIANGLES; + TubeBuilder(int num_stacks, int num_slices) { + const int num_vertices = num_slices * (num_stacks + 1); + positions_.reserve(num_vertices); + orientations_.reserve(num_vertices); - TubeBuilder(int num_stacks, int num_slices) - : num_stacks_(num_stacks), num_slices_(num_slices) {} - - std::size_t NumVertices() const { - return num_slices_ * (num_stacks_ + 1); - } - - std::size_t NumIndices() const { - return kNumIndicesPerQuad * num_slices_ * num_stacks_; - } - - void GenerateVertices(VertexType* ptr, size_t num) const { - const float delta_angle = 2.f * std::numbers::pi / (float)num_slices_; - const float delta_stack = 2.f / static_cast(num_stacks_); - - int idx = 0; - for (int i = 0; i < num_slices_; ++i) { + const float delta_angle = 2.f * std::numbers::pi / (float)num_slices; + const float delta_stack = 2.f / static_cast(num_stacks); + for (int i = 0; i < num_slices; ++i) { const float angle = static_cast(i) * delta_angle; const float2 pt{std::cos(angle), std::sin(angle)}; const float4 orientation = CalculateOrientation({pt.x, pt.y, 0}); - for (int j = 0; j <= num_stacks_; ++j) { + for (int j = 0; j <= num_stacks; ++j) { const float z = -1.0f + (static_cast(j) * delta_stack); - ptr[idx++] = VertexType({pt.x, pt.y, z}, orientation); + positions_.emplace_back(pt.x, pt.y, z); + orientations_.push_back(orientation); } } - } - void GenerateIndices(IndexType* ptr, size_t num) const { - const int num_vertices = NumVertices(); - const int num_vertices_in_spine = num_stacks_ + 1; + const int num_indices = kNumIndicesPerQuad * num_slices * num_stacks; + indices_.reserve(num_indices); - int idx = 0; - for (int i = 0; i < num_slices_; ++i) { - for (int j = 0; j < num_stacks_; ++j) { + const int num_vertices_in_spine = num_stacks + 1; + for (int i = 0; i < num_slices; ++i) { + for (int j = 0; j < num_stacks; ++j) { const int base_idx = (i * num_vertices_in_spine) + j; const int i0 = base_idx + 0; const int i1 = base_idx + 1; - const int i2 = (base_idx + num_stacks_ + 2) % num_vertices; - const int i3 = (base_idx + num_stacks_ + 1) % num_vertices; - idx = AppendQuadIndices(ptr, idx, i0, i1, i2, i3); + const int i2 = (base_idx + num_stacks + 2) % num_vertices; + const int i3 = (base_idx + num_stacks + 1) % num_vertices; + AppendQuadIndices(indices_, i0, i1, i2, i3); } } - } - filament::Box GetBounds() const { - return filament::Box().set({-1, -1, -1}, {1, 1, 1}); + bounds_.set({-1, -1, -1}, {1, 1, 1}); } - - private: - int num_stacks_; - int num_slices_; }; -class ConeBuilder { +class ConeBuilder : public BuiltinBuilder { public: - using VertexType = VertexNoUv; - using IndexType = uint16_t; - static constexpr filament::RenderableManager::PrimitiveType kPrimitiveType = - filament::RenderableManager::PrimitiveType::TRIANGLES; + ConeBuilder(int num_stacks, int num_slices) { + const int num_vertices = + (num_slices * kNumVerticesPerTriangle) + + ((num_stacks - 1) * num_slices * kNumVerticesPerQuad); + positions_.reserve(num_vertices); + orientations_.reserve(num_vertices); - ConeBuilder(int num_stacks, int num_slices) - : num_stacks_(num_stacks), num_slices_(num_slices) {} - - std::size_t NumVertices() const { - return (num_slices_ * kNumVerticesPerTriangle) + - ((num_stacks_ - 1) * num_slices_ * kNumVerticesPerQuad); - } - - std::size_t NumIndices() const { - return (num_slices_ * kNumIndicesPerTriangle) + - ((num_stacks_ - 1) * num_slices_ * kNumIndicesPerQuad); - } - void GenerateVertices(VertexType* ptr, std::size_t num) const { // pole: use triangles const float delta_angle = - 2.0 * std::numbers::pi / static_cast(num_slices_); - const float delta_radius = 1.0f / static_cast(num_stacks_); + 2.0 * std::numbers::pi / static_cast(num_slices); + const float delta_radius = 1.0f / static_cast(num_stacks); - int idx = 0; - for (int j = 0; j < num_slices_; ++j) { + for (int j = 0; j < num_slices; ++j) { const float angle1 = (j + 0) * delta_angle; const float angle2 = (j + 1) * delta_angle; - ptr[idx++] = MakeVert(angle1, delta_radius); - ptr[idx++] = MakeVert(angle2, delta_radius); + AppendVert(angle1, delta_radius); + AppendVert(angle2, delta_radius); - VertexType v3; - v3.position = {0, 0, 1}; - v3.orientation = CalculateOrientation(v3.position); - ptr[idx++] = v3; + positions_.emplace_back(0, 0, 1); + orientations_.emplace_back(CalculateOrientation({0, 0, 1})); } // the rest: use quads - for (int i = 1; i < num_stacks_; ++i) { + for (int i = 1; i < num_stacks; ++i) { const float radius1 = delta_radius * (i + 0); const float radius2 = delta_radius * (i + 1); - for (int j = 0; j < num_slices_; ++j) { + for (int j = 0; j < num_slices; ++j) { const float angle1 = (j + 0) * delta_angle; const float angle2 = (j + 1) * delta_angle; - - ptr[idx++] = MakeVert(angle1, radius2); - ptr[idx++] = MakeVert(angle2, radius2); - ptr[idx++] = MakeVert(angle2, radius1); - ptr[idx++] = MakeVert(angle1, radius1); + AppendVert(angle1, radius2); + AppendVert(angle2, radius2); + AppendVert(angle2, radius1); + AppendVert(angle1, radius1); } } - } - void GenerateIndices(IndexType* ptr, std::size_t num) const { - int idx = 0; - for (int j = 0; j < num_slices_ * 3; ++j) { - ptr[idx] = idx; - ++idx; + const int num_indices = + (num_slices * kNumIndicesPerTriangle) + + ((num_stacks - 1) * num_slices * kNumIndicesPerQuad); + indices_.reserve(num_indices); + for (int j = 0; j < num_slices * 3; ++j) { + indices_.push_back(j); } - int quad_idx = idx; - for (int i = 1; i < num_stacks_; ++i) { - for (int j = 0; j < num_slices_; ++j) { + int quad_idx = num_slices * 3; + for (int i = 1; i < num_stacks; ++i) { + for (int j = 0; j < num_slices; ++j) { const int i0 = quad_idx + 0; const int i1 = quad_idx + 1; const int i2 = quad_idx + 2; const int i3 = quad_idx + 3; quad_idx += 4; - idx = AppendQuadIndices(ptr, idx, i0, i1, i2, i3); + AppendQuadIndices(indices_, i0, i1, i2, i3); } } - } - filament::Box GetBounds() const { - return filament::Box().set({-1, -1, 0}, {1, 1, 1}); + bounds_.set({-1, -1, 0}, {1, 1, 1}); } private: - static VertexType MakeVert(float theta, float radius) { + void AppendVert(float theta, float radius) { static constexpr float kNormalScale = 0.70710678118f; const float cz = std::cos(theta); const float sz = std::sin(theta); const float3 pt{cz * radius, sz * radius, 1.f - radius}; const float3 n{cz * kNormalScale, sz * kNormalScale, kNormalScale}; - return VertexType(pt, CalculateOrientation(n)); + positions_.push_back(pt); + orientations_.push_back(CalculateOrientation(n)); } - - int num_stacks_; - int num_slices_; }; -class DiskBuilder { +class DiskBuilder : public BuiltinBuilder { public: - using VertexType = VertexNoUv; - using IndexType = uint16_t; - static constexpr filament::RenderableManager::PrimitiveType kPrimitiveType = - filament::RenderableManager::PrimitiveType::TRIANGLES; - - explicit DiskBuilder(int num_slices) : num_slices_(num_slices) { - orientation_ = CalculateOrientation({0, 0, 1}); - } - - std::size_t NumVertices() const { - return num_slices_ + 1; - } - - std::size_t NumIndices() const { - return num_slices_ * kNumVerticesPerTriangle; - } - - void GenerateVertices(VertexType* ptr, std::size_t num) const { + explicit DiskBuilder(int num_slices) { + const int num_vertices = num_slices + 1; + positions_.reserve(num_vertices); const float delta_angle = - 2.0 * std::numbers::pi / static_cast(num_slices_); + 2.0 * std::numbers::pi / static_cast(num_slices); - int idx = 0; - ptr[idx++] = VertexType(float3{0, 0, 0}, orientation_); - for (int i = 0; i < num_slices_; ++i) { + positions_.push_back({0, 0, 0}); + for (int i = 0; i < num_slices; ++i) { const float angle = static_cast(i) * delta_angle; const float x = std::cos(angle); const float y = std::sin(angle); - ptr[idx++] = VertexType(float3{x, y, 0}, orientation_); + positions_.push_back({x, y, 0}); } - } - void GenerateIndices(IndexType* ptr, std::size_t num) const { - int idx = 0; - for (int i = 0; i < num_slices_; ++i) { - const int next = i < (num_slices_ - 1) ? i + 1 : 0; - ptr[idx++] = 0; - ptr[idx++] = 1 + i; - ptr[idx++] = 1 + next; + orientations_.resize(positions_.size(), CalculateOrientation({0, 0, 1})); + + const int num_indices = num_slices * kNumVerticesPerTriangle; + indices_.reserve(num_indices); + for (int i = 0; i < num_slices; ++i) { + const int next = i < (num_slices - 1) ? i + 1 : 0; + indices_.push_back(0); + indices_.push_back(1 + i); + indices_.push_back(1 + next); } - } - filament::Box GetBounds() const { - return filament::Box().set({-1, -1, -0.001}, {1, 1, 0.001}); + bounds_.set({-1, -1, -0.001}, {1, 1, 0.001}); } - - private: - int num_slices_; - float4 orientation_; }; -class SphereBuilder { +class SphereBuilder : public BuiltinBuilder { public: - using VertexType = VertexNoUv; - using IndexType = uint16_t; - static constexpr filament::RenderableManager::PrimitiveType kPrimitiveType = - filament::RenderableManager::PrimitiveType::TRIANGLES; + SphereBuilder(int num_stacks, int num_slices) { + static constexpr uint16_t kNorthPoleIndex = 0; + static constexpr uint16_t kSouthPoleIndex = 1; - static constexpr IndexType kNorthPoleIndex = 0; - static constexpr IndexType kSouthPoleIndex = 1; + const int num_vertices = (num_stacks * num_slices) + 2; // +2 for poles + positions_.reserve(num_vertices); + orientations_.reserve(num_vertices); - SphereBuilder(int num_stacks, int num_slices) - : num_stacks_(num_stacks), num_slices_(num_slices) {} - - std::size_t NumVertices() const { - return (num_stacks_ * num_slices_) + 2; // +2 for poles - } - - std::size_t NumIndices() const { - const size_t num_tris_polar_cap = num_slices_; - const size_t num_quads_body = num_slices_ * (num_stacks_ - 1); - return (2 * num_tris_polar_cap * kNumIndicesPerTriangle) + - (num_quads_body * kNumIndicesPerQuad); - } - - void GenerateVertices(VertexType* ptr, size_t num) const { const float lat_angle_delta = - std::numbers::pi / static_cast(num_stacks_ + 1); + std::numbers::pi / static_cast(num_stacks + 1); const float lon_angle_delta = - 2.0 * std::numbers::pi / static_cast(num_slices_); + 2.0 * std::numbers::pi / static_cast(num_slices); // Add the north and south poles. - int idx = 0; - ptr[idx++] = MakeVert(0, 0, 1); - ptr[idx++] = MakeVert(0, 0, -1); + AppendVert(0, 0, 1); + AppendVert(0, 0, -1); // Vertices by latitude. - for (int lat = 0; lat < num_stacks_; ++lat) { + for (int lat = 0; lat < num_stacks; ++lat) { // +1 because we handle the north pole (which would be at a lat angle of // 0-degrees) explicitly. const float lat_angle = static_cast(lat + 1) * lat_angle_delta; @@ -586,7 +471,7 @@ class SphereBuilder { const float sin_lat_angle = std::sin(lat_angle); const float z = cos_lat_angle; - for (int lon = 0; lon < num_slices_; ++lon) { + for (int lon = 0; lon < num_slices; ++lon) { const float lon_angle = static_cast(lon) * lon_angle_delta; const float cos_lon_angle = std::cos(lon_angle); @@ -594,101 +479,83 @@ class SphereBuilder { const float x = sin_lat_angle * cos_lon_angle; const float y = sin_lat_angle * sin_lon_angle; - ptr[idx++] = MakeVert(x, y, z); + AppendVert(x, y, z); } } - } - void GenerateIndices(IndexType* ptr, size_t num) const { - int idx = 0; + const size_t num_tris_polar_cap = num_slices; + const size_t num_quads_body = num_slices * (num_stacks - 1); + const int num_indices = (2 * num_tris_polar_cap * kNumIndicesPerTriangle) + + (num_quads_body * kNumIndicesPerQuad); + indices_.reserve(num_indices); // The first two vertices are the poles, so the first vertex in the first // row starts at index 2. - IndexType row_start = kSouthPoleIndex + 1; + uint16_t row_start = kSouthPoleIndex + 1; // North polar cap. - for (int lon = 0; lon < num_slices_; ++lon) { - const int next = lon < (num_slices_ - 1) ? lon + 1 : 0; - ptr[idx++] = kNorthPoleIndex; - ptr[idx++] = row_start + next; - ptr[idx++] = row_start + lon; + for (int lon = 0; lon < num_slices; ++lon) { + const int next = lon < (num_slices - 1) ? lon + 1 : 0; + indices_.push_back(kNorthPoleIndex); + indices_.push_back(row_start + next); + indices_.push_back(row_start + lon); } // Latitudinal triangle strips. - for (int lat = 0; lat < num_stacks_ - 1; lat++) { - const IndexType north_start = row_start; - const IndexType south_start = row_start + num_slices_; - for (int lon = 0; lon < num_slices_; ++lon) { + for (int lat = 0; lat < num_stacks - 1; lat++) { + const uint16_t north_start = row_start; + const uint16_t south_start = row_start + num_slices; + for (int lon = 0; lon < num_slices; ++lon) { // The offset to the index that is adjacent to the current index. - const int adjacent = lon < (num_slices_ - 1) ? lon + 1 : 0; + const int adjacent = lon < (num_slices - 1) ? lon + 1 : 0; const int i0 = (north_start + lon); const int i1 = (south_start + lon); const int i2 = (south_start + adjacent); const int i3 = (north_start + adjacent); - idx = AppendQuadIndices(ptr, idx, i0, i1, i2, i3); + AppendQuadIndices(indices_, i0, i1, i2, i3); } - row_start += num_slices_; + row_start += num_slices; } // South polar cap. - for (int lon = 0; lon < num_slices_; ++lon) { - const int adjacent = lon < (num_slices_ - 1) ? lon + 1 : 0; - ptr[idx++] = kSouthPoleIndex; - ptr[idx++] = row_start + lon; - ptr[idx++] = row_start + adjacent; + for (int lon = 0; lon < num_slices; ++lon) { + const int adjacent = lon < (num_slices - 1) ? lon + 1 : 0; + indices_.push_back(kSouthPoleIndex); + indices_.push_back(row_start + lon); + indices_.push_back(row_start + adjacent); } - } - filament::Box GetBounds() const { - return filament::Box().set({-1, -1, -1}, {1, 1, 1}); + bounds_.set({-1, -1, -1}, {1, 1, 1}); } private: - static VertexType MakeVert(float x, float y, float z) { + void AppendVert(float x, float y, float z) { const float3 pt{x, y, z}; - return VertexType(pt, CalculateOrientation(pt)); + positions_.push_back(pt); + orientations_.push_back(CalculateOrientation(pt)); } - - int num_stacks_; - int num_slices_; }; -class DomeBuilder { +class DomeBuilder : public BuiltinBuilder { public: - using VertexType = VertexNoUv; - using IndexType = uint16_t; - static constexpr filament::RenderableManager::PrimitiveType kPrimitiveType = - filament::RenderableManager::PrimitiveType::TRIANGLES; + DomeBuilder(int num_stacks, int num_slices) { + static constexpr uint16_t kPoleIndex = 0; - static constexpr IndexType kPoleIndex = 0; + const int num_vertices = (num_stacks * num_slices) + 1; // +1 for poles + positions_.reserve(num_vertices); + orientations_.reserve(num_vertices); - DomeBuilder(int num_stacks, int num_slices) - : num_stacks_(num_stacks), num_slices_(num_slices) {} - - std::size_t NumVertices() const { - return (num_stacks_ * num_slices_) + 1; // +1 for poles - } - - std::size_t NumIndices() const { - const size_t num_tris_polar_cap = num_slices_; - const size_t num_quads_body = num_slices_ * (num_stacks_ - 1); - return (num_tris_polar_cap * kNumIndicesPerTriangle) + - (num_quads_body * kNumIndicesPerQuad); - } - - void GenerateVertices(VertexType* ptr, size_t num) const { const float lat_angle_delta = - 0.5 * std::numbers::pi / static_cast(num_stacks_); + 0.5 * std::numbers::pi / static_cast(num_stacks); const float lon_angle_delta = - 2.0 * std::numbers::pi / static_cast(num_slices_); + 2.0 * std::numbers::pi / static_cast(num_slices); // Add the pole. - int idx = 0; - ptr[idx++] = MakeVert(0, 0, 1); + AppendVert(0, 0, 1); // Vertices by latitude. - for (int lat = 0; lat < num_stacks_; ++lat) { + for (int lat = 0; lat < num_stacks; ++lat) { // +1 because we handle the north pole (which would be at a lat angle of // 0-degrees) explicitly. const float lat_angle = static_cast(lat + 1) * lat_angle_delta; @@ -696,138 +563,102 @@ class DomeBuilder { const float sin_lat_angle = std::sin(lat_angle); const float z = cos_lat_angle; - for (int lon = 0; lon < num_slices_; ++lon) { + for (int lon = 0; lon < num_slices; ++lon) { const float lon_angle = static_cast(lon) * lon_angle_delta; const float cos_lon_angle = std::cos(lon_angle); const float sin_lon_angle = std::sin(lon_angle); const float x = sin_lat_angle * cos_lon_angle; const float y = sin_lat_angle * sin_lon_angle; - ptr[idx++] = MakeVert(x, y, z); + AppendVert(x, y, z); } } - } - void GenerateIndices(IndexType* ptr, size_t num) const { - int idx = 0; + const size_t num_tris_polar_cap = num_slices; + const size_t num_quads_body = num_slices * (num_stacks - 1); + const int num_indices = (num_tris_polar_cap * kNumIndicesPerTriangle) + + (num_quads_body * kNumIndicesPerQuad); + indices_.reserve(num_indices); // The first vertex is the poles, so the first vertex in the first row // starts at index 1. - IndexType row_start = kPoleIndex + 1; + uint16_t row_start = kPoleIndex + 1; // North polar cap. - for (int lon = 0; lon < num_slices_; ++lon) { - const int next = lon < (num_slices_ - 1) ? lon + 1 : 0; - - ptr[idx++] = kPoleIndex; - ptr[idx++] = row_start + next; - ptr[idx++] = row_start + lon; + for (int lon = 0; lon < num_slices; ++lon) { + const int next = lon < (num_slices - 1) ? lon + 1 : 0; + indices_.push_back(kPoleIndex); + indices_.push_back(row_start + next); + indices_.push_back(row_start + lon); } // Latitudinal quad strips. The first "stack" was handled above, so we // only need to iterate over N-1 stacks. - for (int lat = 0; lat < num_stacks_ - 1; lat++) { + for (int lat = 0; lat < num_stacks - 1; lat++) { const int north_start = row_start; - const int south_start = row_start + num_slices_; - for (int lon = 0; lon < num_slices_; ++lon) { + const int south_start = row_start + num_slices; + for (int lon = 0; lon < num_slices; ++lon) { // The offset to the index that is adjacent to the current index. - const int adjacent = lon < (num_slices_ - 1) ? lon + 1 : 0; + const int adjacent = lon < (num_slices - 1) ? lon + 1 : 0; const int i0 = (north_start + lon); const int i1 = (south_start + lon); const int i2 = (south_start + adjacent); const int i3 = (north_start + adjacent); - idx = AppendQuadIndices(ptr, idx, i0, i1, i2, i3); + AppendQuadIndices(indices_, i0, i1, i2, i3); } - row_start += num_slices_; + row_start += num_slices; } - } - filament::Box GetBounds() const { - return filament::Box().set({-1, -1, 0}, {1, 1, 1}); + bounds_.set({-1, -1, 0}, {1, 1, 1}); } private: - static VertexType MakeVert(float x, float y, float z) { + void AppendVert(float x, float y, float z) { const float3 pt{x, y, z}; - return VertexType(pt, CalculateOrientation(pt)); + positions_.push_back(pt); + orientations_.push_back(CalculateOrientation(pt)); } - - int num_stacks_; - int num_slices_; }; -template -MeshPtr CreateFromBuilder(filament::Engine* engine, const T& builder) { - using VertexType = typename T::VertexType; - using IndexType = typename T::IndexType; - - const int num_vertices = builder.NumVertices(); - const int num_indices = builder.NumIndices(); - if (num_vertices == 0 || num_indices == 0) { - return {}; - } - - auto vertices = [&](std::byte* buffer, std::size_t len) { - auto* ptr = reinterpret_cast(buffer); - if (sizeof(*ptr) * num_vertices != len) { - mju_error("Buffer size mismatch."); - } - builder.GenerateVertices(ptr, num_vertices); - }; - - auto indices = [&](std::byte* buffer, std::size_t len) { - auto* ptr = reinterpret_cast(buffer); - if (sizeof(*ptr) * num_indices != len) { - mju_error("Buffer size mismatch."); - } - builder.GenerateIndices(ptr, num_indices); - }; - - auto vb = CreateVertexBuffer(engine, num_vertices, vertices); - auto ib = CreateIndexBuffer(engine, num_indices, indices); - return std::make_unique(engine, ib, vb, builder.GetBounds(), - T::kPrimitiveType); -} - MeshPtr CreateLine(filament::Engine* engine) { - return CreateFromBuilder(engine, LineBuilder()); + return BuiltinBuilder::Create(engine); } MeshPtr CreatePlane(filament::Engine* engine, int nquad) { - return CreateFromBuilder(engine, PlaneBuilder(nquad)); + return BuiltinBuilder::Create(engine, nquad); } MeshPtr CreateTriangle(filament::Engine* engine) { - return CreateFromBuilder(engine, TriangleBuilder()); + return BuiltinBuilder::Create(engine); } MeshPtr CreateBox(filament::Engine* engine, int nquad) { - return CreateFromBuilder(engine, BoxBuilder(nquad)); + return BuiltinBuilder::Create(engine, nquad); } MeshPtr CreateLineBox(filament::Engine* engine) { - return CreateFromBuilder(engine, LineBoxBuilder()); + return BuiltinBuilder::Create(engine); } MeshPtr CreateSphere(filament::Engine* engine, int nstack, int nslice) { - return CreateFromBuilder(engine, SphereBuilder(nstack, nslice)); + return BuiltinBuilder::Create(engine, nstack, nslice); } MeshPtr CreateTube(filament::Engine* engine, int nstack, int nslice) { - return CreateFromBuilder(engine, TubeBuilder(nstack, nslice)); + return BuiltinBuilder::Create(engine, nstack, nslice); } MeshPtr CreateDisk(filament::Engine* engine, int nslice) { - return CreateFromBuilder(engine, DiskBuilder(nslice)); + return BuiltinBuilder::Create(engine, nslice); } MeshPtr CreateDome(filament::Engine* engine, int nstack, int nslice) { - return CreateFromBuilder(engine, DomeBuilder(nstack, nslice)); + return BuiltinBuilder::Create(engine, nstack, nslice); } MeshPtr CreateCone(filament::Engine* engine, int nstack, int nslice) { - return CreateFromBuilder(engine, ConeBuilder(nstack, nslice)); + return BuiltinBuilder::Create(engine, nstack, nslice); } } // namespace mujoco diff --git a/src/experimental/filament/filament/geom_util.cc b/src/experimental/filament/filament/geom_util.cc index 38d7509b..fb64e8d0 100644 --- a/src/experimental/filament/filament/geom_util.cc +++ b/src/experimental/filament/filament/geom_util.cc @@ -14,27 +14,19 @@ #include "experimental/filament/filament/geom_util.h" -#include #include -#include #include #include #include -#include #include #include #include -#include #include #include "experimental/filament/filament/buffer_util.h" -#include "experimental/filament/filament/math_util.h" -#include "experimental/filament/filament/vertex_util.h" namespace mujoco { -using filament::math::float3; - static std::span GetPositions(const mjModel* model, const mjvScene* scene, const mjvGeom& geom) { @@ -106,64 +98,6 @@ static std::span GetIndices(const mjModel* model, } } -template -static void FillVertices(std::byte* buffer, std::size_t len, - std::span positions, - std::span normals, - std::span uvs, - float3* vmin, - float3* vmax) { - const int num_vertices = len / sizeof(T); - T* ptr = reinterpret_cast(buffer); - for (int i = 0; i < num_vertices; ++i) { - ptr->position = ReadFloat3(positions.data(), i); - *vmin = min(*vmin, ptr->position); - *vmax = max(*vmax, ptr->position); - ptr->orientation = CalculateOrientation(ReadFloat3(normals.data(), i)); - if constexpr (T::kHasUv) { - ptr->uv.x = uvs[i * 2]; - ptr->uv.y = uvs[i * 2 + 1]; - } - ++ptr; - } -} - -static filament::VertexBuffer* BuildVertexBuffer( - filament::Engine* engine, std::span positions, - std::span normals, std::span uvs, float3* vmin, - float3* vmax) { - const int num_vertices = positions.size() / 3; - if (uvs.data() != nullptr) { - using VertexType = VertexWithUv; - auto fill = [&](std::byte* buffer, std::size_t len) { - FillVertices(buffer, len, positions, normals, uvs, vmin, - vmax); - }; - return CreateVertexBuffer(engine, num_vertices, fill); - } else { - using VertexType = VertexNoUv; - auto fill = [&](std::byte* buffer, std::size_t len) { - FillVertices(buffer, len, positions, normals, uvs, vmin, - vmax); - }; - return CreateVertexBuffer(engine, num_vertices, fill); - } -} - -static filament::IndexBuffer* BuildIndexBuffer(filament::Engine* engine, - std::span indices, - int num_indices) { - if (indices.data() == nullptr) { - auto fill_indices = FillSequence; - return CreateIndexBuffer(engine, num_indices, fill_indices); - } else { - auto fill_indices = [&](std::byte* buffer, std::size_t len) { - std::memcpy(buffer, indices.data(), len); - }; - return CreateIndexBuffer(engine, indices.size(), fill_indices); - } -} - MeshPtr CreateGeomBuffers(filament::Engine* engine, const mjModel* model, const mjvScene* scene, const mjvGeom& geom) { auto positions = GetPositions(model, scene, geom); @@ -176,13 +110,28 @@ MeshPtr CreateGeomBuffers(filament::Engine* engine, const mjModel* model, num_indices = 3 * scene->flexfaceused[geom.objid]; } - float3 vmin = {FLT_MAX, FLT_MAX, FLT_MAX}; - float3 vmax = {-FLT_MAX, -FLT_MAX, -FLT_MAX}; - auto vertex_buffer = BuildVertexBuffer(engine, positions, normals, uvs, &vmin, &vmax); - auto index_buffer = BuildIndexBuffer(engine, indices, num_indices); - filament::Box bounds; - bounds.set(vmin, vmax); - return std::make_unique(engine, index_buffer, vertex_buffer, bounds); + MeshData data; + DefaultMeshData(&data); + + data.nattributes = uvs.data() ? 3 : 2; + data.attributes[0].usage = mjVERTEX_ATTRIBUTE_POSITION; + data.attributes[0].type = mjVERTEX_ATTRIBUTE_TYPE_FLOAT3; + data.attributes[0].bytes = positions.data(); + data.attributes[1].usage = mjVERTEX_ATTRIBUTE_NORMAL; + data.attributes[1].type = mjVERTEX_ATTRIBUTE_TYPE_FLOAT3; + data.attributes[1].bytes = normals.data(); + data.attributes[2].usage = mjVERTEX_ATTRIBUTE_UV; + data.attributes[2].type = mjVERTEX_ATTRIBUTE_TYPE_FLOAT2; + data.attributes[2].bytes = uvs.data(); + data.nvertices = positions.size() / 3; + data.nindices = num_indices; + data.indices = indices.data(); + data.index_type = mjINDEX_TYPE_UINT; + data.primitive_type = mjPRIM_TYPE_TRIANGLES; + data.compute_bounds = true; + data.release_callback = nullptr; + data.user_data = nullptr; + return std::make_unique(engine, data); } } // namespace mujoco diff --git a/src/experimental/filament/filament/gui_view.cc b/src/experimental/filament/filament/gui_view.cc index 2217c95b..6a3bc82d 100644 --- a/src/experimental/filament/filament/gui_view.cc +++ b/src/experimental/filament/filament/gui_view.cc @@ -33,7 +33,6 @@ #include #include "experimental/filament/filament/buffer_util.h" #include "experimental/filament/filament/texture.h" -#include "experimental/filament/filament/vertex_util.h" namespace mujoco { @@ -202,10 +201,14 @@ void GuiView::UpdateRenderable() { } commands->ScaleClipRects(scale); + // 2 floats for position, 2 floats for uv, 4 bytes for color. + constexpr size_t kExpectedVertexSize = + sizeof(float) * 4 + sizeof(uint8_t) * 4; + int num_elements = 0; for (int n = 0; n < commands->CmdListsCount; ++n) { const ImDrawList* cmds = commands->CmdLists[n]; - if (sizeof(GuiVertex) != sizeof(cmds->VtxBuffer.Data[0])) { + if (kExpectedVertexSize != sizeof(cmds->VtxBuffer.Data[0])) { mju_error("Invalid vertex buffer size."); } if (sizeof(uint16_t) != sizeof(cmds->IdxBuffer.Data[0])) { @@ -274,24 +277,26 @@ void GuiView::UpdateRenderable() { int drawable_index = 0; for (int n = 0; n < commands->CmdListsCount; ++n) { const ImDrawList* cmds = commands->CmdLists[n]; - auto vfill = [&](std::byte* dst, std::size_t size) { - if (size != cmds->VtxBuffer.size_in_bytes()) { - mju_error("Invalid vertex buffer size."); - } - std::memcpy(dst, cmds->VtxBuffer.Data, size); - }; - auto ifill = [&](std::byte* dst, std::size_t size) { - if (size != cmds->IdxBuffer.size_in_bytes()) { - mju_error("Invalid index buffer size."); - } - std::memcpy(dst, cmds->IdxBuffer.Data, size); - }; - filament::IndexBuffer* index_buffer = - CreateIndexBuffer(engine_, cmds->IdxBuffer.Size, ifill); - filament::VertexBuffer* vertex_buffer = - CreateVertexBuffer(engine_, cmds->VtxBuffer.Size, vfill); - meshes_.push_back(std::make_unique(engine_, index_buffer, vertex_buffer)); + MeshData data; + DefaultMeshData(&data); + data.nattributes = 3; + data.attributes[0].usage = mjVERTEX_ATTRIBUTE_POSITION; + data.attributes[0].type = mjVERTEX_ATTRIBUTE_TYPE_FLOAT2; + data.attributes[0].bytes = cmds->VtxBuffer.Data; + data.attributes[1].usage = mjVERTEX_ATTRIBUTE_UV; + data.attributes[1].type = mjVERTEX_ATTRIBUTE_TYPE_FLOAT2; + data.attributes[1].bytes = cmds->VtxBuffer.Data + sizeof(float) * 2; + data.attributes[2].usage = mjVERTEX_ATTRIBUTE_COLOR; + data.attributes[2].type = mjVERTEX_ATTRIBUTE_TYPE_UBYTE4; + data.attributes[2].bytes = cmds->VtxBuffer.Data + sizeof(float) * 4; + data.interleaved = true; + data.nvertices = cmds->VtxBuffer.Size; + data.nindices = cmds->IdxBuffer.Size; + data.indices = cmds->IdxBuffer.Data; + data.index_type = mjINDEX_TYPE_USHORT; + data.primitive_type = mjPRIM_TYPE_TRIANGLES; + meshes_.push_back(std::make_unique(engine_, data)); const auto& mesh = meshes_.back(); int index_offset = 0; diff --git a/src/experimental/filament/filament/model_objects.cc b/src/experimental/filament/filament/model_objects.cc index 7f8a438c..3f638695 100644 --- a/src/experimental/filament/filament/model_objects.cc +++ b/src/experimental/filament/filament/model_objects.cc @@ -87,19 +87,16 @@ void ModelObjects::UploadMesh(const mjModel* model, int id) { meshes_.erase(id); convex_hulls_.erase(id); - filament::Box bounds; - auto vertex_buffer = - CreateVertexBuffer(engine_, model, id, MeshType::kNormal, &bounds); - auto index_buffer = CreateIndexBuffer(engine_, model, id, MeshType::kNormal); - meshes_[id] = - std::make_unique(engine_, index_buffer, vertex_buffer, bounds); + MeshData data; + DefaultMeshData(&data); + UpdateMeshData(&data, model, id, MeshType::kNormal); + meshes_[id] = std::make_unique(engine_, data); if (model->mesh_graphadr[id] >= 0) { - vertex_buffer = - CreateVertexBuffer(engine_, model, id, MeshType::kConvexHull, &bounds); - index_buffer = CreateIndexBuffer(engine_, model, id, MeshType::kConvexHull); - convex_hulls_[id] = - std::make_unique(engine_, index_buffer, vertex_buffer, bounds); + MeshData convex_hull_data; + DefaultMeshData(&convex_hull_data); + UpdateMeshData(&convex_hull_data, model, id, MeshType::kConvexHull); + convex_hulls_[id] = std::make_unique(engine_, convex_hull_data); } } @@ -160,13 +157,10 @@ void ModelObjects::UploadHeightField(const mjModel* model, int id) { height_fields_.erase(id); - filament::Box bounds; - auto vertex_buffer = - CreateVertexBuffer(engine_, model, id, MeshType::kHeightField, &bounds); - auto index_buffer = - CreateIndexBuffer(engine_, model, id, MeshType::kHeightField); - height_fields_[id] = - std::make_unique(engine_, index_buffer, vertex_buffer, bounds); + MeshData data; + DefaultMeshData(&data); + UpdateMeshData(&data, model, id, MeshType::kHeightField); + height_fields_[id] = std::make_unique(engine_, data); } const Mesh* ModelObjects::GetMeshBuffer(int data_id) const { diff --git a/src/experimental/filament/filament/model_util.cc b/src/experimental/filament/filament/model_util.cc index 2bd581dd..26ecfaac 100644 --- a/src/experimental/filament/filament/model_util.cc +++ b/src/experimental/filament/filament/model_util.cc @@ -16,15 +16,11 @@ #include #include -#include #include #include +#include -#include -#include -#include -#include -#include +#include #include #include #include @@ -40,6 +36,30 @@ using filament::math::float2; using filament::math::float3; using filament::math::float4; +struct MeshBuilder { + MeshBuilder(int nvertices) : nvertices(nvertices) { + positions.reserve(nvertices); + orientations.reserve(nvertices); + uvs.reserve(nvertices); + } + + void Append(const float3& position, const float4& orientation, + const float2& uv) { + positions.push_back(position); + orientations.push_back(orientation); + uvs.push_back(uv); + bounds_min = min(bounds_min, position); + bounds_max = max(bounds_max, position); + } + + int nvertices = 0; + float3 bounds_min = {FLT_MAX, FLT_MAX, FLT_MAX}; + float3 bounds_max = {-FLT_MAX, -FLT_MAX, -FLT_MAX}; + std::vector positions; + std::vector orientations; + std::vector uvs; +}; + static bool UseFaceNormal(const float3& face_normal, const float3& mesh_normal) { // clang-format off @@ -49,74 +69,42 @@ static bool UseFaceNormal(const float3& face_normal, // clang-format on } -static void UpdateBounds(const float3& v, float3* vmin, float3* vmax) { - vmin->x = std::min(vmin->x, v.x); - vmin->y = std::min(vmin->y, v.y); - vmin->z = std::min(vmin->z, v.z); - vmax->x = std::max(vmax->x, v.x); - vmax->y = std::max(vmax->y, v.y); - vmax->z = std::max(vmax->z, v.z); -} -template -static void FillConvexHullBuffer(T* ptr, std::size_t num, const mjModel* model, - int meshid, float3* vmin, float3* vmax) { +static void FillConvexHullBuffer(MeshBuilder& builder, const mjModel* model, + int meshid) { const int numvert = model->mesh_graph[model->mesh_graphadr[meshid]]; const int numface = model->mesh_graph[model->mesh_graphadr[meshid] + 1]; - - const int vertadr = model->mesh_vertadr[meshid]; - const float* vertices = model->mesh_vert + (3 * vertadr); - const int texcoordadr = model->mesh_texcoordadr[meshid]; - const float* texcoords = model->mesh_texcoord + (2 * texcoordadr); - - if (num != numface * 3) { - mju_error("Invalid vertex count."); + if (builder.nvertices != numface * 3) { + mju_error("Invalid vertex count (%d vs %d).", builder.nvertices, numface * 3); return; } - for (int face = 0; face < numface; ++face) { - int j = - model->mesh_graphadr[meshid] + 2 + 3 * numvert + 3 * numface + 3 * face; + const int dataadr = model->mesh_graphadr[meshid] + 2; + const int vertadr = model->mesh_vertadr[meshid]; + const float* vertices = model->mesh_vert + (3 * vertadr); + const int texcoordadr = model->mesh_texcoordadr[meshid]; + const float* texcoords = texcoordadr >= 0 ? model->mesh_texcoord + (2 * texcoordadr) : nullptr; + for (int face = 0; face < numface; ++face) { + const int j = dataadr + (3 * numvert) + (3 * numface) + (3 * face); const float3 p1 = ReadFloat3(vertices, model->mesh_graph[j + 0]); const float3 p2 = ReadFloat3(vertices, model->mesh_graph[j + 1]); const float3 p3 = ReadFloat3(vertices, model->mesh_graph[j + 2]); const float4 orientation = CalculateOrientation(p1, p2, p3); - - UpdateBounds(p1, vmin, vmax); - UpdateBounds(p2, vmin, vmax); - UpdateBounds(p3, vmin, vmax); - - ptr->position = p1; - ptr->orientation = orientation; - if constexpr (T::kHasUv) { - ptr->uv = ReadFloat2(texcoords, model->mesh_graph[j + 0]); - } - ++ptr; - - ptr->position = p2; - ptr->orientation = orientation; - if constexpr (T::kHasUv) { - ptr->uv = ReadFloat2(texcoords, model->mesh_graph[j + 1]); - } - ++ptr; - - ptr->position = p3; - ptr->orientation = orientation; - if constexpr (T::kHasUv) { - ptr->uv = ReadFloat2(texcoords, model->mesh_graph[j + 2]); - } - ++ptr; + const float2 uv1 = texcoords ? ReadFloat2(texcoords, model->mesh_graph[j + 0]) : float2(0, 0); + const float2 uv2 = texcoords ? ReadFloat2(texcoords, model->mesh_graph[j + 1]) : float2(0, 0); + const float2 uv3 = texcoords ? ReadFloat2(texcoords, model->mesh_graph[j + 2]) : float2(0, 0); + builder.Append(p1, orientation, uv1); + builder.Append(p2, orientation, uv2); + builder.Append(p3, orientation, uv3); } } -template -static void FillMeshBuffer(T* ptr, std::size_t num, const mjModel* model, - int meshid, float3* vmin, float3* vmax) { +static void FillMeshBuffer(MeshBuilder& builder, const mjModel* model, int meshid) { const int faceadr = model->mesh_faceadr[meshid]; const int facenum = model->mesh_facenum[meshid]; - if (num != facenum * 3) { - mju_error("Invalid vertex count."); + if (builder.nvertices != facenum * 3) { + mju_error("Invalid vertex count (%d vs %d).", builder.nvertices, facenum * 3); return; } @@ -125,7 +113,7 @@ static void FillMeshBuffer(T* ptr, std::size_t num, const mjModel* model, const int normaladr = model->mesh_normaladr[meshid]; const float* normals = model->mesh_normal + 3 * normaladr; const int texcoordadr = model->mesh_texcoordadr[meshid]; - const float* texcoords = model->mesh_texcoord + (2 * texcoordadr); + const float* texcoords = texcoordadr >= 0 ? model->mesh_texcoord + (2 * texcoordadr) : nullptr; for (int i = 0; i < facenum; ++i) { const int face = 3 * (faceadr + i); @@ -133,70 +121,41 @@ static void FillMeshBuffer(T* ptr, std::size_t num, const mjModel* model, const float3 p1 = ReadFloat3(vertices, model->mesh_face[face + 0]); const float3 p2 = ReadFloat3(vertices, model->mesh_face[face + 1]); const float3 p3 = ReadFloat3(vertices, model->mesh_face[face + 2]); - - UpdateBounds(p1, vmin, vmax); - UpdateBounds(p2, vmin, vmax); - UpdateBounds(p3, vmin, vmax); - const float3 face_normal = CalculateNormal(p1, p2, p3); const float3 n1 = ReadFloat3(normals, model->mesh_facenormal[face + 0]); const float3 n2 = ReadFloat3(normals, model->mesh_facenormal[face + 1]); const float3 n3 = ReadFloat3(normals, model->mesh_facenormal[face + 2]); + const float2 uv1 = texcoords ? ReadFloat2(texcoords, model->mesh_facetexcoord[face + 0]) : float2(0, 0); + const float2 uv2 = texcoords ? ReadFloat2(texcoords, model->mesh_facetexcoord[face + 1]) : float2(0, 0); + const float2 uv3 = texcoords ? ReadFloat2(texcoords, model->mesh_facetexcoord[face + 2]) : float2(0, 0); - ptr->position = p1; - if constexpr (T::kHasUv) { - ptr->orientation = CalculateOrientation(n1); - ptr->uv = ReadFloat2(texcoords, model->mesh_facetexcoord[face + 0]); - } else if (UseFaceNormal(face_normal, n1)) { - ptr->orientation = CalculateOrientation(face_normal); + if (UseFaceNormal(face_normal, n1)) { + builder.Append(p1, CalculateOrientation(face_normal), uv1); } else { - ptr->orientation = CalculateOrientation(n1); + builder.Append(p1, CalculateOrientation(n1), uv1); } - ++ptr; - ptr->position = p2; - if constexpr (T::kHasUv) { - ptr->orientation = CalculateOrientation(n2); - ptr->uv = ReadFloat2(texcoords, model->mesh_facetexcoord[face + 1]); - } else if (UseFaceNormal(face_normal, n2)) { - ptr->orientation = CalculateOrientation(face_normal); + if (UseFaceNormal(face_normal, n2)) { + builder.Append(p2, CalculateOrientation(face_normal), uv2); } else { - ptr->orientation = CalculateOrientation(n2); + builder.Append(p2, CalculateOrientation(n2), uv2); } - ++ptr; - ptr->position = p3; - if constexpr (T::kHasUv) { - ptr->orientation = CalculateOrientation(n3); - ptr->uv = ReadFloat2(texcoords, model->mesh_facetexcoord[face + 2]); - } else if (UseFaceNormal(face_normal, n3)) { - ptr->orientation = CalculateOrientation(face_normal); + if (UseFaceNormal(face_normal, n3)) { + builder.Append(p3, CalculateOrientation(face_normal), uv3); } else { - ptr->orientation = CalculateOrientation(n3); + builder.Append(p3, CalculateOrientation(n3), uv3); } - ++ptr; } } -static void FillHeightFieldBuffer(VertexNoUv* ptr, std::size_t num, - const mjModel* model, int hfieldid, - float3* vmin, float3* vmax) { - int count = 0; +static void FillHeightFieldBuffer(MeshBuilder& builder, const mjModel* model, + int hfieldid) { auto append_tri = [&](float3 a, float3 b, float3 c) { float4 orientation = CalculateOrientation(a, b, c); - ptr[count].position = a; - ptr[count].orientation = orientation; - ++count; - ptr[count].position = b; - ptr[count].orientation = orientation; - ++count; - ptr[count].position = c; - ptr[count].orientation = orientation; - ++count; - - UpdateBounds(a, vmin, vmax); - UpdateBounds(b, vmin, vmax); - UpdateBounds(c, vmin, vmax); + builder.Append(a, orientation, float2(0, 0)); + builder.Append(b, orientation, float2(0, 0)); + builder.Append(c, orientation, float2(0, 0)); }; auto append_quad = [&](float3 a, float3 b, float3 c, float3 d) { append_tri(a, b, d); @@ -314,9 +273,6 @@ static void FillHeightFieldBuffer(VertexNoUv* ptr, std::size_t num, {x1, y0, -sz[3]}); } } - if (count != num) { - mju_error("Vertex count mismatch."); - } } static int CalculateHeightFieldVertexCount(const mjModel* model, int hfieldid) { @@ -340,149 +296,85 @@ static int CalculateHeightFieldVertexCount(const mjModel* model, int hfieldid) { return total_count; } -template -static filament::VertexBuffer* CreateVertexBuffer(filament::Engine* engine, - const mjModel* model, int id, - int vertex_count, - FillFn fill_fn, - filament::Box* bounds) { - float3 vmin = {FLT_MAX, FLT_MAX, FLT_MAX}; - float3 vmax = {-FLT_MAX, -FLT_MAX, -FLT_MAX}; - filament::VertexBuffer* buffer = CreateVertexBuffer( - engine, vertex_count, [&](std::byte* buffer, std::size_t num_bytes) { - auto* ptr = reinterpret_cast(buffer); - fill_fn(ptr, num_bytes / sizeof(T), model, id, &vmin, &vmax); - }); - bounds->set(vmin, vmax); - return buffer; +static bool HasUvs(const mjModel* model, int id, MeshType mesh_type) { + return mesh_type != MeshType::kHeightField && + model->mesh_texcoordadr[id] >= 0; } -filament::VertexBuffer* CreateVertexBuffer(filament::Engine* engine, - const mjModel* model, int id, - MeshType mesh_type, - filament::Box* bounds) { - if (id < 0) { - mju_error("Invalid mesh index %d", id); - return nullptr; - } - - int vertex_count = 0; +static bool IsValidIndex(const mjModel* model, int id, MeshType mesh_type) { switch (mesh_type) { case MeshType::kNormal: - if (id >= model->nmesh) { - mju_error("Invalid mesh index %d", id); - return nullptr; - } - vertex_count = 3 * model->mesh_facenum[id]; - break; + return id >= 0 && id < model->nmesh; case MeshType::kConvexHull: - if (id >= model->nmesh) { - mju_error("Invalid mesh index %d", id); - return nullptr; - } - vertex_count = 3 * model->mesh_graph[model->mesh_graphadr[id] + 1]; - break; + return id >= 0 && id < model->nmesh; case MeshType::kHeightField: - if (id >= model->nhfield) { - mju_error("Invalid height field index %d", id); - return nullptr; - } - vertex_count = CalculateHeightFieldVertexCount(model, id); - break; + return id >= 0 && id < model->nhfield; } - - if (vertex_count == 0) { - mju_error("Vertex count is zero."); - return nullptr; - } - - const bool has_texcoords = mesh_type == MeshType::kHeightField - ? false - : model->mesh_texcoordadr[id] >= 0; - if (has_texcoords) { - using VertexType = VertexWithUv; - switch (mesh_type) { - case MeshType::kNormal: - return CreateVertexBuffer(engine, model, id, vertex_count, - FillMeshBuffer, - bounds); - break; - case MeshType::kConvexHull: - return CreateVertexBuffer(engine, model, id, vertex_count, - FillConvexHullBuffer, - bounds); - break; - case MeshType::kHeightField: - mju_error("Height fields do not support UV coordinates."); - return nullptr; - } - } else { - using VertexType = VertexNoUv; - switch (mesh_type) { - case MeshType::kNormal: - return CreateVertexBuffer(engine, model, id, vertex_count, - FillMeshBuffer, - bounds); - break; - case MeshType::kConvexHull: - return CreateVertexBuffer(engine, model, id, vertex_count, - FillConvexHullBuffer, - bounds); - break; - case MeshType::kHeightField: - return CreateVertexBuffer(engine, model, id, vertex_count, - FillHeightFieldBuffer, bounds); - break; - } - } - - return nullptr; } -filament::IndexBuffer* CreateIndexBuffer(filament::Engine* engine, - const mjModel* model, int id, - MeshType mesh_type) { - if (id < 0) { - mju_error("Invalid index %d", id); - return nullptr; - } - - int index_count = 0; +static int GetNumVertices(const mjModel* model, int id, MeshType mesh_type) { switch (mesh_type) { case MeshType::kNormal: - if (id >= model->nmesh) { - mju_error("Invalid mesh index %d", id); - return nullptr; - } - index_count = 3 * model->mesh_facenum[id]; + return 3 * model->mesh_facenum[id]; + case MeshType::kConvexHull: + return 3 * model->mesh_graph[model->mesh_graphadr[id] + 1]; + case MeshType::kHeightField: + return CalculateHeightFieldVertexCount(model, id); + } +} + +void UpdateMeshData(MeshData* data, const mjModel* model, int id, + MeshType mesh_type) { + if (!IsValidIndex(model, id, mesh_type)) { + mju_error("Invalid index %d for type %d", id, mesh_type); + return; + } + + const int num_vertices = GetNumVertices(model, id, mesh_type); + const bool has_uvs = HasUvs(model, id, mesh_type); + + MeshBuilder* builder = new MeshBuilder(num_vertices); + data->user_data = builder; + data->release_callback = [](void* user_data) { + delete static_cast(user_data); + }; + + switch (mesh_type) { + case MeshType::kNormal: + FillMeshBuffer(*builder, model, id); break; case MeshType::kConvexHull: - if (id >= model->nmesh) { - mju_error("Invalid mesh index %d", id); - return nullptr; - } - index_count = 3 * model->mesh_graph[model->mesh_graphadr[id] + 1]; + FillConvexHullBuffer(*builder, model, id); break; case MeshType::kHeightField: - if (id >= model->nhfield) { - mju_error("Invalid height field index %d", id); - return nullptr; - } - index_count = CalculateHeightFieldVertexCount(model, id); + FillHeightFieldBuffer(*builder, model, id); break; } - if (index_count == 0) { - mju_error("Index count is zero."); - return nullptr; - } - - if (index_count >= std::numeric_limits::max()) { - return CreateIndexBuffer(engine, index_count, - FillSequence); - } else { - return CreateIndexBuffer(engine, index_count, - FillSequence); + data->primitive_type = mjPRIM_TYPE_TRIANGLES; + data->nvertices = num_vertices; + data->nindices = data->nvertices; + data->indices = nullptr; + data->index_type = data->nvertices >= std::numeric_limits::max() + ? mjINDEX_TYPE_UINT + : mjINDEX_TYPE_USHORT; + data->nattributes = has_uvs ? 3 : 2; + data->attributes[0].usage = mjVERTEX_ATTRIBUTE_POSITION; + data->attributes[0].type = mjVERTEX_ATTRIBUTE_TYPE_FLOAT3; + data->attributes[0].bytes = builder->positions.data(); + data->attributes[1].usage = mjVERTEX_ATTRIBUTE_TANGENTS; + data->attributes[1].type = mjVERTEX_ATTRIBUTE_TYPE_FLOAT4; + data->attributes[1].bytes = builder->orientations.data(); + if (has_uvs) { + data->attributes[2].usage = mjVERTEX_ATTRIBUTE_UV; + data->attributes[2].type = mjVERTEX_ATTRIBUTE_TYPE_FLOAT2; + data->attributes[2].bytes = builder->uvs.data(); } + data->bounds_min[0] = builder->bounds_min.x; + data->bounds_min[1] = builder->bounds_min.y; + data->bounds_min[2] = builder->bounds_min.z; + data->bounds_max[0] = builder->bounds_max.x; + data->bounds_max[1] = builder->bounds_max.y; + data->bounds_max[2] = builder->bounds_max.z; } } // namespace mujoco diff --git a/src/experimental/filament/filament/model_util.h b/src/experimental/filament/filament/model_util.h index edf14fed..4ca36c86 100644 --- a/src/experimental/filament/filament/model_util.h +++ b/src/experimental/filament/filament/model_util.h @@ -17,16 +17,12 @@ #include -#include -#include -#include -#include -#include #include #include #include #include #include +#include "experimental/filament/filament/buffer_util.h" namespace mujoco { @@ -37,16 +33,9 @@ enum class MeshType { kHeightField, }; -// Generates a filament VertexBuffer for a given mesh in the mjModel. -filament::VertexBuffer* CreateVertexBuffer(filament::Engine* engine, - const mjModel* model, int id, - MeshType mesh_type, - filament::Box* bounds); - -// Generates a filament IndexBuffer for a given mesh in the mjModel. -filament::IndexBuffer* CreateIndexBuffer(filament::Engine* engine, - const mjModel* model, int id, - MeshType mesh_type); +// Populates the given MeshData with data for the element in the model. +void UpdateMeshData(MeshData* data, const mjModel* model, int id, + MeshType mesh_type); // Reads a value with the given name from the mjModel's data sections. The // default_value is returned if the named element is not found. diff --git a/src/experimental/filament/filament/renderables.cc b/src/experimental/filament/filament/renderables.cc index 5be61556..f8cbab1c 100644 --- a/src/experimental/filament/filament/renderables.cc +++ b/src/experimental/filament/filament/renderables.cc @@ -73,13 +73,13 @@ void Renderables::Update(int index, MeshPtr mesh) { void Renderables::Append(const Mesh* mesh) { utils::Entity entity = CreateEntity(mesh); entities_.push_back(entity); - meshes_.emplace_back(nullptr, mesh); + meshes_.push_back({nullptr, mesh}); } void Renderables::Append(MeshPtr mesh) { utils::Entity entity = CreateEntity(mesh.get()); entities_.push_back(entity); - meshes_.emplace_back(std::move(mesh), mesh.get()); + meshes_.push_back({std::move(mesh), mesh.get()}); } utils::Entity Renderables::CreateEntity(const Mesh* mesh) { diff --git a/src/experimental/filament/filament/vertex_util.h b/src/experimental/filament/filament/vertex_util.h index f31c5e62..e8bd7919 100644 --- a/src/experimental/filament/filament/vertex_util.h +++ b/src/experimental/filament/filament/vertex_util.h @@ -15,7 +15,6 @@ #ifndef MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_VERTEX_UTIL_H_ #define MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_VERTEX_UTIL_H_ -#include #include #include @@ -37,59 +36,6 @@ filament::math::float4 CalculateOrientation( const filament::math::float3& p2, const filament::math::float3& p3); -// A standard vertex with no UV coordinates. -struct VertexNoUv { - VertexNoUv() = default; - VertexNoUv(filament::math::float3 position, - filament::math::float4 orientation) - : position(position), orientation(orientation) {} - - filament::math::float3 position; - filament::math::float4 orientation; - - static constexpr bool kHasPosition = true; - static constexpr bool kHasPosition2d = false; - static constexpr bool kHasOrientation = true; - static constexpr bool kHasUv = false; - static constexpr bool kHasColor = false; -}; - -// A standard vertex with UV coordinates. -struct VertexWithUv { - VertexWithUv() = default; - VertexWithUv(filament::math::float3 position, - filament::math::float4 orientation, filament::math::float2 uv) - : position(position), orientation(orientation), uv(uv) {} - - filament::math::float3 position; - filament::math::float4 orientation; - filament::math::float2 uv; - - static constexpr bool kHasPosition = true; - static constexpr bool kHasPosition2d = false; - static constexpr bool kHasOrientation = true; - static constexpr bool kHasUv = true; - static constexpr bool kHasColor = false; -}; - -// A vertex for rendering GUI elements. -struct GuiVertex { - GuiVertex() = default; - GuiVertex(filament::math::float2 position, filament::math::float2 uv, - filament::math::ubyte4 color) - : position(position), uv(uv), color(color) {} - - filament::math::float2 position; - filament::math::float2 uv; - filament::math::ubyte4 color; - - static constexpr bool kHasPosition = false; - static constexpr bool kHasPosition2d = true; - static constexpr bool kHasOrientation = false; - static constexpr bool kHasUv = true; - static constexpr bool kHasColor = true; -}; - } // namespace mujoco #endif // MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_VERTEX_UTIL_H_