Remove Drawable abstraction.

Instead, use a set of functions to create/update a Renderable
from an mjvGeom.

This completely isolates mjvScene/mjvGeom from SceneView,
making SceneView a more general purpose class.

PiperOrigin-RevId: 899475268
Change-Id: I48a3a45bc8fff3e1f514847c7a1ca8ab3a1ff16e
This commit is contained in:
Haroon Qureshi
2026-04-14 03:13:11 -07:00
committed by Copybara-Service
parent 171e6dc177
commit fd5a7004f8
8 changed files with 227 additions and 246 deletions
+2 -2
View File
@@ -27,8 +27,6 @@ target_sources(${MUJOCO_FILAMENT_TARGET_NAME}
filament/builtins.h filament/builtins.h
filament/color_grading_options.cc filament/color_grading_options.cc
filament/color_grading_options.h filament/color_grading_options.h
filament/drawable.cc
filament/drawable.h
filament/filament_context.cc filament/filament_context.cc
filament/filament_context.h filament/filament_context.h
filament/filament_platform_factory.cc filament/filament_platform_factory.cc
@@ -56,6 +54,8 @@ target_sources(${MUJOCO_FILAMENT_TARGET_NAME}
filament/renderable.h filament/renderable.h
filament/scene_bridge.cc filament/scene_bridge.cc
filament/scene_bridge.h filament/scene_bridge.h
filament/scene_geom_util.cc
filament/scene_geom_util.h
filament/scene_view.cc filament/scene_view.cc
filament/scene_view.h filament/scene_view.h
filament/texture.cc filament/texture.cc
@@ -1,70 +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_DRAWABLE_H_
#define MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_DRAWABLE_H_
#include <math/mat4.h>
#include <mujoco/mjmodel.h>
#include <mujoco/mjtnum.h>
#include <mujoco/mjvisualize.h>
#include "experimental/filament/filament/material.h"
#include "experimental/filament/filament/model_objects.h"
#include "experimental/filament/filament/object_manager.h"
#include "experimental/filament/filament/renderable.h"
namespace mujoco {
// Manages the filament Entities and MaterialInstances for a single mjvGeom.
class Drawable {
public:
Drawable(ModelObjects* model_objects, const mjvScene* scene,
const mjvGeom& geom);
~Drawable() noexcept = default;
Drawable(const Drawable&) = delete;
Drawable& operator=(const Drawable&) = delete;
// Updates the transform of the drawable for rendering.
void SetTransform(const mjvGeom& geom);
// Updates the material parameters of the drawable for rendering.
void UpdateMaterial(const mjModel* model, const mjvGeom& geom,
ModelObjects* model_objs, const float headpos[3],
const mjtByte render_flags[mjNRNDFLAG],
ObjectManager::MaterialType* out_material_type);
// Returns the transform of the drawable.
const filament::math::mat4& GetTransform() const { return transform_; }
// Returns the renderable for the drawable.
Renderable& GetRenderable() { return renderable_; }
// Returns the material for the drawable.
Material& GetMaterial() { return renderable_.GetMaterial(); }
private:
void AddMesh(ModelObjects* model_objs, int data_id);
void AddGeom(ModelObjects* model_objs, const mjvScene* scene,
const mjvGeom& geom);
void AddHeightField(ModelObjects* model_objs, int hfield_id);
void AddShape(ModelObjects* model_objs, ModelObjects::ShapeType shape_type);
Renderable renderable_;
filament::math::mat4 transform_;
};
} // namespace mujoco
#endif // MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_DRAWABLE_H_
@@ -29,7 +29,6 @@
#include <filament/RenderTarget.h> #include <filament/RenderTarget.h>
#include <filament/Skybox.h> #include <filament/Skybox.h>
#include <filament/View.h> #include <filament/View.h>
#include <filament/Viewport.h>
#include <math/TMatHelpers.h> #include <math/TMatHelpers.h>
#include <math/mat4.h> #include <math/mat4.h>
#include <math/mathfwd.h> #include <math/mathfwd.h>
@@ -38,7 +37,6 @@
#include <math/TVecHelpers.h> #include <math/TVecHelpers.h>
#include <mujoco/mujoco.h> #include <mujoco/mujoco.h>
#include "experimental/filament/filament/color_grading_options.h" #include "experimental/filament/filament/color_grading_options.h"
#include "experimental/filament/filament/drawable.h"
#include "experimental/filament/filament/gui_view.h" #include "experimental/filament/filament/gui_view.h"
#include "experimental/filament/filament/light.h" #include "experimental/filament/filament/light.h"
#include "experimental/filament/filament/material.h" #include "experimental/filament/filament/material.h"
@@ -46,6 +44,8 @@
#include "experimental/filament/filament/model_objects.h" #include "experimental/filament/filament/model_objects.h"
#include "experimental/filament/filament/model_util.h" #include "experimental/filament/filament/model_util.h"
#include "experimental/filament/filament/object_manager.h" #include "experimental/filament/filament/object_manager.h"
#include "experimental/filament/filament/renderable.h"
#include "experimental/filament/filament/scene_geom_util.h"
#include "experimental/filament/filament/scene_view.h" #include "experimental/filament/filament/scene_view.h"
namespace mujoco { namespace mujoco {
@@ -164,10 +164,10 @@ SceneBridge::~SceneBridge() {
} }
lights_.clear(); lights_.clear();
for (auto& iter : drawables_) { for (auto& iter : renderables_) {
scene_view_->RemoveFromScene(iter.get()); scene_view_->RemoveFromScene(iter.get());
} }
drawables_.clear(); renderables_.clear();
} }
void SceneBridge::SetEnvironmentLight(std::string_view filename, void SceneBridge::SetEnvironmentLight(std::string_view filename,
@@ -305,16 +305,15 @@ void SceneBridge::Update(const mjrRect& viewport, const mjvScene* scene) {
mju_n2f(headpos, hpos, 3); mju_n2f(headpos, hpos, 3);
mju_n2f(gazedir, hfwd, 3); mju_n2f(gazedir, hfwd, 3);
const mjModel* model = model_objects_->GetModel();
const mjvGLCamera gl_camera = const mjvGLCamera gl_camera =
mjv_averageCamera(scene->camera, scene->camera + 1); mjv_averageCamera(scene->camera, scene->camera + 1);
clip_from_world_ = CalculateClipFromWorld(viewport, gl_camera); clip_from_world_ = CalculateClipFromWorld(viewport, gl_camera);
// Remove all drawables from previous render and prepare new ones. // Remove all drawables from previous render and prepare new ones.
for (auto& iter : drawables_) { for (auto& iter : renderables_) {
scene_view_->RemoveFromScene(iter.get()); scene_view_->RemoveFromScene(iter.get());
} }
drawables_.clear(); renderables_.clear();
for (int i = 0; i < scene->ngeom; ++i) { for (int i = 0; i < scene->ngeom; ++i) {
const mjvGeom* geom = scene->geoms + i; const mjvGeom* geom = scene->geoms + i;
@@ -324,28 +323,12 @@ void SceneBridge::Update(const mjrRect& viewport, const mjvScene* scene) {
} }
} }
auto drawable = std::unique_ptr<Renderable> renderable =
std::make_unique<Drawable>(model_objects_.get(), scene, *geom); CreateGeomRenderable(*geom, scene, object_mgr_, model_objects_.get(),
drawable->SetTransform(*geom); headpos, &fallback_textures_);
ObjectManager::MaterialType material_type = ObjectManager::kNumMaterials; scene_view_->AddToScene(renderable.get());
drawable->UpdateMaterial(model, *geom, model_objects_.get(), headpos, renderables_.push_back(std::move(renderable));
scene->flags, &material_type);
Material& material = drawable->GetMaterial();
material.SetFallbackTextures(&fallback_textures_);
material.SetMaterial(
Material::DrawMode::kNormal,
object_mgr_->GetMaterial(material_type));
material.SetMaterial(
Material::DrawMode::kDepth,
object_mgr_->GetMaterial(ObjectManager::kUnlitDepth));
material.SetMaterial(
Material::DrawMode::kSegmentation,
object_mgr_->GetMaterial(ObjectManager::kUnlitSegmentation));
scene_view_->AddToScene(drawable.get());
drawables_.push_back(std::move(drawable));
} }
bool headlight_enabled = false; bool headlight_enabled = false;
@@ -24,11 +24,11 @@
#include <math/vec3.h> #include <math/vec3.h>
#include <mujoco/mjvisualize.h> #include <mujoco/mjvisualize.h>
#include <mujoco/mujoco.h> #include <mujoco/mujoco.h>
#include "experimental/filament/filament/drawable.h"
#include "experimental/filament/filament/light.h" #include "experimental/filament/filament/light.h"
#include "experimental/filament/filament/material.h" #include "experimental/filament/filament/material.h"
#include "experimental/filament/filament/model_objects.h" #include "experimental/filament/filament/model_objects.h"
#include "experimental/filament/filament/object_manager.h" #include "experimental/filament/filament/object_manager.h"
#include "experimental/filament/filament/renderable.h"
#include "experimental/filament/filament/scene_view.h" #include "experimental/filament/filament/scene_view.h"
namespace mujoco { namespace mujoco {
@@ -72,7 +72,7 @@ class SceneBridge {
ObjectManager* object_mgr_ = nullptr; ObjectManager* object_mgr_ = nullptr;
std::unique_ptr<ModelObjects> model_objects_; std::unique_ptr<ModelObjects> model_objects_;
std::vector<std::unique_ptr<Light>> lights_; std::vector<std::unique_ptr<Light>> lights_;
std::vector<std::unique_ptr<Drawable>> drawables_; std::vector<std::unique_ptr<Renderable>> renderables_;
filament::math::mat4 clip_from_world_; filament::math::mat4 clip_from_world_;
int default_shadow_map_size_ = 2048; int default_shadow_map_size_ = 2048;
float default_vsm_blur_width_ = 0.0f; float default_vsm_blur_width_ = 0.0f;
@@ -12,10 +12,11 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "experimental/filament/filament/drawable.h" #include "experimental/filament/filament/scene_geom_util.h"
#include <cmath> #include <cmath>
#include <cstdint> #include <cstdint>
#include <memory>
#include <numbers> #include <numbers>
#include <filament/Material.h> #include <filament/Material.h>
@@ -81,80 +82,111 @@ static float GetPlaneTileSize(const mjModel* model, int matid,
} }
static bool IsBehind(const float* headpos, const float* pos, const float* mat) { static bool IsBehind(const float* headpos, const float* pos, const float* mat) {
return ((headpos[0] - pos[0]) * mat[2] + return ((headpos[0] - pos[0]) * mat[2] + (headpos[1] - pos[1]) * mat[5] +
(headpos[1] - pos[1]) * mat[5] + (headpos[2] - pos[2]) * mat[8] <
(headpos[2] - pos[2]) * mat[8] < 0.0f); 0.0f);
} }
Drawable::Drawable(ModelObjects* model_objects, const mjvScene* scene, static void AddMesh(Renderable& renderable, ModelObjects* model_objs,
const mjvGeom& geom) int data_id) {
: renderable_(model_objects->GetEngine()) { const Mesh* mesh = model_objs->GetMeshBuffer(data_id);
if (geom.category == mjCAT_DECOR) { if (mesh == nullptr) {
renderable_.SetCastShadows(false); mju_error("Unknown mesh %d", data_id);
renderable_.SetReceiveShadows(false);
} }
renderable.Append(mesh);
}
static void AddGeom(Renderable& renderable, ModelObjects* model_objs,
const mjvScene* scene, const mjvGeom& geom) {
if (geom.type == mjGEOM_FLEX) {
renderable.Append(model_objs->CreateFlexMesh(scene, geom));
} else if (geom.type == mjGEOM_SKIN) {
renderable.Append(model_objs->CreateSkinMesh(scene, geom));
}
}
static void AddHeightField(Renderable& renderable, ModelObjects* model_objs,
int hfield_id) {
const Mesh* mesh = model_objs->GetHeightFieldBuffer(hfield_id);
if (mesh == nullptr) {
mju_error("Unknown height field %d", hfield_id);
}
renderable.Append(mesh);
}
static void AddShape(Renderable& renderable, ModelObjects* model_objs,
ModelObjects::ShapeType shape_type) {
const Mesh* mesh = model_objs->GetShapeBuffer(shape_type);
if (mesh == nullptr) {
mju_error("Unknown shape %d", shape_type);
}
renderable.Append(mesh);
}
static void PrepareGeomMeshes(Renderable& renderable, const mjvGeom& geom,
const mjvScene* scene,
ModelObjects* model_objects) {
switch ((mjtGeom)geom.type) { switch ((mjtGeom)geom.type) {
case mjGEOM_MESH: case mjGEOM_MESH:
AddMesh(model_objects, geom.dataid); AddMesh(renderable, model_objects, geom.dataid);
break; break;
case mjGEOM_HFIELD: case mjGEOM_HFIELD:
AddHeightField(model_objects, geom.dataid); AddHeightField(renderable, model_objects, geom.dataid);
break; break;
case mjGEOM_PLANE: case mjGEOM_PLANE:
AddShape(model_objects, ModelObjects::kPlane); AddShape(renderable, model_objects, ModelObjects::kPlane);
break; break;
case mjGEOM_SPHERE: case mjGEOM_SPHERE:
AddShape(model_objects, ModelObjects::kSphere); AddShape(renderable, model_objects, ModelObjects::kSphere);
break; break;
case mjGEOM_ELLIPSOID: case mjGEOM_ELLIPSOID:
AddShape(model_objects, ModelObjects::kSphere); AddShape(renderable, model_objects, ModelObjects::kSphere);
break; break;
case mjGEOM_BOX: case mjGEOM_BOX:
AddShape(model_objects, ModelObjects::kBox); AddShape(renderable, model_objects, ModelObjects::kBox);
break; break;
case mjGEOM_CAPSULE: case mjGEOM_CAPSULE:
AddShape(model_objects, ModelObjects::kTube); AddShape(renderable, model_objects, ModelObjects::kTube);
AddShape(model_objects, ModelObjects::kDome); AddShape(renderable, model_objects, ModelObjects::kDome);
AddShape(model_objects, ModelObjects::kDome); AddShape(renderable, model_objects, ModelObjects::kDome);
break; break;
case mjGEOM_CYLINDER: case mjGEOM_CYLINDER:
AddShape(model_objects, ModelObjects::kTube); AddShape(renderable, model_objects, ModelObjects::kTube);
AddShape(model_objects, ModelObjects::kDisk); AddShape(renderable, model_objects, ModelObjects::kDisk);
AddShape(model_objects, ModelObjects::kDisk); AddShape(renderable, model_objects, ModelObjects::kDisk);
break; break;
case mjGEOM_ARROW: case mjGEOM_ARROW:
AddShape(model_objects, ModelObjects::kTube); AddShape(renderable, model_objects, ModelObjects::kTube);
AddShape(model_objects, ModelObjects::kCone); AddShape(renderable, model_objects, ModelObjects::kCone);
AddShape(model_objects, ModelObjects::kDisk); AddShape(renderable, model_objects, ModelObjects::kDisk);
break; break;
case mjGEOM_ARROW1: case mjGEOM_ARROW1:
AddShape(model_objects, ModelObjects::kTube); AddShape(renderable, model_objects, ModelObjects::kTube);
AddShape(model_objects, ModelObjects::kCone); AddShape(renderable, model_objects, ModelObjects::kCone);
AddShape(model_objects, ModelObjects::kDisk); AddShape(renderable, model_objects, ModelObjects::kDisk);
AddShape(model_objects, ModelObjects::kDisk); AddShape(renderable, model_objects, ModelObjects::kDisk);
break; break;
case mjGEOM_ARROW2: case mjGEOM_ARROW2:
AddShape(model_objects, ModelObjects::kTube); AddShape(renderable, model_objects, ModelObjects::kTube);
AddShape(model_objects, ModelObjects::kCone); AddShape(renderable, model_objects, ModelObjects::kCone);
AddShape(model_objects, ModelObjects::kCone); AddShape(renderable, model_objects, ModelObjects::kCone);
AddShape(model_objects, ModelObjects::kDisk); AddShape(renderable, model_objects, ModelObjects::kDisk);
AddShape(model_objects, ModelObjects::kDisk); AddShape(renderable, model_objects, ModelObjects::kDisk);
break; break;
case mjGEOM_LINE: case mjGEOM_LINE:
AddShape(model_objects, ModelObjects::kLine); AddShape(renderable, model_objects, ModelObjects::kLine);
break; break;
case mjGEOM_LINEBOX: case mjGEOM_LINEBOX:
AddShape(model_objects, ModelObjects::kLineBox); AddShape(renderable, model_objects, ModelObjects::kLineBox);
break; break;
case mjGEOM_TRIANGLE: case mjGEOM_TRIANGLE:
AddShape(model_objects, ModelObjects::kTriangle); AddShape(renderable, model_objects, ModelObjects::kTriangle);
break; break;
case mjGEOM_FLEX: case mjGEOM_FLEX:
AddGeom(model_objects, scene, geom); AddGeom(renderable, model_objects, scene, geom);
break; break;
case mjGEOM_SKIN: case mjGEOM_SKIN:
AddGeom(model_objects, scene, geom); AddGeom(renderable, model_objects, scene, geom);
break; break;
case mjGEOM_NONE: case mjGEOM_NONE:
case mjGEOM_LABEL: case mjGEOM_LABEL:
@@ -167,56 +199,22 @@ Drawable::Drawable(ModelObjects* model_objects, const mjvScene* scene,
} }
} }
void Drawable::AddMesh(ModelObjects* model_objs, int data_id) { static void SetGeomTransform(Renderable& renderable, const mjvGeom& geom) {
const Mesh* mesh = model_objs->GetMeshBuffer(data_id);
if (mesh == nullptr) {
mju_error("Unknown mesh %d", data_id);
}
renderable_.Append(mesh);
}
void Drawable::AddGeom(ModelObjects* model_objs, const mjvScene* scene,
const mjvGeom& geom) {
if (geom.type == mjGEOM_FLEX) {
renderable_.Append(model_objs->CreateFlexMesh(scene, geom));
} else if (geom.type == mjGEOM_SKIN) {
renderable_.Append(model_objs->CreateSkinMesh(scene, geom));
}
}
void Drawable::AddHeightField(ModelObjects* model_objs, int hfield_id) {
const Mesh* mesh = model_objs->GetHeightFieldBuffer(hfield_id);
if (mesh == nullptr) {
mju_error("Unknown height field %d", hfield_id);
}
renderable_.Append(mesh);
}
void Drawable::AddShape(ModelObjects* model_objs,
ModelObjects::ShapeType shape_type) {
const Mesh* mesh = model_objs->GetShapeBuffer(shape_type);
if (mesh == nullptr) {
mju_error("Unknown shape %d", shape_type);
}
renderable_.Append(mesh);
}
void Drawable::SetTransform(const mjvGeom& geom) {
// Flex and skin geometries are in global space. // Flex and skin geometries are in global space.
if (geom.type == mjGEOM_FLEX || geom.type == mjGEOM_SKIN) { if (geom.type == mjGEOM_FLEX || geom.type == mjGEOM_SKIN) {
return; return;
} }
transform_ = mat4(ReadMat3(geom.mat), ReadFloat3(geom.pos)); mat4 transform = mat4(ReadMat3(geom.mat), ReadFloat3(geom.pos));
float3 size = ReadFloat3(geom.size); float3 size = ReadFloat3(geom.size);
filament::TransformManager& tm = filament::TransformManager& tm =
renderable_.GetEngine()->getTransformManager(); renderable.GetEngine()->getTransformManager();
for (int j = 0; j < renderable_.GetNumEntities(); ++j) { for (int j = 0; j < renderable.GetNumEntities(); ++j) {
const utils::Entity& entity = renderable_[j]; const utils::Entity& entity = renderable[j];
// Update object transform. // Update object transform.
mat4 entity_transform = transform_; mat4 entity_transform = transform;
// Some built-in drawables are composed of multiple entities. For example, // Some built-in drawables are composed of multiple entities. For example,
// capsules are a combination of a open tube and two dome end caps. // capsules are a combination of a open tube and two dome end caps.
@@ -318,27 +316,34 @@ void Drawable::SetTransform(const mjvGeom& geom) {
} }
} }
void Drawable::UpdateMaterial(const mjModel* model, const mjvGeom& geom, static void UpdateGeomMaterial(Renderable& renderable, const mjvGeom& geom,
ModelObjects* model_objs, const float headpos[3], const mjvScene* scene, ModelObjects* model_objs,
const mjtByte render_flags[mjNRNDFLAG], ObjectManager* object_mgr,
ObjectManager::MaterialType* out_material_type) { const float headpos[3]) {
const bool use_segid_color = render_flags[mjRND_IDCOLOR]; const mjModel* model = model_objs->GetModel();
const bool enable_reflection = render_flags[mjRND_REFLECTION]; Material& material = renderable.GetMaterial();
const bool use_segid_color = scene->flags[mjRND_IDCOLOR];
const bool enable_reflection = scene->flags[mjRND_REFLECTION];
Material::Params params; Material::Params params;
params.color = ReadFloat4(geom.rgba); params.color = ReadFloat4(geom.rgba);
if (geom.type == mjGEOM_PLANE) { if (geom.type == mjGEOM_PLANE) {
if (IsBehind(headpos, geom.pos, geom.mat)) { if (IsBehind(headpos, geom.pos, geom.mat)) {
params.color[3] *= 0.3; params.color[3] *= 0.3;
renderable_.SetReceiveShadows(false); renderable.SetReceiveShadows(false);
params.reflective = false; params.reflective = false;
} else { } else {
renderable_.SetReceiveShadows(true); renderable.SetReceiveShadows(true);
params.reflective = params.reflective =
enable_reflection && geom.reflectance > 0 && params.color.a == 1.0f; enable_reflection && geom.reflectance > 0 && params.color.a == 1.0f;
} }
} }
renderable_.SetWireframe(render_flags[mjRND_WIREFRAME]); renderable.SetWireframe(scene->flags[mjRND_WIREFRAME]);
if (geom.category == mjCAT_DECOR) {
renderable.SetCastShadows(false);
renderable.SetReceiveShadows(false);
}
Material::Textures textures; Material::Textures textures;
if (geom.matid >= 0) { if (geom.matid >= 0) {
@@ -351,25 +356,26 @@ void Drawable::UpdateMaterial(const mjModel* model, const mjvGeom& geom,
model_objs->GetTexture(geom.matid, mjTEXROLE_ROUGHNESS); model_objs->GetTexture(geom.matid, mjTEXROLE_ROUGHNESS);
textures.occlusion = textures.occlusion =
model_objs->GetTexture(geom.matid, mjTEXROLE_OCCLUSION); model_objs->GetTexture(geom.matid, mjTEXROLE_OCCLUSION);
GetMaterial().UpdateTextures(textures); material.UpdateTextures(textures);
} }
ObjectManager::MaterialType material_type = ObjectManager::kNumMaterials;
if (geom.type == mjGEOM_LINE || geom.type == mjGEOM_LINEBOX) { if (geom.type == mjGEOM_LINE || geom.type == mjGEOM_LINEBOX) {
*out_material_type = ObjectManager::kUnlitLine; material_type = ObjectManager::kUnlitLine;
} else { } else {
bool material_assigned = false; bool material_assigned = false;
if (geom.matid >= 0) { if (geom.matid >= 0) {
material_assigned = true; material_assigned = true;
if (textures.orm) { if (textures.orm) {
*out_material_type = ObjectManager::kPbrPacked; material_type = ObjectManager::kPbrPacked;
} else if (textures.metallic) { } else if (textures.metallic) {
*out_material_type = ObjectManager::kPbr; material_type = ObjectManager::kPbr;
} else if (textures.roughness) { } else if (textures.roughness) {
*out_material_type = ObjectManager::kPbr; material_type = ObjectManager::kPbr;
} else if (model->mat_metallic[geom.matid] >= 0) { } else if (model->mat_metallic[geom.matid] >= 0) {
*out_material_type = ObjectManager::kPbr; material_type = ObjectManager::kPbr;
} else if (model->mat_roughness[geom.matid] >= 0) { } else if (model->mat_roughness[geom.matid] >= 0) {
*out_material_type = ObjectManager::kPbr; material_type = ObjectManager::kPbr;
} else { } else {
material_assigned = false; material_assigned = false;
} }
@@ -388,36 +394,36 @@ void Drawable::UpdateMaterial(const mjModel* model, const mjvGeom& geom,
if (textures.color == nullptr) { if (textures.color == nullptr) {
if (params.color.a < 1.0f) { if (params.color.a < 1.0f) {
*out_material_type = ObjectManager::kPhongColorFade; material_type = ObjectManager::kPhongColorFade;
} else if (params.reflective) { } else if (params.reflective) {
*out_material_type = ObjectManager::kPhongColorReflect; material_type = ObjectManager::kPhongColorReflect;
} else { } else {
*out_material_type = ObjectManager::kPhongColor; material_type = ObjectManager::kPhongColor;
} }
} else if (textures.color->GetFilamentTexture()->getTarget() == } else if (textures.color->GetFilamentTexture()->getTarget() ==
filament::Texture::Sampler::SAMPLER_CUBEMAP) { filament::Texture::Sampler::SAMPLER_CUBEMAP) {
if (params.color.a < 1.0f) { if (params.color.a < 1.0f) {
*out_material_type = ObjectManager::kPhongCubeFade; material_type = ObjectManager::kPhongCubeFade;
} else if (params.reflective) { } else if (params.reflective) {
*out_material_type = ObjectManager::kPhongCubeReflect; material_type = ObjectManager::kPhongCubeReflect;
} else { } else {
*out_material_type = ObjectManager::kPhongCube; material_type = ObjectManager::kPhongCube;
} }
} else if (has_texcoords) { } else if (has_texcoords) {
if (params.color.a < 1.0f) { if (params.color.a < 1.0f) {
*out_material_type = ObjectManager::kPhong2dUvFade; material_type = ObjectManager::kPhong2dUvFade;
} else if (params.reflective) { } else if (params.reflective) {
*out_material_type = ObjectManager::kPhong2dUvReflect; material_type = ObjectManager::kPhong2dUvReflect;
} else { } else {
*out_material_type = ObjectManager::kPhong2dUv; material_type = ObjectManager::kPhong2dUv;
} }
} else { } else {
if (params.color.a < 1.0f) { if (params.color.a < 1.0f) {
*out_material_type = ObjectManager::kPhong2dFade; material_type = ObjectManager::kPhong2dFade;
} else if (params.reflective) { } else if (params.reflective) {
*out_material_type = ObjectManager::kPhong2dReflect; material_type = ObjectManager::kPhong2dReflect;
} else { } else {
*out_material_type = ObjectManager::kPhong2d; material_type = ObjectManager::kPhong2d;
} }
} }
} }
@@ -522,7 +528,32 @@ void Drawable::UpdateMaterial(const mjModel* model, const mjvGeom& geom,
params.emissive *= model_objs->GetEmissiveMultiplier(); params.emissive *= model_objs->GetEmissiveMultiplier();
params.specular *= model_objs->GetSpecularMultiplier(); params.specular *= model_objs->GetSpecularMultiplier();
params.glossiness *= model_objs->GetShininessMultiplier(); params.glossiness *= model_objs->GetShininessMultiplier();
material.UpdateParams(params);
GetMaterial().UpdateParams(params); material.SetMaterial(
Material::DrawMode::kNormal,
object_mgr->GetMaterial(material_type));
material.SetMaterial(
Material::DrawMode::kDepth,
object_mgr->GetMaterial(ObjectManager::kUnlitDepth));
material.SetMaterial(
Material::DrawMode::kSegmentation,
object_mgr->GetMaterial(ObjectManager::kUnlitSegmentation));
}
std::unique_ptr<Renderable> CreateGeomRenderable(
const mjvGeom& geom, const mjvScene* scene, ObjectManager* object_mgr,
ModelObjects* model_objs, const float headpos[3],
Material::Textures* fallback_textures) {
auto renderable = std::make_unique<Renderable>(model_objs->GetEngine());
// The order of these calls is important. e.g. We need to create the filament
// renderable entities before we can set their transform.
PrepareGeomMeshes(*renderable, geom, scene, model_objs);
SetGeomTransform(*renderable, geom);
renderable->GetMaterial().SetFallbackTextures(fallback_textures);
UpdateGeomMaterial(*renderable, geom, scene, model_objs, object_mgr, headpos);
return renderable;
} }
} // namespace mujoco } // namespace mujoco
@@ -0,0 +1,36 @@
// 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_SCENE_GEOM_UTIL_H_
#define MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_SCENE_GEOM_UTIL_H_
#include <memory>
#include <mujoco/mjvisualize.h>
#include "experimental/filament/filament/material.h"
#include "experimental/filament/filament/model_objects.h"
#include "experimental/filament/filament/object_manager.h"
#include "experimental/filament/filament/renderable.h"
namespace mujoco {
// Creates a Renderable from the given mjvGeom.
std::unique_ptr<Renderable> CreateGeomRenderable(
const mjvGeom& geom, const mjvScene* scene, ObjectManager* object_mgr,
ModelObjects* model_objs, const float headpos[3],
Material::Textures* fallback_textures);
} // namespace mujoco
#endif // MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_SCENE_GEOM_UTIL_H_
@@ -40,7 +40,6 @@
#include <utils/EntityManager.h> #include <utils/EntityManager.h>
#include <mujoco/mujoco.h> #include <mujoco/mujoco.h>
#include "experimental/filament/filament/color_grading_options.h" #include "experimental/filament/filament/color_grading_options.h"
#include "experimental/filament/filament/drawable.h"
#include "experimental/filament/filament/light.h" #include "experimental/filament/filament/light.h"
#include "experimental/filament/filament/material.h" #include "experimental/filament/filament/material.h"
#include "experimental/filament/filament/math_util.h" #include "experimental/filament/filament/math_util.h"
@@ -162,11 +161,11 @@ SceneView::~SceneView() {
for (auto& light : lights_) { for (auto& light : lights_) {
light->RemoveFromScene(scene_); light->RemoveFromScene(scene_);
} }
for (auto& drawable : drawables_) { for (auto& renderable : renderables_) {
drawable->GetRenderable().RemoveFromScene(scene_); renderable->RemoveFromScene(scene_);
} }
lights_.clear(); lights_.clear();
drawables_.clear(); renderables_.clear();
reflect_targets_.clear(); reflect_targets_.clear();
engine_->destroyCameraComponent(reflect_camera_->getEntity()); engine_->destroyCameraComponent(reflect_camera_->getEntity());
engine_->destroy(reflect_view_); engine_->destroy(reflect_view_);
@@ -192,22 +191,22 @@ void SceneView::RemoveFromScene(Light* light) {
} }
} }
void SceneView::AddToScene(Drawable* drawable) { void SceneView::AddToScene(Renderable* renderable) {
if (drawables_.insert(drawable).second) { if (renderables_.insert(renderable).second) {
drawable->GetRenderable().AddToScene(scene_); renderable->AddToScene(scene_);
if (drawable->GetMaterial().GetParams().reflective) { if (renderable->GetMaterial().GetParams().reflective) {
AddReflectiveDrawable(drawable); AddReflectiveRenderable(renderable);
} }
} }
} }
void SceneView::RemoveFromScene(Drawable* drawable) { void SceneView::RemoveFromScene(Renderable* renderable) {
if (drawables_.erase(drawable)) { if (renderables_.erase(renderable)) {
auto it = std::find(reflectives_.begin(), reflectives_.end(), drawable); auto it = std::find(reflectives_.begin(), reflectives_.end(), renderable);
if (it != reflectives_.end()) { if (it != reflectives_.end()) {
reflectives_.erase(it); reflectives_.erase(it);
} }
drawable->GetRenderable().RemoveFromScene(scene_); renderable->RemoveFromScene(scene_);
} }
} }
@@ -246,11 +245,9 @@ void SceneView::Render(filament::Renderer* renderer,
SetupCamera(request.camera, viewport, camera_); SetupCamera(request.camera, viewport, camera_);
for (auto& iter : drawables_) { for (auto& iter : renderables_) {
Material& material = iter->GetMaterial(); Material& material = iter->GetMaterial();
Renderable& renderable = iter->GetRenderable(); iter->SetMaterialInstance(material.GetMaterialInstance(request.draw_mode));
renderable.SetMaterialInstance(
material.GetMaterialInstance(request.draw_mode));
} }
filament::View* view = views_[static_cast<int>(request.draw_mode)]; filament::View* view = views_[static_cast<int>(request.draw_mode)];
@@ -266,13 +263,17 @@ void SceneView::Render(filament::Renderer* renderer,
// Render reflection passes. // Render reflection passes.
if (request.draw_mode == DrawMode::kNormal) { if (request.draw_mode == DrawMode::kNormal) {
filament::TransformManager& tm = engine_->getTransformManager();
for (size_t i = 0; i < reflectives_.size(); ++i) { for (size_t i = 0; i < reflectives_.size(); ++i) {
Drawable* drawable = reflectives_[i]; Renderable* renderable = reflectives_[i];
SetupReflectionCamera(drawable->GetTransform(), camera_, reflect_camera_); // We assume the 0th entity is the reflective entity.
const utils::Entity entity = (*renderable)[0];
const mat4 transform(tm.getTransform(tm.getInstance(entity)));
SetupReflectionCamera(transform, camera_, reflect_camera_);
// Hide reflective surface from its own reflection pass. // Hide reflective surface from its own reflection pass.
drawable->GetRenderable().SetLayerMask(0x00); renderable->SetLayerMask(0x00);
// Render the reflection to its render target. // Render the reflection to its render target.
reflect_view_->setRenderTarget( reflect_view_->setRenderTarget(
@@ -280,7 +281,7 @@ void SceneView::Render(filament::Renderer* renderer,
renderer->render(reflect_view_); renderer->render(reflect_view_);
// Unhide the reflective surface. // Unhide the reflective surface.
drawable->GetRenderable().SetLayerMask(0x01); renderable->SetLayerMask(0x01);
} }
} }
@@ -293,24 +294,24 @@ void SceneView::Render(filament::Renderer* renderer,
} }
} }
void SceneView::AddReflectiveDrawable(Drawable* drawable) { void SceneView::AddReflectiveRenderable(Renderable* renderable) {
const int index = reflectives_.size(); const int index = reflectives_.size();
reflectives_.push_back(drawable); reflectives_.push_back(renderable);
// Ensure we have the same number of render targets as we do reflective // Ensure we have the same number of render targets as we do reflective
// drawables. // renderables.
while (reflect_targets_.size() < reflectives_.size()) { while (reflect_targets_.size() < reflectives_.size()) {
reflect_targets_.push_back(std::make_unique<RenderTarget>( reflect_targets_.push_back(std::make_unique<RenderTarget>(
engine_, RenderTargetTextureType::kReflectionColor, engine_, RenderTargetTextureType::kReflectionColor,
RenderTargetTextureType::kDepth)); RenderTargetTextureType::kDepth));
} }
// Prepare a render target for the reflective drawable. // Prepare a render target for the reflective renderable.
auto viewport = reflect_view_->getViewport(); auto viewport = reflect_view_->getViewport();
auto& target = reflect_targets_[index]; auto& target = reflect_targets_[index];
target->Prepare(viewport.width, viewport.height); target->Prepare(viewport.width, viewport.height);
Material& material = drawable->GetMaterial(); Material& material = renderable->GetMaterial();
Material::Textures textures = material.GetTextures(); Material::Textures textures = material.GetTextures();
textures.reflection = target->GetColorTexture(); textures.reflection = target->GetColorTexture();
material.UpdateTextures(textures); material.UpdateTextures(textures);
@@ -27,9 +27,9 @@
#include <filament/View.h> #include <filament/View.h>
#include <mujoco/mujoco.h> #include <mujoco/mujoco.h>
#include "experimental/filament/filament/color_grading_options.h" #include "experimental/filament/filament/color_grading_options.h"
#include "experimental/filament/filament/drawable.h"
#include "experimental/filament/filament/light.h" #include "experimental/filament/filament/light.h"
#include "experimental/filament/filament/material.h" #include "experimental/filament/filament/material.h"
#include "experimental/filament/filament/renderable.h"
#include "experimental/filament/filament/render_target.h" #include "experimental/filament/filament/render_target.h"
namespace mujoco { namespace mujoco {
@@ -47,8 +47,8 @@ class SceneView {
// Adds/removes entities from the scene. // Adds/removes entities from the scene.
void AddToScene(Light* light); void AddToScene(Light* light);
void RemoveFromScene(Light* light); void RemoveFromScene(Light* light);
void AddToScene(Drawable* drawable); void AddToScene(Renderable* renderable);
void RemoveFromScene(Drawable* drawable); void RemoveFromScene(Renderable* renderable);
void AddToScene(filament::Skybox* skybox); void AddToScene(filament::Skybox* skybox);
void RemoveFromScene(filament::Skybox* skybox); void RemoveFromScene(filament::Skybox* skybox);
void AddToScene(filament::IndirectLight* indirect_light); void AddToScene(filament::IndirectLight* indirect_light);
@@ -85,9 +85,9 @@ class SceneView {
SceneView& operator=(const SceneView&) = delete; SceneView& operator=(const SceneView&) = delete;
private: private:
// Marks a drawable as reflective. Reflective drawables have to be rendered // Marks a renderable as reflective. Reflective renderables have to be
// in their own passes to create the reflective texture. // rendered in their own passes to create the reflective texture.
void AddReflectiveDrawable(Drawable* drawable); void AddReflectiveRenderable(Renderable* renderable);
filament::Engine* engine_ = nullptr; filament::Engine* engine_ = nullptr;
filament::Scene* scene_ = nullptr; filament::Scene* scene_ = nullptr;
@@ -99,7 +99,7 @@ class SceneView {
// Scene objects. // Scene objects.
std::unordered_set<Light*> lights_; std::unordered_set<Light*> lights_;
std::unordered_set<Drawable*> drawables_; std::unordered_set<Renderable*> renderables_;
filament::Skybox* skybox_ = nullptr; filament::Skybox* skybox_ = nullptr;
filament::IndirectLight* indirect_light_ = nullptr; filament::IndirectLight* indirect_light_ = nullptr;
@@ -107,8 +107,8 @@ class SceneView {
filament::View* reflect_view_ = nullptr; filament::View* reflect_view_ = nullptr;
filament::Camera* reflect_camera_ = nullptr; filament::Camera* reflect_camera_ = nullptr;
// The list of reflective drawables and their corresponding render targets. // The list of reflective renderables and their corresponding render targets.
std::vector<Drawable*> reflectives_; std::vector<Renderable*> reflectives_;
std::vector<std::unique_ptr<RenderTarget>> reflect_targets_; std::vector<std::unique_ptr<RenderTarget>> reflect_targets_;
}; };
} // namespace mujoco } // namespace mujoco