Rename FilamentBuffers class to Mesh.

Update the Mesh class so that it manages the lifetime of the
vertex and index buffers.

PiperOrigin-RevId: 895794022
Change-Id: I5eda578b8b7ed7f918e792f6181ec724729b5215
This commit is contained in:
Haroon Qureshi
2026-04-07 03:24:09 -07:00
committed by Copybara-Service
parent 6de35648d1
commit 28d8ddcbeb
12 changed files with 238 additions and 221 deletions
@@ -18,6 +18,7 @@
#include <cstddef>
#include <cstdint>
#include <functional>
#include <memory>
#include <optional>
#include <type_traits>
#include <backend/BufferDescriptor.h>
@@ -30,15 +31,59 @@
// Functions for creating filament vertex and index buffers.
namespace mujoco {
// Simple tuple-type of a IndexBuffer+VertexBuffer.
struct FilamentBuffers {
filament::IndexBuffer* index_buffer = nullptr;
filament::VertexBuffer* vertex_buffer = nullptr;
std::optional<filament::Box> bounds = std::nullopt;
filament::RenderableManager::PrimitiveType type =
// Owns a Vertex and Index buffer representing a geometry mesh.
class Mesh {
public:
Mesh(filament::Engine* engine, filament::IndexBuffer* index_buffer,
filament::VertexBuffer* vertex_buffer,
std::optional<filament::Box> 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() {
if (index_buffer_) {
engine_->destroy(index_buffer_);
}
if (vertex_buffer_) {
engine_->destroy(vertex_buffer_);
}
}
filament::IndexBuffer* GetFilamentIndexBuffer() const {
return index_buffer_;
}
filament::VertexBuffer* GetFilamentVertexBuffer() const {
return vertex_buffer_;
}
filament::RenderableManager::PrimitiveType GetPrimitiveType() const {
return type_;
}
bool HasBounds() const {
return bounds_.has_value();
}
filament::Box GetBounds() const {
return bounds_.value();
}
Mesh(const Mesh&) = delete;
Mesh& operator=(const Mesh&) = delete;
private:
filament::Engine* engine_ = nullptr;
filament::IndexBuffer* index_buffer_ = nullptr;
filament::VertexBuffer* vertex_buffer_ = nullptr;
filament::RenderableManager::PrimitiveType type_ =
filament::RenderableManager::PrimitiveType::TRIANGLES;
std::optional<filament::Box> bounds_;
};
using MeshPtr = std::unique_ptr<Mesh>;
// Function that fills in the given buffer with actual data.
using FillBufferFn = std::function<void(std::byte*, std::size_t)>;
+44 -43
View File
@@ -17,6 +17,7 @@
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <numbers>
#include <filament/Box.h>
@@ -422,8 +423,8 @@ class ConeBuilder {
int idx = 0;
for (int j = 0; j < num_slices_; ++j) {
const float angle1 = (j+0) * delta_angle;
const float angle2 = (j+1) * delta_angle;
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);
@@ -436,12 +437,12 @@ class ConeBuilder {
// the rest: use quads
for (int i = 1; i < num_stacks_; ++i) {
const float radius1 = delta_radius * (i+0);
const float radius2 = delta_radius * (i+1);
const float radius1 = delta_radius * (i + 0);
const float radius2 = delta_radius * (i + 1);
for (int j = 0; j < num_slices_; ++j) {
const float angle1 = (j+0) * delta_angle;
const float angle2 = (j+1) * delta_angle;
const float angle1 = (j + 0) * delta_angle;
const float angle2 = (j + 1) * delta_angle;
ptr[idx++] = MakeVert(angle1, radius2);
ptr[idx++] = MakeVert(angle2, radius2);
@@ -676,34 +677,34 @@ class DomeBuilder {
(num_quads_body * kNumIndicesPerQuad);
}
void GenerateVertices(VertexType* ptr, size_t num) const {
const float lat_angle_delta =
0.5 * std::numbers::pi / static_cast<float>(num_stacks_);
const float lon_angle_delta =
2.0 * std::numbers::pi / static_cast<float>(num_slices_);
void GenerateVertices(VertexType* ptr, size_t num) const {
const float lat_angle_delta =
0.5 * std::numbers::pi / static_cast<float>(num_stacks_);
const float lon_angle_delta =
2.0 * std::numbers::pi / static_cast<float>(num_slices_);
// Add the pole.
int idx = 0;
ptr[idx++] = MakeVert(0, 0, 1);
// Add the pole.
int idx = 0;
ptr[idx++] = MakeVert(0, 0, 1);
// Vertices by latitude.
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<float>(lat + 1) * lat_angle_delta;
const float cos_lat_angle = std::cos(lat_angle);
const float sin_lat_angle = std::sin(lat_angle);
const float z = cos_lat_angle;
// Vertices by latitude.
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<float>(lat + 1) * lat_angle_delta;
const float cos_lat_angle = std::cos(lat_angle);
const float sin_lat_angle = std::sin(lat_angle);
const float z = cos_lat_angle;
for (int lon = 0; lon < num_slices_; ++lon) {
const float lon_angle = static_cast<float>(lon) * lon_angle_delta;
const float cos_lon_angle = std::cos(lon_angle);
const float sin_lon_angle = std::sin(lon_angle);
for (int lon = 0; lon < num_slices_; ++lon) {
const float lon_angle = static_cast<float>(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);
}
const float x = sin_lat_angle * cos_lon_angle;
const float y = sin_lat_angle * sin_lon_angle;
ptr[idx++] = MakeVert(x, y, z);
}
}
}
@@ -756,9 +757,8 @@ class DomeBuilder {
int num_slices_;
};
template <typename T>
FilamentBuffers CreateFromBuilder(filament::Engine* engine, const T& builder) {
MeshPtr CreateFromBuilder(filament::Engine* engine, const T& builder) {
using VertexType = typename T::VertexType;
using IndexType = typename T::IndexType;
@@ -786,46 +786,47 @@ FilamentBuffers CreateFromBuilder(filament::Engine* engine, const T& builder) {
auto vb = CreateVertexBuffer<VertexType>(engine, num_vertices, vertices);
auto ib = CreateIndexBuffer<IndexType>(engine, num_indices, indices);
return {ib, vb, builder.GetBounds(), T::kPrimitiveType};
return std::make_unique<Mesh>(engine, ib, vb, builder.GetBounds(),
T::kPrimitiveType);
}
FilamentBuffers CreateLine(filament::Engine* engine) {
MeshPtr CreateLine(filament::Engine* engine) {
return CreateFromBuilder(engine, LineBuilder());
}
FilamentBuffers CreatePlane(filament::Engine* engine, int nquad) {
MeshPtr CreatePlane(filament::Engine* engine, int nquad) {
return CreateFromBuilder(engine, PlaneBuilder(nquad));
}
FilamentBuffers CreateTriangle(filament::Engine* engine) {
MeshPtr CreateTriangle(filament::Engine* engine) {
return CreateFromBuilder(engine, TriangleBuilder());
}
FilamentBuffers CreateBox(filament::Engine* engine, int nquad) {
MeshPtr CreateBox(filament::Engine* engine, int nquad) {
return CreateFromBuilder(engine, BoxBuilder(nquad));
}
FilamentBuffers CreateLineBox(filament::Engine* engine) {
MeshPtr CreateLineBox(filament::Engine* engine) {
return CreateFromBuilder(engine, LineBoxBuilder());
}
FilamentBuffers CreateSphere(filament::Engine* engine, int nstack, int nslice) {
MeshPtr CreateSphere(filament::Engine* engine, int nstack, int nslice) {
return CreateFromBuilder(engine, SphereBuilder(nstack, nslice));
}
FilamentBuffers CreateTube(filament::Engine* engine, int nstack, int nslice) {
MeshPtr CreateTube(filament::Engine* engine, int nstack, int nslice) {
return CreateFromBuilder(engine, TubeBuilder(nstack, nslice));
}
FilamentBuffers CreateDisk(filament::Engine* engine, int nslice) {
MeshPtr CreateDisk(filament::Engine* engine, int nslice) {
return CreateFromBuilder(engine, DiskBuilder(nslice));
}
FilamentBuffers CreateDome(filament::Engine* engine, int nstack, int nslice) {
MeshPtr CreateDome(filament::Engine* engine, int nstack, int nslice) {
return CreateFromBuilder(engine, DomeBuilder(nstack, nslice));
}
FilamentBuffers CreateCone(filament::Engine* engine, int nstack, int nslice) {
MeshPtr CreateCone(filament::Engine* engine, int nstack, int nslice) {
return CreateFromBuilder(engine, ConeBuilder(nstack, nslice));
}
+10 -10
View File
@@ -21,16 +21,16 @@
// Generates buffers for built-in shapes.
namespace mujoco {
FilamentBuffers CreateLine(filament::Engine* engine);
FilamentBuffers CreatePlane(filament::Engine* engine, int nquad);
FilamentBuffers CreateTriangle(filament::Engine* engine);
FilamentBuffers CreateBox(filament::Engine* engine, int nquad);
FilamentBuffers CreateLineBox(filament::Engine* engine);
FilamentBuffers CreateSphere(filament::Engine* engine, int nstack, int nslice);
FilamentBuffers CreateTube(filament::Engine* engine, int nstack, int nslice);
FilamentBuffers CreateDisk(filament::Engine* engine, int nslice);
FilamentBuffers CreateDome(filament::Engine* engine, int nstack, int nslice);
FilamentBuffers CreateCone(filament::Engine* engine, int nstack, int nslice);
MeshPtr CreateLine(filament::Engine* engine);
MeshPtr CreatePlane(filament::Engine* engine, int nquad);
MeshPtr CreateTriangle(filament::Engine* engine);
MeshPtr CreateBox(filament::Engine* engine, int nquad);
MeshPtr CreateLineBox(filament::Engine* engine);
MeshPtr CreateSphere(filament::Engine* engine, int nstack, int nslice);
MeshPtr CreateTube(filament::Engine* engine, int nstack, int nslice);
MeshPtr CreateDisk(filament::Engine* engine, int nslice);
MeshPtr CreateDome(filament::Engine* engine, int nstack, int nslice);
MeshPtr CreateCone(filament::Engine* engine, int nstack, int nslice);
} // namespace mujoco
+10 -9
View File
@@ -16,6 +16,7 @@
#include <cmath>
#include <cstdint>
#include <memory>
#include <numbers>
#include <utility>
@@ -173,12 +174,12 @@ void Drawable::Update(const mjModel* model, const mjvScene* scene,
if (geom.type == mjGEOM_FLEX || geom.type == mjGEOM_SKIN) {
// Flex geometry is updated every frame with new vertex data.
filament::Engine* engine = renderables_.GetEngine();
FilamentBuffers buffers = CreateGeomBuffers(engine, model, scene, geom);
std::unique_ptr<Mesh> mesh = CreateGeomBuffers(engine, model, scene, geom);
if (renderables_.GetNumEntities() == 0) {
renderables_.Append(std::move(buffers));
renderables_.Append(std::move(mesh));
} else {
renderables_.Update(0, std::move(buffers));
renderables_.Update(0, std::move(mesh));
}
}
@@ -192,27 +193,27 @@ void Drawable::Update(const mjModel* model, const mjvScene* scene,
}
void Drawable::AddMesh(int data_id) {
const FilamentBuffers* buffers = model_objs_->GetMeshBuffer(data_id);
const Mesh* buffers = model_objs_->GetMeshBuffer(data_id);
if (buffers == nullptr) {
mju_error("Unknown mesh %d", data_id);
}
renderables_.Append(*buffers);
renderables_.Append(buffers);
}
void Drawable::AddHeightField(int hfield_id) {
const FilamentBuffers* buffers = model_objs_->GetHeightFieldBuffer(hfield_id);
const Mesh* buffers = model_objs_->GetHeightFieldBuffer(hfield_id);
if (buffers == nullptr) {
mju_error("Unknown height field %d", hfield_id);
}
renderables_.Append(*buffers);
renderables_.Append(buffers);
}
void Drawable::AddShape(ModelObjects::ShapeType shape_type) {
const FilamentBuffers* buffers = model_objs_->GetShapeBuffer(shape_type);
const Mesh* buffers = model_objs_->GetShapeBuffer(shape_type);
if (buffers == nullptr) {
mju_error("Unknown shape %d", shape_type);
}
renderables_.Append(*buffers);
renderables_.Append(buffers);
}
void Drawable::AddToScene(filament::Scene* scene) {
@@ -18,8 +18,10 @@
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <memory>
#include <span>
#include <filament/Box.h>
#include <filament/Engine.h>
#include <filament/IndexBuffer.h>
#include <filament/VertexBuffer.h>
@@ -162,9 +164,8 @@ static filament::IndexBuffer* BuildIndexBuffer(filament::Engine* engine,
}
}
FilamentBuffers CreateGeomBuffers(filament::Engine* engine,
const mjModel* model, const mjvScene* scene,
const mjvGeom& geom) {
MeshPtr CreateGeomBuffers(filament::Engine* engine, const mjModel* model,
const mjvScene* scene, const mjvGeom& geom) {
auto positions = GetPositions(model, scene, geom);
auto normals = GetNormals(model, scene, geom);
auto uvs = GetUvs(model, scene, geom);
@@ -175,14 +176,13 @@ FilamentBuffers CreateGeomBuffers(filament::Engine* engine,
num_indices = 3 * scene->flexfaceused[geom.objid];
}
FilamentBuffers buffers;
float3 vmin = {FLT_MAX, FLT_MAX, FLT_MAX};
float3 vmax = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
buffers.vertex_buffer =
BuildVertexBuffer(engine, positions, normals, uvs, &vmin, &vmax);
buffers.index_buffer = BuildIndexBuffer(engine, indices, num_indices);
buffers.bounds.emplace().set(vmin, vmax);
return buffers;
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<Mesh>(engine, index_buffer, vertex_buffer, bounds);
}
} // namespace mujoco
@@ -22,9 +22,8 @@
namespace mujoco {
// Populates the FilamentBuffers for a flex geometry.
FilamentBuffers CreateGeomBuffers(filament::Engine* engine,
const mjModel* model, const mjvScene* scene,
const mjvGeom& geom);
MeshPtr CreateGeomBuffers(filament::Engine* engine, const mjModel* model,
const mjvScene* scene, const mjvGeom& geom);
} // namespace mujoco
+13 -22
View File
@@ -62,10 +62,7 @@ GuiView::~GuiView() {
}
auto& em = utils::EntityManager::get();
em.destroy(renderable_);
for (auto& buffer : buffers_) {
engine_->destroy(buffer.vertex_buffer);
engine_->destroy(buffer.index_buffer);
}
meshes_.clear();
for (auto& instance : instances_) {
engine_->destroy(instance);
}
@@ -84,12 +81,7 @@ void GuiView::ResetRenderable() {
em.destroy(renderable_);
renderable_ = utils::Entity();
}
for (auto& buffer : buffers_) {
engine_->destroy(buffer.vertex_buffer);
engine_->destroy(buffer.index_buffer);
}
buffers_.clear();
meshes_.clear();
}
uintptr_t GuiView::UploadImage(uintptr_t tex_id, const uint8_t* pixels,
@@ -275,12 +267,7 @@ void GuiView::UpdateRenderable() {
builder.build(*engine_, renderable_);
scene_->addEntity(renderable_);
}
for (auto& buffer : buffers_) {
engine_->destroy(buffer.vertex_buffer);
engine_->destroy(buffer.index_buffer);
}
buffers_.clear();
meshes_.clear();
auto ri = rm.getInstance(renderable_);
@@ -299,10 +286,13 @@ void GuiView::UpdateRenderable() {
}
std::memcpy(dst, cmds->IdxBuffer.Data, size);
};
buffers_.push_back(
{CreateIndexBuffer<uint16_t>(engine_, cmds->IdxBuffer.Size, ifill),
CreateVertexBuffer<GuiVertex>(engine_, cmds->VtxBuffer.Size, vfill)});
const mujoco::FilamentBuffers& buffer = buffers_.back();
filament::IndexBuffer* index_buffer =
CreateIndexBuffer<uint16_t>(engine_, cmds->IdxBuffer.Size, ifill);
filament::VertexBuffer* vertex_buffer =
CreateVertexBuffer<GuiVertex>(engine_, cmds->VtxBuffer.Size, vfill);
meshes_.push_back(std::make_unique<Mesh>(engine_, index_buffer, vertex_buffer));
const auto& mesh = meshes_.back();
int index_offset = 0;
for (const ImDrawCmd& command : cmds->CmdBuffer) {
@@ -327,8 +317,9 @@ void GuiView::UpdateRenderable() {
rm.setMaterialInstanceAt(
ri, drawable_index,
GetMaterialInstance(drawable_index, clip_rect, command.GetTexID()));
rm.setGeometryAt(ri, drawable_index, kTriangles, buffer.vertex_buffer,
buffer.index_buffer, index_offset, command.ElemCount);
rm.setGeometryAt(
ri, drawable_index, kTriangles, mesh->GetFilamentVertexBuffer(),
mesh->GetFilamentIndexBuffer(), index_offset, command.ElemCount);
rm.setBlendOrderAt(ri, drawable_index, drawable_index);
index_offset += command.ElemCount;
@@ -71,7 +71,7 @@ class GuiView {
filament::View* view_ = nullptr;
filament::Material* material_ = nullptr;
utils::Entity renderable_;
std::vector<FilamentBuffers> buffers_;
std::vector<MeshPtr> meshes_;
std::vector<filament::MaterialInstance*> instances_;
std::unordered_map<uintptr_t, std::unique_ptr<Texture>> textures_;
int num_elements_ = 0;
@@ -19,6 +19,7 @@
#include <utility>
#include <vector>
#include <filament/Box.h>
#include <filament/Engine.h>
#include <filament/IndirectLight.h>
#include <filament/Material.h>
@@ -29,7 +30,6 @@
#include "experimental/filament/filament/model_util.h"
#include "experimental/filament/filament/texture.h"
namespace mujoco {
ModelObjects::ModelObjects(const mjModel* model, filament::Engine* engine)
@@ -73,14 +73,7 @@ ModelObjects::~ModelObjects() {
for (auto& iter : indirect_lights_) {
engine_->destroy(iter);
}
for (auto& iter : meshes_) {
engine_->destroy(iter.second.vertex_buffer);
engine_->destroy(iter.second.index_buffer);
}
for (auto& iter : shapes_) {
engine_->destroy(iter.vertex_buffer);
engine_->destroy(iter.index_buffer);
}
meshes_.clear();
textures_.clear();
}
@@ -88,32 +81,25 @@ void ModelObjects::UploadMesh(const mjModel* model, int id) {
if (model != model_) {
mju_error("Model mismatch.");
}
if (id < 0 || id >= model->nmesh) {
if (id < 0 || id >= model->nmesh) {
mju_error("Invalid mesh index %d", id);
}
meshes_.erase(id);
convex_hulls_.erase(id);
if (auto iter = meshes_.find(id); iter != meshes_.end()) {
engine_->destroy(iter->second.vertex_buffer);
engine_->destroy(iter->second.index_buffer);
}
if (auto iter = convex_hulls_.find(id); iter != convex_hulls_.end()) {
engine_->destroy(iter->second.vertex_buffer);
engine_->destroy(iter->second.index_buffer);
}
FilamentBuffers& buffers = meshes_[id];
buffers.vertex_buffer = CreateVertexBuffer(
engine_, model, id, MeshType::kNormal, &buffers.bounds.emplace());
buffers.index_buffer =
CreateIndexBuffer(engine_, model, id, MeshType::kNormal);
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<Mesh>(engine_, index_buffer, vertex_buffer, bounds);
if (model->mesh_graphadr[id] >= 0) {
FilamentBuffers& hull_buffers = convex_hulls_[id];
hull_buffers.vertex_buffer =
CreateVertexBuffer(engine_, model, id, MeshType::kConvexHull,
&hull_buffers.bounds.emplace());
hull_buffers.index_buffer =
CreateIndexBuffer(engine_, model, id, MeshType::kConvexHull);
vertex_buffer =
CreateVertexBuffer(engine_, model, id, MeshType::kConvexHull, &bounds);
index_buffer = CreateIndexBuffer(engine_, model, id, MeshType::kConvexHull);
convex_hulls_[id] =
std::make_unique<Mesh>(engine_, index_buffer, vertex_buffer, bounds);
}
}
@@ -172,43 +158,41 @@ void ModelObjects::UploadHeightField(const mjModel* model, int id) {
mju_error("Invalid height field index %d", id);
}
if (auto iter = height_fields_.find(id); iter != height_fields_.end()) {
engine_->destroy(iter->second.vertex_buffer);
engine_->destroy(iter->second.index_buffer);
}
height_fields_.erase(id);
FilamentBuffers& buffers = height_fields_[id];
buffers.vertex_buffer = CreateVertexBuffer(
engine_, model, id, MeshType::kHeightField, &buffers.bounds.emplace());
buffers.index_buffer =
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<Mesh>(engine_, index_buffer, vertex_buffer, bounds);
}
const FilamentBuffers* ModelObjects::GetMeshBuffer(int data_id) const {
const Mesh* ModelObjects::GetMeshBuffer(int data_id) const {
// As defined by mjv_updateScene:
// original mesh: mesh_id * 2
// convex hull: (mesh_id * 2) + 1
const int mesh_id = data_id / 2;
if (data_id % 2 == 0) {
auto it = meshes_.find(mesh_id);
return it != meshes_.end() ? &it->second : nullptr;
return it != meshes_.end() ? it->second.get() : nullptr;
} else {
auto it = convex_hulls_.find(mesh_id);
return it != convex_hulls_.end() ? &it->second : nullptr;
return it != convex_hulls_.end() ? it->second.get() : nullptr;
}
}
const FilamentBuffers* ModelObjects::GetHeightFieldBuffer(
int hfield_id) const {
const Mesh* ModelObjects::GetHeightFieldBuffer(int hfield_id) const {
auto it = height_fields_.find(hfield_id);
return it != height_fields_.end() ? &it->second : nullptr;
return it != height_fields_.end() ? it->second.get() : nullptr;
}
const FilamentBuffers* ModelObjects::GetShapeBuffer(ShapeType shape) const {
const Mesh* ModelObjects::GetShapeBuffer(ShapeType shape) const {
if (shape < 0 || shape >= kNumShapes) {
mju_error("Invalid shape type: %d", shape);
}
return &shapes_[shape];
return shapes_[shape].get();
}
const Texture* ModelObjects::GetTexture(int tex_id) const {
@@ -61,9 +61,9 @@ class ModelObjects {
filament::Engine* GetEngine() const { return engine_; }
// Returns the cached instance of a filament object created from the mjModel.
const FilamentBuffers* GetShapeBuffer(ShapeType shape) const;
const FilamentBuffers* GetMeshBuffer(int data_id) const;
const FilamentBuffers* GetHeightFieldBuffer(int hfield_id) const;
const Mesh* GetShapeBuffer(ShapeType shape) const;
const Mesh* GetMeshBuffer(int data_id) const;
const Mesh* GetHeightFieldBuffer(int hfield_id) const;
const Texture* GetTexture(int tex_id) const;
const Texture* GetTexture(int mat_id, int role) const;
@@ -84,10 +84,10 @@ class ModelObjects {
filament::Engine* engine_ = nullptr;
std::vector<filament::Skybox*> skyboxes_;
std::vector<filament::IndirectLight*> indirect_lights_;
std::array<FilamentBuffers, kNumShapes> shapes_;
std::unordered_map<int, FilamentBuffers> meshes_;
std::unordered_map<int, FilamentBuffers> convex_hulls_;
std::unordered_map<int, FilamentBuffers> height_fields_;
std::array<MeshPtr, kNumShapes> shapes_;
std::unordered_map<int, MeshPtr> meshes_;
std::unordered_map<int, MeshPtr> convex_hulls_;
std::unordered_map<int, MeshPtr> height_fields_;
std::unordered_map<int, std::unique_ptr<Texture>> textures_;
float specular_multiplier_ = 0.2f;
float shininess_multiplier_ = 0.1f;
@@ -15,7 +15,7 @@
#include "experimental/filament/filament/renderables.h"
#include <cstdint>
#include <optional>
#include <utility>
#include <filament/Engine.h>
#include <filament/RenderableManager.h>
@@ -49,67 +49,65 @@ void Renderables::RemoveLast() {
engine_->destroy(entity);
em.destroy(entity);
entities_.pop_back();
if (owned_buffers_.back().owned) {
engine_->destroy(owned_buffers_.back().buffers.vertex_buffer);
engine_->destroy(owned_buffers_.back().buffers.index_buffer);
}
owned_buffers_.pop_back();
meshes_.pop_back();
}
void Renderables::Update(int index, const FilamentBuffers& buffers) {
void Renderables::Update(int index, const Mesh* mesh) {
if (index < 0 || index >= entities_.size()) {
mju_error("Invalid index %d for renderable.", index);
}
utils::Entity& entity = entities_[index];
UpdateEntity(entity, buffers);
UpdateBuffers(index, buffers, false);
UpdateEntity(entity, mesh);
UpdateMeshes(index, mesh);
}
void Renderables::Update(int index, FilamentBuffers&& buffers) {
void Renderables::Update(int index, MeshPtr mesh) {
if (index < 0 || index >= entities_.size()) {
mju_error("Invalid index %d for renderable.", index);
}
utils::Entity& entity = entities_[index];
UpdateEntity(entity, buffers);
UpdateBuffers(index, buffers, true);
UpdateEntity(entity, mesh.get());
UpdateMeshes(index, mesh.get(), std::move(mesh));
}
void Renderables::Append(const FilamentBuffers& buffers) {
utils::Entity entity = CreateEntity(buffers);
void Renderables::Append(const Mesh* mesh) {
utils::Entity entity = CreateEntity(mesh);
entities_.push_back(entity);
owned_buffers_.push_back({.owned = false, .buffers = buffers});
meshes_.emplace_back(nullptr, mesh);
}
void Renderables::Append(FilamentBuffers&& buffers) {
utils::Entity entity = CreateEntity(buffers);
void Renderables::Append(MeshPtr mesh) {
utils::Entity entity = CreateEntity(mesh.get());
entities_.push_back(entity);
owned_buffers_.push_back({.owned = true, .buffers = buffers});
meshes_.emplace_back(std::move(mesh), mesh.get());
}
utils::Entity Renderables::CreateEntity(const FilamentBuffers& buffers) {
if (buffers.vertex_buffer == nullptr) {
utils::Entity Renderables::CreateEntity(const Mesh* mesh) {
filament::VertexBuffer* vertex_buffer = mesh->GetFilamentVertexBuffer();
if (vertex_buffer == nullptr) {
mju_error("Invalid (null) vertex buffer.");
}
if (buffers.index_buffer == nullptr) {
filament::IndexBuffer* index_buffer = mesh->GetFilamentIndexBuffer();
if (index_buffer == nullptr) {
mju_error("Invalid (null) index buffer.");
}
utils::Entity entity = utils::EntityManager::get().create();
if (entity.isNull()) {
mju_error("Failed to create entity.");
}
filament::RenderableManager::Builder builder(1);
builder.geometry(0, buffers.type, buffers.vertex_buffer,
buffers.index_buffer);
if (material_instance_) {
builder.material(0, material_instance_);
}
if (buffers.bounds.has_value()) {
builder.boundingBox(buffers.bounds.value());
builder.geometry(0, mesh->GetPrimitiveType(), vertex_buffer, index_buffer);
if (mesh->HasBounds()) {
builder.boundingBox(mesh->GetBounds());
} else {
builder.culling(false);
}
if (material_instance_) {
builder.material(0, material_instance_);
}
builder.castShadows(cast_shadows_);
builder.receiveShadows(receive_shadows_);
builder.layerMask(0xff, layer_mask_);
@@ -123,30 +121,29 @@ utils::Entity Renderables::CreateEntity(const FilamentBuffers& buffers) {
return entity;
}
void Renderables::UpdateEntity(utils::Entity entity,
const FilamentBuffers& buffers) {
if (buffers.vertex_buffer == nullptr) {
void Renderables::UpdateEntity(utils::Entity entity, const Mesh* mesh) {
filament::VertexBuffer* vertex_buffer = mesh->GetFilamentVertexBuffer();
if (vertex_buffer == nullptr) {
mju_error("Invalid (null) vertex buffer.");
}
if (buffers.index_buffer == nullptr) {
filament::IndexBuffer* index_buffer = mesh->GetFilamentIndexBuffer();
if (index_buffer == nullptr) {
mju_error("Invalid (null) index buffer.");
}
filament::RenderableManager& rm = engine_->getRenderableManager();
rm.setGeometryAt(rm.getInstance(entity), 0, buffers.type,
buffers.vertex_buffer, buffers.index_buffer, 0,
buffers.index_buffer->getIndexCount());
rm.setGeometryAt(rm.getInstance(entity), 0, mesh->GetPrimitiveType(),
vertex_buffer, index_buffer, 0,
index_buffer->getIndexCount());
}
void Renderables::UpdateBuffers(int index, FilamentBuffers buffers, bool owned) {
if (index < 0 || index >= owned_buffers_.size()) {
void Renderables::UpdateMeshes(int index, const Mesh* mesh, MeshPtr owned_mesh) {
if (index < 0 || index >= meshes_.size()) {
mju_error("Invalid index %d for renderable.", index);
}
if (owned_buffers_[index].owned) {
engine_->destroy(owned_buffers_[index].buffers.vertex_buffer);
engine_->destroy(owned_buffers_[index].buffers.index_buffer);
}
owned_buffers_[index].buffers = buffers;
owned_buffers_[index].owned = owned;
meshes_[index].owned_mesh = std::move(owned_mesh);
meshes_[index].mesh = mesh;
}
void Renderables::AddToScene(filament::Scene* scene) {
@@ -239,11 +236,13 @@ void Renderables::SetWireframe(bool wireframe) {
filament::RenderableManager& rm = engine_->getRenderableManager();
for (int i = 0; i < entities_.size(); ++i) {
utils::Entity& entity = entities_[i];
FilamentBuffers& buffers = owned_buffers_[i].buffers;
const Mesh* mesh = meshes_[i].mesh;
filament::VertexBuffer* vertex_buffer = mesh->GetFilamentVertexBuffer();
filament::IndexBuffer* index_buffer = mesh->GetFilamentIndexBuffer();
rm.setGeometryAt(rm.getInstance(entity), 0,
wireframe_ ? kWireframeType : buffers.type,
buffers.vertex_buffer, buffers.index_buffer, 0,
buffers.index_buffer->getIndexCount());
wireframe_ ? kWireframeType : mesh->GetPrimitiveType(),
vertex_buffer, index_buffer, 0,
index_buffer->getIndexCount());
}
}
}
@@ -16,7 +16,6 @@
#define MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_RENDERABLES_H_
#include <cstdint>
#include <optional>
#include <vector>
#include <filament/Engine.h>
@@ -39,13 +38,13 @@ class Renderables {
Renderables(const Renderables&) = delete;
Renderables& operator=(const Renderables&) = delete;
// Appends a new renderable entity built from the given buffers.
void Append(const FilamentBuffers& buffers);
void Append(FilamentBuffers&& buffers);
// Appends a new renderable entity built from the given mesh.
void Append(const Mesh* mesh);
void Append(MeshPtr mesh);
// Updates the entity at the index with new buffers.
void Update(int index, const FilamentBuffers& buffers);
void Update(int index, FilamentBuffers&& buffers);
// Updates the entity at the index with new mesh.
void Update(int index, const Mesh* mesh);
void Update(int index, MeshPtr mesh);
// Removes the last entity.
void RemoveLast();
@@ -53,7 +52,7 @@ class Renderables {
// Returns the entity at the given index.
utils::Entity operator[](int index) { return entities_[index]; }
// Returns the owned buffers at the given index.
// Returns the number of Entities that make up this renderable.
int GetNumEntities() const { return entities_.size(); }
// Hides all managed entities.
@@ -84,22 +83,20 @@ class Renderables {
filament::Engine* GetEngine() { return engine_; }
private:
utils::Entity CreateEntity(const FilamentBuffers& buffers);
void UpdateEntity(utils::Entity entity, const FilamentBuffers& buffers);
void UpdateBuffers(int index, FilamentBuffers buffers, bool owned);
utils::Entity CreateEntity(const Mesh* mesh);
void UpdateEntity(utils::Entity entity, const Mesh* mesh);
void UpdateMeshes(int index, const Mesh* mesh, MeshPtr owned_mesh = nullptr);
// Tracks whether of not the filament buffers should be destroyed by this
// class.
struct OwnedBuffers {
bool owned = false;
FilamentBuffers buffers;
struct MeshWrapper {
MeshPtr owned_mesh;
const Mesh* mesh = nullptr;
};
filament::Engine* engine_ = nullptr;
filament::Scene* assigned_scene_ = nullptr;
filament::MaterialInstance* material_instance_ = nullptr;
std::vector<utils::Entity> entities_;
std::vector<OwnedBuffers> owned_buffers_;
std::vector<MeshWrapper> meshes_;
std::uint8_t priority_ = kDefaultPriority;
std::uint8_t layer_mask_ = kDefaultLayerMask;
bool wireframe_ = false;