From a37389ccfb4b6b11f1752b8c30929f52b1e0ce99 Mon Sep 17 00:00:00 2001 From: Haroon Qureshi Date: Thu, 11 Jun 2026 23:35:40 -0700 Subject: [PATCH] Split SceneObjects out from ModelObjects. PiperOrigin-RevId: 930960334 Change-Id: I7958a8240a90e2eb7fb87e58e5bea561459a7695 --- src/experimental/filament/CMakeLists.txt | 2 + .../filament/compat/model_objects.cc | 134 -------------- .../filament/compat/model_objects.h | 31 ++-- .../filament/compat/scene_bridge.cc | 9 +- .../filament/compat/scene_bridge.h | 2 + .../filament/compat/scene_geom_util.cc | 12 +- .../filament/compat/scene_geom_util.h | 3 +- .../filament/compat/scene_objects.cc | 170 ++++++++++++++++++ .../filament/compat/scene_objects.h | 51 ++++++ 9 files changed, 261 insertions(+), 153 deletions(-) create mode 100644 src/experimental/filament/compat/scene_objects.cc create mode 100644 src/experimental/filament/compat/scene_objects.h diff --git a/src/experimental/filament/CMakeLists.txt b/src/experimental/filament/CMakeLists.txt index 0db157ae..6f0b8ebf 100644 --- a/src/experimental/filament/CMakeLists.txt +++ b/src/experimental/filament/CMakeLists.txt @@ -29,6 +29,8 @@ target_sources(${MUJOCO_FILAMENT_EXPERIMENTAL_TARGET_NAME} compat/scene_bridge.h compat/scene_geom_util.cc compat/scene_geom_util.h + compat/scene_objects.cc + compat/scene_objects.h ) if(MUJOCO_USE_FILAMENT_MJR_COMPAT) target_sources(${MUJOCO_FILAMENT_EXPERIMENTAL_TARGET_NAME} diff --git a/src/experimental/filament/compat/model_objects.cc b/src/experimental/filament/compat/model_objects.cc index bbcaea39..a4711674 100644 --- a/src/experimental/filament/compat/model_objects.cc +++ b/src/experimental/filament/compat/model_objects.cc @@ -16,11 +16,9 @@ #include #include -#include #include #include #include -#include #include #include @@ -331,77 +329,6 @@ static int GetNumVertices(const mjModel* model, int id, MeshType mesh_type) { } } -static std::span GetPositions(const mjModel* model, - const mjvScene* scene, - const mjvGeom& geom) { - if (geom.type == mjGEOM_FLEX) { - const int num = 9 * scene->flexfaceused[geom.objid]; - const int addr = scene->flexfaceadr[geom.objid]; - const float* ptr = scene->flexface + (9 * addr); - return {ptr, static_cast(num)}; - } else { - const int num = 3 * scene->skinvertnum[geom.objid]; - const int addr = scene->skinvertadr[geom.objid]; - const float* ptr = scene->skinvert + (3 * addr); - return {ptr, static_cast(num)}; - } -} - -static std::span GetNormals(const mjModel* model, - const mjvScene* scene, - const mjvGeom& geom) { - if (geom.type == mjGEOM_FLEX) { - const int num = 9 * scene->flexfaceused[geom.objid]; - const int addr = scene->flexfaceadr[geom.objid]; - const float* ptr = scene->flexnormal + (9 * addr); - return {ptr, static_cast(num)}; - } else { - const int num = 3 * scene->skinvertnum[geom.objid]; - const int addr = scene->skinvertadr[geom.objid]; - const float* ptr = scene->skinnormal + (3 * addr); - return {ptr, static_cast(num)}; - } -} - -static std::span GetUvs(const mjModel* model, - const mjvScene* scene, - const mjvGeom& geom) { - if (geom.type == mjGEOM_FLEX) { - if (geom.texcoord && geom.matid >= 0) { - const int num = 6 * scene->flexfaceused[geom.objid]; - const int addr = scene->flexfaceadr[geom.objid]; - const float* ptr = scene->flextexcoord + (6 * addr); - return {ptr, static_cast(num)}; - } else { - const float* ptr = nullptr; - return {ptr, 0}; - } - } else { - if (model->skin_texcoordadr[geom.objid] >= 0) { - const int num = 3 * scene->skinvertnum[geom.objid]; - const int addr = model->skin_texcoordadr[geom.objid]; - const float* ptr = model->skin_texcoord + (2 * addr); - return {ptr, static_cast(num)}; - } else { - const float* ptr = nullptr; - return {ptr, 0}; - } - } -} - -static std::span GetIndices(const mjModel* model, - const mjvScene* scene, - const mjvGeom& geom) { - if (geom.type == mjGEOM_FLEX) { - const int* ptr = nullptr; - return {ptr, 0}; - } else { - const int num = 3 * model->skin_facenum[geom.objid]; - const int* ptr = model->skin_face + 3 * model->skin_faceadr[geom.objid]; - return {ptr, static_cast(num)}; - } -} - static void UpdateMeshData(mjrfMeshData* data, const mjModel* model, int id, MeshType mesh_type) { if (!IsValidIndex(model, id, mesh_type)) { @@ -457,38 +384,6 @@ static void UpdateMeshData(mjrfMeshData* data, const mjModel* model, int id, data->bounds_max[2] = builder->bounds_max.z; } -void UpdateSkinFlexMeshData(mjrfMeshData* data, 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); - auto indices = GetIndices(model, scene, geom); - - int num_indices = indices.size(); - if (num_indices == 0 && geom.type == mjGEOM_FLEX) { - num_indices = 3 * scene->flexfaceused[geom.objid]; - } - - data->nattributes = uvs.data() ? 3 : 2; - data->attributes[0].usage = mjVERTEX_ATTRIBUTE_USAGE_POSITION; - data->attributes[0].type = mjVERTEX_ATTRIBUTE_TYPE_FLOAT3; - data->attributes[0].bytes = positions.data(); - data->attributes[1].usage = mjVERTEX_ATTRIBUTE_USAGE_NORMAL; - data->attributes[1].type = mjVERTEX_ATTRIBUTE_TYPE_FLOAT3; - data->attributes[1].bytes = normals.data(); - data->attributes[2].usage = mjVERTEX_ATTRIBUTE_USAGE_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_U32; - data->primitive_type = mjMESH_PRIMITIVE_TYPE_TRIANGLES; - data->compute_bounds = true; - data->release = nullptr; - data->user_data = nullptr; -} - ModelObjects::ModelObjects(const mjModel* model, mjrfContext* ctx) : model_(model), ctx_(ctx) { @@ -595,19 +490,6 @@ void ModelObjects::UploadHeightField(const mjModel* model, int id) { height_fields_.insert_or_assign(id, CreateMesh(ctx_, data)); } -void ModelObjects::CreateSkinFlexMesh(const mjvScene* scene, const mjvGeom& geom) { - mjrfMeshData data; - mjrf_defaultMeshData(&data); - UpdateSkinFlexMeshData(&data, model_, scene, geom); - if (geom.type == mjGEOM_FLEX) { - flexes_.insert_or_assign(geom.objid, CreateMesh(ctx_, data)); - } else if (geom.type == mjGEOM_SKIN) { - skins_.insert_or_assign(geom.objid, CreateMesh(ctx_, data)); - } else { - mju_error("Unsupported dynamic mesh type: %d", geom.type); - } -} - const mjrfMesh* ModelObjects::GetMesh(int data_id) const { // As defined by mjv_updateScene: // original mesh: mesh_id * 2 @@ -630,22 +512,6 @@ const mjrfMesh* ModelObjects::GetHeightField(int hfield_id) const { return nullptr; } -const mjrfMesh* ModelObjects::GetFlexMesh(int geom_id) const { - if (auto it = flexes_.find(geom_id); it != flexes_.end()) { - return it->second.get(); - } - mju_error("Unknown flex mesh %d", geom_id); - return nullptr; -} - -const mjrfMesh* ModelObjects::GetSkinMesh(int geom_id) const { - if (auto it = skins_.find(geom_id); it != skins_.end()) { - return it->second.get(); - } - mju_error("Unknown skin mesh %d", geom_id); - return nullptr; -} - const mjrfTexture* ModelObjects::GetTexture(int tex_id) const { if (auto it = textures_.find(tex_id); it != textures_.end()) { return it->second.get(); diff --git a/src/experimental/filament/compat/model_objects.h b/src/experimental/filament/compat/model_objects.h index f88f1ed5..c1de7a3d 100644 --- a/src/experimental/filament/compat/model_objects.h +++ b/src/experimental/filament/compat/model_objects.h @@ -24,33 +24,46 @@ namespace mujoco { -// Creates and owns various filament objects based on the mjModel. +// Creates and owns meshes and textures read from an mjModel. class ModelObjects { public: ModelObjects(const mjModel* model, mjrfContext* ctx); + // Uploads a new mesh from the model with the given id. void UploadMesh(const mjModel* model, int id); + // Uploads a new texture from the model with the given id. void UploadTexture(const mjModel* model, int id); + // Uploads a new height field from the model with the given id. void UploadHeightField(const mjModel* model, int id); - void CreateSkinFlexMesh(const mjvScene* scene, const mjvGeom& geom); - - // Returns the cached instance of a filament object created from the mjModel. + // Returns the mjModel mesh with the given data_id. The data_id is the + // mesh_id * 2 of the mesh in the mjModel. const mjrfMesh* GetMesh(int data_id) const; + + // Returns the mjModel convex hulll mesh with the given data_id. The data_id + // is the (mesh_id * 2) + 1 of the mesh in the mjModel. + const mjrfMesh* GetConvexHull(int data_id) const; + + // Returns the mjModel height field mesh with the given id. const mjrfMesh* GetHeightField(int hfield_id) const; - const mjrfMesh* GetSkinMesh(int geom_id) const; - const mjrfMesh* GetFlexMesh(int geom_id) const; + + // Returns the mjModel texture with the given id. const mjrfTexture* GetTexture(int tex_id) const; + + // Returns the skybox texture in the mjModel. const mjrfTexture* GetSkyboxTexture() const; + // Returns the mjModel from which the Model Objects are created. + const mjModel* GetModel() const { return model_; } + + // Returns the multipliers used for mapping legacy material properties to + // filament material properties. float GetSpecularMultiplier() const { return specular_multiplier_; } float GetShininessMultiplier() const { return shininess_multiplier_; } float GetEmissiveMultiplier() const { return emissive_multiplier_; } - const mjModel* GetModel() const { return model_; } - ModelObjects(const ModelObjects&) = delete; ModelObjects& operator=(const ModelObjects&) = delete; @@ -60,8 +73,6 @@ class ModelObjects { std::unordered_map> meshes_; std::unordered_map> convex_hulls_; std::unordered_map> height_fields_; - std::unordered_map> skins_; - std::unordered_map> flexes_; std::unordered_map> textures_; float specular_multiplier_ = 0.2f; float shininess_multiplier_ = 0.1f; diff --git a/src/experimental/filament/compat/scene_bridge.cc b/src/experimental/filament/compat/scene_bridge.cc index 07295651..b4fcee85 100644 --- a/src/experimental/filament/compat/scene_bridge.cc +++ b/src/experimental/filament/compat/scene_bridge.cc @@ -28,6 +28,7 @@ #include "experimental/filament/compat/light_manager.h" #include "experimental/filament/compat/model_objects.h" #include "experimental/filament/compat/scene_geom_util.h" +#include "experimental/filament/compat/scene_objects.h" #include "render/filament/mjrfilament.h" #include "render/filament/mjrfilament_cpp.h" #include "render/filament/support/filament_util.h" @@ -45,6 +46,7 @@ SceneBridge::SceneBridge(mjrfContext* ctx, const mjModel* model) mjrf_defaultSceneParams(¶ms); scene_ = CreateScene(ctx_, params); model_objects_ = std::make_unique(model, ctx_); + scene_objects_ = std::make_unique(ctx_); mjrf_configureSceneFromModel(scene_.get(), model); @@ -124,11 +126,12 @@ void SceneBridge::Update(const mjrRect& viewport, const mjvScene* scene) { } if (geom->type == mjGEOM_FLEX || geom->type == mjGEOM_SKIN) { - model_objects_->CreateSkinFlexMesh(scene, *geom); + scene_objects_->CreateSkinFlexMesh(scene, model_objects_->GetModel(), + *geom); } - UniquePtr renderable = - CreateGeomRenderable(*geom, ctx_, model_objects_.get(), scene->flags); + UniquePtr renderable = CreateGeomRenderable( + *geom, ctx_, model_objects_.get(), scene_objects_.get(), scene->flags); mjrf_addRenderableToScene(scene_.get(), renderable.get()); renderables_.push_back(std::move(renderable)); diff --git a/src/experimental/filament/compat/scene_bridge.h b/src/experimental/filament/compat/scene_bridge.h index 43d0c651..961d5776 100644 --- a/src/experimental/filament/compat/scene_bridge.h +++ b/src/experimental/filament/compat/scene_bridge.h @@ -26,6 +26,7 @@ #include #include "experimental/filament/compat/light_manager.h" #include "experimental/filament/compat/model_objects.h" +#include "experimental/filament/compat/scene_objects.h" #include "render/filament/mjrfilament.h" #include "render/filament/mjrfilament_cpp.h" @@ -64,6 +65,7 @@ class SceneBridge { mjrfContext* ctx_ = nullptr; std::unique_ptr model_objects_; + std::unique_ptr scene_objects_; std::unique_ptr light_manager_; mjrCamera camera_; DrawTextAtFn draw_text_callback_; diff --git a/src/experimental/filament/compat/scene_geom_util.cc b/src/experimental/filament/compat/scene_geom_util.cc index 46e35161..5b0b1b96 100644 --- a/src/experimental/filament/compat/scene_geom_util.cc +++ b/src/experimental/filament/compat/scene_geom_util.cc @@ -22,6 +22,7 @@ #include #include #include "experimental/filament/compat/model_objects.h" +#include "experimental/filament/compat/scene_objects.h" #include "render/filament/mjrfilament.h" #include "render/filament/mjrfilament_cpp.h" @@ -41,7 +42,8 @@ static float GetPlaneTileSize(const mjModel* model, int matid, } static void PrepareGeomMeshes(mjrfRenderable* renderable, const mjvGeom& geom, - ModelObjects* model_objs) { + ModelObjects* model_objs, + SceneObjects* scene_objs) { const mjModel* model = model_objs->GetModel(); const int nstack = model->vis.quality.numstacks; const int nslice = model->vis.quality.numslices; @@ -113,7 +115,7 @@ static void PrepareGeomMeshes(mjrfRenderable* renderable, const mjvGeom& geom, mjrf_setRenderableSize(renderable, geom.size); break; case mjGEOM_FLEX: - mjrf_setRenderableMesh(renderable, model_objs->GetFlexMesh(geom.objid), 0, 0); + mjrf_setRenderableMesh(renderable, scene_objs->GetFlexMesh(geom.objid), 0, 0); // Flexes are defined in global space. std::memset(position, 0, sizeof(position)); std::memset(rotation, 0, sizeof(rotation)); @@ -122,7 +124,7 @@ static void PrepareGeomMeshes(mjrfRenderable* renderable, const mjvGeom& geom, rotation[8] = 1.f; break; case mjGEOM_SKIN: - mjrf_setRenderableMesh(renderable, model_objs->GetSkinMesh(geom.objid), 0, 0); + mjrf_setRenderableMesh(renderable, scene_objs->GetSkinMesh(geom.objid), 0, 0); // Skins are defined in global space. std::memset(position, 0, sizeof(position)); std::memset(rotation, 0, sizeof(rotation)); @@ -271,11 +273,11 @@ static void UpdateGeomMaterial(mjrfRenderable* renderable, const mjvGeom& geom, UniquePtr CreateGeomRenderable( const mjvGeom& geom, mjrfContext* ctx, ModelObjects* model_objs, - const mjtByte render_flags[mjNRNDFLAG]) { + SceneObjects* scene_objs, const mjtByte render_flags[mjNRNDFLAG]) { mjrfRenderableParams params; mjrf_defaultRenderableParams(¶ms); auto renderable = CreateRenderable(ctx, params); - PrepareGeomMeshes(renderable.get(), geom, model_objs); + PrepareGeomMeshes(renderable.get(), geom, model_objs, scene_objs); UpdateGeomMaterial(renderable.get(), geom, model_objs, render_flags); return renderable; } diff --git a/src/experimental/filament/compat/scene_geom_util.h b/src/experimental/filament/compat/scene_geom_util.h index 6bd10e39..3ec3ff32 100644 --- a/src/experimental/filament/compat/scene_geom_util.h +++ b/src/experimental/filament/compat/scene_geom_util.h @@ -18,6 +18,7 @@ #include #include #include "experimental/filament/compat/model_objects.h" +#include "experimental/filament/compat/scene_objects.h" #include "render/filament/mjrfilament.h" #include "render/filament/mjrfilament_cpp.h" @@ -26,7 +27,7 @@ namespace mujoco { // Creates a Renderable from the given mjvGeom. UniquePtr CreateGeomRenderable( const mjvGeom& geom, mjrfContext* ctx, ModelObjects* model_objs, - const mjtByte render_flags[mjNRNDFLAG]); + SceneObjects* scene_objs, const mjtByte render_flags[mjNRNDFLAG]); } // namespace mujoco diff --git a/src/experimental/filament/compat/scene_objects.cc b/src/experimental/filament/compat/scene_objects.cc new file mode 100644 index 00000000..ead0614b --- /dev/null +++ b/src/experimental/filament/compat/scene_objects.cc @@ -0,0 +1,170 @@ +// Copyright 2026 DeepMind Technologies Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "experimental/filament/compat/scene_objects.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include "render/filament/mjrfilament.h" +#include "render/filament/mjrfilament_cpp.h" + +namespace mujoco { + +using filament::math::float2; +using filament::math::float3; +using filament::math::float4; + +static std::span GetPositions(const mjModel* model, + const mjvScene* scene, + const mjvGeom& geom) { + if (geom.type == mjGEOM_FLEX) { + const int num = 9 * scene->flexfaceused[geom.objid]; + const int addr = scene->flexfaceadr[geom.objid]; + const float* ptr = scene->flexface + (9 * addr); + return {ptr, static_cast(num)}; + } else { + const int num = 3 * scene->skinvertnum[geom.objid]; + const int addr = scene->skinvertadr[geom.objid]; + const float* ptr = scene->skinvert + (3 * addr); + return {ptr, static_cast(num)}; + } +} + +static std::span GetNormals(const mjModel* model, + const mjvScene* scene, + const mjvGeom& geom) { + if (geom.type == mjGEOM_FLEX) { + const int num = 9 * scene->flexfaceused[geom.objid]; + const int addr = scene->flexfaceadr[geom.objid]; + const float* ptr = scene->flexnormal + (9 * addr); + return {ptr, static_cast(num)}; + } else { + const int num = 3 * scene->skinvertnum[geom.objid]; + const int addr = scene->skinvertadr[geom.objid]; + const float* ptr = scene->skinnormal + (3 * addr); + return {ptr, static_cast(num)}; + } +} + +static std::span GetUvs(const mjModel* model, + const mjvScene* scene, + const mjvGeom& geom) { + if (geom.type == mjGEOM_FLEX) { + if (geom.texcoord && geom.matid >= 0) { + const int num = 6 * scene->flexfaceused[geom.objid]; + const int addr = scene->flexfaceadr[geom.objid]; + const float* ptr = scene->flextexcoord + (6 * addr); + return {ptr, static_cast(num)}; + } else { + const float* ptr = nullptr; + return {ptr, 0}; + } + } else { + if (model->skin_texcoordadr[geom.objid] >= 0) { + const int num = 3 * scene->skinvertnum[geom.objid]; + const int addr = model->skin_texcoordadr[geom.objid]; + const float* ptr = model->skin_texcoord + (2 * addr); + return {ptr, static_cast(num)}; + } else { + const float* ptr = nullptr; + return {ptr, 0}; + } + } +} + +static std::span GetIndices(const mjModel* model, + const mjvScene* scene, + const mjvGeom& geom) { + if (geom.type == mjGEOM_FLEX) { + const int* ptr = nullptr; + return {ptr, 0}; + } else { + const int num = 3 * model->skin_facenum[geom.objid]; + const int* ptr = model->skin_face + 3 * model->skin_faceadr[geom.objid]; + return {ptr, static_cast(num)}; + } +} + +static void UpdateSkinFlexMeshData(mjrfMeshData* data, 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); + auto indices = GetIndices(model, scene, geom); + + int num_indices = indices.size(); + if (num_indices == 0 && geom.type == mjGEOM_FLEX) { + num_indices = 3 * scene->flexfaceused[geom.objid]; + } + + data->nattributes = uvs.data() ? 3 : 2; + data->attributes[0].usage = mjVERTEX_ATTRIBUTE_USAGE_POSITION; + data->attributes[0].type = mjVERTEX_ATTRIBUTE_TYPE_FLOAT3; + data->attributes[0].bytes = positions.data(); + data->attributes[1].usage = mjVERTEX_ATTRIBUTE_USAGE_NORMAL; + data->attributes[1].type = mjVERTEX_ATTRIBUTE_TYPE_FLOAT3; + data->attributes[1].bytes = normals.data(); + data->attributes[2].usage = mjVERTEX_ATTRIBUTE_USAGE_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_U32; + data->primitive_type = mjMESH_PRIMITIVE_TYPE_TRIANGLES; + data->compute_bounds = true; + data->release = nullptr; + data->user_data = nullptr; +} + +SceneObjects::SceneObjects(mjrfContext* ctx) : ctx_(ctx) {} + +void SceneObjects::CreateSkinFlexMesh(const mjvScene* scene, + const mjModel* model, + const mjvGeom& geom) { + mjrfMeshData data; + mjrf_defaultMeshData(&data); + UpdateSkinFlexMeshData(&data, model, scene, geom); + if (geom.type == mjGEOM_FLEX) { + flexes_.insert_or_assign(geom.objid, CreateMesh(ctx_, data)); + } else if (geom.type == mjGEOM_SKIN) { + skins_.insert_or_assign(geom.objid, CreateMesh(ctx_, data)); + } else { + mju_error("Unsupported dynamic mesh type: %d", geom.type); + } +} + +const mjrfMesh* SceneObjects::GetFlexMesh(int geom_id) const { + if (auto it = flexes_.find(geom_id); it != flexes_.end()) { + return it->second.get(); + } + mju_error("Unknown flex mesh %d", geom_id); + return nullptr; +} + +const mjrfMesh* SceneObjects::GetSkinMesh(int geom_id) const { + if (auto it = skins_.find(geom_id); it != skins_.end()) { + return it->second.get(); + } + mju_error("Unknown skin mesh %d", geom_id); + return nullptr; +} +} // namespace mujoco diff --git a/src/experimental/filament/compat/scene_objects.h b/src/experimental/filament/compat/scene_objects.h new file mode 100644 index 00000000..d1a20ec4 --- /dev/null +++ b/src/experimental/filament/compat/scene_objects.h @@ -0,0 +1,51 @@ +// Copyright 2026 DeepMind Technologies Limited +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef MUJOCO_SRC_EXPERIMENTAL_FILAMENT_COMPAT_SCENE_OBJECTS_H_ +#define MUJOCO_SRC_EXPERIMENTAL_FILAMENT_COMPAT_SCENE_OBJECTS_H_ + +#include + +#include +#include +#include "render/filament/mjrfilament.h" +#include "render/filament/mjrfilament_cpp.h" + +namespace mujoco { + +// Creates and owns meshes read from an mjvScene. +class SceneObjects { + public: + explicit SceneObjects(mjrfContext* ctx); + + // Creates a skin or flex mesh from the given geom in the mjvScene. + void CreateSkinFlexMesh(const mjvScene* scene, const mjModel* model, + const mjvGeom& geom); + + // Returns the mesh for the given geom id, as created by CreateSkinFlexMesh. + const mjrfMesh* GetSkinMesh(int geom_id) const; + const mjrfMesh* GetFlexMesh(int geom_id) const; + + SceneObjects(const SceneObjects&) = delete; + SceneObjects& operator=(const SceneObjects&) = delete; + + private: + mjrfContext* ctx_ = nullptr; + std::unordered_map> skins_; + std::unordered_map> flexes_; +}; + +} // namespace mujoco + +#endif // MUJOCO_SRC_EXPERIMENTAL_FILAMENT_COMPAT_SCENE_OBJECTS_H_