diff --git a/src/experimental/filament/CMakeLists.txt b/src/experimental/filament/CMakeLists.txt index 86d0b009..367f2725 100644 --- a/src/experimental/filament/CMakeLists.txt +++ b/src/experimental/filament/CMakeLists.txt @@ -33,8 +33,6 @@ target_sources(${MUJOCO_FILAMENT_TARGET_NAME} filament/filament_context.h filament/filament_platform_factory.cc filament/filament_platform_factory.h - filament/geom_util.cc - filament/geom_util.h filament/gui_view.cc filament/gui_view.h filament/imgui_editor.cc diff --git a/src/experimental/filament/filament/drawable.cc b/src/experimental/filament/filament/drawable.cc index b3649350..53c91144 100644 --- a/src/experimental/filament/filament/drawable.cc +++ b/src/experimental/filament/filament/drawable.cc @@ -16,9 +16,7 @@ #include #include -#include #include -#include #include #include @@ -32,7 +30,6 @@ #include #include #include -#include "experimental/filament/filament/geom_util.h" #include "experimental/filament/filament/material.h" #include "experimental/filament/filament/math_util.h" #include "experimental/filament/filament/mesh.h" @@ -171,15 +168,18 @@ Drawable::Drawable(ObjectManager* object_mgr, ModelObjects* model_objects, void Drawable::Update(const mjModel* model, const mjvScene* scene, const mjvGeom& geom) { - if (geom.type == mjGEOM_FLEX || geom.type == mjGEOM_SKIN) { - // Flex geometry is updated every frame with new vertex data. - filament::Engine* engine = renderables_.GetEngine(); - std::unique_ptr mesh = CreateGeomBuffers(engine, model, scene, geom); - + // Flex and skin geometries are recreated every frame from the scene data. + if (geom.type == mjGEOM_FLEX) { if (renderables_.GetNumEntities() == 0) { - renderables_.Append(std::move(mesh)); + renderables_.Append(model_objs_->CreateFlexMesh(scene, geom)); } else { - renderables_.Update(0, std::move(mesh)); + renderables_.Update(0, model_objs_->CreateFlexMesh(scene, geom)); + } + } else if (geom.type == mjGEOM_SKIN) { + if (renderables_.GetNumEntities() == 0) { + renderables_.Append(model_objs_->CreateSkinMesh(scene, geom)); + } else { + renderables_.Update(0, model_objs_->CreateSkinMesh(scene, geom)); } } diff --git a/src/experimental/filament/filament/geom_util.cc b/src/experimental/filament/filament/geom_util.cc deleted file mode 100644 index 7b02a02a..00000000 --- a/src/experimental/filament/filament/geom_util.cc +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright 2025 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/filament/geom_util.h" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include "experimental/filament/filament/mesh.h" - -namespace mujoco { - -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)}; - } -} - -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); - 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]; - } - - 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/geom_util.h b/src/experimental/filament/filament/geom_util.h deleted file mode 100644 index 939c8d91..00000000 --- a/src/experimental/filament/filament/geom_util.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2025 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_FILAMENT_GEOM_UTIL_H_ -#define MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_GEOM_UTIL_H_ - -#include -#include -#include "experimental/filament/filament/mesh.h" - -namespace mujoco { - -// Populates the FilamentBuffers for a flex geometry. -MeshPtr CreateGeomBuffers(filament::Engine* engine, const mjModel* model, - const mjvScene* scene, const mjvGeom& geom); - -} // namespace mujoco - -#endif // MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_GEOM_UTIL_H_ diff --git a/src/experimental/filament/filament/model_objects.cc b/src/experimental/filament/filament/model_objects.cc index 5c955032..1f88dce0 100644 --- a/src/experimental/filament/filament/model_objects.cc +++ b/src/experimental/filament/filament/model_objects.cc @@ -17,9 +17,11 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -339,6 +341,77 @@ 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(MeshData* data, const mjModel* model, int id, MeshType mesh_type) { if (!IsValidIndex(model, id, mesh_type)) { @@ -394,6 +467,38 @@ static void UpdateMeshData(MeshData* data, const mjModel* model, int id, data->bounds_max[2] = builder->bounds_max.z; } +void UpdateSkinFlexMeshData(MeshData* 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_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; +} + ModelObjects::ModelObjects(const mjModel* model, filament::Engine* engine) : model_(model), engine_(engine) { const int nstack = model->vis.quality.numstacks; @@ -525,6 +630,22 @@ void ModelObjects::UploadHeightField(const mjModel* model, int id) { height_fields_[id] = std::make_unique(engine_, data); } +MeshPtr ModelObjects::CreateFlexMesh(const mjvScene* scene, + const mjvGeom& geom) { + MeshData data; + DefaultMeshData(&data); + UpdateSkinFlexMeshData(&data, model_, scene, geom); + return std::make_unique(engine_, data); +} + +MeshPtr ModelObjects::CreateSkinMesh(const mjvScene* scene, + const mjvGeom& geom) { + MeshData data; + DefaultMeshData(&data); + UpdateSkinFlexMeshData(&data, model_, scene, geom); + return std::make_unique(engine_, data); +} + const Mesh* ModelObjects::GetMeshBuffer(int data_id) const { // As defined by mjv_updateScene: // original mesh: mesh_id * 2 diff --git a/src/experimental/filament/filament/model_objects.h b/src/experimental/filament/filament/model_objects.h index f132d9ba..bc6a005b 100644 --- a/src/experimental/filament/filament/model_objects.h +++ b/src/experimental/filament/filament/model_objects.h @@ -15,7 +15,6 @@ #ifndef MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_MODEL_OBJECTS_H_ #define MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_MODEL_OBJECTS_H_ -#include #include #include #include @@ -24,6 +23,7 @@ #include #include #include +#include #include "experimental/filament/filament/mesh.h" #include "experimental/filament/filament/texture.h" @@ -66,6 +66,9 @@ class ModelObjects { const Texture* GetTexture(int tex_id) const; const Texture* GetTexture(int mat_id, int role) const; + MeshPtr CreateFlexMesh(const mjvScene* scene, const mjvGeom& geom); + MeshPtr CreateSkinMesh(const mjvScene* scene, const mjvGeom& geom); + filament::Skybox* CreateSkybox(); filament::IndirectLight* CreateIndirectLight(int tex_id, float intensity);