diff --git a/src/experimental/filament/CMakeLists.txt b/src/experimental/filament/CMakeLists.txt index 4d792c67..8d720365 100644 --- a/src/experimental/filament/CMakeLists.txt +++ b/src/experimental/filament/CMakeLists.txt @@ -48,6 +48,8 @@ target_sources(${MUJOCO_FILAMENT_TARGET_NAME} filament/model_util.h filament/object_manager.cc filament/object_manager.h + filament/render_target_util.cc + filament/render_target_util.h filament/renderables.cc filament/renderables.h filament/scene_view.cc diff --git a/src/experimental/filament/filament/filament_context.cc b/src/experimental/filament/filament/filament_context.cc index 014fb13a..1df934e5 100644 --- a/src/experimental/filament/filament/filament_context.cc +++ b/src/experimental/filament/filament/filament_context.cc @@ -43,7 +43,7 @@ #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/texture_util.h" +#include "experimental/filament/filament/render_target_util.h" #include "experimental/filament/render_context_filament.h" namespace mujoco { @@ -219,43 +219,18 @@ void FilamentContext::SetFrameBuffer(int framebuffer) { } void FilamentContext::PrepareRenderTargets(int width, int height) { - for (int i = 0; i < kNumRenderTargetTextureTypes; ++i) { - target_textures_[i] = CreateRenderTargetTexture( - engine_, width, height, static_cast(i)); - } + color_target_ = std::make_unique( + engine_, kRenderTargetColor, kRenderTargetDepth); + color_target_->Prepare(width, height); - // Render target for color pass. - filament::RenderTarget::Builder color_target_builder; - color_target_builder.texture(filament::RenderTarget::AttachmentPoint::COLOR0, - target_textures_[kRenderTargetColor]); - color_target_builder.texture(filament::RenderTarget::AttachmentPoint::DEPTH, - target_textures_[kRenderTargetDepth]); - color_target_ = color_target_builder.build(*engine_); - - // Render target for depth pass. - filament::RenderTarget::Builder depth_target_builder; - depth_target_builder.texture(filament::RenderTarget::AttachmentPoint::COLOR0, - target_textures_[kRenderTargetDepthColor]); - depth_target_builder.texture(filament::RenderTarget::AttachmentPoint::DEPTH, - target_textures_[kRenderTargetDepth]); - depth_target_ = depth_target_builder.build(*engine_); + depth_target_ = std::make_unique( + engine_, kRenderTargetDepthColor, kRenderTargetDepth); + depth_target_->Prepare(width, height); } void FilamentContext::DestroyRenderTargets() { - if (depth_target_) { - engine_->destroy(depth_target_); - depth_target_ = nullptr; - } - if (color_target_) { - engine_->destroy(color_target_); - color_target_ = nullptr; - } - for (int i = 0; i < kNumRenderTargetTextureTypes; ++i) { - if (target_textures_[i]) { - engine_->destroy(target_textures_[i]); - target_textures_[i] = nullptr; - } - } + depth_target_.reset(); + color_target_.reset(); } static void ReadColorPixels(filament::Renderer* renderer, @@ -295,15 +270,17 @@ void FilamentContext::ReadPixels(mjrRect viewport, unsigned char* rgb, if (rgb) { if (renderer_->beginFrame(offscreen_swap_chain_)) { - scene_view_->Render(renderer_, last_render_mode_, color_target_); + scene_view_->Render(renderer_, last_render_mode_, + color_target_->GetRenderTarget()); // Render the GUI to the texture as well if requested. if (gui_view_ && gui_swap_chain_target_ == kOffscreenSwapChain) { - gui_view_->Render(renderer_, color_target_); + gui_view_->Render(renderer_, color_target_->GetRenderTarget()); } const size_t num_bytes = viewport.width * viewport.height * 3; - ReadColorPixels(renderer_, color_target_, viewport, rgb, num_bytes); + ReadColorPixels(renderer_, color_target_->GetRenderTarget(), viewport, + rgb, num_bytes); renderer_->endFrame(); } @@ -312,10 +289,11 @@ void FilamentContext::ReadPixels(mjrRect viewport, unsigned char* rgb, if (depth) { if (renderer_->beginFrame(offscreen_swap_chain_)) { scene_view_->Render(renderer_, SceneView::DrawMode::kDepth, - depth_target_); + depth_target_->GetRenderTarget()); const size_t num_bytes = viewport.width * viewport.height * sizeof(float); - ReadDepthPixels(renderer_, depth_target_, viewport, depth, num_bytes); + ReadDepthPixels(renderer_, depth_target_->GetRenderTarget(), viewport, + depth, num_bytes); renderer_->endFrame(); } diff --git a/src/experimental/filament/filament/filament_context.h b/src/experimental/filament/filament/filament_context.h index d0e7a75e..230be2ab 100644 --- a/src/experimental/filament/filament/filament_context.h +++ b/src/experimental/filament/filament/filament_context.h @@ -26,7 +26,7 @@ #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/texture_util.h" +#include "experimental/filament/filament/render_target_util.h" #include "experimental/filament/render_context_filament.h" namespace mujoco { @@ -77,15 +77,11 @@ class FilamentContext { filament::SwapChain* window_swap_chain_ = nullptr; filament::SwapChain* offscreen_swap_chain_ = nullptr; filament::Renderer* renderer_ = nullptr; - filament::RenderTarget* color_target_ = nullptr; - filament::RenderTarget* depth_target_ = nullptr; - filament::Texture* target_textures_[kNumRenderTargetTextureTypes] = { - nullptr, nullptr, nullptr}; - SceneView::DrawMode last_render_mode_ = SceneView::DrawMode::kNormal; SwapChainType scene_swap_chain_target_ = kWindowSwapChain; SwapChainType gui_swap_chain_target_ = kWindowSwapChain; - + std::unique_ptr color_target_; + std::unique_ptr depth_target_; std::unique_ptr object_manager_; std::unique_ptr scene_view_; std::unique_ptr gui_view_; diff --git a/src/experimental/filament/filament/render_target_util.cc b/src/experimental/filament/filament/render_target_util.cc new file mode 100644 index 00000000..52cbc25c --- /dev/null +++ b/src/experimental/filament/filament/render_target_util.cc @@ -0,0 +1,103 @@ +// 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/render_target_util.h" + +#include +#include +#include +#include + +namespace mujoco { + +static filament::Texture* CreateRenderTargetTexture( + filament::Engine* engine, int width, int height, + RenderTargetTextureType type) { + filament::Texture::Builder builder; + builder.width(width); + builder.height(height); + switch (type) { + case kRenderTargetColor: + builder.usage(filament::Texture::Usage::COLOR_ATTACHMENT | + filament::Texture::Usage::BLIT_SRC); + builder.format(filament::Texture::InternalFormat::RGB8); + break; + case kRenderTargetDepth: + builder.usage(filament::Texture::Usage::DEPTH_ATTACHMENT | + filament::Texture::Usage::SAMPLEABLE); + builder.format(filament::Texture::InternalFormat::DEPTH32F); + break; + case kRenderTargetDepthColor: + builder.usage(filament::Texture::Usage::COLOR_ATTACHMENT | + filament::Texture::Usage::BLIT_SRC); + builder.format(filament::Texture::InternalFormat::R32F); + break; + case kRenderTargetReflectionColor: + builder.usage(filament::Texture::Usage::COLOR_ATTACHMENT | + filament::Texture::Usage::BLIT_SRC | + filament::Texture::Usage::SAMPLEABLE); + builder.format(filament::Texture::InternalFormat::RGBA8); + break; + default: + mju_error("Unknown type: %d", static_cast(type)); + } + return builder.build(*engine); +} + +RenderTargetAndTextures::RenderTargetAndTextures(filament::Engine* engine, + RenderTargetTextureType color, + RenderTargetTextureType depth) + : engine_(engine), color_type_(color), depth_type_(depth) {} + +RenderTargetAndTextures::~RenderTargetAndTextures() noexcept { + Destroy(); +} + +void RenderTargetAndTextures::Prepare(int width, int height) { + if (width == width_ && height == height_) { + return; + } + Destroy(); + width_ = width; + height_ = height; + + color_texture_ = + CreateRenderTargetTexture(engine_, width, height, color_type_); + depth_texture_ = + CreateRenderTargetTexture(engine_, width, height, depth_type_); + + filament::RenderTarget::Builder builder; + builder.texture(filament::RenderTarget::AttachmentPoint::COLOR, + color_texture_); + builder.texture(filament::RenderTarget::AttachmentPoint::DEPTH, + depth_texture_); + render_target_ = builder.build(*engine_); +} + +void RenderTargetAndTextures::Destroy() { + if (render_target_) { + engine_->destroy(render_target_); + render_target_ = nullptr; + } + if (color_texture_) { + engine_->destroy(color_texture_); + color_texture_ = nullptr; + } + if (depth_texture_) { + engine_->destroy(depth_texture_); + depth_texture_ = nullptr; + } +} + +} // namespace mujoco diff --git a/src/experimental/filament/filament/render_target_util.h b/src/experimental/filament/filament/render_target_util.h new file mode 100644 index 00000000..e8dfb939 --- /dev/null +++ b/src/experimental/filament/filament/render_target_util.h @@ -0,0 +1,74 @@ +// 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_RENDER_TARGET_UTIL_H_ +#define MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_RENDER_TARGET_UTIL_H_ + +#include +#include + +namespace mujoco { + +// The different types of textures we can create for a render target. +enum RenderTargetTextureType { + kRenderTargetNone, + kRenderTargetColor, + kRenderTargetDepth, + kRenderTargetDepthColor, + kRenderTargetReflectionColor, + kNumRenderTargetTextureTypes, +}; + +// Manages a filament RenderTarget and the textures which are bound to it. +class RenderTargetAndTextures { + public: + // Defines the types of textures to create for the color and depth + // attachments. + RenderTargetAndTextures(filament::Engine* engine, + RenderTargetTextureType color, + RenderTargetTextureType depth); + ~RenderTargetAndTextures() noexcept; + + RenderTargetAndTextures(const RenderTargetAndTextures&) = delete; + RenderTargetAndTextures& operator=(const RenderTargetAndTextures&) = delete; + + // Creates the textures and render target if the width of height differ from + // the last time the render target was prepared. + void Prepare(int width, int height); + + // Returns the color texture. + filament::Texture* GetColorTexture() const { return color_texture_; } + + // Returns the depth texture. + filament::Texture* GetDepthTexture() const { return depth_texture_; } + + // Returns the render target. + filament::RenderTarget* GetRenderTarget() const { return render_target_; } + + private: + void Destroy(); + + filament::Engine* engine_ = nullptr; + filament::Texture* color_texture_ = nullptr; + filament::Texture* depth_texture_ = nullptr; + filament::RenderTarget* render_target_ = nullptr; + RenderTargetTextureType color_type_ = kRenderTargetNone; + RenderTargetTextureType depth_type_ = kRenderTargetNone; + int width_ = 0; + int height_ = 0; +}; + +} // namespace mujoco + +#endif // MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_RENDER_TARGET_UTIL_H_ diff --git a/src/experimental/filament/filament/texture_util.cc b/src/experimental/filament/filament/texture_util.cc index 58f12113..1cf5567c 100644 --- a/src/experimental/filament/filament/texture_util.cc +++ b/src/experimental/filament/filament/texture_util.cc @@ -178,33 +178,4 @@ filament::Texture* CreateKtxTexture( const bool is_srgb = false; return ktxreader::Ktx1Reader::createTexture(engine, bundle, is_srgb); } - -filament::Texture* CreateRenderTargetTexture(filament::Engine* engine, - int width, int height, - RenderTargetTextureType type) { - filament::Texture::Builder builder; - builder.width(width); - builder.height(height); - switch (type) { - case kRenderTargetColor: - builder.usage(filament::Texture::Usage::COLOR_ATTACHMENT | - filament::Texture::Usage::BLIT_SRC); - builder.format(filament::Texture::InternalFormat::RGB8); - break; - case kRenderTargetDepth: - builder.usage(filament::Texture::Usage::DEPTH_ATTACHMENT | - filament::Texture::Usage::SAMPLEABLE); - builder.format(filament::Texture::InternalFormat::DEPTH32F); - break; - case kRenderTargetDepthColor: - builder.usage(filament::Texture::Usage::COLOR_ATTACHMENT | - filament::Texture::Usage::BLIT_SRC); - builder.format(filament::Texture::InternalFormat::R32F); - break; - default: - mju_error("Unknown type: %d", static_cast(type)); - } - return builder.build(*engine); -} - } // namespace mujoco diff --git a/src/experimental/filament/filament/texture_util.h b/src/experimental/filament/filament/texture_util.h index 447954ba..3136b81c 100644 --- a/src/experimental/filament/filament/texture_util.h +++ b/src/experimental/filament/filament/texture_util.h @@ -39,18 +39,6 @@ filament::Texture* CreateKtxTexture( filament::Engine* engine, const uint8_t* data, int size, filament::math::float3* spherical_harmonics_out); -enum RenderTargetTextureType { - kRenderTargetColor, - kRenderTargetDepth, - kRenderTargetDepthColor, - kNumRenderTargetTextureTypes, -}; - -// Creates a filament RenderTargetTexture for the given target type. -filament::Texture* CreateRenderTargetTexture(filament::Engine* engine, - int width, int height, - RenderTargetTextureType type); - } // namespace mujoco #endif // MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_TEXTURE_UTIL_H_