Update compat library to use public functions.

There are still a few places where the compat library is downcasting
to the internal types due to limitations in the public APIs.

PiperOrigin-RevId: 910646480
Change-Id: I1ccb6714db08a2010d9535f59338e5eba06d1d35
This commit is contained in:
Haroon Qureshi
2026-05-05 06:32:19 -07:00
committed by Copybara-Service
parent b9c1877ecb
commit 24ce1eff10
14 changed files with 229 additions and 249 deletions
@@ -18,31 +18,28 @@
#include <cstdint> #include <cstdint>
#include <cstring> #include <cstring>
#include <memory> #include <memory>
#include <utility>
#include <vector> #include <vector>
#include <imgui.h> #include <imgui.h>
#include <math/mat3.h> #include <math/mat3.h>
#include <math/vec3.h> #include <math/vec3.h>
#include <mujoco/mujoco.h> #include <mujoco/mujoco.h>
#include "experimental/filament/filament/filament_context.h"
#include "experimental/filament/filament/mesh.h"
#include "experimental/filament/filament/renderable.h"
#include "experimental/filament/filament/scene_view.h"
#include "experimental/filament/filament/texture.h"
#include "experimental/filament/render_context_filament.h" #include "experimental/filament/render_context_filament.h"
#include "experimental/filament/render_context_filament_cpp.h"
namespace mujoco { namespace mujoco {
using filament::math::float3; using filament::math::float3;
using filament::math::mat3f; using filament::math::mat3f;
ImguiBridge::ImguiBridge(FilamentContext* ctx) : ctx_(ctx) { ImguiBridge::ImguiBridge(mjrfContext* ctx) : ctx_(ctx) {
mjrSceneParams params; mjrSceneParams params;
mjr_defaultSceneParams(&params); mjr_defaultSceneParams(&params);
params.enable_post_processing = false; params.enable_post_processing = false;
params.enable_reflections = false; params.enable_reflections = false;
params.enable_shadows = false; params.enable_shadows = false;
scene_view_ = std::make_unique<SceneView>(ctx_, params); scene_ = CreateScene(ctx_, params);
} }
ImguiBridge::~ImguiBridge() { ImguiBridge::~ImguiBridge() {
@@ -77,12 +74,12 @@ uintptr_t ImguiBridge::UploadImage(uintptr_t tex_id, const uint8_t* pixels,
tex_id = next_tex_id_++; tex_id = next_tex_id_++;
} }
std::unique_ptr<Texture>& texture = textures_[tex_id]; mjrTexture* texture = GetTexture(tex_id);
// If the texture does not exist or the dimensions have changed, we create a // If the texture does not exist or the dimensions have changed, we create a
// new texture. // new texture.
if (texture == nullptr || texture->GetWidth() != width || if (texture == nullptr || mjrf_getTextureWidth(texture) != width ||
texture->GetHeight() != height) { mjrf_getTextureHeight(texture) != height) {
mjrTextureConfig config; mjrTextureConfig config;
mjr_defaultTextureConfig(&config); mjr_defaultTextureConfig(&config);
config.width = width; config.width = width;
@@ -90,7 +87,9 @@ uintptr_t ImguiBridge::UploadImage(uintptr_t tex_id, const uint8_t* pixels,
config.target = mjTEXTURE_2D; config.target = mjTEXTURE_2D;
config.format = bpp == 4 ? mjPIXEL_FORMAT_RGBA8 : mjPIXEL_FORMAT_RGB8; config.format = bpp == 4 ? mjPIXEL_FORMAT_RGBA8 : mjPIXEL_FORMAT_RGB8;
config.color_space = mjCOLORSPACE_LINEAR; config.color_space = mjCOLORSPACE_LINEAR;
texture = std::make_unique<Texture>(ctx_, config); UniquePtr<mjrTexture> new_texture = ::mujoco::CreateTexture(ctx_, config);
texture = new_texture.get();
textures_.insert_or_assign(tex_id, std::move(new_texture));
} }
// Create a copy of the image to pass it to filament as we don't know the // Create a copy of the image to pass it to filament as we don't know the
@@ -108,7 +107,7 @@ uintptr_t ImguiBridge::UploadImage(uintptr_t tex_id, const uint8_t* pixels,
texture_data.release_callback = callback; texture_data.release_callback = callback;
std::memcpy(bytes, pixels, num_bytes); std::memcpy(bytes, pixels, num_bytes);
texture->Upload(texture_data); mjrf_setTextureData(texture, &texture_data);
return tex_id; return tex_id;
} }
@@ -126,7 +125,7 @@ void ImguiBridge::CreateTexture(ImTextureData* data) {
config.color_space = mjCOLORSPACE_LINEAR; config.color_space = mjCOLORSPACE_LINEAR;
const uintptr_t tex_id = next_tex_id_++; const uintptr_t tex_id = next_tex_id_++;
textures_[tex_id] = std::make_unique<Texture>(ctx_, config); textures_.insert_or_assign(tex_id, ::mujoco::CreateTexture(ctx_, config));
data->SetTexID((ImTextureID)tex_id); data->SetTexID((ImTextureID)tex_id);
UpdateTexture(data); UpdateTexture(data);
} }
@@ -143,7 +142,7 @@ void ImguiBridge::UpdateTexture(ImTextureData* data) {
texture_data.nbytes = data->Width * data->Height * 4; texture_data.nbytes = data->Width * data->Height * 4;
texture_data.user_data = nullptr; texture_data.user_data = nullptr;
texture_data.release_callback = nullptr; texture_data.release_callback = nullptr;
iter->second->Upload(texture_data); mjrf_setTextureData(iter->second.get(), &texture_data);
data->SetStatus(ImTextureStatus_OK); data->SetStatus(ImTextureStatus_OK);
} }
@@ -156,6 +155,14 @@ void ImguiBridge::DestroyTexture(ImTextureData* data) {
} }
} }
mjrTexture* ImguiBridge::GetTexture(uintptr_t tex_id) const {
auto iter = textures_.find(tex_id);
if (iter == textures_.end()) {
return nullptr;
}
return iter->second.get();
}
void ImguiBridge::Update() { void ImguiBridge::Update() {
if (!ImGui::GetCurrentContext()) { if (!ImGui::GetCurrentContext()) {
PrepareRenderables(0); PrepareRenderables(0);
@@ -233,21 +240,22 @@ void ImguiBridge::Update() {
data.indices = cmds->IdxBuffer.Data; data.indices = cmds->IdxBuffer.Data;
data.index_type = mjINDEX_TYPE_U16; data.index_type = mjINDEX_TYPE_U16;
data.primitive_type = mjMESH_PRIMITIVE_TYPE_TRIANGLES; data.primitive_type = mjMESH_PRIMITIVE_TYPE_TRIANGLES;
meshes_.push_back(std::make_unique<Mesh>(ctx_, data)); meshes_.push_back(CreateMesh(ctx_, data));
const Mesh* mesh = meshes_.back().get(); const mjrMesh* mesh = meshes_.back().get();
int index_offset = 0; int index_offset = 0;
for (const ImDrawCmd& command : cmds->CmdBuffer) { for (const ImDrawCmd& command : cmds->CmdBuffer) {
const int width = size.x * scale.x; const int width = size.x * scale.x;
const int height = size.y * scale.y; const int height = size.y * scale.y;
auto& renderable = renderables_[renderable_index]; UniquePtr<mjrRenderable>& renderable = renderables_[renderable_index];
renderable->SetMesh(mesh, index_offset, command.ElemCount); mjrf_setRenderableMesh(renderable.get(), mesh, index_offset,
command.ElemCount);
mjrMaterialTextures textures; mjrMaterialTextures textures;
mjr_defaultMaterialTextures(&textures); mjr_defaultMaterialTextures(&textures);
textures.color = textures_[command.GetTexID()].get(); textures.color = GetTexture(command.GetTexID());
mjrMaterialParams properties; mjrMaterialParams properties;
mjr_defaultMaterialParams(&properties); mjr_defaultMaterialParams(&properties);
@@ -264,9 +272,12 @@ void ImguiBridge::Update() {
properties.scissor[2] = width; properties.scissor[2] = width;
properties.scissor[3] = height; properties.scissor[3] = height;
} }
renderable->UpdateMaterial(properties, textures); mjrf_setRenderableMaterial(renderable.get(), &properties, &textures);
renderable->SetTransform(
{float3{0, 0, 0}, mat3f(), float3(scale.x, scale.y, 1.0f)}); const float position[] = {0, 0, 0};
const float rotation[] = {1, 0, 0, 0, 1, 0, 0, 0, 1};
const float size[] = {scale.x, scale.y, 1.0f};
mjrf_setRenderableTransform(renderable.get(), position, rotation, size);
index_offset += command.ElemCount; index_offset += command.ElemCount;
++renderable_index; ++renderable_index;
@@ -279,15 +290,14 @@ void ImguiBridge::PrepareRenderables(int count) {
mjrRenderableParams params; mjrRenderableParams params;
mjr_defaultRenderableParams(&params); mjr_defaultRenderableParams(&params);
params.shading_model = mjSHADING_MODEL_UX; params.shading_model = mjSHADING_MODEL_UX;
auto& r = params.cast_shadows = false;
renderables_.emplace_back(std::make_unique<Renderable>(ctx_, params)); params.receive_shadows = false;
r->SetCastShadows(false); params.blend_order = static_cast<std::uint16_t>(renderables_.size() + 1);
r->SetReceiveShadows(false); auto& renderable = renderables_.emplace_back(CreateRenderable(ctx_, params));
r->SetBlendOrder(static_cast<std::uint16_t>(renderables_.size())); mjrf_addRenderableToScene(scene_.get(), renderable.get());
scene_view_->AddToScene(r.get());
} }
while (renderables_.size() > count) { while (renderables_.size() > count) {
scene_view_->RemoveFromScene(renderables_.back().get()); mjrf_removeRenderableFromScene(scene_.get(), renderables_.back().get());
renderables_.pop_back(); renderables_.pop_back();
} }
} }
+10 -13
View File
@@ -16,23 +16,19 @@
#define MUJOCO_SRC_EXPERIMENTAL_FILAMENT_COMPAT_IMGUI_BRIDGE_H_ #define MUJOCO_SRC_EXPERIMENTAL_FILAMENT_COMPAT_IMGUI_BRIDGE_H_
#include <cstdint> #include <cstdint>
#include <memory>
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
#include <imgui.h> #include <imgui.h>
#include "experimental/filament/filament/filament_context.h" #include "experimental/filament/render_context_filament.h"
#include "experimental/filament/filament/mesh.h" #include "experimental/filament/render_context_filament_cpp.h"
#include "experimental/filament/filament/renderable.h"
#include "experimental/filament/filament/scene_view.h"
#include "experimental/filament/filament/texture.h"
namespace mujoco { namespace mujoco {
// Creates and manages a SceneView using data read from ImGui. // Creates and manages a SceneView using data read from ImGui.
class ImguiBridge { class ImguiBridge {
public: public:
explicit ImguiBridge(FilamentContext* ctx); explicit ImguiBridge(mjrfContext* ctx);
~ImguiBridge(); ~ImguiBridge();
// Prepares the Renderables using data from the current ImGui state. This // Prepares the Renderables using data from the current ImGui state. This
@@ -41,7 +37,7 @@ class ImguiBridge {
void Update(); void Update();
// Returns the managed UX scene. // Returns the managed UX scene.
SceneView* GetSceneView() const { return scene_view_.get(); } mjrScene* GetScene() const { return scene_.get(); }
// Uploads texture to be used with ImGui's Image and ImageButton functions. // Uploads texture to be used with ImGui's Image and ImageButton functions.
uintptr_t UploadImage(uintptr_t tex_id, const uint8_t* pixels, int width, uintptr_t UploadImage(uintptr_t tex_id, const uint8_t* pixels, int width,
@@ -58,12 +54,13 @@ class ImguiBridge {
void CreateTexture(ImTextureData* data); void CreateTexture(ImTextureData* data);
void UpdateTexture(ImTextureData* data); void UpdateTexture(ImTextureData* data);
void DestroyTexture(ImTextureData* data); void DestroyTexture(ImTextureData* data);
mjrTexture* GetTexture(uintptr_t tex_id) const;
FilamentContext* ctx_ = nullptr; mjrfContext* ctx_ = nullptr;
std::unique_ptr<SceneView> scene_view_; UniquePtr<mjrScene> scene_{nullptr, nullptr};
std::vector<std::unique_ptr<Renderable>> renderables_; std::vector<UniquePtr<mjrRenderable>> renderables_;
std::vector<std::unique_ptr<Mesh>> meshes_; std::vector<UniquePtr<mjrMesh>> meshes_;
std::unordered_map<uintptr_t, std::unique_ptr<Texture>> textures_; std::unordered_map<uintptr_t, UniquePtr<mjrTexture>> textures_;
uintptr_t next_tex_id_ = 1; uintptr_t next_tex_id_ = 1;
}; };
@@ -651,7 +651,7 @@ void DrawLightGui(filament::LightManager& lm,
} }
void DrawGui(SceneBridge* scene_bridge) { void DrawGui(SceneBridge* scene_bridge) {
SceneView* scene_view = scene_bridge->GetSceneView(); SceneView* scene_view = SceneView::downcast(scene_bridge->GetScene());
filament::View* view = scene_view->GetDefaultRenderView(); filament::View* view = scene_view->GetDefaultRenderView();
filament::Engine* engine = scene_view->GetEngine(); filament::Engine* engine = scene_view->GetEngine();
filament::LightManager& lm = engine->getLightManager(); filament::LightManager& lm = engine->getLightManager();
@@ -27,8 +27,8 @@
#include "experimental/filament/compat/scene_bridge.h" #include "experimental/filament/compat/scene_bridge.h"
#include "experimental/filament/filament/filament_context.h" #include "experimental/filament/filament/filament_context.h"
#include "experimental/filament/filament/model_util.h" #include "experimental/filament/filament/model_util.h"
#include "experimental/filament/filament/render_target.h"
#include "experimental/filament/render_context_filament.h" #include "experimental/filament/render_context_filament.h"
#include "experimental/filament/render_context_filament_cpp.h"
namespace mujoco { namespace mujoco {
@@ -43,10 +43,10 @@ void MjrFilamentRenderer::Init(const mjModel* model) {
mjr_defaultRenderRequest(&render_requests_[0]); mjr_defaultRenderRequest(&render_requests_[0]);
mjr_defaultRenderRequest(&render_requests_[1]); mjr_defaultRenderRequest(&render_requests_[1]);
render_requests_[0].scene = scene_bridge_->GetSceneView(); render_requests_[0].scene = scene_bridge_->GetScene();
render_requests_[0].draw_mode = mjDRAW_MODE_COLOR; render_requests_[0].draw_mode = mjDRAW_MODE_COLOR;
render_requests_[1].scene = imgui_bridge_->GetSceneView(); render_requests_[1].scene = imgui_bridge_->GetScene();
render_requests_[1].draw_mode = mjDRAW_MODE_COLOR; render_requests_[1].draw_mode = mjDRAW_MODE_COLOR;
// The UX camera is a fixed orthographic camera. We only need to change the // The UX camera is a fixed orthographic camera. We only need to change the
@@ -135,8 +135,7 @@ void MjrFilamentRenderer::ReadPixels(mjrRect viewport, unsigned char* rgb,
config.height = viewport.height; config.height = viewport.height;
config.color_format = mjPIXEL_FORMAT_RGB8; config.color_format = mjPIXEL_FORMAT_RGB8;
config.depth_format = mjPIXEL_FORMAT_DEPTH32F; config.depth_format = mjPIXEL_FORMAT_DEPTH32F;
auto target = auto target = CreateRenderTarget(filament_context_.get(), config);
std::make_unique<RenderTarget>(filament_context_.get(), config);
render_requests_[0].target = target.get(); render_requests_[0].target = target.get();
render_requests_[1].target = target.get(); render_requests_[1].target = target.get();
@@ -158,11 +157,11 @@ void MjrFilamentRenderer::ReadPixels(mjrRect viewport, unsigned char* rgb,
if (depth) { if (depth) {
mjrRenderTargetConfig config; mjrRenderTargetConfig config;
mjr_defaultRenderTargetConfig(&config); mjr_defaultRenderTargetConfig(&config);
config.width = viewport.width;
config.height = viewport.height;
config.color_format = mjPIXEL_FORMAT_R32F; config.color_format = mjPIXEL_FORMAT_R32F;
config.depth_format = mjPIXEL_FORMAT_DEPTH32F; config.depth_format = mjPIXEL_FORMAT_DEPTH32F;
auto target = auto target = CreateRenderTarget(filament_context_.get(), config);
std::make_unique<RenderTarget>(filament_context_.get(), config);
target->Prepare(viewport.width, viewport.height);
render_requests_[0].target = target.get(); render_requests_[0].target = target.get();
render_requests_[1].target = target.get(); render_requests_[1].target = target.get();
@@ -14,7 +14,6 @@
#include "experimental/filament/compat/model_objects.h" #include "experimental/filament/compat/model_objects.h"
#include <array>
#include <algorithm> #include <algorithm>
#include <cfloat> #include <cfloat>
#include <cstddef> #include <cstddef>
@@ -25,18 +24,16 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <filament/Engine.h>
#include <math/TVecHelpers.h> #include <math/TVecHelpers.h>
#include <math/vec2.h> #include <math/vec2.h>
#include <math/vec3.h> #include <math/vec3.h>
#include <math/vec4.h> #include <math/vec4.h>
#include <mujoco/mujoco.h> #include <mujoco/mujoco.h>
#include "experimental/filament/filament/builtins.h" #include "experimental/filament/filament/builtins.h"
#include "experimental/filament/filament/filament_context.h"
#include "experimental/filament/filament/math_util.h" #include "experimental/filament/filament/math_util.h"
#include "experimental/filament/filament/mesh.h"
#include "experimental/filament/filament/model_util.h" #include "experimental/filament/filament/model_util.h"
#include "experimental/filament/filament/texture.h" #include "experimental/filament/render_context_filament.h"
#include "experimental/filament/render_context_filament_cpp.h"
namespace mujoco { namespace mujoco {
@@ -407,7 +404,7 @@ static std::span<const int> GetIndices(const mjModel* model,
} }
} }
static void UpdatemjrMeshData(mjrMeshData* data, const mjModel* model, int id, static void UpdateMeshData(mjrMeshData* data, const mjModel* model, int id,
MeshType mesh_type) { MeshType mesh_type) {
if (!IsValidIndex(model, id, mesh_type)) { if (!IsValidIndex(model, id, mesh_type)) {
mju_error("Invalid index %d for type %d", id, mesh_type); mju_error("Invalid index %d for type %d", id, mesh_type);
@@ -462,7 +459,7 @@ static void UpdatemjrMeshData(mjrMeshData* data, const mjModel* model, int id,
data->bounds_max[2] = builder->bounds_max.z; data->bounds_max[2] = builder->bounds_max.z;
} }
void UpdateSkinFlexmjrMeshData(mjrMeshData* data, const mjModel* model, void UpdateSkinFlexMeshData(mjrMeshData* data, const mjModel* model,
const mjvScene* scene, const mjvGeom& geom) { const mjvScene* scene, const mjvGeom& geom) {
auto positions = GetPositions(model, scene, geom); auto positions = GetPositions(model, scene, geom);
auto normals = GetNormals(model, scene, geom); auto normals = GetNormals(model, scene, geom);
@@ -494,21 +491,21 @@ void UpdateSkinFlexmjrMeshData(mjrMeshData* data, const mjModel* model,
data->user_data = nullptr; data->user_data = nullptr;
} }
ModelObjects::ModelObjects(const mjModel* model, FilamentContext* ctx) ModelObjects::ModelObjects(const mjModel* model, mjrfContext* ctx)
: model_(model), ctx_(ctx) { : model_(model), ctx_(ctx) {
const int nstack = model->vis.quality.numstacks; const int nstack = model->vis.quality.numstacks;
const int nslice = model->vis.quality.numslices; const int nslice = model->vis.quality.numslices;
const int nquad = model->vis.quality.numquads; const int nquad = model->vis.quality.numquads;
shapes_[kLine] = CreateLine(ctx_); shapes_.insert({kLine, CreateLine(ctx_)});
shapes_[kBox] = CreateBox(ctx_, nquad); shapes_.insert({kBox, CreateBox(ctx_, nquad)});
shapes_[kLineBox] = CreateLineBox(ctx_); shapes_.insert({kLineBox, CreateLineBox(ctx_)});
shapes_[kCone] = CreateCone(ctx_, nstack, nslice); shapes_.insert({kCone, CreateCone(ctx_, nstack, nslice)});
shapes_[kDisk] = CreateDisk(ctx_, nslice); shapes_.insert({kDisk, CreateDisk(ctx_, nslice)});
shapes_[kDome] = CreateDome(ctx_, nstack / 2, nslice); shapes_.insert({kDome, CreateDome(ctx_, nstack / 2, nslice)});
shapes_[kTube] = CreateTube(ctx_, nstack, nslice); shapes_.insert({kTube, CreateTube(ctx_, nstack, nslice)});
shapes_[kPlane] = CreatePlane(ctx_, nquad); shapes_.insert({kPlane, CreatePlane(ctx_, nquad)});
shapes_[kSphere] = CreateSphere(ctx_, nstack, nslice); shapes_.insert({kSphere, CreateSphere(ctx_, nstack, nslice)});
shapes_[kTriangle] = CreateTriangle(ctx_); shapes_.insert({kTriangle, CreateTriangle(ctx_)});
for (int i = 0; i < model_->ntex; ++i) { for (int i = 0; i < model_->ntex; ++i) {
UploadTexture(model_, i); UploadTexture(model_, i);
@@ -545,14 +542,14 @@ void ModelObjects::UploadMesh(const mjModel* model, int id) {
mjrMeshData data; mjrMeshData data;
mjr_defaultMeshData(&data); mjr_defaultMeshData(&data);
UpdatemjrMeshData(&data, model, id, MeshType::kNormal); UpdateMeshData(&data, model, id, MeshType::kNormal);
meshes_[id] = std::make_unique<Mesh>(ctx_, data); meshes_.insert_or_assign(id, CreateMesh(ctx_, data));
if (model->mesh_graphadr[id] >= 0) { if (model->mesh_graphadr[id] >= 0) {
mjrMeshData convex_hull_data; mjrMeshData convex_hull_data;
mjr_defaultMeshData(&convex_hull_data); mjr_defaultMeshData(&convex_hull_data);
UpdatemjrMeshData(&convex_hull_data, model, id, MeshType::kConvexHull); UpdateMeshData(&convex_hull_data, model, id, MeshType::kConvexHull);
convex_hulls_[id] = std::make_unique<Mesh>(ctx_, convex_hull_data); convex_hulls_.insert_or_assign(id, CreateMesh(ctx_, convex_hull_data));
} }
} }
@@ -597,9 +594,9 @@ void ModelObjects::UploadTexture(const mjModel* model, int id) {
payload.user_data = nullptr; payload.user_data = nullptr;
payload.release_callback = nullptr; payload.release_callback = nullptr;
auto texture = std::make_unique<Texture>(ctx_, config); auto texture = CreateTexture(ctx_, config);
texture->Upload(payload); mjrf_setTextureData(texture.get(), &payload);
textures_[id] = std::move(texture); textures_.insert_or_assign(id, std::move(texture));
} }
void ModelObjects::UploadHeightField(const mjModel* model, int id) { void ModelObjects::UploadHeightField(const mjModel* model, int id) {
@@ -614,18 +611,18 @@ void ModelObjects::UploadHeightField(const mjModel* model, int id) {
mjrMeshData data; mjrMeshData data;
mjr_defaultMeshData(&data); mjr_defaultMeshData(&data);
UpdatemjrMeshData(&data, model, id, MeshType::kHeightField); UpdateMeshData(&data, model, id, MeshType::kHeightField);
height_fields_[id] = std::make_unique<Mesh>(ctx_, data); height_fields_.insert_or_assign(id, CreateMesh(ctx_, data));
} }
void ModelObjects::CreateSkinFlexMesh(const mjvScene* scene, const mjvGeom& geom) { void ModelObjects::CreateSkinFlexMesh(const mjvScene* scene, const mjvGeom& geom) {
mjrMeshData data; mjrMeshData data;
mjr_defaultMeshData(&data); mjr_defaultMeshData(&data);
UpdateSkinFlexmjrMeshData(&data, model_, scene, geom); UpdateSkinFlexMeshData(&data, model_, scene, geom);
dynamic_meshes_[geom.objid] = std::make_unique<Mesh>(ctx_, data); dynamic_meshes_.insert_or_assign(geom.objid, CreateMesh(ctx_, data));
} }
const Mesh* ModelObjects::GetMeshBuffer(int data_id) const { const mjrMesh* ModelObjects::GetMeshBuffer(int data_id) const {
// As defined by mjv_updateScene: // As defined by mjv_updateScene:
// original mesh: mesh_id * 2 // original mesh: mesh_id * 2
// convex hull: (mesh_id * 2) + 1 // convex hull: (mesh_id * 2) + 1
@@ -639,29 +636,27 @@ const Mesh* ModelObjects::GetMeshBuffer(int data_id) const {
} }
} }
const Mesh* ModelObjects::GetHeightFieldBuffer(int hfield_id) const { const mjrMesh* ModelObjects::GetHeightFieldBuffer(int hfield_id) const {
auto it = height_fields_.find(hfield_id); auto it = height_fields_.find(hfield_id);
return it != height_fields_.end() ? it->second.get() : nullptr; return it != height_fields_.end() ? it->second.get() : nullptr;
} }
const Mesh* ModelObjects::GetShapeBuffer(ShapeType shape) const { const mjrMesh* ModelObjects::GetShapeBuffer(ShapeType shape) const {
if (shape < 0 || shape >= kNumShapes) { auto it = shapes_.find(shape);
mju_error("Invalid shape type: %d", shape); return it != shapes_.end() ? it->second.get() : nullptr;
}
return shapes_[shape].get();
} }
const Mesh* ModelObjects::GetFlexSkinGeomMesh(int geom_id) const { const mjrMesh* ModelObjects::GetFlexSkinGeomMesh(int geom_id) const {
auto it = dynamic_meshes_.find(geom_id); auto it = dynamic_meshes_.find(geom_id);
return it != dynamic_meshes_.end() ? it->second.get() : nullptr; return it != dynamic_meshes_.end() ? it->second.get() : nullptr;
} }
const Texture* ModelObjects::GetTexture(int tex_id) const { const mjrTexture* ModelObjects::GetTexture(int tex_id) const {
auto it = textures_.find(tex_id); auto it = textures_.find(tex_id);
return it != textures_.end() ? it->second.get() : nullptr; return it != textures_.end() ? it->second.get() : nullptr;
} }
const Texture* ModelObjects::GetTexture(int mat_id, int role) const { const mjrTexture* ModelObjects::GetTexture(int mat_id, int role) const {
if (mat_id < 0 || mat_id >= model_->nmat || role < 0 || role >= mjNTEXROLE) { if (mat_id < 0 || mat_id >= model_->nmat || role < 0 || role >= mjNTEXROLE) {
return nullptr; return nullptr;
} }
@@ -669,7 +664,7 @@ const Texture* ModelObjects::GetTexture(int mat_id, int role) const {
return GetTexture(tex_id); return GetTexture(tex_id);
} }
const Texture* ModelObjects::GetSkyboxTexture() const { const mjrTexture* ModelObjects::GetSkyboxTexture() const {
for (auto& iter : textures_) { for (auto& iter : textures_) {
if (model_->tex_type[iter.first] == mjTEXTURE_SKYBOX) { if (model_->tex_type[iter.first] == mjTEXTURE_SKYBOX) {
return iter.second.get(); return iter.second.get();
@@ -15,22 +15,19 @@
#ifndef MUJOCO_SRC_EXPERIMENTAL_FILAMENT_COMPAT_MODEL_OBJECTS_H_ #ifndef MUJOCO_SRC_EXPERIMENTAL_FILAMENT_COMPAT_MODEL_OBJECTS_H_
#define MUJOCO_SRC_EXPERIMENTAL_FILAMENT_COMPAT_MODEL_OBJECTS_H_ #define MUJOCO_SRC_EXPERIMENTAL_FILAMENT_COMPAT_MODEL_OBJECTS_H_
#include <array>
#include <memory>
#include <unordered_map> #include <unordered_map>
#include <mujoco/mjmodel.h> #include <mujoco/mjmodel.h>
#include <mujoco/mujoco.h> #include <mujoco/mujoco.h>
#include "experimental/filament/filament/filament_context.h" #include "experimental/filament/render_context_filament.h"
#include "experimental/filament/filament/mesh.h" #include "experimental/filament/render_context_filament_cpp.h"
#include "experimental/filament/filament/texture.h"
namespace mujoco { namespace mujoco {
// Creates and owns various filament objects based on the mjModel. // Creates and owns various filament objects based on the mjModel.
class ModelObjects { class ModelObjects {
public: public:
ModelObjects(const mjModel* model, FilamentContext* ctx); ModelObjects(const mjModel* model, mjrfContext* ctx);
~ModelObjects(); ~ModelObjects();
enum ShapeType { enum ShapeType {
@@ -56,13 +53,13 @@ class ModelObjects {
void CreateSkinFlexMesh(const mjvScene* scene, const mjvGeom& geom); void CreateSkinFlexMesh(const mjvScene* scene, const mjvGeom& geom);
// Returns the cached instance of a filament object created from the mjModel. // Returns the cached instance of a filament object created from the mjModel.
const Mesh* GetShapeBuffer(ShapeType shape) const; const mjrMesh* GetShapeBuffer(ShapeType shape) const;
const Mesh* GetMeshBuffer(int data_id) const; const mjrMesh* GetMeshBuffer(int data_id) const;
const Mesh* GetHeightFieldBuffer(int hfield_id) const; const mjrMesh* GetHeightFieldBuffer(int hfield_id) const;
const Mesh* GetFlexSkinGeomMesh(int geom_id) const; const mjrMesh* GetFlexSkinGeomMesh(int geom_id) const;
const Texture* GetTexture(int tex_id) const; const mjrTexture* GetTexture(int tex_id) const;
const Texture* GetTexture(int mat_id, int role) const; const mjrTexture* GetTexture(int mat_id, int role) const;
const Texture* GetSkyboxTexture() const; const mjrTexture* GetSkyboxTexture() const;
float GetSpecularMultiplier() const { return specular_multiplier_; } float GetSpecularMultiplier() const { return specular_multiplier_; }
float GetShininessMultiplier() const { return shininess_multiplier_; } float GetShininessMultiplier() const { return shininess_multiplier_; }
@@ -75,13 +72,13 @@ class ModelObjects {
private: private:
const mjModel* model_ = nullptr; const mjModel* model_ = nullptr;
FilamentContext* ctx_ = nullptr; mjrfContext* ctx_ = nullptr;
std::array<std::unique_ptr<Mesh>, kNumShapes> shapes_; std::unordered_map<ShapeType, UniquePtr<mjrMesh>> shapes_;
std::unordered_map<int, std::unique_ptr<Mesh>> meshes_; std::unordered_map<int, UniquePtr<mjrMesh>> meshes_;
std::unordered_map<int, std::unique_ptr<Mesh>> convex_hulls_; std::unordered_map<int, UniquePtr<mjrMesh>> convex_hulls_;
std::unordered_map<int, std::unique_ptr<Mesh>> height_fields_; std::unordered_map<int, UniquePtr<mjrMesh>> height_fields_;
std::unordered_map<int, std::unique_ptr<Mesh>> dynamic_meshes_; std::unordered_map<int, UniquePtr<mjrMesh>> dynamic_meshes_;
std::unordered_map<int, std::unique_ptr<Texture>> textures_; std::unordered_map<int, UniquePtr<mjrTexture>> textures_;
float specular_multiplier_ = 0.2f; float specular_multiplier_ = 0.2f;
float shininess_multiplier_ = 0.1f; float shininess_multiplier_ = 0.1f;
float emissive_multiplier_ = 0.3f; float emissive_multiplier_ = 0.3f;
@@ -19,8 +19,6 @@
#include <string_view> #include <string_view>
#include <utility> #include <utility>
#include <filament/Options.h>
#include <filament/View.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>
@@ -31,16 +29,13 @@
#include "experimental/filament/compat/imgui_bridge.h" #include "experimental/filament/compat/imgui_bridge.h"
#include "experimental/filament/compat/model_objects.h" #include "experimental/filament/compat/model_objects.h"
#include "experimental/filament/compat/scene_geom_util.h" #include "experimental/filament/compat/scene_geom_util.h"
#include "experimental/filament/filament/color_grading_options.h"
#include "experimental/filament/filament/filament_context.h" #include "experimental/filament/filament/filament_context.h"
#include "experimental/filament/filament/light.h" #include "experimental/filament/filament/object_manager.h"
#include "experimental/filament/filament/math_util.h" #include "experimental/filament/filament/math_util.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/renderable.h"
#include "experimental/filament/filament/scene_view.h" #include "experimental/filament/filament/scene_view.h"
#include "experimental/filament/filament/texture.h"
#include "experimental/filament/render_context_filament.h" #include "experimental/filament/render_context_filament.h"
#include "experimental/filament/render_context_filament_cpp.h"
namespace mujoco { namespace mujoco {
@@ -49,14 +44,14 @@ using filament::math::float4;
using filament::math::mat3; using filament::math::mat3;
using filament::math::mat4; using filament::math::mat4;
static std::unique_ptr<Texture> CreateFallbackIndirectLightTexture( static UniquePtr<mjrTexture> CreateFallbackIndirectLightTexture(
FilamentContext* ctx, std::string_view filename = "") { mjrfContext* ctx, std::string_view filename = "") {
if (filename.empty()) { if (filename.empty()) {
filename = ObjectManager::kDefaultEnvironmentLight; filename = ObjectManager::kDefaultEnvironmentLight;
} }
std::unique_ptr<ObjectManager::Asset> asset = std::unique_ptr<ObjectManager::Asset> asset =
ctx->GetObjectManager()->LoadAsset(filename); FilamentContext::downcast(ctx)->GetObjectManager()->LoadAsset(filename);
mjrTextureConfig config; mjrTextureConfig config;
mjr_defaultTextureConfig(&config); mjr_defaultTextureConfig(&config);
@@ -66,7 +61,7 @@ static std::unique_ptr<Texture> CreateFallbackIndirectLightTexture(
config.format = mjPIXEL_FORMAT_KTX; config.format = mjPIXEL_FORMAT_KTX;
config.color_space = mjCOLORSPACE_AUTO; config.color_space = mjCOLORSPACE_AUTO;
auto texture = std::make_unique<Texture>(ctx, config); auto texture = CreateTexture(ctx, config);
mjrTextureData payload; mjrTextureData payload;
mjr_defaultTextureData(&payload); mjr_defaultTextureData(&payload);
@@ -77,20 +72,20 @@ static std::unique_ptr<Texture> CreateFallbackIndirectLightTexture(
}; };
payload.user_data = asset.release(); payload.user_data = asset.release();
texture->Upload(payload); mjrf_setTextureData(texture.get(), &payload);
return texture; return texture;
} }
SceneBridge::SceneBridge(FilamentContext* ctx, const mjModel* model) SceneBridge::SceneBridge(mjrfContext* ctx, const mjModel* model)
: ctx_(ctx) { : ctx_(ctx) {
mjrSceneParams params; mjrSceneParams params;
mjr_defaultSceneParams(&params); mjr_defaultSceneParams(&params);
params.layer_mask = mjCAT_ALL; params.layer_mask = mjCAT_ALL;
params.reflection_layer_mask = mjCAT_DYNAMIC | mjCAT_STATIC; params.reflection_layer_mask = mjCAT_DYNAMIC | mjCAT_STATIC;
scene_view_ = std::make_unique<SceneView>(ctx_, params); scene_ = CreateScene(ctx_, params);
model_objects_ = std::make_unique<ModelObjects>(model, ctx_); model_objects_ = std::make_unique<ModelObjects>(model, ctx_);
scene_view_->Configure(model); mjrf_configureSceneFromModel(scene_.get(), model);
default_shadow_map_size_ = ReadElement( default_shadow_map_size_ = ReadElement(
model, "filament.shadows.map_size", default_shadow_map_size_); model, "filament.shadows.map_size", default_shadow_map_size_);
@@ -111,15 +106,15 @@ SceneBridge::SceneBridge(FilamentContext* ctx, const mjModel* model)
SceneBridge::~SceneBridge() { SceneBridge::~SceneBridge() {
for (auto& iter : lights_) { for (auto& iter : lights_) {
scene_view_->RemoveFromScene(iter.get()); mjrf_removeLightFromScene(scene_.get(), iter.get());
} }
lights_.clear(); lights_.clear();
if (fallback_ibl_) { if (fallback_ibl_) {
scene_view_->RemoveFromScene(fallback_ibl_.get()); mjrf_removeLightFromScene(scene_.get(), fallback_ibl_.get());
} }
fallback_ibl_.reset(); fallback_ibl_.reset();
for (auto& iter : renderables_) { for (auto& iter : renderables_) {
scene_view_->RemoveFromScene(iter.get()); mjrf_removeRenderableFromScene(scene_.get(), iter.get());
} }
renderables_.clear(); renderables_.clear();
} }
@@ -127,14 +122,14 @@ SceneBridge::~SceneBridge() {
void SceneBridge::SetEnvironmentLight(std::string_view filename, void SceneBridge::SetEnvironmentLight(std::string_view filename,
float intensity) { float intensity) {
for (auto& light : lights_) { for (auto& light : lights_) {
if (light->GetType() == mjLIGHT_IMAGE) { if (mjrf_getLightType(light.get()) == mjLIGHT_IMAGE) {
scene_view_->RemoveFromScene(light.get()); mjrf_removeLightFromScene(scene_.get(), light.get());
light.reset(); light.reset();
break; break;
} }
} }
if (fallback_ibl_) { if (fallback_ibl_) {
scene_view_->RemoveFromScene(fallback_ibl_.get()); mjrf_removeLightFromScene(scene_.get(), fallback_ibl_.get());
fallback_ibl_.reset(); fallback_ibl_.reset();
} }
@@ -145,8 +140,8 @@ void SceneBridge::SetEnvironmentLight(std::string_view filename,
params.type = mjLIGHT_IMAGE; params.type = mjLIGHT_IMAGE;
params.texture = fallback_ibl_texture_.get(); params.texture = fallback_ibl_texture_.get();
params.intensity = intensity; params.intensity = intensity;
fallback_ibl_ = std::make_unique<Light>(ctx_, params); fallback_ibl_ = CreateLight(ctx_, params);
scene_view_->AddToScene(fallback_ibl_.get()); mjrf_addLightToScene(scene_.get(), fallback_ibl_.get());
} }
std::optional<float3> SceneBridge::ClipFromWorld(const float3& pos) const{ std::optional<float3> SceneBridge::ClipFromWorld(const float3& pos) const{
@@ -171,8 +166,8 @@ void SceneBridge::PrepareLights() {
params.type = mjLIGHT_IMAGE; params.type = mjLIGHT_IMAGE;
params.texture = model_objects_->GetTexture(model->light_texid[i]); params.texture = model_objects_->GetTexture(model->light_texid[i]);
params.intensity = model->light_intensity[i]; params.intensity = model->light_intensity[i];
auto light_obj = std::make_unique<Light>(ctx_, params); auto light_obj = CreateLight(ctx_, params);
scene_view_->AddToScene(light_obj.get()); mjrf_addLightToScene(scene_.get(), light_obj.get());
lights_.emplace_back(std::move(light_obj)); lights_.emplace_back(std::move(light_obj));
has_image_based_light = true; has_image_based_light = true;
} else { } else {
@@ -192,8 +187,8 @@ void SceneBridge::PrepareLights() {
params.spot_cone_angle = model->light_cutoff[i]; params.spot_cone_angle = model->light_cutoff[i];
} }
auto light_obj = std::make_unique<Light>(ctx_, params); auto light_obj = CreateLight(ctx_, params);
scene_view_->AddToScene(light_obj.get()); mjrf_addLightToScene(scene_.get(), light_obj.get());
lights_.emplace_back(std::move(light_obj)); lights_.emplace_back(std::move(light_obj));
} }
} }
@@ -212,8 +207,8 @@ void SceneBridge::PrepareLights() {
params.cast_shadows = 0; params.cast_shadows = 0;
params.intensity = 0.0f; params.intensity = 0.0f;
params.spot_cone_angle = 90.0f; params.spot_cone_angle = 90.0f;
auto light_obj = std::make_unique<Light>(ctx_, params); auto light_obj = CreateLight(ctx_, params);
scene_view_->AddToScene(light_obj.get()); mjrf_addLightToScene(scene_.get(), light_obj.get());
lights_.emplace_back(std::move(light_obj)); lights_.emplace_back(std::move(light_obj));
} }
@@ -224,8 +219,8 @@ void SceneBridge::PrepareLights() {
mjr_defaultLightParams(&params); mjr_defaultLightParams(&params);
params.type = mjLIGHT_IMAGE; params.type = mjLIGHT_IMAGE;
params.intensity = 10.0f; params.intensity = 10.0f;
fallback_ibl_ = std::make_unique<Light>(ctx_, params); fallback_ibl_ = CreateLight(ctx_, params);
scene_view_->AddToScene(fallback_ibl_.get()); mjrf_addLightToScene(scene_.get(), fallback_ibl_.get());
} }
// There are no "physical" lights in the scene which means we're likely // There are no "physical" lights in the scene which means we're likely
@@ -240,21 +235,22 @@ void SceneBridge::PrepareLights() {
params.type = mjLIGHT_IMAGE; params.type = mjLIGHT_IMAGE;
params.texture = fallback_ibl_texture_.get(); params.texture = fallback_ibl_texture_.get();
params.intensity = fallback_environment_light_intensity_; params.intensity = fallback_environment_light_intensity_;
fallback_ibl_ = std::make_unique<Light>(ctx_, params); fallback_ibl_ = CreateLight(ctx_, params);
scene_view_->AddToScene(fallback_ibl_.get()); mjrf_addLightToScene(scene_.get(), fallback_ibl_.get());
// Distribute the fallback scene light intensity among the lights. // Distribute the fallback scene light intensity among the lights.
const float intensity = fallback_scene_light_intensity_ / lights_.size(); const float intensity = fallback_scene_light_intensity_ / lights_.size();
for (auto& light : lights_) { for (auto& light : lights_) {
if (light) { if (light) {
const bool is_headlight = (light == lights_.back()); const bool is_headlight = (light == lights_.back());
light->SetIntensity(is_headlight ? fallback_head_light_intensity_ mjrf_setLightIntensity(light.get(),
: intensity); is_headlight ? fallback_head_light_intensity_
: intensity);
} }
} }
} }
scene_view_->SetSkybox(model_objects_->GetSkyboxTexture()); mjrf_setSceneSkybox(scene_.get(), model_objects_->GetSkyboxTexture());
} }
mat4 CalculateClipFromWorld(const mjrRect& viewport, const mjvGLCamera& cam) { mat4 CalculateClipFromWorld(const mjrRect& viewport, const mjvGLCamera& cam) {
@@ -285,16 +281,8 @@ mat4 CalculateClipFromWorld(const mjrRect& viewport, const mjvGLCamera& cam) {
} }
void SceneBridge::Update(const mjrRect& viewport, const mjvScene* scene) { void SceneBridge::Update(const mjrRect& viewport, const mjvScene* scene) {
if (scene->flags[mjRND_SHADOW]) { mjrf_setSceneShadowsEnabled(scene_.get(), scene->flags[mjRND_SHADOW]);
scene_view_->EnableShadows(); mjrf_setSceneReflectionsEnabled(scene_.get(), scene->flags[mjRND_REFLECTION]);
} else {
scene_view_->DisableShadows();
}
if (scene->flags[mjRND_REFLECTION]) {
scene_view_->EnableReflections();
} else {
scene_view_->DisableReflections();
}
mjtNum hpos[3], hfwd[3]; mjtNum hpos[3], hfwd[3];
float headpos[3], gazedir[3]; float headpos[3], gazedir[3];
@@ -308,7 +296,7 @@ void SceneBridge::Update(const mjrRect& viewport, const mjvScene* scene) {
// Remove all drawables from previous render and prepare new ones. // Remove all drawables from previous render and prepare new ones.
for (auto& iter : renderables_) { for (auto& iter : renderables_) {
scene_view_->RemoveFromScene(iter.get()); mjrf_removeRenderableFromScene(scene_.get(), iter.get());
} }
renderables_.clear(); renderables_.clear();
for (int i = 0; i < scene->ngeom; ++i) { for (int i = 0; i < scene->ngeom; ++i) {
@@ -324,10 +312,10 @@ void SceneBridge::Update(const mjrRect& viewport, const mjvScene* scene) {
model_objects_->CreateSkinFlexMesh(scene, *geom); model_objects_->CreateSkinFlexMesh(scene, *geom);
} }
std::unique_ptr<Renderable> renderable = CreateGeomRenderable( UniquePtr<mjrRenderable> renderable = CreateGeomRenderable(
*geom, scene, ctx_, model_objects_.get(), headpos); *geom, scene, ctx_, model_objects_.get(), headpos);
scene_view_->AddToScene(renderable.get()); mjrf_addRenderableToScene(scene_.get(), renderable.get());
renderables_.push_back(std::move(renderable)); renderables_.push_back(std::move(renderable));
} }
@@ -343,16 +331,15 @@ void SceneBridge::Update(const mjrRect& viewport, const mjvScene* scene) {
headpos[2] -= gazedir[2] * 0.05f; headpos[2] -= gazedir[2] * 0.05f;
// The headlight is always the "back" light. // The headlight is always the "back" light.
std::unique_ptr<Light>& light = lights_.back(); UniquePtr<mjrLight>& light = lights_.back();
light->SetColor(ReadFloat3(scene_light.diffuse)); mjrf_setLightColor(light.get(), scene_light.diffuse);
light->SetTransform(ReadFloat3(headpos), ReadFloat3(gazedir)); mjrf_setLightTransform(light.get(), headpos, gazedir);
continue; continue;
} else if (scene_light.id < lights_.size() - 1) { } else if (scene_light.id < lights_.size() - 1) {
std::unique_ptr<Light>& light = lights_[scene_light.id]; UniquePtr<mjrLight>& light = lights_[scene_light.id];
if (light) { if (light) {
light->SetColor(ReadFloat3(scene_light.diffuse)); mjrf_setLightColor(light.get(), scene_light.diffuse);
light->SetTransform(ReadFloat3(scene_light.pos), mjrf_setLightTransform(light.get(), scene_light.pos, scene_light.dir);
ReadFloat3(scene_light.dir));
} }
} else { } else {
mju_error("Unexpected light id: %d", scene_light.id); mju_error("Unexpected light id: %d", scene_light.id);
@@ -360,11 +347,7 @@ void SceneBridge::Update(const mjrRect& viewport, const mjvScene* scene) {
} }
// Enable/disable the headlight based on whether or not it's in the scene. // Enable/disable the headlight based on whether or not it's in the scene.
if (headlight_enabled) { mjrf_setLightEnabled(lights_.back().get(), headlight_enabled);
lights_.back()->Enable();
} else {
lights_.back()->Disable();
}
} }
void SceneBridge::UploadMesh(const mjModel* model, int id) { void SceneBridge::UploadMesh(const mjModel* model, int id) {
+10 -13
View File
@@ -25,18 +25,15 @@
#include <mujoco/mjvisualize.h> #include <mujoco/mjvisualize.h>
#include <mujoco/mujoco.h> #include <mujoco/mujoco.h>
#include "experimental/filament/compat/model_objects.h" #include "experimental/filament/compat/model_objects.h"
#include "experimental/filament/filament/filament_context.h" #include "experimental/filament/render_context_filament.h"
#include "experimental/filament/filament/light.h" #include "experimental/filament/render_context_filament_cpp.h"
#include "experimental/filament/filament/renderable.h"
#include "experimental/filament/filament/scene_view.h"
#include "experimental/filament/filament/texture.h"
namespace mujoco { namespace mujoco {
// Manages all mjModel data and updates a SceneView using an mjvScene. // Manages all mjModel data and updates a SceneView using an mjvScene.
class SceneBridge { class SceneBridge {
public: public:
SceneBridge(FilamentContext* ctx, const mjModel* model); SceneBridge(mjrfContext* ctx, const mjModel* model);
~SceneBridge(); ~SceneBridge();
// Updates the environment light using the KTX image at the given path. // Updates the environment light using the KTX image at the given path.
@@ -55,7 +52,7 @@ class SceneBridge {
void UploadHeightField(const mjModel* model, int id); void UploadHeightField(const mjModel* model, int id);
// Returns the managed scene. // Returns the managed scene.
SceneView* GetSceneView() const { return scene_view_.get(); } mjrScene* GetScene() const { return scene_.get(); }
SceneBridge(const SceneBridge&) = delete; SceneBridge(const SceneBridge&) = delete;
SceneBridge& operator=(const SceneBridge&) = delete; SceneBridge& operator=(const SceneBridge&) = delete;
@@ -68,13 +65,13 @@ class SceneBridge {
std::optional<filament::math::float3> ClipFromWorld( std::optional<filament::math::float3> ClipFromWorld(
const filament::math::float3& pos) const; const filament::math::float3& pos) const;
FilamentContext* ctx_ = nullptr; mjrfContext* ctx_ = nullptr;
std::unique_ptr<SceneView> scene_view_;
std::unique_ptr<ModelObjects> model_objects_; std::unique_ptr<ModelObjects> model_objects_;
std::unique_ptr<Light> fallback_ibl_; UniquePtr<mjrScene> scene_{nullptr, nullptr};
std::unique_ptr<Texture> fallback_ibl_texture_; UniquePtr<mjrLight> fallback_ibl_{nullptr, nullptr};
std::vector<std::unique_ptr<Light>> lights_; UniquePtr<mjrTexture> fallback_ibl_texture_{nullptr, nullptr};
std::vector<std::unique_ptr<Renderable>> renderables_; std::vector<UniquePtr<mjrLight>> lights_;
std::vector<UniquePtr<mjrRenderable>> 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;
@@ -16,6 +16,7 @@
#include <cmath> #include <cmath>
#include <cstdint> #include <cstdint>
#include <cstring>
#include <memory> #include <memory>
#include <numbers> #include <numbers>
#include <vector> #include <vector>
@@ -27,12 +28,10 @@
#include <mujoco/mjvisualize.h> #include <mujoco/mjvisualize.h>
#include <mujoco/mujoco.h> #include <mujoco/mujoco.h>
#include "experimental/filament/compat/model_objects.h" #include "experimental/filament/compat/model_objects.h"
#include "experimental/filament/filament/filament_context.h"
#include "experimental/filament/filament/math_util.h" #include "experimental/filament/filament/math_util.h"
#include "experimental/filament/filament/mesh.h"
#include "experimental/filament/filament/renderable.h" #include "experimental/filament/filament/renderable.h"
#include "experimental/filament/filament/texture.h"
#include "experimental/filament/render_context_filament.h" #include "experimental/filament/render_context_filament.h"
#include "experimental/filament/render_context_filament_cpp.h"
namespace mujoco { namespace mujoco {
@@ -64,39 +63,39 @@ static bool IsBehind(const float* headpos, const float* pos, const float* mat) {
0.0f); 0.0f);
} }
static const Mesh* GetMesh(ModelObjects* model_objs, int data_id) { static const mjrMesh* GetMesh(ModelObjects* model_objs, int data_id) {
const Mesh* mesh = model_objs->GetMeshBuffer(data_id); const mjrMesh* mesh = model_objs->GetMeshBuffer(data_id);
if (mesh == nullptr) { if (mesh == nullptr) {
mju_error("Unknown mesh %d", data_id); mju_error("Unknown mesh %d", data_id);
} }
return mesh; return mesh;
} }
static const Mesh* GetSkinFlexMesh(ModelObjects* model_objs, int objid) { static const mjrMesh* GetSkinFlexMesh(ModelObjects* model_objs, int objid) {
return model_objs->GetFlexSkinGeomMesh(objid); return model_objs->GetFlexSkinGeomMesh(objid);
} }
static const Mesh* GetHeightField(ModelObjects* model_objs, int hfield_id) { static const mjrMesh* GetHeightField(ModelObjects* model_objs, int hfield_id) {
const Mesh* mesh = model_objs->GetHeightFieldBuffer(hfield_id); const mjrMesh* mesh = model_objs->GetHeightFieldBuffer(hfield_id);
if (mesh == nullptr) { if (mesh == nullptr) {
mju_error("Unknown height field %d", hfield_id); mju_error("Unknown height field %d", hfield_id);
} }
return mesh; return mesh;
} }
static const Mesh* GetShape(ModelObjects* model_objs, static const mjrMesh* GetShape(ModelObjects* model_objs,
ModelObjects::ShapeType shape_type) { ModelObjects::ShapeType shape_type) {
const Mesh* mesh = model_objs->GetShapeBuffer(shape_type); const mjrMesh* mesh = model_objs->GetShapeBuffer(shape_type);
if (mesh == nullptr) { if (mesh == nullptr) {
mju_error("Unknown shape %d", shape_type); mju_error("Unknown shape %d", shape_type);
} }
return mesh; return mesh;
} }
static void PrepareGeomMeshes(Renderable& renderable, const mjvGeom& geom, static void PrepareGeomMeshes(mjrRenderable* renderable, const mjvGeom& geom,
const mjvScene* scene, const mjvScene* scene,
ModelObjects* model_objects) { ModelObjects* model_objects) {
std::vector<const Mesh*> meshes; std::vector<const mjrMesh*> meshes;
Renderable::GetTransformFn get_transforms; Renderable::GetTransformFn get_transforms;
Trs trs = { Trs trs = {
@@ -334,11 +333,18 @@ static void PrepareGeomMeshes(Renderable& renderable, const mjvGeom& geom,
break; break;
} }
renderable.SetMeshes(meshes, get_transforms); Renderable::downcast(renderable)->SetMeshes(meshes, get_transforms);
renderable.SetTransform(trs);
float position[3];
std::memcpy(position, &trs.translation[0], 3 * sizeof(float));
float rotation[9];
std::memcpy(rotation, &trs.rotation[0], 9 * sizeof(float));
float size[3];
std::memcpy(size, &trs.size[0], 3 * sizeof(float));
mjrf_setRenderableTransform(renderable, position, rotation, size);
} }
static void UpdateGeomMaterial(Renderable& renderable, const mjvGeom& geom, static void UpdateGeomMaterial(mjrRenderable* renderable, const mjvGeom& geom,
const mjvScene* scene, ModelObjects* model_objs, const mjvScene* scene, ModelObjects* model_objs,
const float headpos[3]) { const float headpos[3]) {
const mjModel* model = model_objs->GetModel(); const mjModel* model = model_objs->GetModel();
@@ -353,19 +359,19 @@ static void UpdateGeomMaterial(Renderable& renderable, const mjvGeom& geom,
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); mjrf_setRenderableReceiveShadows(renderable, false);
params.reflective = false; params.reflective = false;
} else { } else {
renderable.SetReceiveShadows(true); mjrf_setRenderableReceiveShadows(renderable, true);
params.reflective = geom.reflectance > 0 && params.color[3] == 1.0f; params.reflective = geom.reflectance > 0 && params.color[3] == 1.0f;
} }
} }
renderable.SetLayerMask(geom.category); mjrf_setRenderableLayerMask(renderable, geom.category);
if (geom.category == mjCAT_DECOR) { if (geom.category == mjCAT_DECOR) {
renderable.SetCastShadows(false); mjrf_setRenderableCastShadows(renderable, false);
renderable.SetReceiveShadows(false); mjrf_setRenderableReceiveShadows(renderable, false);
} else { } else {
renderable.SetWireframe(scene->flags[mjRND_WIREFRAME]); mjrf_setRenderableWireframe(renderable, scene->flags[mjRND_WIREFRAME]);
} }
mjrMaterialTextures textures; mjrMaterialTextures textures;
@@ -420,7 +426,7 @@ static void UpdateGeomMaterial(Renderable& renderable, const mjvGeom& geom,
// the programmatic UVs. // the programmatic UVs.
if (textures.color) { if (textures.color) {
if (Texture::downcast(textures.color)->GetTarget() == mjTEXTURE_2D) { if (mjrf_getTextureTarget(textures.color) == mjTEXTURE_2D) {
// For 2D textures, `tex_repeat` specifies how many times the texture // For 2D textures, `tex_repeat` specifies how many times the texture
// image is repeated. The `tex_uniform` flag determines if the repetition // image is repeated. The `tex_uniform` flag determines if the repetition
// is applied at in object space (false) or in world space (true). // is applied at in object space (false) or in world space (true).
@@ -482,11 +488,11 @@ static void UpdateGeomMaterial(Renderable& renderable, const mjvGeom& geom,
params.specular *= model_objs->GetSpecularMultiplier(); params.specular *= model_objs->GetSpecularMultiplier();
params.glossiness *= model_objs->GetShininessMultiplier(); params.glossiness *= model_objs->GetShininessMultiplier();
renderable.UpdateMaterial(params, textures); mjrf_setRenderableMaterial(renderable, &params, &textures);
} }
std::unique_ptr<Renderable> CreateGeomRenderable( UniquePtr<mjrRenderable> CreateGeomRenderable(
const mjvGeom& geom, const mjvScene* scene, FilamentContext* ctx, const mjvGeom& geom, const mjvScene* scene, mjrfContext* ctx,
ModelObjects* model_objs, const float headpos[3]) { ModelObjects* model_objs, const float headpos[3]) {
mjrShadingModel shading_model = mjSHADING_MODEL_SCENE_OBJECT; mjrShadingModel shading_model = mjSHADING_MODEL_SCENE_OBJECT;
if (geom.type == mjGEOM_LINE || geom.type == mjGEOM_LINEBOX) { if (geom.type == mjGEOM_LINE || geom.type == mjGEOM_LINEBOX) {
@@ -498,9 +504,9 @@ std::unique_ptr<Renderable> CreateGeomRenderable(
mjrRenderableParams params; mjrRenderableParams params;
mjr_defaultRenderableParams(&params); mjr_defaultRenderableParams(&params);
params.shading_model = shading_model; params.shading_model = shading_model;
auto renderable = std::make_unique<Renderable>(ctx, params); auto renderable = CreateRenderable(ctx, params);
PrepareGeomMeshes(*renderable, geom, scene, model_objs); PrepareGeomMeshes(renderable.get(), geom, scene, model_objs);
UpdateGeomMaterial(*renderable, geom, scene, model_objs, headpos); UpdateGeomMaterial(renderable.get(), geom, scene, model_objs, headpos);
return renderable; return renderable;
} }
} // namespace mujoco } // namespace mujoco
@@ -15,18 +15,16 @@
#ifndef MUJOCO_SRC_EXPERIMENTAL_FILAMENT_COMPAT_SCENE_GEOM_UTIL_H_ #ifndef MUJOCO_SRC_EXPERIMENTAL_FILAMENT_COMPAT_SCENE_GEOM_UTIL_H_
#define MUJOCO_SRC_EXPERIMENTAL_FILAMENT_COMPAT_SCENE_GEOM_UTIL_H_ #define MUJOCO_SRC_EXPERIMENTAL_FILAMENT_COMPAT_SCENE_GEOM_UTIL_H_
#include <memory>
#include <mujoco/mjvisualize.h> #include <mujoco/mjvisualize.h>
#include "experimental/filament/compat/model_objects.h" #include "experimental/filament/compat/model_objects.h"
#include "experimental/filament/filament/filament_context.h" #include "experimental/filament/render_context_filament.h"
#include "experimental/filament/filament/renderable.h" #include "experimental/filament/render_context_filament_cpp.h"
namespace mujoco { namespace mujoco {
// Creates a Renderable from the given mjvGeom. // Creates a Renderable from the given mjvGeom.
std::unique_ptr<Renderable> CreateGeomRenderable( UniquePtr<mjrRenderable> CreateGeomRenderable(
const mjvGeom& geom, const mjvScene* scene, FilamentContext* ctx, const mjvGeom& geom, const mjvScene* scene, mjrfContext* ctx,
ModelObjects* model_objs, const float headpos[3]); ModelObjects* model_objs, const float headpos[3]);
} // namespace mujoco } // namespace mujoco
+13 -13
View File
@@ -28,6 +28,7 @@
#include "experimental/filament/filament/math_util.h" #include "experimental/filament/filament/math_util.h"
#include "experimental/filament/filament/mesh.h" #include "experimental/filament/filament/mesh.h"
#include "experimental/filament/render_context_filament.h" #include "experimental/filament/render_context_filament.h"
#include "experimental/filament/render_context_filament_cpp.h"
namespace mujoco { namespace mujoco {
@@ -64,15 +65,14 @@ class BuiltinBuilder : public mjrMeshData {
virtual ~BuiltinBuilder() = default; virtual ~BuiltinBuilder() = default;
template <typename T, typename... Args> template <typename T, typename... Args>
static std::unique_ptr<Mesh> Create(FilamentContext* ctx, static UniquePtr<mjrMesh> Create(mjrfContext* ctx, Args&&... args) {
Args&&... args) {
auto builder = new T(std::forward<Args>(args)...); auto builder = new T(std::forward<Args>(args)...);
mjrMeshData* mesh_data = builder->PrepareMeshData(); mjrMeshData* mesh_data = builder->PrepareMeshData();
mesh_data->release_callback = +[](void* user_data) { mesh_data->release_callback = +[](void* user_data) {
delete static_cast<BuiltinBuilder*>(user_data); delete static_cast<BuiltinBuilder*>(user_data);
}; };
mesh_data->user_data = builder; mesh_data->user_data = builder;
return std::make_unique<Mesh>(ctx, *mesh_data); return CreateMesh(ctx, *mesh_data);
} }
mjrMeshData* PrepareMeshData() { mjrMeshData* PrepareMeshData() {
@@ -617,43 +617,43 @@ class DomeBuilder : public BuiltinBuilder {
} }
}; };
std::unique_ptr<Mesh> CreateLine(FilamentContext* ctx) { UniquePtr<mjrMesh> CreateLine(mjrfContext* ctx) {
return BuiltinBuilder::Create<LineBuilder>(ctx); return BuiltinBuilder::Create<LineBuilder>(ctx);
} }
std::unique_ptr<Mesh> CreatePlane(FilamentContext* ctx, int nquad) { UniquePtr<mjrMesh> CreatePlane(mjrfContext* ctx, int nquad) {
return BuiltinBuilder::Create<PlaneBuilder>(ctx, nquad); return BuiltinBuilder::Create<PlaneBuilder>(ctx, nquad);
} }
std::unique_ptr<Mesh> CreateTriangle(FilamentContext* ctx) { UniquePtr<mjrMesh> CreateTriangle(mjrfContext* ctx) {
return BuiltinBuilder::Create<TriangleBuilder>(ctx); return BuiltinBuilder::Create<TriangleBuilder>(ctx);
} }
std::unique_ptr<Mesh> CreateBox(FilamentContext* ctx, int nquad) { UniquePtr<mjrMesh> CreateBox(mjrfContext* ctx, int nquad) {
return BuiltinBuilder::Create<BoxBuilder>(ctx, nquad); return BuiltinBuilder::Create<BoxBuilder>(ctx, nquad);
} }
std::unique_ptr<Mesh> CreateLineBox(FilamentContext* ctx) { UniquePtr<mjrMesh> CreateLineBox(mjrfContext* ctx) {
return BuiltinBuilder::Create<LineBoxBuilder>(ctx); return BuiltinBuilder::Create<LineBoxBuilder>(ctx);
} }
std::unique_ptr<Mesh> CreateSphere(FilamentContext* ctx, int nstack, int nslice) { UniquePtr<mjrMesh> CreateSphere(mjrfContext* ctx, int nstack, int nslice) {
return BuiltinBuilder::Create<SphereBuilder>(ctx, nstack, nslice); return BuiltinBuilder::Create<SphereBuilder>(ctx, nstack, nslice);
} }
std::unique_ptr<Mesh> CreateTube(FilamentContext* ctx, int nstack, int nslice) { UniquePtr<mjrMesh> CreateTube(mjrfContext* ctx, int nstack, int nslice) {
return BuiltinBuilder::Create<TubeBuilder>(ctx, nstack, nslice); return BuiltinBuilder::Create<TubeBuilder>(ctx, nstack, nslice);
} }
std::unique_ptr<Mesh> CreateDisk(FilamentContext* ctx, int nslice) { UniquePtr<mjrMesh> CreateDisk(mjrfContext* ctx, int nslice) {
return BuiltinBuilder::Create<DiskBuilder>(ctx, nslice); return BuiltinBuilder::Create<DiskBuilder>(ctx, nslice);
} }
std::unique_ptr<Mesh> CreateDome(FilamentContext* ctx, int nstack, int nslice) { UniquePtr<mjrMesh> CreateDome(mjrfContext* ctx, int nstack, int nslice) {
return BuiltinBuilder::Create<DomeBuilder>(ctx, nstack, nslice); return BuiltinBuilder::Create<DomeBuilder>(ctx, nstack, nslice);
} }
std::unique_ptr<Mesh> CreateCone(FilamentContext* ctx, int nstack, int nslice) { UniquePtr<mjrMesh> CreateCone(mjrfContext* ctx, int nstack, int nslice) {
return BuiltinBuilder::Create<ConeBuilder>(ctx, nstack, nslice); return BuiltinBuilder::Create<ConeBuilder>(ctx, nstack, nslice);
} }
+12 -14
View File
@@ -15,24 +15,22 @@
#ifndef MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_BUILTINS_H_ #ifndef MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_BUILTINS_H_
#define MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_BUILTINS_H_ #define MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_BUILTINS_H_
#include <memory> #include "experimental/filament/render_context_filament.h"
#include "experimental/filament/render_context_filament_cpp.h"
#include "experimental/filament/filament/filament_context.h"
#include "experimental/filament/filament/mesh.h"
// Generates buffers for built-in shapes. // Generates buffers for built-in shapes.
namespace mujoco { namespace mujoco {
std::unique_ptr<Mesh> CreateLine(FilamentContext* ctx); UniquePtr<mjrMesh> CreateLine(mjrfContext* ctx);
std::unique_ptr<Mesh> CreatePlane(FilamentContext* ctx, int nquad); UniquePtr<mjrMesh> CreatePlane(mjrfContext* ctx, int nquad);
std::unique_ptr<Mesh> CreateTriangle(FilamentContext* ctx); UniquePtr<mjrMesh> CreateTriangle(mjrfContext* ctx);
std::unique_ptr<Mesh> CreateBox(FilamentContext* ctx, int nquad); UniquePtr<mjrMesh> CreateBox(mjrfContext* ctx, int nquad);
std::unique_ptr<Mesh> CreateLineBox(FilamentContext* ctx); UniquePtr<mjrMesh> CreateLineBox(mjrfContext* ctx);
std::unique_ptr<Mesh> CreateSphere(FilamentContext* ctx, int nstack, int nslice); UniquePtr<mjrMesh> CreateSphere(mjrfContext* ctx, int nstack, int nslice);
std::unique_ptr<Mesh> CreateTube(FilamentContext* ctx, int nstack, int nslice); UniquePtr<mjrMesh> CreateTube(mjrfContext* ctx, int nstack, int nslice);
std::unique_ptr<Mesh> CreateDisk(FilamentContext* ctx, int nslice); UniquePtr<mjrMesh> CreateDisk(mjrfContext* ctx, int nslice);
std::unique_ptr<Mesh> CreateDome(FilamentContext* ctx, int nstack, int nslice); UniquePtr<mjrMesh> CreateDome(mjrfContext* ctx, int nstack, int nslice);
std::unique_ptr<Mesh> CreateCone(FilamentContext* ctx, int nstack, int nslice); UniquePtr<mjrMesh> CreateCone(mjrfContext* ctx, int nstack, int nslice);
} // namespace mujoco } // namespace mujoco
@@ -159,7 +159,7 @@ const mat4f& Renderable::GetTransform() const {
return transform_; return transform_;
} }
void Renderable::SetMeshes(std::span<const Mesh*> meshes, void Renderable::SetMeshes(std::span<const mjrMesh*> meshes,
GetTransformFn get_transform_fn) { GetTransformFn get_transform_fn) {
if (!parts_.empty()) { if (!parts_.empty()) {
mju_error("Cannot set meshes for renderable with multiple parts."); mju_error("Cannot set meshes for renderable with multiple parts.");
@@ -168,7 +168,7 @@ void Renderable::SetMeshes(std::span<const Mesh*> meshes,
get_transform_fn_ = get_transform_fn; get_transform_fn_ = get_transform_fn;
for (int i = 0; i < meshes.size(); ++i) { for (int i = 0; i < meshes.size(); ++i) {
Part& part = parts_.emplace_back(); Part& part = parts_.emplace_back();
part.mesh = meshes[i]; part.mesh = Mesh::downcast(meshes[i]);
part.elem_offset = 0; part.elem_offset = 0;
part.elem_count = part.mesh->GetFilamentIndexBuffer()->getIndexCount(); part.elem_count = part.mesh->GetFilamentIndexBuffer()->getIndexCount();
InitPartEntity(part); InitPartEntity(part);
@@ -70,7 +70,7 @@ class Renderable : public mjrRenderable {
// relative to the transform of the renderable itself. This allows users to // relative to the transform of the renderable itself. This allows users to
// construct compound (but rigid) objects from multiple meshes. // construct compound (but rigid) objects from multiple meshes.
using GetTransformFn = std::function<filament::math::mat4f(int, const Trs&)>; using GetTransformFn = std::function<filament::math::mat4f(int, const Trs&)>;
void SetMeshes(std::span<const Mesh*> meshes, void SetMeshes(std::span<const mjrMesh*> meshes,
GetTransformFn get_transform = nullptr); GetTransformFn get_transform = nullptr);
// Sets the layer mask for the managed filament Entities. Layer masks can be // Sets the layer mask for the managed filament Entities. Layer masks can be