Factor out mjModel-specific objects from ObjectManager.
All objects that are specific to the mjModel (meshes, textures, etc.) are now managed by a ModelObjects class which is owned by the SceneView and not the FilamentContext. PiperOrigin-RevId: 892250776 Change-Id: Iddad66fd3ab1a60c4becdcb5d0c935ed9ea8ad90
This commit is contained in:
committed by
Copybara-Service
parent
51b2f52296
commit
06d6bda5bb
@@ -47,6 +47,8 @@ target_sources(${MUJOCO_FILAMENT_TARGET_NAME}
|
||||
filament/material.h
|
||||
filament/math_util.cc
|
||||
filament/math_util.h
|
||||
filament/model_objects.cc
|
||||
filament/model_objects.h
|
||||
filament/model_util.cc
|
||||
filament/model_util.h
|
||||
filament/object_manager.cc
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "experimental/filament/filament/geom_util.h"
|
||||
#include "experimental/filament/filament/material.h"
|
||||
#include "experimental/filament/filament/math_util.h"
|
||||
#include "experimental/filament/filament/model_objects.h"
|
||||
#include "experimental/filament/filament/object_manager.h"
|
||||
|
||||
namespace mujoco {
|
||||
@@ -85,8 +86,11 @@ static bool IsBehind(const mjtNum* headpos, const float* pos, const float* mat)
|
||||
(headpos[2] - pos[2]) * mat[8] < 0.0f);
|
||||
}
|
||||
|
||||
Drawable::Drawable(ObjectManager* object_mgr, const mjvGeom& geom)
|
||||
: material_(object_mgr), renderables_(object_mgr->GetEngine()) {
|
||||
Drawable::Drawable(ObjectManager* object_mgr, ModelObjects* model_objects,
|
||||
const mjvGeom& geom)
|
||||
: material_(object_mgr),
|
||||
model_objs_(model_objects),
|
||||
renderables_(object_mgr->GetEngine()) {
|
||||
if (geom.category == mjCAT_DECOR) {
|
||||
renderables_.SetCastShadows(false);
|
||||
renderables_.SetReceiveShadows(false);
|
||||
@@ -100,53 +104,53 @@ Drawable::Drawable(ObjectManager* object_mgr, const mjvGeom& geom)
|
||||
AddHeightField(geom.dataid);
|
||||
break;
|
||||
case mjGEOM_PLANE:
|
||||
AddShape(ObjectManager::kPlane);
|
||||
AddShape(ModelObjects::kPlane);
|
||||
break;
|
||||
case mjGEOM_SPHERE:
|
||||
AddShape(ObjectManager::kSphere);
|
||||
AddShape(ModelObjects::kSphere);
|
||||
break;
|
||||
case mjGEOM_ELLIPSOID:
|
||||
AddShape(ObjectManager::kSphere);
|
||||
AddShape(ModelObjects::kSphere);
|
||||
break;
|
||||
case mjGEOM_BOX:
|
||||
AddShape(ObjectManager::kBox);
|
||||
AddShape(ModelObjects::kBox);
|
||||
break;
|
||||
case mjGEOM_CAPSULE:
|
||||
AddShape(ObjectManager::kTube);
|
||||
AddShape(ObjectManager::kDome);
|
||||
AddShape(ObjectManager::kDome);
|
||||
AddShape(ModelObjects::kTube);
|
||||
AddShape(ModelObjects::kDome);
|
||||
AddShape(ModelObjects::kDome);
|
||||
break;
|
||||
case mjGEOM_CYLINDER:
|
||||
AddShape(ObjectManager::kTube);
|
||||
AddShape(ObjectManager::kDisk);
|
||||
AddShape(ObjectManager::kDisk);
|
||||
AddShape(ModelObjects::kTube);
|
||||
AddShape(ModelObjects::kDisk);
|
||||
AddShape(ModelObjects::kDisk);
|
||||
break;
|
||||
case mjGEOM_ARROW:
|
||||
AddShape(ObjectManager::kTube);
|
||||
AddShape(ObjectManager::kCone);
|
||||
AddShape(ObjectManager::kDisk);
|
||||
AddShape(ModelObjects::kTube);
|
||||
AddShape(ModelObjects::kCone);
|
||||
AddShape(ModelObjects::kDisk);
|
||||
break;
|
||||
case mjGEOM_ARROW1:
|
||||
AddShape(ObjectManager::kTube);
|
||||
AddShape(ObjectManager::kCone);
|
||||
AddShape(ObjectManager::kDisk);
|
||||
AddShape(ObjectManager::kDisk);
|
||||
AddShape(ModelObjects::kTube);
|
||||
AddShape(ModelObjects::kCone);
|
||||
AddShape(ModelObjects::kDisk);
|
||||
AddShape(ModelObjects::kDisk);
|
||||
break;
|
||||
case mjGEOM_ARROW2:
|
||||
AddShape(ObjectManager::kTube);
|
||||
AddShape(ObjectManager::kCone);
|
||||
AddShape(ObjectManager::kCone);
|
||||
AddShape(ObjectManager::kDisk);
|
||||
AddShape(ObjectManager::kDisk);
|
||||
AddShape(ModelObjects::kTube);
|
||||
AddShape(ModelObjects::kCone);
|
||||
AddShape(ModelObjects::kCone);
|
||||
AddShape(ModelObjects::kDisk);
|
||||
AddShape(ModelObjects::kDisk);
|
||||
break;
|
||||
case mjGEOM_LINE:
|
||||
AddShape(ObjectManager::kLine);
|
||||
AddShape(ModelObjects::kLine);
|
||||
break;
|
||||
case mjGEOM_LINEBOX:
|
||||
AddShape(ObjectManager::kLineBox);
|
||||
AddShape(ModelObjects::kLineBox);
|
||||
break;
|
||||
case mjGEOM_TRIANGLE:
|
||||
AddShape(ObjectManager::kTriangle);
|
||||
AddShape(ModelObjects::kTriangle);
|
||||
break;
|
||||
case mjGEOM_FLEX:
|
||||
case mjGEOM_SKIN:
|
||||
@@ -187,8 +191,7 @@ void Drawable::Update(const mjModel* model, const mjvScene* scene,
|
||||
}
|
||||
|
||||
void Drawable::AddMesh(int data_id) {
|
||||
ObjectManager* object_mgr = material_.GetObjectManager();
|
||||
const FilamentBuffers* buffers = object_mgr->GetMeshBuffer(data_id);
|
||||
const FilamentBuffers* buffers = model_objs_->GetMeshBuffer(data_id);
|
||||
if (buffers == nullptr) {
|
||||
mju_error("Unknown mesh %d", data_id);
|
||||
}
|
||||
@@ -196,17 +199,15 @@ void Drawable::AddMesh(int data_id) {
|
||||
}
|
||||
|
||||
void Drawable::AddHeightField(int hfield_id) {
|
||||
ObjectManager* object_mgr = material_.GetObjectManager();
|
||||
const FilamentBuffers* buffers = object_mgr->GetHeightFieldBuffer(hfield_id);
|
||||
const FilamentBuffers* buffers = model_objs_->GetHeightFieldBuffer(hfield_id);
|
||||
if (buffers == nullptr) {
|
||||
mju_error("Unknown height field %d", hfield_id);
|
||||
}
|
||||
renderables_.Append(*buffers);
|
||||
}
|
||||
|
||||
void Drawable::AddShape(ObjectManager::ShapeType shape_type) {
|
||||
ObjectManager* object_mgr = material_.GetObjectManager();
|
||||
const FilamentBuffers* buffers = object_mgr->GetShapeBuffer(shape_type);
|
||||
void Drawable::AddShape(ModelObjects::ShapeType shape_type) {
|
||||
const FilamentBuffers* buffers = model_objs_->GetShapeBuffer(shape_type);
|
||||
if (buffers == nullptr) {
|
||||
mju_error("Unknown shape %d", shape_type);
|
||||
}
|
||||
@@ -352,8 +353,7 @@ void Drawable::SetTransform(const mjvGeom& geom) {
|
||||
|
||||
void Drawable::UpdateMaterial(const mjvGeom& geom, bool use_segid_color,
|
||||
bool enable_reflection, const mjtNum* headpos) {
|
||||
ObjectManager* object_mgr = material_.GetObjectManager();
|
||||
const mjModel* model = object_mgr->GetModel();
|
||||
const mjModel* model = model_objs_->GetModel();
|
||||
|
||||
float4 color = ReadFloat4(geom.rgba);
|
||||
if (geom.type == mjGEOM_PLANE) {
|
||||
@@ -370,15 +370,15 @@ void Drawable::UpdateMaterial(const mjvGeom& geom, bool use_segid_color,
|
||||
|
||||
Material::Textures textures;
|
||||
if (geom.matid >= 0) {
|
||||
textures.color = object_mgr->GetTexture(geom.matid, mjTEXROLE_RGB);
|
||||
textures.normal = object_mgr->GetTexture(geom.matid, mjTEXROLE_NORMAL);
|
||||
textures.emissive = object_mgr->GetTexture(geom.matid, mjTEXROLE_EMISSIVE);
|
||||
textures.orm = object_mgr->GetTexture(geom.matid, mjTEXROLE_ORM);
|
||||
textures.metallic = object_mgr->GetTexture(geom.matid, mjTEXROLE_METALLIC);
|
||||
textures.color = model_objs_->GetTexture(geom.matid, mjTEXROLE_RGB);
|
||||
textures.normal = model_objs_->GetTexture(geom.matid, mjTEXROLE_NORMAL);
|
||||
textures.emissive = model_objs_->GetTexture(geom.matid, mjTEXROLE_EMISSIVE);
|
||||
textures.orm = model_objs_->GetTexture(geom.matid, mjTEXROLE_ORM);
|
||||
textures.metallic = model_objs_->GetTexture(geom.matid, mjTEXROLE_METALLIC);
|
||||
textures.roughness =
|
||||
object_mgr->GetTexture(geom.matid, mjTEXROLE_ROUGHNESS);
|
||||
model_objs_->GetTexture(geom.matid, mjTEXROLE_ROUGHNESS);
|
||||
textures.occlusion =
|
||||
object_mgr->GetTexture(geom.matid, mjTEXROLE_OCCLUSION);
|
||||
model_objs_->GetTexture(geom.matid, mjTEXROLE_OCCLUSION);
|
||||
material_.UpdateTextures(textures);
|
||||
}
|
||||
|
||||
@@ -548,9 +548,9 @@ void Drawable::UpdateMaterial(const mjvGeom& geom, bool use_segid_color,
|
||||
}
|
||||
|
||||
// Apply material multipliers from the model.
|
||||
params.emissive *= object_mgr->GetEmissiveMultiplier();
|
||||
params.specular *= object_mgr->GetSpecularMultiplier();
|
||||
params.glossiness *= object_mgr->GetShininessMultiplier();
|
||||
params.emissive *= model_objs_->GetEmissiveMultiplier();
|
||||
params.specular *= model_objs_->GetSpecularMultiplier();
|
||||
params.glossiness *= model_objs_->GetShininessMultiplier();
|
||||
|
||||
material_.UpdateParams(params);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#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/renderables.h"
|
||||
|
||||
@@ -31,7 +32,8 @@ namespace mujoco {
|
||||
// Manages the filament Entities and MaterialInstances for a single mjvGeom.
|
||||
class Drawable {
|
||||
public:
|
||||
Drawable(ObjectManager* object_mgr, const mjvGeom& geom);
|
||||
Drawable(ObjectManager* object_mgr, ModelObjects* model_objects,
|
||||
const mjvGeom& geom);
|
||||
~Drawable() noexcept = default;
|
||||
|
||||
Drawable(const Drawable&) = delete;
|
||||
@@ -71,7 +73,7 @@ class Drawable {
|
||||
private:
|
||||
void AddMesh(int data_id);
|
||||
void AddHeightField(int hfield_id);
|
||||
void AddShape(ObjectManager::ShapeType shape_type);
|
||||
void AddShape(ModelObjects::ShapeType shape_type);
|
||||
|
||||
// Updates the transform of the drawable for rendering.
|
||||
void SetTransform(const mjvGeom& geom);
|
||||
@@ -81,6 +83,7 @@ class Drawable {
|
||||
bool enable_reflection, const mjtNum* headpos);
|
||||
|
||||
Material material_;
|
||||
ModelObjects* model_objs_ = nullptr;
|
||||
Renderables renderables_;
|
||||
bool reflective_ = false;
|
||||
filament::math::mat4 transform_;
|
||||
|
||||
@@ -41,10 +41,10 @@
|
||||
#include "experimental/filament/filament/filament_platform_factory.h"
|
||||
#include "experimental/filament/filament/gui_view.h"
|
||||
#include "experimental/filament/filament/imgui_editor.h"
|
||||
#include "experimental/filament/filament/object_manager.h"
|
||||
#include "experimental/filament/filament/model_util.h"
|
||||
#include "experimental/filament/filament/scene_view.h"
|
||||
#include "experimental/filament/filament/object_manager.h"
|
||||
#include "experimental/filament/filament/render_target_util.h"
|
||||
#include "experimental/filament/filament/scene_view.h"
|
||||
#include "experimental/filament/render_context_filament.h"
|
||||
|
||||
namespace mujoco {
|
||||
@@ -72,6 +72,8 @@ FilamentContext::FilamentContext(const mjrFilamentConfig* config)
|
||||
}
|
||||
#endif
|
||||
offscreen_swap_chain_ = engine_->createSwapChain(config_.width, config_.height);
|
||||
|
||||
object_manager_ = std::make_unique<ObjectManager>(engine_);
|
||||
}
|
||||
|
||||
FilamentContext::~FilamentContext() {
|
||||
@@ -86,8 +88,7 @@ FilamentContext::~FilamentContext() {
|
||||
}
|
||||
|
||||
void FilamentContext::Init(const mjModel* model) {
|
||||
object_manager_ = std::make_unique<ObjectManager>(model, engine_);
|
||||
scene_view_ = std::make_unique<SceneView>(engine_, object_manager_.get());
|
||||
scene_view_ = std::make_unique<SceneView>(object_manager_.get(), model);
|
||||
gui_view_ = std::make_unique<GuiView>(
|
||||
engine_, object_manager_->GetMaterial(ObjectManager::kUnlitUi));
|
||||
|
||||
@@ -270,15 +271,24 @@ void FilamentContext::ReadPixels(mjrRect viewport, unsigned char* rgb,
|
||||
}
|
||||
|
||||
void FilamentContext::UploadMesh(const mjModel* model, int id) {
|
||||
object_manager_->UploadMesh(model, id);
|
||||
if (!scene_view_) {
|
||||
mju_error("SceneView is not initialized.");
|
||||
}
|
||||
scene_view_->UploadMesh(model, id);
|
||||
}
|
||||
|
||||
void FilamentContext::UploadTexture(const mjModel* model, int id) {
|
||||
object_manager_->UploadTexture(model, id);
|
||||
if (!scene_view_) {
|
||||
mju_error("SceneView is not initialized.");
|
||||
}
|
||||
scene_view_->UploadTexture(model, id);
|
||||
}
|
||||
|
||||
void FilamentContext::UploadHeightField(const mjModel* model, int id) {
|
||||
object_manager_->UploadHeightField(model, id);
|
||||
if (!scene_view_) {
|
||||
mju_error("SceneView is not initialized.");
|
||||
}
|
||||
scene_view_->UploadHeightField(model, id);
|
||||
}
|
||||
|
||||
uintptr_t FilamentContext::UploadGuiImage(uintptr_t tex_id,
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
#include <mujoco/mjvisualize.h>
|
||||
#include "experimental/filament/filament/gui_view.h"
|
||||
#include "experimental/filament/filament/object_manager.h"
|
||||
#include "experimental/filament/filament/scene_view.h"
|
||||
#include "experimental/filament/filament/render_target_util.h"
|
||||
#include "experimental/filament/filament/scene_view.h"
|
||||
#include "experimental/filament/render_context_filament.h"
|
||||
|
||||
namespace mujoco {
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace mujoco {
|
||||
|
||||
Material::Material(ObjectManager* object_mgr) : object_mgr_(object_mgr) {
|
||||
instances_[kDepth] =
|
||||
object_mgr->GetMaterial(ObjectManager::kUnlitDepth)->createInstance();
|
||||
object_mgr_->GetMaterial(ObjectManager::kUnlitDepth)->createInstance();
|
||||
instances_[kSegmentation] =
|
||||
object_mgr_->GetMaterial(ObjectManager::kUnlitSegmentation)
|
||||
->createInstance();
|
||||
|
||||
@@ -89,10 +89,6 @@ class Material {
|
||||
return instances_[mode];
|
||||
}
|
||||
|
||||
// Returns the ObjectManager owning the Materials which are used to create
|
||||
// the MaterialInstances.
|
||||
ObjectManager* GetObjectManager() { return object_mgr_; }
|
||||
|
||||
private:
|
||||
// Updates the material instances based on the currently set parameters and
|
||||
// textures.
|
||||
|
||||
@@ -0,0 +1,258 @@
|
||||
// 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/filament/model_objects.h"
|
||||
|
||||
#include <array>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/IndirectLight.h>
|
||||
#include <filament/Material.h>
|
||||
#include <filament/Skybox.h>
|
||||
#include <mujoco/mujoco.h>
|
||||
#include "experimental/filament/filament/buffer_util.h"
|
||||
#include "experimental/filament/filament/builtins.h"
|
||||
#include "experimental/filament/filament/model_util.h"
|
||||
#include "experimental/filament/filament/texture_util.h"
|
||||
|
||||
|
||||
namespace mujoco {
|
||||
|
||||
ModelObjects::ModelObjects(const mjModel* model, filament::Engine* engine)
|
||||
: model_(model), engine_(engine) {
|
||||
const int nstack = model->vis.quality.numstacks;
|
||||
const int nslice = model->vis.quality.numslices;
|
||||
const int nquad = model->vis.quality.numquads;
|
||||
shapes_[kLine] = CreateLine(engine_);
|
||||
shapes_[kBox] = CreateBox(engine_, nquad);
|
||||
shapes_[kLineBox] = CreateLineBox(engine_);
|
||||
shapes_[kCone] = CreateCone(engine_, nstack, nslice);
|
||||
shapes_[kDisk] = CreateDisk(engine_, nslice);
|
||||
shapes_[kDome] = CreateDome(engine_, nstack / 2, nslice);
|
||||
shapes_[kTube] = CreateTube(engine_, nstack, nslice);
|
||||
shapes_[kPlane] = CreatePlane(engine_, nquad);
|
||||
shapes_[kSphere] = CreateSphere(engine_, nstack, nslice);
|
||||
shapes_[kTriangle] = CreateTriangle(engine_);
|
||||
|
||||
for (int i = 0; i < model_->ntex; ++i) {
|
||||
UploadTexture(model_, i);
|
||||
}
|
||||
for (int i = 0; i < model_->nmesh; ++i) {
|
||||
UploadMesh(model_, i);
|
||||
}
|
||||
for (int i = 0; i < model_->nhfield; ++i) {
|
||||
UploadHeightField(model_, i);
|
||||
}
|
||||
|
||||
specular_multiplier_ = ReadElement(
|
||||
model_, "filament.phong.specular_multiplier", specular_multiplier_);
|
||||
shininess_multiplier_ = ReadElement(
|
||||
model_, "filament.phong.shininess_multiplier", shininess_multiplier_);
|
||||
emissive_multiplier_ = ReadElement(
|
||||
model_, "filament.phong.emissive_multiplier", emissive_multiplier_);
|
||||
}
|
||||
|
||||
ModelObjects::~ModelObjects() {
|
||||
for (auto& iter : skyboxes_) {
|
||||
engine_->destroy(iter);
|
||||
}
|
||||
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);
|
||||
}
|
||||
for (auto& iter : textures_) {
|
||||
engine_->destroy(iter.second);
|
||||
}
|
||||
}
|
||||
|
||||
void ModelObjects::UploadMesh(const mjModel* model, int id) {
|
||||
if (model != model_) {
|
||||
mju_error("Model mismatch.");
|
||||
}
|
||||
if (id < 0 || id >= model->nmesh) {
|
||||
mju_error("Invalid mesh index %d", 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.index_buffer =
|
||||
CreateIndexBuffer(engine_, model, id, MeshType::kNormal);
|
||||
|
||||
if (model->mesh_graphadr[id] >= 0) {
|
||||
FilamentBuffers& hull_buffers = convex_hulls_[id];
|
||||
hull_buffers.vertex_buffer =
|
||||
CreateVertexBuffer(engine_, model, id, MeshType::kConvexHull);
|
||||
hull_buffers.index_buffer =
|
||||
CreateIndexBuffer(engine_, model, id, MeshType::kConvexHull);
|
||||
}
|
||||
}
|
||||
|
||||
void ModelObjects::UploadTexture(const mjModel* model, int id) {
|
||||
if (model != model_) {
|
||||
mju_error("Model mismatch.");
|
||||
}
|
||||
if (id < 0 || id >= model->ntex) {
|
||||
mju_error("Invalid texture index: %d", id);
|
||||
}
|
||||
|
||||
if (auto iter = textures_.find(id); iter != textures_.end()) {
|
||||
engine_->destroy(iter->second);
|
||||
}
|
||||
|
||||
const int texture_type = model->tex_type[id];
|
||||
if (model->tex_height[id] == 1) {
|
||||
const mjtByte* bytes = model->tex_data + model->tex_adr[id];
|
||||
const int num_bytes = model->tex_width[id];
|
||||
textures_[id] =
|
||||
CreateKtxTexture(engine_, bytes, num_bytes, spherical_harmonics_[id]);
|
||||
} else if (texture_type == mjTEXTURE_2D) {
|
||||
textures_[id] = CreateTexture(engine_, model, id, TextureType::kNormal2d);
|
||||
} else if (texture_type == mjTEXTURE_CUBE) {
|
||||
textures_[id] = CreateTexture(engine_, model, id, TextureType::kCube);
|
||||
} else if (texture_type == mjTEXTURE_SKYBOX) {
|
||||
textures_[id] = CreateTexture(engine_, model, id, TextureType::kCube);
|
||||
} else {
|
||||
mju_error("Unsupported: Texture type: %d", texture_type);
|
||||
}
|
||||
}
|
||||
|
||||
void ModelObjects::UploadHeightField(const mjModel* model, int id) {
|
||||
if (model != model_) {
|
||||
mju_error("Model mismatch.");
|
||||
}
|
||||
if (id < 0 || id >= model->nhfield) {
|
||||
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);
|
||||
}
|
||||
|
||||
FilamentBuffers& buffers = height_fields_[id];
|
||||
buffers.vertex_buffer =
|
||||
CreateVertexBuffer(engine_, model, id, MeshType::kHeightField);
|
||||
buffers.index_buffer =
|
||||
CreateIndexBuffer(engine_, model, id, MeshType::kHeightField);
|
||||
}
|
||||
|
||||
const FilamentBuffers* 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;
|
||||
} else {
|
||||
auto it = convex_hulls_.find(mesh_id);
|
||||
return it != convex_hulls_.end() ? &it->second : nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const FilamentBuffers* ModelObjects::GetHeightFieldBuffer(
|
||||
int hfield_id) const {
|
||||
auto it = height_fields_.find(hfield_id);
|
||||
return it != height_fields_.end() ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
const FilamentBuffers* ModelObjects::GetShapeBuffer(ShapeType shape) const {
|
||||
if (shape < 0 || shape >= kNumShapes) {
|
||||
mju_error("Invalid shape type: %d", shape);
|
||||
}
|
||||
return &shapes_[shape];
|
||||
}
|
||||
|
||||
const filament::Texture* ModelObjects::GetTexture(int tex_id) const {
|
||||
auto it = textures_.find(tex_id);
|
||||
return it != textures_.end() ? it->second : nullptr;
|
||||
}
|
||||
|
||||
const filament::Texture* ModelObjects::GetTexture(int mat_id, int role) const {
|
||||
if (mat_id < 0 || mat_id >= model_->nmat || role < 0 || role >= mjNTEXROLE) {
|
||||
return nullptr;
|
||||
}
|
||||
const int tex_id = model_->mat_texid[mat_id * mjNTEXROLE + role];
|
||||
return GetTexture(tex_id);
|
||||
}
|
||||
|
||||
filament::IndirectLight* ModelObjects::CreateIndirectLight(int tex_id,
|
||||
float intensity) {
|
||||
filament::Texture* texture = nullptr;
|
||||
auto texture_iter = textures_.find(tex_id);
|
||||
if (texture_iter != textures_.end()) {
|
||||
texture = texture_iter->second;
|
||||
}
|
||||
|
||||
SphericalHarmonics* spherical_harmonics = nullptr;
|
||||
auto sh_iter = spherical_harmonics_.find(tex_id);
|
||||
if (sh_iter != spherical_harmonics_.end()) {
|
||||
spherical_harmonics = &sh_iter->second;
|
||||
}
|
||||
|
||||
filament::IndirectLight::Builder builder;
|
||||
builder.reflections(texture);
|
||||
if (spherical_harmonics != nullptr) {
|
||||
builder.irradiance(3, *spherical_harmonics);
|
||||
}
|
||||
builder.intensity(intensity);
|
||||
// Rotate the light to match mujoco's Z-up convention.
|
||||
builder.rotation(filament::math::mat3f::rotation(
|
||||
filament::math::f::PI / 2, filament::math::float3{1, 0, 0}));
|
||||
filament::IndirectLight* indirect_light = builder.build(*engine_);
|
||||
indirect_lights_.push_back(indirect_light);
|
||||
return indirect_light;
|
||||
}
|
||||
|
||||
filament::Skybox* ModelObjects::CreateSkybox() {
|
||||
filament::Texture* skybox_texture = nullptr;
|
||||
for (auto& iter : textures_) {
|
||||
const int texture_type = model_->tex_type[iter.first];
|
||||
if (texture_type == mjTEXTURE_SKYBOX) {
|
||||
skybox_texture = iter.second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (skybox_texture == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
filament::Skybox::Builder builder;
|
||||
builder.environment(skybox_texture);
|
||||
filament::Skybox* skybox = builder.build(*engine_);
|
||||
skyboxes_.push_back(skybox);
|
||||
return skybox;
|
||||
}
|
||||
|
||||
} // namespace mujoco
|
||||
@@ -0,0 +1,100 @@
|
||||
// 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_FILAMENT_MODEL_OBJECTS_H_
|
||||
#define MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_MODEL_OBJECTS_H_
|
||||
|
||||
#include <array>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/IndirectLight.h>
|
||||
#include <filament/Skybox.h>
|
||||
#include <math/vec3.h>
|
||||
#include <mujoco/mjmodel.h>
|
||||
#include "experimental/filament/filament/buffer_util.h"
|
||||
|
||||
namespace mujoco {
|
||||
|
||||
// Creates and owns various filament objects based on the data in a mjrContext.
|
||||
class ModelObjects {
|
||||
public:
|
||||
ModelObjects(const mjModel* model, filament::Engine* engine);
|
||||
~ModelObjects();
|
||||
|
||||
enum ShapeType {
|
||||
kLine,
|
||||
kLineBox,
|
||||
kPlane,
|
||||
kTriangle,
|
||||
kBox,
|
||||
kSphere,
|
||||
kCone,
|
||||
kDisk,
|
||||
kDome,
|
||||
kTube,
|
||||
kNumShapes,
|
||||
};
|
||||
|
||||
void UploadMesh(const mjModel* model, int id);
|
||||
|
||||
void UploadTexture(const mjModel* model, int id);
|
||||
|
||||
void UploadHeightField(const mjModel* model, int id);
|
||||
|
||||
// Returns the filament engine used by the ModelObjects to create filament
|
||||
// objects.
|
||||
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 filament::Texture* GetTexture(int tex_id) const;
|
||||
const filament::Texture* GetTexture(int mat_id, int role) const;
|
||||
|
||||
filament::Skybox* CreateSkybox();
|
||||
filament::IndirectLight* CreateIndirectLight(int tex_id, float intensity);
|
||||
|
||||
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;
|
||||
|
||||
private:
|
||||
using SphericalHarmonics = filament::math::float3[9];
|
||||
|
||||
const mjModel* model_ = nullptr;
|
||||
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::unordered_map<int, filament::Texture*> textures_;
|
||||
std::unordered_map<int, SphericalHarmonics> spherical_harmonics_;
|
||||
float specular_multiplier_ = 0.2f;
|
||||
float shininess_multiplier_ = 0.1f;
|
||||
float emissive_multiplier_ = 0.3f;
|
||||
};
|
||||
|
||||
} // namespace mujoco
|
||||
|
||||
#endif // MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_MODEL_OBJECTS_H_
|
||||
@@ -14,12 +14,9 @@
|
||||
|
||||
#include "experimental/filament/filament/object_manager.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/IndirectLight.h>
|
||||
@@ -29,11 +26,7 @@
|
||||
#include <math/scalar.h>
|
||||
#include <math/vec3.h>
|
||||
#include <mujoco/mujoco.h>
|
||||
#include "experimental/filament/filament/buffer_util.h"
|
||||
#include "experimental/filament/filament/builtins.h"
|
||||
#include "experimental/filament/filament/model_util.h"
|
||||
#include "experimental/filament/filament/texture_util.h"
|
||||
#include "experimental/filament/render_context_filament.h"
|
||||
#include "user/user_resource.h"
|
||||
|
||||
namespace mujoco {
|
||||
@@ -64,23 +57,8 @@ struct Asset {
|
||||
|
||||
} // namespace
|
||||
|
||||
ObjectManager::ObjectManager(const mjModel* model, filament::Engine* engine)
|
||||
: model_(model), engine_(engine) {
|
||||
const int nquad = model->vis.quality.numquads;
|
||||
const int nstack = model->vis.quality.numstacks;
|
||||
const int nslice = model->vis.quality.numslices;
|
||||
|
||||
shapes_[kLine] = CreateLine(engine_);
|
||||
shapes_[kBox] = CreateBox(engine_, nquad);
|
||||
shapes_[kLineBox] = CreateLineBox(engine_);
|
||||
shapes_[kCone] = CreateCone(engine_, nstack, nslice);
|
||||
shapes_[kDisk] = CreateDisk(engine_, nslice);
|
||||
shapes_[kDome] = CreateDome(engine_, nstack / 2, nslice);
|
||||
shapes_[kTube] = CreateTube(engine_, nstack, nslice);
|
||||
shapes_[kPlane] = CreatePlane(engine_, nquad);
|
||||
shapes_[kSphere] = CreateSphere(engine_, nstack, nslice);
|
||||
shapes_[kTriangle] = CreateTriangle(engine_);
|
||||
|
||||
ObjectManager::ObjectManager(filament::Engine* engine)
|
||||
: engine_(engine) {
|
||||
auto LoadMaterial = [this](std::string_view filename) {
|
||||
Asset asset(filename);
|
||||
filament::Material::Builder material_builder;
|
||||
@@ -107,16 +85,6 @@ ObjectManager::ObjectManager(const mjModel* model, filament::Engine* engine)
|
||||
materials_[kUnlitDepth] = LoadMaterial("unlit_depth.filamat");
|
||||
materials_[kUnlitUi] = LoadMaterial("unlit_ui.filamat");
|
||||
|
||||
for (int i = 0; i < model_->ntex; ++i) {
|
||||
UploadTexture(model_, i);
|
||||
}
|
||||
for (int i = 0; i < model_->nmesh; ++i) {
|
||||
UploadMesh(model_, i);
|
||||
}
|
||||
for (int i = 0; i < model_->nhfield; ++i) {
|
||||
UploadHeightField(model_, i);
|
||||
}
|
||||
|
||||
static uint8_t black_rgb[3] = {0, 0, 0};
|
||||
fallback_black_ = Create2dTexture(engine_, 1, 1, 3, black_rgb, false);
|
||||
static uint8_t white_rgb[3] = {255, 255, 255};
|
||||
@@ -135,37 +103,19 @@ ObjectManager::ObjectManager(const mjModel* model, filament::Engine* engine)
|
||||
fallback_textures_[mjTEXROLE_EMISSIVE] = fallback_black_;
|
||||
fallback_textures_[mjTEXROLE_ORM] = fallback_orm_;
|
||||
|
||||
fallback_indirect_light_ = LoadFallbackIndirectLight("ibl.ktx", 1.0f);
|
||||
|
||||
specular_multiplier_ = ReadElement(
|
||||
model_, "filament.phong.specular_multiplier", specular_multiplier_);
|
||||
shininess_multiplier_ = ReadElement(
|
||||
model_, "filament.phong.shininess_multiplier", shininess_multiplier_);
|
||||
emissive_multiplier_ = ReadElement(
|
||||
model_, "filament.phong.emissive_multiplier", emissive_multiplier_);
|
||||
LoadFallbackIndirectLight("ibl.ktx", 1.0f);
|
||||
}
|
||||
|
||||
ObjectManager::~ObjectManager() {
|
||||
for (auto& iter : skyboxes_) {
|
||||
engine_->destroy(iter);
|
||||
if (fallback_indirect_light_) {
|
||||
engine_->destroy(fallback_indirect_light_);
|
||||
}
|
||||
for (auto& iter : indirect_lights_) {
|
||||
engine_->destroy(iter);
|
||||
if (fallback_indirect_light_texture_) {
|
||||
engine_->destroy(fallback_indirect_light_texture_);
|
||||
}
|
||||
for (auto& iter : materials_) {
|
||||
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);
|
||||
}
|
||||
for (auto& iter : textures_) {
|
||||
engine_->destroy(iter.second);
|
||||
}
|
||||
// fallback_textures_ maps to these textures.
|
||||
engine_->destroy(fallback_white_);
|
||||
engine_->destroy(fallback_black_);
|
||||
@@ -173,87 +123,6 @@ ObjectManager::~ObjectManager() {
|
||||
engine_->destroy(fallback_orm_);
|
||||
}
|
||||
|
||||
void ObjectManager::UploadMesh(const mjModel* model, int id) {
|
||||
if (model != model_) {
|
||||
mju_error("Model mismatch.");
|
||||
}
|
||||
if (id < 0 || id >= model->nmesh) {
|
||||
mju_error("Invalid mesh index %d", 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.index_buffer =
|
||||
CreateIndexBuffer(engine_, model, id, MeshType::kNormal);
|
||||
|
||||
if (model->mesh_graphadr[id] >= 0) {
|
||||
FilamentBuffers& hull_buffers = convex_hulls_[id];
|
||||
hull_buffers.vertex_buffer =
|
||||
CreateVertexBuffer(engine_, model, id, MeshType::kConvexHull);
|
||||
hull_buffers.index_buffer =
|
||||
CreateIndexBuffer(engine_, model, id, MeshType::kConvexHull);
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectManager::UploadTexture(const mjModel* model, int id) {
|
||||
if (model != model_) {
|
||||
mju_error("Model mismatch.");
|
||||
}
|
||||
if (id < 0 || id >= model->ntex) {
|
||||
mju_error("Invalid texture index: %d", id);
|
||||
}
|
||||
|
||||
if (auto iter = textures_.find(id); iter != textures_.end()) {
|
||||
engine_->destroy(iter->second);
|
||||
}
|
||||
|
||||
const int texture_type = model->tex_type[id];
|
||||
if (model->tex_height[id] == 1) {
|
||||
const mjtByte* bytes = model->tex_data + model->tex_adr[id];
|
||||
const int num_bytes = model->tex_width[id];
|
||||
textures_[id] =
|
||||
CreateKtxTexture(engine_, bytes, num_bytes, spherical_harmonics_[id]);
|
||||
} else if (texture_type == mjTEXTURE_2D) {
|
||||
textures_[id] = CreateTexture(engine_, model, id, TextureType::kNormal2d);
|
||||
} else if (texture_type == mjTEXTURE_CUBE) {
|
||||
textures_[id] = CreateTexture(engine_, model, id, TextureType::kCube);
|
||||
} else if (texture_type == mjTEXTURE_SKYBOX) {
|
||||
textures_[id] = CreateTexture(engine_, model, id, TextureType::kCube);
|
||||
} else {
|
||||
mju_error("Unsupported: Texture type: %d", texture_type);
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectManager::UploadHeightField(const mjModel* model, int id) {
|
||||
if (model != model_) {
|
||||
mju_error("Model mismatch.");
|
||||
}
|
||||
if (id < 0 || id >= model->nhfield) {
|
||||
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);
|
||||
}
|
||||
|
||||
FilamentBuffers& buffers = height_fields_[id];
|
||||
buffers.vertex_buffer =
|
||||
CreateVertexBuffer(engine_, model, id, MeshType::kHeightField);
|
||||
buffers.index_buffer =
|
||||
CreateIndexBuffer(engine_, model, id, MeshType::kHeightField);
|
||||
}
|
||||
|
||||
filament::Material* ObjectManager::GetMaterial(MaterialType type) const {
|
||||
if (type < 0 || type >= kNumMaterials) {
|
||||
mju_error("Invalid material type: %d", type);
|
||||
@@ -261,137 +130,50 @@ filament::Material* ObjectManager::GetMaterial(MaterialType type) const {
|
||||
return materials_[type];
|
||||
}
|
||||
|
||||
const FilamentBuffers* ObjectManager::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;
|
||||
} else {
|
||||
auto it = convex_hulls_.find(mesh_id);
|
||||
return it != convex_hulls_.end() ? &it->second : nullptr;
|
||||
const filament::Texture* ObjectManager::GetFallbackTexture(
|
||||
mjtTextureRole role) const {
|
||||
if (role < 0 || role >= mjNTEXROLE) {
|
||||
mju_error("Invalid texture role: %d", role);
|
||||
}
|
||||
}
|
||||
|
||||
const FilamentBuffers* ObjectManager::GetHeightFieldBuffer(
|
||||
int hfield_id) const {
|
||||
auto it = height_fields_.find(hfield_id);
|
||||
return it != height_fields_.end() ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
const FilamentBuffers* ObjectManager::GetShapeBuffer(ShapeType shape) const {
|
||||
if (shape < 0 || shape >= kNumShapes) {
|
||||
mju_error("Invalid shape type: %d", shape);
|
||||
}
|
||||
return &shapes_[shape];
|
||||
}
|
||||
|
||||
const filament::Texture* ObjectManager::GetTexture(int tex_id) const {
|
||||
auto it = textures_.find(tex_id);
|
||||
return it != textures_.end() ? it->second : nullptr;
|
||||
}
|
||||
|
||||
const filament::Texture* ObjectManager::GetTexture(int mat_id, int role) const {
|
||||
if (mat_id < 0 || mat_id >= model_->nmat || role < 0 || role >= mjNTEXROLE) {
|
||||
return nullptr;
|
||||
}
|
||||
const int tex_id = model_->mat_texid[mat_id * mjNTEXROLE + role];
|
||||
return GetTexture(tex_id);
|
||||
}
|
||||
|
||||
const filament::Texture* ObjectManager::GetTextureWithFallback(int mat_id,
|
||||
int role) const {
|
||||
if (auto texture = GetTexture(mat_id, role)) {
|
||||
return texture;
|
||||
}
|
||||
return GetFallbackTexture(role);
|
||||
}
|
||||
|
||||
const filament::Texture* ObjectManager::GetFallbackTexture(int role) const {
|
||||
auto iter = fallback_textures_.find(role);
|
||||
if (iter != fallback_textures_.end()) {
|
||||
return iter->second;
|
||||
}
|
||||
return nullptr;
|
||||
return fallback_textures_[role];
|
||||
}
|
||||
|
||||
filament::IndirectLight* ObjectManager::GetFallbackIndirectLight() {
|
||||
return fallback_indirect_light_;
|
||||
}
|
||||
|
||||
filament::IndirectLight* ObjectManager::CreateIndirectLight(int tex_id,
|
||||
float intensity) {
|
||||
filament::Texture* texture = nullptr;
|
||||
auto texture_iter = textures_.find(tex_id);
|
||||
if (texture_iter != textures_.end()) {
|
||||
texture = texture_iter->second;
|
||||
}
|
||||
|
||||
if (texture == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SphericalHarmonics* spherical_harmonics = nullptr;
|
||||
auto sh_iter = spherical_harmonics_.find(tex_id);
|
||||
if (sh_iter != spherical_harmonics_.end()) {
|
||||
spherical_harmonics = &sh_iter->second;
|
||||
}
|
||||
|
||||
return CreateIndirectLight(texture, spherical_harmonics, intensity);
|
||||
}
|
||||
|
||||
filament::IndirectLight* ObjectManager::LoadFallbackIndirectLight(
|
||||
void ObjectManager::LoadFallbackIndirectLight(
|
||||
std::string_view filename, float intensity) {
|
||||
if (fallback_indirect_light_texture_ != nullptr) {
|
||||
engine_->destroy(fallback_indirect_light_texture_);
|
||||
fallback_indirect_light_texture_ = nullptr;
|
||||
}
|
||||
if (fallback_indirect_light_ != nullptr) {
|
||||
engine_->destroy(fallback_indirect_light_);
|
||||
fallback_indirect_light_ = nullptr;
|
||||
}
|
||||
|
||||
Asset asset(filename);
|
||||
if (asset.size == 0) {
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
filament::math::float3 spherical_harmonics[9];
|
||||
filament::Texture* tex =
|
||||
fallback_indirect_light_texture_ =
|
||||
CreateKtxTexture(engine_, reinterpret_cast<const uint8_t*>(asset.payload),
|
||||
asset.size, spherical_harmonics);
|
||||
return CreateIndirectLight(tex, &spherical_harmonics, intensity);
|
||||
}
|
||||
|
||||
filament::IndirectLight* ObjectManager::CreateIndirectLight(
|
||||
filament::Texture* texture, SphericalHarmonics* spherical_harmonics,
|
||||
float intensity) {
|
||||
filament::IndirectLight::Builder builder;
|
||||
builder.reflections(texture);
|
||||
if (spherical_harmonics != nullptr) {
|
||||
builder.irradiance(3, *spherical_harmonics);
|
||||
if (fallback_indirect_light_texture_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Build the indirect light.
|
||||
filament::IndirectLight::Builder builder;
|
||||
builder.reflections(fallback_indirect_light_texture_);
|
||||
builder.irradiance(3, spherical_harmonics);
|
||||
builder.intensity(intensity);
|
||||
// Rotate the light to match mujoco's Z-up convention.
|
||||
builder.rotation(filament::math::mat3f::rotation(
|
||||
filament::math::f::PI / 2, filament::math::float3{1, 0, 0}));
|
||||
filament::IndirectLight* indirect_light = builder.build(*engine_);
|
||||
indirect_lights_.push_back(indirect_light);
|
||||
return indirect_light;
|
||||
fallback_indirect_light_ = builder.build(*engine_);
|
||||
}
|
||||
|
||||
filament::Skybox* ObjectManager::CreateSkybox() {
|
||||
filament::Texture* skybox_texture = nullptr;
|
||||
for (auto& iter : textures_) {
|
||||
const int texture_type = model_->tex_type[iter.first];
|
||||
if (texture_type == mjTEXTURE_SKYBOX) {
|
||||
skybox_texture = iter.second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (skybox_texture == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
filament::Skybox::Builder builder;
|
||||
builder.environment(skybox_texture);
|
||||
filament::Skybox* skybox = builder.build(*engine_);
|
||||
skyboxes_.push_back(skybox);
|
||||
return skybox;
|
||||
}
|
||||
|
||||
} // namespace mujoco
|
||||
|
||||
@@ -16,25 +16,19 @@
|
||||
#define MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_OBJECT_MANAGER_H_
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/IndirectLight.h>
|
||||
#include <filament/Skybox.h>
|
||||
#include <math/vec3.h>
|
||||
#include <mujoco/mjmodel.h>
|
||||
#include "experimental/filament/filament/buffer_util.h"
|
||||
#include "experimental/filament/render_context_filament.h"
|
||||
#include <mujoco/mujoco.h>
|
||||
|
||||
namespace mujoco {
|
||||
|
||||
// Creates and owns various filament objects based on the data in a mjrContext.
|
||||
class ObjectManager {
|
||||
public:
|
||||
ObjectManager(const mjModel* model, filament::Engine* engine);
|
||||
ObjectManager(filament::Engine* engine);
|
||||
~ObjectManager();
|
||||
|
||||
enum MaterialType {
|
||||
@@ -59,85 +53,34 @@ class ObjectManager {
|
||||
kNumMaterials,
|
||||
};
|
||||
|
||||
enum ShapeType {
|
||||
kLine,
|
||||
kLineBox,
|
||||
kPlane,
|
||||
kTriangle,
|
||||
kBox,
|
||||
kSphere,
|
||||
kCone,
|
||||
kDisk,
|
||||
kDome,
|
||||
kTube,
|
||||
kNumShapes,
|
||||
};
|
||||
|
||||
using SphericalHarmonics = filament::math::float3[9];
|
||||
|
||||
void UploadMesh(const mjModel* model, int id);
|
||||
|
||||
void UploadTexture(const mjModel* model, int id);
|
||||
|
||||
void UploadHeightField(const mjModel* model, int id);
|
||||
|
||||
// Returns the filament engine used by the ObjectManager to create filament
|
||||
// objects.
|
||||
// Returns the filament Engine that owns the assets.
|
||||
filament::Engine* GetEngine() const { return engine_; }
|
||||
|
||||
// Returns the Material of the given type.
|
||||
filament::Material* GetMaterial(MaterialType type) const;
|
||||
|
||||
// Returns the cached instance of a filament object created from the mjModel.
|
||||
const FilamentBuffers* GetMeshBuffer(int data_id) const;
|
||||
const FilamentBuffers* GetShapeBuffer(ShapeType shape) const;
|
||||
const FilamentBuffers* GetHeightFieldBuffer(int hfield_id) const;
|
||||
const filament::Texture* GetTexture(int tex_id) const;
|
||||
const filament::Texture* GetTexture(int mat_id, int role) const;
|
||||
const filament::Texture* GetTextureWithFallback(int mat_id, int role) const;
|
||||
const filament::Texture* GetFallbackTexture(int role) const;
|
||||
// Returns the fallback Texture with the given role.
|
||||
const filament::Texture* GetFallbackTexture(mjtTextureRole role) const;
|
||||
|
||||
// Returns the fallback IndirectLight.
|
||||
filament::IndirectLight* GetFallbackIndirectLight();
|
||||
|
||||
// Creates and returns a new instance of a filament object. The objects are
|
||||
// owned by the ObjectManager and will be deleted in the destructor.
|
||||
filament::Skybox* CreateSkybox();
|
||||
filament::IndirectLight* CreateIndirectLight(
|
||||
filament::Texture* texture, SphericalHarmonics* spherical_harmonics,
|
||||
float intensity);
|
||||
filament::IndirectLight* CreateIndirectLight(int tex_id, float intensity);
|
||||
filament::IndirectLight* LoadFallbackIndirectLight(std::string_view filename,
|
||||
float intensity);
|
||||
|
||||
float GetSpecularMultiplier() const { return specular_multiplier_; }
|
||||
float GetShininessMultiplier() const { return shininess_multiplier_; }
|
||||
float GetEmissiveMultiplier() const { return emissive_multiplier_; }
|
||||
|
||||
const mjModel* GetModel() const { return model_; }
|
||||
// Loads an indirect light from a file, setting it to the fallback.
|
||||
void LoadFallbackIndirectLight(std::string_view filename, float intensity);
|
||||
|
||||
ObjectManager(const ObjectManager&) = delete;
|
||||
ObjectManager& operator=(const ObjectManager&) = delete;
|
||||
|
||||
private:
|
||||
const mjModel* model_ = nullptr;
|
||||
filament::Engine* engine_ = nullptr;
|
||||
|
||||
std::array<FilamentBuffers, kNumShapes> shapes_;
|
||||
std::array<filament::Material*, kNumMaterials> materials_;
|
||||
std::vector<filament::Skybox*> skyboxes_;
|
||||
std::vector<filament::IndirectLight*> indirect_lights_;
|
||||
std::unordered_map<int, FilamentBuffers> meshes_;
|
||||
std::unordered_map<int, FilamentBuffers> convex_hulls_;
|
||||
std::unordered_map<int, FilamentBuffers> height_fields_;
|
||||
std::unordered_map<int, filament::Texture*> textures_;
|
||||
std::unordered_map<int, SphericalHarmonics> spherical_harmonics_;
|
||||
std::unordered_map<int, filament::Texture*> fallback_textures_;
|
||||
std::array<filament::Texture*, mjNTEXROLE> fallback_textures_;
|
||||
filament::Texture* fallback_white_ = nullptr;
|
||||
filament::Texture* fallback_black_ = nullptr;
|
||||
filament::Texture* fallback_normal_ = nullptr;
|
||||
filament::Texture* fallback_orm_ = nullptr;
|
||||
filament::Texture* fallback_indirect_light_texture_ = nullptr;
|
||||
filament::IndirectLight* fallback_indirect_light_ = nullptr;
|
||||
float specular_multiplier_ = 0.2f;
|
||||
float shininess_multiplier_ = 0.1f;
|
||||
float emissive_multiplier_ = 0.3f;
|
||||
};
|
||||
|
||||
} // namespace mujoco
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#include "experimental/filament/filament/gui_view.h"
|
||||
#include "experimental/filament/filament/light.h"
|
||||
#include "experimental/filament/filament/math_util.h"
|
||||
#include "experimental/filament/filament/model_objects.h"
|
||||
#include "experimental/filament/filament/model_util.h"
|
||||
#include "experimental/filament/filament/object_manager.h"
|
||||
#include "experimental/filament/filament/render_target_util.h"
|
||||
@@ -113,37 +114,38 @@ static void SetupReflectionCamera(const mat4& surface_xform,
|
||||
reflection_camera->setCustomProjection(oblique, near, far);
|
||||
}
|
||||
|
||||
SceneView::SceneView(filament::Engine* engine, ObjectManager* object_mgr)
|
||||
: object_mgr_(object_mgr), engine_(engine) {
|
||||
scene_ = engine_->createScene();
|
||||
camera_ = engine_->createCamera(utils::EntityManager::get().create());
|
||||
reflect_camera_ = engine_->createCamera(utils::EntityManager::get().create());
|
||||
SceneView::SceneView(ObjectManager* object_mgr, const mjModel* model)
|
||||
: object_mgr_(object_mgr) {
|
||||
filament::Engine* engine = object_mgr_->GetEngine();
|
||||
model_objects_ = std::make_unique<ModelObjects>(model, engine);
|
||||
|
||||
scene_ = engine->createScene();
|
||||
camera_ = engine->createCamera(utils::EntityManager::get().create());
|
||||
reflect_camera_ = engine->createCamera(utils::EntityManager::get().create());
|
||||
|
||||
for (auto& view : views_) {
|
||||
view = engine_->createView();
|
||||
view = engine->createView();
|
||||
view->setScene(scene_);
|
||||
view->setCamera(camera_);
|
||||
}
|
||||
|
||||
reflect_view_ = engine_->createView();
|
||||
reflect_view_ = engine->createView();
|
||||
reflect_view_->setScene(scene_);
|
||||
reflect_view_->setCamera(reflect_camera_);
|
||||
reflect_view_->setShadowingEnabled(false);
|
||||
reflect_view_->setPostProcessingEnabled(false);
|
||||
|
||||
const mjModel* m = object_mgr_->GetModel();
|
||||
|
||||
// Configure options for the normal view.
|
||||
auto& cg = color_grading_options_;
|
||||
cg.exposure = ReadElement(m, "filament.out.exposure", cg.exposure);
|
||||
cg.contrast = ReadElement(m, "filament.out.contrast", cg.contrast);
|
||||
cg.vibrance = ReadElement(m, "filament.out.vibrance", cg.vibrance);
|
||||
cg.saturation = ReadElement(m, "filament.out.saturation", cg.saturation);
|
||||
cg.temperature = ReadElement(m, "filament.out.temperature", cg.temperature);
|
||||
cg.tint = ReadElement(m, "filament.out.tint", cg.tint);
|
||||
cg.exposure = ReadElement(model, "filament.out.exposure", cg.exposure);
|
||||
cg.contrast = ReadElement(model, "filament.out.contrast", cg.contrast);
|
||||
cg.vibrance = ReadElement(model, "filament.out.vibrance", cg.vibrance);
|
||||
cg.saturation = ReadElement(model, "filament.out.saturation", cg.saturation);
|
||||
cg.temperature = ReadElement(model, "filament.out.temperature", cg.temperature);
|
||||
cg.tint = ReadElement(model, "filament.out.tint", cg.tint);
|
||||
|
||||
auto tone_mapping =
|
||||
ReadElement<std::string_view>(m, "filament.out.tone_mapping");
|
||||
ReadElement<std::string_view>(model, "filament.out.tone_mapping");
|
||||
if (tone_mapping == "aces") {
|
||||
cg.tone_mapper = ToneMapperType::kACES;
|
||||
} else if (tone_mapping == "aces_legacy") {
|
||||
@@ -158,9 +160,9 @@ SceneView::SceneView(filament::Engine* engine, ObjectManager* object_mgr)
|
||||
SetColorGradingOptions(cg);
|
||||
|
||||
auto ao = views_[kNormalIndex]->getAmbientOcclusionOptions();
|
||||
ao.enabled = ReadElement(m, "filament.ao.enabled", true);
|
||||
ao.bentNormals = ReadElement(m, "filament.ao.bent_normals", false);
|
||||
ao.ssct.enabled = ReadElement(m, "filament.ao.ssct", ao.ssct.enabled);
|
||||
ao.enabled = ReadElement(model, "filament.ao.enabled", true);
|
||||
ao.bentNormals = ReadElement(model, "filament.ao.bent_normals", false);
|
||||
ao.ssct.enabled = ReadElement(model, "filament.ao.ssct", ao.ssct.enabled);
|
||||
ao.quality = filament::QualityLevel::ULTRA;
|
||||
ao.lowPassFilter = filament::QualityLevel::ULTRA;
|
||||
ao.upsampling = filament::QualityLevel::ULTRA;
|
||||
@@ -168,16 +170,16 @@ SceneView::SceneView(filament::Engine* engine, ObjectManager* object_mgr)
|
||||
views_[kNormalIndex]->setAmbientOcclusionOptions(ao);
|
||||
|
||||
auto msaa = views_[kNormalIndex]->getMultiSampleAntiAliasingOptions();
|
||||
msaa.enabled = ReadElement(m, "filament.msaa.enabled", true);
|
||||
msaa.enabled = ReadElement(model, "filament.msaa.enabled", true);
|
||||
views_[kNormalIndex]->setMultiSampleAntiAliasingOptions(msaa);
|
||||
|
||||
default_shadow_map_size_ = ReadElement(
|
||||
m, "filament.shadows.map_size", default_shadow_map_size_);
|
||||
model, "filament.shadows.map_size", default_shadow_map_size_);
|
||||
default_vsm_blur_width_ = ReadElement(
|
||||
m, "filament.shadows.vsm_blur_width", default_vsm_blur_width_);
|
||||
model, "filament.shadows.vsm_blur_width", default_vsm_blur_width_);
|
||||
|
||||
auto shadow_type = views_[kNormalIndex]->getShadowType();
|
||||
shadow_type = ReadElement(m, "filament.shadows.type", shadow_type);
|
||||
shadow_type = ReadElement(model, "filament.shadows.type", shadow_type);
|
||||
views_[kNormalIndex]->setShadowType(shadow_type);
|
||||
|
||||
// Disable post processing for the depth and segmentation views to preserve
|
||||
@@ -190,44 +192,44 @@ SceneView::SceneView(filament::Engine* engine, ObjectManager* object_mgr)
|
||||
auto& tm = engine->getTransformManager();
|
||||
tm.create(fog);
|
||||
auto rotation_axis = ReadElement(
|
||||
m, "filament.fog.rotation_axis", float3{-1, 0, 0});
|
||||
model, "filament.fog.rotation_axis", float3{-1, 0, 0});
|
||||
tm.setTransform(tm.getInstance(fog),
|
||||
mat4::rotation(filament::math::f::PI / 2, rotation_axis));
|
||||
|
||||
auto fog_opts = views_[kNormalIndex]->getFogOptions();
|
||||
fog_opts.enabled = ReadElement(m, "filament.fog.enabled", fog_opts.enabled);
|
||||
fog_opts.color = ReadElement(m, "filament.fog.color", fog_opts.color);
|
||||
fog_opts.enabled =
|
||||
ReadElement(model, "filament.fog.enabled", fog_opts.enabled);
|
||||
fog_opts.color = ReadElement(model, "filament.fog.color", fog_opts.color);
|
||||
fog_opts.distance = ReadElement(
|
||||
m, "filament.fog.distance", fog_opts.distance);
|
||||
model, "filament.fog.distance", fog_opts.distance);
|
||||
fog_opts.density = ReadElement(
|
||||
m, "filament.fog.density", fog_opts.density);
|
||||
model, "filament.fog.density", fog_opts.density);
|
||||
fog_opts.cutOffDistance = ReadElement(
|
||||
m, "filament.fog.cutOffDistance", fog_opts.cutOffDistance);
|
||||
model, "filament.fog.cutOffDistance", fog_opts.cutOffDistance);
|
||||
fog_opts.maximumOpacity = ReadElement(
|
||||
m, "filament.fog.maximumOpacity", fog_opts.maximumOpacity);
|
||||
fog_opts.height = ReadElement(m, "filament.fog.height", fog_opts.height);
|
||||
model, "filament.fog.maximumOpacity", fog_opts.maximumOpacity);
|
||||
fog_opts.height = ReadElement(model, "filament.fog.height", fog_opts.height);
|
||||
fog_opts.heightFalloff = ReadElement(
|
||||
m, "filament.fog.heightFalloff", fog_opts.heightFalloff);
|
||||
model, "filament.fog.heightFalloff", fog_opts.heightFalloff);
|
||||
fog_opts.inScatteringStart = ReadElement(
|
||||
m, "filament.fog.inScatteringStart", fog_opts.inScatteringStart);
|
||||
model, "filament.fog.inScatteringStart", fog_opts.inScatteringStart);
|
||||
fog_opts.inScatteringSize = ReadElement(
|
||||
m, "filament.fog.inScatteringSize", fog_opts.inScatteringSize);
|
||||
model, "filament.fog.inScatteringSize", fog_opts.inScatteringSize);
|
||||
views_[kNormalIndex]->setFogOptions(fog_opts);
|
||||
|
||||
fallback_head_light_intensity_ =
|
||||
ReadElement(m, "filament.fallback.head_light_intensity",
|
||||
ReadElement(model, "filament.fallback.head_light_intensity",
|
||||
fallback_head_light_intensity_);
|
||||
fallback_scene_light_intensity_ =
|
||||
ReadElement(m, "filament.fallback.scene_light_intensity",
|
||||
ReadElement(model, "filament.fallback.scene_light_intensity",
|
||||
fallback_scene_light_intensity_);
|
||||
fallback_environment_light_intensity_ =
|
||||
ReadElement(m, "filament.fallback.environment_light_intensity",
|
||||
ReadElement(model, "filament.fallback.environment_light_intensity",
|
||||
fallback_environment_light_intensity_);
|
||||
|
||||
// Create an empty/black indirect light to ensure that the skybox is oriented
|
||||
// to respect mujoco's Z-up convention.
|
||||
scene_->setIndirectLight(
|
||||
object_mgr_->CreateIndirectLight(nullptr, nullptr, 100000));
|
||||
scene_->setIndirectLight(model_objects_->CreateIndirectLight(-1, 100000));
|
||||
|
||||
PrepareLights();
|
||||
}
|
||||
@@ -237,15 +239,16 @@ SceneView::~SceneView() {
|
||||
drawables_.clear();
|
||||
reflect_targets_.clear();
|
||||
|
||||
engine_->destroyCameraComponent(reflect_camera_->getEntity());
|
||||
engine_->destroy(reflect_view_);
|
||||
filament::Engine* engine = object_mgr_->GetEngine();
|
||||
engine->destroyCameraComponent(reflect_camera_->getEntity());
|
||||
engine->destroy(reflect_view_);
|
||||
|
||||
engine_->destroyCameraComponent(camera_->getEntity());
|
||||
engine_->destroy(views_[kNormalIndex]->getColorGrading());
|
||||
engine->destroyCameraComponent(camera_->getEntity());
|
||||
engine->destroy(views_[kNormalIndex]->getColorGrading());
|
||||
for (auto& view : views_) {
|
||||
engine_->destroy(view);
|
||||
engine->destroy(view);
|
||||
}
|
||||
engine_->destroy(scene_);
|
||||
engine->destroy(scene_);
|
||||
}
|
||||
|
||||
void SceneView::Render(filament::Renderer* renderer, DrawMode draw_mode,
|
||||
@@ -304,22 +307,23 @@ void SceneView::SetViewport(mjrRect viewport) {
|
||||
}
|
||||
|
||||
void SceneView::SetColorGradingOptions(const ColorGradingOptions& opts) {
|
||||
filament::Engine* engine = object_mgr_->GetEngine();
|
||||
|
||||
auto tone_mapper = CreateToneMapper(opts.tone_mapper);
|
||||
auto color_grading = ToBuilder(color_grading_options_)
|
||||
.toneMapper(tone_mapper.get())
|
||||
.build(*engine_);
|
||||
.build(*engine);
|
||||
views_[kNormalIndex]->setColorGrading(color_grading);
|
||||
engine_->destroy(color_grading_);
|
||||
engine->destroy(color_grading_);
|
||||
color_grading_ = color_grading;
|
||||
color_grading_options_ = opts;
|
||||
}
|
||||
|
||||
void SceneView::SetEnvironmentLight(std::string_view filename,
|
||||
float intensity) {
|
||||
auto* ibl = object_mgr_->LoadFallbackIndirectLight(filename, intensity);
|
||||
if (ibl) {
|
||||
scene_->setIndirectLight(ibl);
|
||||
}
|
||||
scene_->setIndirectLight(nullptr);
|
||||
object_mgr_->LoadFallbackIndirectLight(filename, intensity);
|
||||
scene_->setIndirectLight(object_mgr_->GetFallbackIndirectLight());
|
||||
}
|
||||
|
||||
void SceneView::SetFallbackEnvironmentLight(float intensity) {
|
||||
@@ -357,8 +361,9 @@ std::optional<float3> SceneView::ClipFromWorld(const float3& pos) const{
|
||||
}
|
||||
|
||||
void SceneView::PrepareLights() {
|
||||
const mjModel* model = object_mgr_->GetModel();
|
||||
filament::Skybox* skybox = object_mgr_->CreateSkybox();
|
||||
filament::Engine* engine = object_mgr_->GetEngine();
|
||||
const mjModel* model = model_objects_->GetModel();
|
||||
filament::Skybox* skybox = model_objects_->CreateSkybox();
|
||||
if (skybox) {
|
||||
scene_->setSkybox(skybox);
|
||||
}
|
||||
@@ -369,7 +374,7 @@ void SceneView::PrepareLights() {
|
||||
total_light_intensity += model->light_intensity[i];
|
||||
|
||||
if (model->light_type[i] == mjLIGHT_IMAGE) {
|
||||
auto* indirect_light = object_mgr_->CreateIndirectLight(
|
||||
auto* indirect_light = model_objects_->CreateIndirectLight(
|
||||
model->light_texid[i], model->light_intensity[i]);
|
||||
if (indirect_light) {
|
||||
scene_->setIndirectLight(indirect_light);
|
||||
@@ -390,7 +395,7 @@ void SceneView::PrepareLights() {
|
||||
params.spot_cone_angle = model->light_cutoff[i];
|
||||
}
|
||||
|
||||
auto light_obj = std::make_unique<Light>(engine_, params);
|
||||
auto light_obj = std::make_unique<Light>(engine, params);
|
||||
#ifndef __EMSCRIPTEN__
|
||||
// TODO(b/458045799): Re-enable when lights work on glinux and chromebook.
|
||||
light_obj->AddToScene(scene_);
|
||||
@@ -408,7 +413,7 @@ void SceneView::PrepareLights() {
|
||||
params.type = mjLIGHT_DIRECTIONAL;
|
||||
params.castshadow = 0;
|
||||
params.intensity = 0;
|
||||
auto light_obj = std::make_unique<Light>(engine_, params);
|
||||
auto light_obj = std::make_unique<Light>(engine, params);
|
||||
#ifndef __EMSCRIPTEN__
|
||||
// TODO(b/458045799): Re-enable when lights work on glinux and chromebook.
|
||||
light_obj->AddToScene(scene_);
|
||||
@@ -456,9 +461,10 @@ void SceneView::UpdateScene(const mjvScene* scene) {
|
||||
}
|
||||
}
|
||||
|
||||
auto drawable = std::make_unique<Drawable>(object_mgr_, *geom);
|
||||
auto drawable =
|
||||
std::make_unique<Drawable>(object_mgr_, model_objects_.get(), *geom);
|
||||
drawable->AddToScene(scene_);
|
||||
drawable->Update(object_mgr_->GetModel(), scene, *geom);
|
||||
drawable->Update(model_objects_->GetModel(), scene, *geom);
|
||||
if (drawable->IsReflective()) {
|
||||
AddReflectiveDrawable(drawable.get());
|
||||
}
|
||||
@@ -507,9 +513,10 @@ void SceneView::AddReflectiveDrawable(Drawable* drawable) {
|
||||
|
||||
// Ensure we have the same number of render targets as we do reflective
|
||||
// drawables.
|
||||
filament::Engine* engine = object_mgr_->GetEngine();
|
||||
while (reflect_targets_.size() < reflectives_.size()) {
|
||||
reflect_targets_.push_back(std::make_unique<RenderTargetAndTextures>(
|
||||
engine_, kRenderTargetReflectionColor, kRenderTargetDepth));
|
||||
engine, kRenderTargetReflectionColor, kRenderTargetDepth));
|
||||
}
|
||||
|
||||
// Prepare a render target for the reflective drawable.
|
||||
@@ -519,7 +526,21 @@ void SceneView::AddReflectiveDrawable(Drawable* drawable) {
|
||||
drawable->UpdateReflectionTexture(target->GetColorTexture());
|
||||
}
|
||||
|
||||
filament::Engine* SceneView::GetEngine() const { return engine_; }
|
||||
void SceneView::UploadMesh(const mjModel* model, int id) {
|
||||
model_objects_->UploadMesh(model, id);
|
||||
}
|
||||
|
||||
void SceneView::UploadTexture(const mjModel* model, int id) {
|
||||
model_objects_->UploadTexture(model, id);
|
||||
}
|
||||
|
||||
void SceneView::UploadHeightField(const mjModel* model, int id) {
|
||||
model_objects_->UploadHeightField(model, id);
|
||||
}
|
||||
|
||||
filament::Engine* SceneView::GetEngine() const {
|
||||
return object_mgr_->GetEngine();
|
||||
}
|
||||
|
||||
filament::View* SceneView::GetDefaultRenderView() {
|
||||
return views_[kNormalIndex];
|
||||
|
||||
@@ -31,10 +31,12 @@
|
||||
#include <math/vec3.h>
|
||||
#include <mujoco/mjrender.h>
|
||||
#include <mujoco/mjvisualize.h>
|
||||
#include <mujoco/mujoco.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/material.h"
|
||||
#include "experimental/filament/filament/model_objects.h"
|
||||
#include "experimental/filament/filament/object_manager.h"
|
||||
#include "experimental/filament/filament/render_target_util.h"
|
||||
|
||||
@@ -47,7 +49,7 @@ namespace mujoco {
|
||||
// different rendering modes (e.g. normal, depth, segmentation, etc.)
|
||||
class SceneView {
|
||||
public:
|
||||
SceneView(filament::Engine* engine, ObjectManager* object_mgr);
|
||||
SceneView(ObjectManager* object_mgr, const mjModel* model);
|
||||
~SceneView();
|
||||
|
||||
// Updates all views to render into the given viewport.
|
||||
@@ -71,6 +73,10 @@ class SceneView {
|
||||
void Render(filament::Renderer* renderer, DrawMode draw_mode,
|
||||
filament::RenderTarget* target = nullptr);
|
||||
|
||||
void UploadMesh(const mjModel* model, int id);
|
||||
void UploadTexture(const mjModel* model, int id);
|
||||
void UploadHeightField(const mjModel* model, int id);
|
||||
|
||||
// Accessors.
|
||||
filament::Engine* GetEngine() const;
|
||||
filament::View* GetDefaultRenderView();
|
||||
@@ -96,12 +102,12 @@ class SceneView {
|
||||
const filament::math::float3& pos) const;
|
||||
|
||||
ObjectManager* object_mgr_ = nullptr;
|
||||
filament::Engine* engine_ = nullptr;
|
||||
filament::Scene* scene_ = nullptr;
|
||||
filament::Camera* camera_ = nullptr;
|
||||
filament::ColorGrading* color_grading_ = nullptr;
|
||||
std::vector<std::unique_ptr<Light>> lights_;
|
||||
std::vector<std::unique_ptr<Drawable>> drawables_;
|
||||
std::unique_ptr<ModelObjects> model_objects_;
|
||||
std::array<filament::View*, DrawMode::kNumDrawModes> views_;
|
||||
filament::math::mat4 clip_from_world_;
|
||||
ColorGradingOptions color_grading_options_;
|
||||
|
||||
Reference in New Issue
Block a user