Move flex/skin Mesh creation into ModelObjects.

PiperOrigin-RevId: 896419032
Change-Id: Ib0f0cd0c80c9f630127f2f72dbaed7c644046663
This commit is contained in:
Haroon Qureshi
2026-04-08 04:37:30 -07:00
committed by Copybara-Service
parent 87b0ea785e
commit c6a434a408
6 changed files with 135 additions and 180 deletions
-2
View File
@@ -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
+10 -10
View File
@@ -16,9 +16,7 @@
#include <cmath>
#include <cstdint>
#include <memory>
#include <numbers>
#include <utility>
#include <filament/Material.h>
#include <filament/RenderableManager.h>
@@ -32,7 +30,6 @@
#include <utils/Entity.h>
#include <mujoco/mjvisualize.h>
#include <mujoco/mujoco.h>
#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> 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));
}
}
@@ -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 <cstddef>
#include <cstring>
#include <memory>
#include <span>
#include <filament/Engine.h>
#include <filament/IndexBuffer.h>
#include <filament/VertexBuffer.h>
#include <mujoco/mujoco.h>
#include "experimental/filament/filament/mesh.h"
namespace mujoco {
static std::span<const float> 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<size_t>(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<size_t>(num)};
}
}
static std::span<const float> 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<size_t>(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<size_t>(num)};
}
}
static std::span<const float> 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<size_t>(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<size_t>(num)};
} else {
const float* ptr = nullptr;
return {ptr, 0};
}
}
}
static std::span<const int> 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<size_t>(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<Mesh>(engine, data);
}
} // namespace mujoco
@@ -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 <filament/Engine.h>
#include <mujoco/mujoco.h>
#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_
@@ -17,9 +17,11 @@
#include <array>
#include <algorithm>
#include <cfloat>
#include <cstddef>
#include <cstdint>
#include <limits>
#include <memory>
#include <span>
#include <utility>
#include <vector>
@@ -339,6 +341,77 @@ static int GetNumVertices(const mjModel* model, int id, MeshType mesh_type) {
}
}
static std::span<const float> 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<size_t>(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<size_t>(num)};
}
}
static std::span<const float> 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<size_t>(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<size_t>(num)};
}
}
static std::span<const float> 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<size_t>(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<size_t>(num)};
} else {
const float* ptr = nullptr;
return {ptr, 0};
}
}
}
static std::span<const int> 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<size_t>(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<Mesh>(engine_, data);
}
MeshPtr ModelObjects::CreateFlexMesh(const mjvScene* scene,
const mjvGeom& geom) {
MeshData data;
DefaultMeshData(&data);
UpdateSkinFlexMeshData(&data, model_, scene, geom);
return std::make_unique<Mesh>(engine_, data);
}
MeshPtr ModelObjects::CreateSkinMesh(const mjvScene* scene,
const mjvGeom& geom) {
MeshData data;
DefaultMeshData(&data);
UpdateSkinFlexMeshData(&data, model_, scene, geom);
return std::make_unique<Mesh>(engine_, data);
}
const Mesh* ModelObjects::GetMeshBuffer(int data_id) const {
// As defined by mjv_updateScene:
// original mesh: mesh_id * 2
@@ -15,7 +15,6 @@
#ifndef MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_MODEL_OBJECTS_H_
#define MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_MODEL_OBJECTS_H_
#include <array>
#include <memory>
#include <unordered_map>
#include <vector>
@@ -24,6 +23,7 @@
#include <filament/IndirectLight.h>
#include <filament/Skybox.h>
#include <mujoco/mjmodel.h>
#include <mujoco/mujoco.h>
#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);