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_