Introduce a Texture class that wraps filament::Texture.

PiperOrigin-RevId: 892839636
Change-Id: I3c08fba0a514cfb758ec2842d8510c6d88300874
This commit is contained in:
Haroon Qureshi
2026-04-01 03:51:23 -07:00
committed by Copybara-Service
parent 6d32038417
commit 95666da039
12 changed files with 292 additions and 315 deletions
@@ -37,6 +37,7 @@
#include "experimental/filament/filament/math_util.h" #include "experimental/filament/filament/math_util.h"
#include "experimental/filament/filament/model_objects.h" #include "experimental/filament/filament/model_objects.h"
#include "experimental/filament/filament/object_manager.h" #include "experimental/filament/filament/object_manager.h"
#include "experimental/filament/filament/texture_util.h"
namespace mujoco { namespace mujoco {
@@ -226,7 +227,7 @@ void Drawable::SetDrawMode(Material::DrawMode mode) {
renderables_.SetMaterialInstance(material_.GetMaterialInstance(mode)); renderables_.SetMaterialInstance(material_.GetMaterialInstance(mode));
} }
void Drawable::UpdateReflectionTexture(const filament::Texture* tex) { void Drawable::UpdateReflectionTexture(const Texture* tex) {
material_.UpdateReflectionTexture(tex); material_.UpdateReflectionTexture(tex);
} }
@@ -422,7 +423,7 @@ void Drawable::UpdateMaterial(const mjvGeom& geom, bool use_segid_color,
} else { } else {
material_.SetNormalMaterialType(ObjectManager::kPhongColor); material_.SetNormalMaterialType(ObjectManager::kPhongColor);
} }
} else if (textures.color->getTarget() == } else if (textures.color->GetFilamentTexture()->getTarget() ==
filament::Texture::Sampler::SAMPLER_CUBEMAP) { filament::Texture::Sampler::SAMPLER_CUBEMAP) {
if (color.a < 1.0f) { if (color.a < 1.0f) {
material_.SetNormalMaterialType(ObjectManager::kPhongCubeFade); material_.SetNormalMaterialType(ObjectManager::kPhongCubeFade);
@@ -490,7 +491,8 @@ void Drawable::UpdateMaterial(const mjvGeom& geom, bool use_segid_color,
// the programmatic UVs. // the programmatic UVs.
if (textures.color) { if (textures.color) {
if (textures.color->getTarget() == filament::Texture::Sampler::SAMPLER_2D) { if (textures.color->GetFilamentTexture()->getTarget() ==
filament::Texture::Sampler::SAMPLER_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).
@@ -26,6 +26,7 @@
#include "experimental/filament/filament/model_objects.h" #include "experimental/filament/filament/model_objects.h"
#include "experimental/filament/filament/object_manager.h" #include "experimental/filament/filament/object_manager.h"
#include "experimental/filament/filament/renderables.h" #include "experimental/filament/filament/renderables.h"
#include "experimental/filament/filament/texture_util.h"
namespace mujoco { namespace mujoco {
@@ -68,7 +69,7 @@ class Drawable {
// Sets the reflection texture for the drawable. We have a separate setter // Sets the reflection texture for the drawable. We have a separate setter
// because we need to render the reflection texture before it can be applied // because we need to render the reflection texture before it can be applied
// to the material. // to the material.
void UpdateReflectionTexture(const filament::Texture* tex); void UpdateReflectionTexture(const Texture* tex);
private: private:
void AddMesh(int data_id); void AddMesh(int data_id);
+21 -64
View File
@@ -21,6 +21,7 @@
#include <filament/TextureSampler.h> #include <filament/TextureSampler.h>
#include <mujoco/mjmodel.h> #include <mujoco/mjmodel.h>
#include "experimental/filament/filament/object_manager.h" #include "experimental/filament/filament/object_manager.h"
#include "experimental/filament/filament/texture_util.h"
namespace mujoco { namespace mujoco {
@@ -71,7 +72,7 @@ void Material::UpdateTextures(const Textures& textures) {
UpdateMaterialInstances(); UpdateMaterialInstances();
} }
void Material::UpdateReflectionTexture(const filament::Texture* tex) { void Material::UpdateReflectionTexture(const Texture* tex) {
textures_.reflection = tex; textures_.reflection = tex;
UpdateMaterialInstances(); UpdateMaterialInstances();
} }
@@ -128,70 +129,26 @@ void Material::UpdateMaterialInstances() {
sampler.setMinFilter( sampler.setMinFilter(
filament::TextureSampler::MinFilter::LINEAR_MIPMAP_LINEAR); filament::TextureSampler::MinFilter::LINEAR_MIPMAP_LINEAR);
if (material->hasParameter("BaseColor")) { auto TrySetTexture = [&](const char* name, const Texture* texture,
if (textures_.color) { mjtTextureRole role) {
instance->setParameter("BaseColor", textures_.color, sampler); if (material->hasParameter(name)) {
} else { if (texture) {
auto* fallback = object_mgr_->GetFallbackTexture(mjTEXROLE_RGB); instance->setParameter(name, texture->GetFilamentTexture(), sampler);
instance->setParameter("BaseColor", fallback, sampler); } else {
auto* fallback = object_mgr_->GetFallbackTexture(role);
instance->setParameter(name, fallback->GetFilamentTexture(), sampler);
}
} }
} };
if (material->hasParameter("Normal")) {
if (textures_.normal) { TrySetTexture("BaseColor", textures_.color, mjTEXROLE_RGB);
instance->setParameter("Normal", textures_.normal, sampler); TrySetTexture("Normal", textures_.normal, mjTEXROLE_NORMAL);
} else { TrySetTexture("Metallic", textures_.metallic, mjTEXROLE_METALLIC);
auto* fallback = object_mgr_->GetFallbackTexture(mjTEXROLE_NORMAL); TrySetTexture("Roughness", textures_.roughness, mjTEXROLE_ROUGHNESS);
instance->setParameter("Normal", fallback, sampler); TrySetTexture("Occlusion", textures_.occlusion, mjTEXROLE_OCCLUSION);
} TrySetTexture("ORM", textures_.orm, mjTEXROLE_ORM);
} TrySetTexture("Emissive", textures_.emissive, mjTEXROLE_EMISSIVE);
if (material->hasParameter("Metallic")) { TrySetTexture("Reflection", textures_.reflection, mjTEXROLE_USER);
if (textures_.metallic) {
instance->setParameter("Metallic", textures_.metallic, sampler);
} else {
auto* fallback = object_mgr_->GetFallbackTexture(mjTEXROLE_METALLIC);
instance->setParameter("Metallic", fallback, sampler);
}
}
if (material->hasParameter("Roughness")) {
if (textures_.roughness) {
instance->setParameter("Roughness", textures_.roughness, sampler);
} else {
auto* fallback = object_mgr_->GetFallbackTexture(mjTEXROLE_ROUGHNESS);
instance->setParameter("Roughness", fallback, sampler);
}
}
if (material->hasParameter("Occlusion")) {
if (textures_.occlusion) {
instance->setParameter("Occlusion", textures_.occlusion, sampler);
} else {
auto* fallback = object_mgr_->GetFallbackTexture(mjTEXROLE_OCCLUSION);
instance->setParameter("Occlusion", fallback, sampler);
}
}
if (material->hasParameter("ORM")) {
if (textures_.orm) {
instance->setParameter("ORM", textures_.orm, sampler);
} else {
auto* fallback = object_mgr_->GetFallbackTexture(mjTEXROLE_ORM);
instance->setParameter("ORM", fallback, sampler);
}
}
if (material->hasParameter("Emissive")) {
if (textures_.emissive) {
instance->setParameter("Emissive", textures_.emissive, sampler);
} else {
auto* fallback = object_mgr_->GetFallbackTexture(mjTEXROLE_EMISSIVE);
instance->setParameter("Emissive", fallback, sampler);
}
}
if (material->hasParameter("Reflection")) {
if (textures_.reflection) {
instance->setParameter("Reflection", textures_.reflection, sampler);
} else {
auto* fallback = object_mgr_->GetFallbackTexture(mjTEXROLE_USER);
instance->setParameter("Reflection", fallback, sampler);
}
}
} }
} // namespace mujoco } // namespace mujoco
+10 -10
View File
@@ -17,11 +17,11 @@
#include <filament/Engine.h> #include <filament/Engine.h>
#include <filament/MaterialInstance.h> #include <filament/MaterialInstance.h>
#include <filament/Texture.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 "experimental/filament/filament/object_manager.h" #include "experimental/filament/filament/object_manager.h"
#include "experimental/filament/filament/texture_util.h"
namespace mujoco { namespace mujoco {
@@ -39,14 +39,14 @@ class Material {
// The textures that can be assigned to the drawable's material. // The textures that can be assigned to the drawable's material.
struct Textures { struct Textures {
const filament::Texture* color = nullptr; const Texture* color = nullptr;
const filament::Texture* normal = nullptr; const Texture* normal = nullptr;
const filament::Texture* metallic = nullptr; const Texture* metallic = nullptr;
const filament::Texture* roughness = nullptr; const Texture* roughness = nullptr;
const filament::Texture* occlusion = nullptr; const Texture* occlusion = nullptr;
const filament::Texture* orm = nullptr; const Texture* orm = nullptr;
const filament::Texture* emissive = nullptr; const Texture* emissive = nullptr;
const filament::Texture* reflection = nullptr; const Texture* reflection = nullptr;
}; };
// The parameters that can be applied to the drawable's material. // The parameters that can be applied to the drawable's material.
@@ -82,7 +82,7 @@ class Material {
// Update the reflection texture. We do this separately since the reflection // Update the reflection texture. We do this separately since the reflection
// texture needs to be rendered before it can be applied to the material. // texture needs to be rendered before it can be applied to the material.
void UpdateReflectionTexture(const filament::Texture* tex); void UpdateReflectionTexture(const Texture* tex);
// Returns the material instance assigned to the draw mode. // Returns the material instance assigned to the draw mode.
filament::MaterialInstance* GetMaterialInstance(DrawMode mode) { filament::MaterialInstance* GetMaterialInstance(DrawMode mode) {
@@ -15,6 +15,7 @@
#include "experimental/filament/filament/model_objects.h" #include "experimental/filament/filament/model_objects.h"
#include <array> #include <array>
#include <memory>
#include <utility> #include <utility>
#include <vector> #include <vector>
@@ -80,9 +81,7 @@ ModelObjects::~ModelObjects() {
engine_->destroy(iter.vertex_buffer); engine_->destroy(iter.vertex_buffer);
engine_->destroy(iter.index_buffer); engine_->destroy(iter.index_buffer);
} }
for (auto& iter : textures_) { textures_.clear();
engine_->destroy(iter.second);
}
} }
void ModelObjects::UploadMesh(const mjModel* model, int id) { void ModelObjects::UploadMesh(const mjModel* model, int id) {
@@ -126,25 +125,30 @@ void ModelObjects::UploadTexture(const mjModel* model, int id) {
mju_error("Invalid texture index: %d", id); mju_error("Invalid texture index: %d", id);
} }
if (auto iter = textures_.find(id); iter != textures_.end()) { const int width = model->tex_width[id];
engine_->destroy(iter->second); const int height = model->tex_height[id];
} const int num_channels = model->tex_nchannel[id];
const int tex_type = model->tex_type[id];
const mjtByte* data = model->tex_data + model->tex_adr[id];
const mjtColorSpace color_space = (mjtColorSpace)model->tex_colorspace[id];
const int texture_type = model->tex_type[id]; const TextureType type = [&] {
if (model->tex_height[id] == 1) { if (height == 1) {
const mjtByte* bytes = model->tex_data + model->tex_adr[id]; return TextureType::kKtx;
const int num_bytes = model->tex_width[id]; } else if (tex_type == mjTEXTURE_2D) {
textures_[id] = return TextureType::kNormal2d;
CreateKtxTexture(engine_, bytes, num_bytes, spherical_harmonics_[id]); } else if (tex_type == mjTEXTURE_CUBE) {
} else if (texture_type == mjTEXTURE_2D) { return TextureType::kCube;
textures_[id] = CreateTexture(engine_, model, id, TextureType::kNormal2d); } else if (tex_type == mjTEXTURE_SKYBOX) {
} else if (texture_type == mjTEXTURE_CUBE) { return TextureType::kCube;
textures_[id] = CreateTexture(engine_, model, id, TextureType::kCube); } else {
} else if (texture_type == mjTEXTURE_SKYBOX) { mju_error("Unsupported texture type: %d", tex_type);
textures_[id] = CreateTexture(engine_, model, id, TextureType::kCube); return TextureType::kNormal2d;
} else { }
mju_error("Unsupported: Texture type: %d", texture_type); }();
}
textures_[id] = std::make_unique<Texture>(engine_, type, color_space, width,
height, num_channels, data);
} }
void ModelObjects::UploadHeightField(const mjModel* model, int id) { void ModelObjects::UploadHeightField(const mjModel* model, int id) {
@@ -194,12 +198,12 @@ const FilamentBuffers* ModelObjects::GetShapeBuffer(ShapeType shape) const {
return &shapes_[shape]; return &shapes_[shape];
} }
const filament::Texture* ModelObjects::GetTexture(int tex_id) const { const Texture* ModelObjects::GetTexture(int tex_id) const {
auto it = textures_.find(tex_id); auto it = textures_.find(tex_id);
return it != textures_.end() ? it->second : nullptr; return it != textures_.end() ? it->second.get() : nullptr;
} }
const filament::Texture* ModelObjects::GetTexture(int mat_id, int role) const { const Texture* 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;
} }
@@ -210,15 +214,11 @@ const filament::Texture* ModelObjects::GetTexture(int mat_id, int role) const {
filament::IndirectLight* ModelObjects::CreateIndirectLight(int tex_id, filament::IndirectLight* ModelObjects::CreateIndirectLight(int tex_id,
float intensity) { float intensity) {
filament::Texture* texture = nullptr; filament::Texture* texture = nullptr;
const Texture::SphericalHarmonics* spherical_harmonics = nullptr;
auto texture_iter = textures_.find(tex_id); auto texture_iter = textures_.find(tex_id);
if (texture_iter != textures_.end()) { if (texture_iter != textures_.end()) {
texture = texture_iter->second; texture = texture_iter->second->GetFilamentTexture();
} spherical_harmonics = texture_iter->second->GetSphericalHarmonics();
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; filament::IndirectLight::Builder builder;
@@ -240,7 +240,7 @@ filament::Skybox* ModelObjects::CreateSkybox() {
for (auto& iter : textures_) { for (auto& iter : textures_) {
const int texture_type = model_->tex_type[iter.first]; const int texture_type = model_->tex_type[iter.first];
if (texture_type == mjTEXTURE_SKYBOX) { if (texture_type == mjTEXTURE_SKYBOX) {
skybox_texture = iter.second; skybox_texture = iter.second->GetFilamentTexture();
break; break;
} }
} }
@@ -16,6 +16,7 @@
#define MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_MODEL_OBJECTS_H_ #define MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_MODEL_OBJECTS_H_
#include <array> #include <array>
#include <memory>
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
@@ -25,6 +26,7 @@
#include <math/vec3.h> #include <math/vec3.h>
#include <mujoco/mjmodel.h> #include <mujoco/mjmodel.h>
#include "experimental/filament/filament/buffer_util.h" #include "experimental/filament/filament/buffer_util.h"
#include "experimental/filament/filament/texture_util.h"
namespace mujoco { namespace mujoco {
@@ -62,8 +64,8 @@ class ModelObjects {
const FilamentBuffers* GetShapeBuffer(ShapeType shape) const; const FilamentBuffers* GetShapeBuffer(ShapeType shape) const;
const FilamentBuffers* GetMeshBuffer(int data_id) const; const FilamentBuffers* GetMeshBuffer(int data_id) const;
const FilamentBuffers* GetHeightFieldBuffer(int hfield_id) const; const FilamentBuffers* GetHeightFieldBuffer(int hfield_id) const;
const filament::Texture* GetTexture(int tex_id) const; const Texture* GetTexture(int tex_id) const;
const filament::Texture* GetTexture(int mat_id, int role) const; const Texture* GetTexture(int mat_id, int role) const;
filament::Skybox* CreateSkybox(); filament::Skybox* CreateSkybox();
filament::IndirectLight* CreateIndirectLight(int tex_id, float intensity); filament::IndirectLight* CreateIndirectLight(int tex_id, float intensity);
@@ -78,8 +80,6 @@ class ModelObjects {
ModelObjects& operator=(const ModelObjects&) = delete; ModelObjects& operator=(const ModelObjects&) = delete;
private: private:
using SphericalHarmonics = filament::math::float3[9];
const mjModel* model_ = nullptr; const mjModel* model_ = nullptr;
filament::Engine* engine_ = nullptr; filament::Engine* engine_ = nullptr;
std::vector<filament::Skybox*> skyboxes_; std::vector<filament::Skybox*> skyboxes_;
@@ -88,8 +88,7 @@ class ModelObjects {
std::unordered_map<int, FilamentBuffers> meshes_; std::unordered_map<int, FilamentBuffers> meshes_;
std::unordered_map<int, FilamentBuffers> convex_hulls_; std::unordered_map<int, FilamentBuffers> convex_hulls_;
std::unordered_map<int, FilamentBuffers> height_fields_; std::unordered_map<int, FilamentBuffers> height_fields_;
std::unordered_map<int, filament::Texture*> textures_; std::unordered_map<int, std::unique_ptr<Texture>> textures_;
std::unordered_map<int, SphericalHarmonics> spherical_harmonics_;
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;
@@ -15,6 +15,7 @@
#include "experimental/filament/filament/object_manager.h" #include "experimental/filament/filament/object_manager.h"
#include <cstdint> #include <cstdint>
#include <memory>
#include <string> #include <string>
#include <string_view> #include <string_view>
@@ -86,22 +87,27 @@ ObjectManager::ObjectManager(filament::Engine* engine)
materials_[kUnlitUi] = LoadMaterial("unlit_ui.filamat"); materials_[kUnlitUi] = LoadMaterial("unlit_ui.filamat");
static uint8_t black_rgb[3] = {0, 0, 0}; static uint8_t black_rgb[3] = {0, 0, 0};
fallback_black_ = Create2dTexture(engine_, 1, 1, 3, black_rgb, false); fallback_black_ = std::make_unique<Texture>(
engine_, TextureType::kNormal2d, mjCOLORSPACE_LINEAR, 1, 1, 3, black_rgb);
static uint8_t white_rgb[3] = {255, 255, 255}; static uint8_t white_rgb[3] = {255, 255, 255};
fallback_white_ = Create2dTexture(engine_, 1, 1, 3, white_rgb, false); fallback_white_ = std::make_unique<Texture>(
engine_, TextureType::kNormal2d, mjCOLORSPACE_LINEAR, 1, 1, 3, white_rgb);
static uint8_t normal_data[3] = {128, 128, 255}; static uint8_t normal_data[3] = {128, 128, 255};
fallback_normal_ = Create2dTexture(engine_, 1, 1, 3, normal_data, false); fallback_normal_ =
std::make_unique<Texture>(engine_, TextureType::kNormal2d,
mjCOLORSPACE_LINEAR, 1, 1, 3, normal_data);
static uint8_t orm_data[3] = {0, 255, 0}; static uint8_t orm_data[3] = {0, 255, 0};
fallback_orm_ = Create2dTexture(engine_, 1, 1, 3, orm_data, false); fallback_orm_ = std::make_unique<Texture>(
engine_, TextureType::kNormal2d, mjCOLORSPACE_LINEAR, 1, 1, 3, orm_data);
fallback_textures_[mjTEXROLE_USER] = fallback_black_; fallback_textures_[mjTEXROLE_USER] = fallback_black_.get();
fallback_textures_[mjTEXROLE_RGB] = fallback_white_; fallback_textures_[mjTEXROLE_RGB] = fallback_white_.get();
fallback_textures_[mjTEXROLE_OCCLUSION] = fallback_white_; fallback_textures_[mjTEXROLE_OCCLUSION] = fallback_white_.get();
fallback_textures_[mjTEXROLE_ROUGHNESS] = fallback_white_; fallback_textures_[mjTEXROLE_ROUGHNESS] = fallback_white_.get();
fallback_textures_[mjTEXROLE_METALLIC] = fallback_black_; fallback_textures_[mjTEXROLE_METALLIC] = fallback_black_.get();
fallback_textures_[mjTEXROLE_NORMAL] = fallback_normal_; fallback_textures_[mjTEXROLE_NORMAL] = fallback_normal_.get();
fallback_textures_[mjTEXROLE_EMISSIVE] = fallback_black_; fallback_textures_[mjTEXROLE_EMISSIVE] = fallback_black_.get();
fallback_textures_[mjTEXROLE_ORM] = fallback_orm_; fallback_textures_[mjTEXROLE_ORM] = fallback_orm_.get();
LoadFallbackIndirectLight("ibl.ktx", 1.0f); LoadFallbackIndirectLight("ibl.ktx", 1.0f);
} }
@@ -110,17 +116,10 @@ ObjectManager::~ObjectManager() {
if (fallback_indirect_light_) { if (fallback_indirect_light_) {
engine_->destroy(fallback_indirect_light_); engine_->destroy(fallback_indirect_light_);
} }
if (fallback_indirect_light_texture_) { fallback_indirect_light_texture_.reset();
engine_->destroy(fallback_indirect_light_texture_);
}
for (auto& iter : materials_) { for (auto& iter : materials_) {
engine_->destroy(iter); engine_->destroy(iter);
} }
// fallback_textures_ maps to these textures.
engine_->destroy(fallback_white_);
engine_->destroy(fallback_black_);
engine_->destroy(fallback_normal_);
engine_->destroy(fallback_orm_);
} }
filament::Material* ObjectManager::GetMaterial(MaterialType type) const { filament::Material* ObjectManager::GetMaterial(MaterialType type) const {
@@ -130,7 +129,7 @@ filament::Material* ObjectManager::GetMaterial(MaterialType type) const {
return materials_[type]; return materials_[type];
} }
const filament::Texture* ObjectManager::GetFallbackTexture( const Texture* ObjectManager::GetFallbackTexture(
mjtTextureRole role) const { mjtTextureRole role) const {
if (role < 0 || role >= mjNTEXROLE) { if (role < 0 || role >= mjNTEXROLE) {
mju_error("Invalid texture role: %d", role); mju_error("Invalid texture role: %d", role);
@@ -144,10 +143,7 @@ filament::IndirectLight* ObjectManager::GetFallbackIndirectLight() {
void ObjectManager::LoadFallbackIndirectLight( void ObjectManager::LoadFallbackIndirectLight(
std::string_view filename, float intensity) { std::string_view filename, float intensity) {
if (fallback_indirect_light_texture_ != nullptr) { fallback_indirect_light_texture_.reset();
engine_->destroy(fallback_indirect_light_texture_);
fallback_indirect_light_texture_ = nullptr;
}
if (fallback_indirect_light_ != nullptr) { if (fallback_indirect_light_ != nullptr) {
engine_->destroy(fallback_indirect_light_); engine_->destroy(fallback_indirect_light_);
fallback_indirect_light_ = nullptr; fallback_indirect_light_ = nullptr;
@@ -158,18 +154,22 @@ void ObjectManager::LoadFallbackIndirectLight(
return; return;
} }
filament::math::float3 spherical_harmonics[9]; fallback_indirect_light_texture_ = std::make_unique<Texture>(
fallback_indirect_light_texture_ = engine_, TextureType::kKtx, mjCOLORSPACE_AUTO, asset.size, 1, 1,
CreateKtxTexture(engine_, reinterpret_cast<const uint8_t*>(asset.payload), reinterpret_cast<const uint8_t*>(asset.payload));
asset.size, spherical_harmonics);
if (fallback_indirect_light_texture_ == nullptr) { if (fallback_indirect_light_texture_ == nullptr) {
return; return;
} }
const Texture::SphericalHarmonics* spherical_harmonics =
fallback_indirect_light_texture_->GetSphericalHarmonics();
// Build the indirect light. // Build the indirect light.
filament::IndirectLight::Builder builder; filament::IndirectLight::Builder builder;
builder.reflections(fallback_indirect_light_texture_); builder.reflections(fallback_indirect_light_texture_->GetFilamentTexture());
builder.irradiance(3, spherical_harmonics); if (spherical_harmonics) {
builder.irradiance(3, *spherical_harmonics);
}
builder.intensity(intensity); builder.intensity(intensity);
// Rotate the light to match mujoco's Z-up convention. // Rotate the light to match mujoco's Z-up convention.
builder.rotation(filament::math::mat3f::rotation( builder.rotation(filament::math::mat3f::rotation(
@@ -16,12 +16,14 @@
#define MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_OBJECT_MANAGER_H_ #define MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_OBJECT_MANAGER_H_
#include <array> #include <array>
#include <memory>
#include <string_view> #include <string_view>
#include <filament/Engine.h> #include <filament/Engine.h>
#include <filament/IndirectLight.h> #include <filament/IndirectLight.h>
#include <filament/Skybox.h> #include <filament/Skybox.h>
#include <mujoco/mujoco.h> #include <mujoco/mujoco.h>
#include "experimental/filament/filament/texture_util.h"
namespace mujoco { namespace mujoco {
@@ -60,7 +62,7 @@ class ObjectManager {
filament::Material* GetMaterial(MaterialType type) const; filament::Material* GetMaterial(MaterialType type) const;
// Returns the fallback Texture with the given role. // Returns the fallback Texture with the given role.
const filament::Texture* GetFallbackTexture(mjtTextureRole role) const; const Texture* GetFallbackTexture(mjtTextureRole role) const;
// Returns the fallback IndirectLight. // Returns the fallback IndirectLight.
filament::IndirectLight* GetFallbackIndirectLight(); filament::IndirectLight* GetFallbackIndirectLight();
@@ -74,12 +76,12 @@ class ObjectManager {
private: private:
filament::Engine* engine_ = nullptr; filament::Engine* engine_ = nullptr;
std::array<filament::Material*, kNumMaterials> materials_; std::array<filament::Material*, kNumMaterials> materials_;
std::array<filament::Texture*, mjNTEXROLE> fallback_textures_; std::array<Texture*, mjNTEXROLE> fallback_textures_;
filament::Texture* fallback_white_ = nullptr; std::unique_ptr<Texture> fallback_white_ = nullptr;
filament::Texture* fallback_black_ = nullptr; std::unique_ptr<Texture> fallback_black_ = nullptr;
filament::Texture* fallback_normal_ = nullptr; std::unique_ptr<Texture> fallback_normal_ = nullptr;
filament::Texture* fallback_orm_ = nullptr; std::unique_ptr<Texture> fallback_orm_ = nullptr;
filament::Texture* fallback_indirect_light_texture_ = nullptr; std::unique_ptr<Texture> fallback_indirect_light_texture_ = nullptr;
filament::IndirectLight* fallback_indirect_light_ = nullptr; filament::IndirectLight* fallback_indirect_light_ = nullptr;
}; };
@@ -14,15 +14,15 @@
#include "experimental/filament/filament/render_target_util.h" #include "experimental/filament/filament/render_target_util.h"
#include <memory>
#include <filament/Engine.h> #include <filament/Engine.h>
#include <filament/RenderTarget.h> #include <filament/RenderTarget.h>
#include <filament/Texture.h> #include <filament/Texture.h>
#include <mujoco/mujoco.h> #include "experimental/filament/filament/texture_util.h"
namespace mujoco { namespace mujoco {
RenderTargetAndTextures::RenderTargetAndTextures(filament::Engine* engine, RenderTargetAndTextures::RenderTargetAndTextures(filament::Engine* engine,
RenderTargetTextureType color, RenderTargetTextureType color,
RenderTargetTextureType depth) RenderTargetTextureType depth)
@@ -41,15 +41,15 @@ void RenderTargetAndTextures::Prepare(int width, int height) {
height_ = height; height_ = height;
color_texture_ = color_texture_ =
CreateRenderTargetTexture(engine_, width, height, color_type_); std::make_unique<Texture>(engine_, color_type_, width, height);
depth_texture_ = depth_texture_ =
CreateRenderTargetTexture(engine_, width, height, depth_type_); std::make_unique<Texture>(engine_, depth_type_, width, height);
filament::RenderTarget::Builder builder; filament::RenderTarget::Builder builder;
builder.texture(filament::RenderTarget::AttachmentPoint::COLOR, builder.texture(filament::RenderTarget::AttachmentPoint::COLOR,
color_texture_); color_texture_->GetFilamentTexture());
builder.texture(filament::RenderTarget::AttachmentPoint::DEPTH, builder.texture(filament::RenderTarget::AttachmentPoint::DEPTH,
depth_texture_); depth_texture_->GetFilamentTexture());
render_target_ = builder.build(*engine_); render_target_ = builder.build(*engine_);
} }
@@ -58,14 +58,20 @@ void RenderTargetAndTextures::Destroy() {
engine_->destroy(render_target_); engine_->destroy(render_target_);
render_target_ = nullptr; render_target_ = nullptr;
} }
if (color_texture_) { color_texture_.reset();
engine_->destroy(color_texture_); depth_texture_.reset();
color_texture_ = nullptr; }
}
if (depth_texture_) { Texture* RenderTargetAndTextures::GetColorTexture() const {
engine_->destroy(depth_texture_); return color_texture_.get();
depth_texture_ = nullptr; }
}
Texture* RenderTargetAndTextures::GetDepthTexture() const {
return depth_texture_.get();
}
filament::RenderTarget* RenderTargetAndTextures::GetRenderTarget() const {
return render_target_;
} }
} // namespace mujoco } // namespace mujoco
@@ -15,6 +15,8 @@
#ifndef MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_RENDER_TARGET_UTIL_H_ #ifndef MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_RENDER_TARGET_UTIL_H_
#define MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_RENDER_TARGET_UTIL_H_ #define MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_RENDER_TARGET_UTIL_H_
#include <memory>
#include <filament/Engine.h> #include <filament/Engine.h>
#include <filament/Texture.h> #include <filament/Texture.h>
#include "experimental/filament/filament/texture_util.h" #include "experimental/filament/filament/texture_util.h"
@@ -39,21 +41,21 @@ class RenderTargetAndTextures {
void Prepare(int width, int height); void Prepare(int width, int height);
// Returns the color texture. // Returns the color texture.
filament::Texture* GetColorTexture() const { return color_texture_; } Texture* GetColorTexture() const;
// Returns the depth texture. // Returns the depth texture.
filament::Texture* GetDepthTexture() const { return depth_texture_; } Texture* GetDepthTexture() const;
// Returns the render target. // Returns the render target.
filament::RenderTarget* GetRenderTarget() const { return render_target_; } filament::RenderTarget* GetRenderTarget() const;
private: private:
void Destroy(); void Destroy();
filament::Engine* engine_ = nullptr; filament::Engine* engine_ = nullptr;
filament::Texture* color_texture_ = nullptr;
filament::Texture* depth_texture_ = nullptr;
filament::RenderTarget* render_target_ = nullptr; filament::RenderTarget* render_target_ = nullptr;
std::unique_ptr<Texture> color_texture_ = nullptr;
std::unique_ptr<Texture> depth_texture_ = nullptr;
RenderTargetTextureType color_type_; RenderTargetTextureType color_type_;
RenderTargetTextureType depth_type_; RenderTargetTextureType depth_type_;
int width_ = 0; int width_ = 0;
+117 -122
View File
@@ -23,7 +23,6 @@
#include <filament/Texture.h> #include <filament/Texture.h>
#include <image/Ktx1Bundle.h> #include <image/Ktx1Bundle.h>
#include <ktxreader/Ktx1Reader.h> #include <ktxreader/Ktx1Reader.h>
#include <math/vec3.h>
#include <mujoco/mujoco.h> #include <mujoco/mujoco.h>
namespace mujoco { namespace mujoco {
@@ -69,107 +68,24 @@ static filament::Texture::InternalFormat GetTextureInternalFormat(
} }
} }
filament::Texture* Create2dTexture(filament::Engine* engine, int width, Texture::Texture(filament::Engine* engine, TextureType texture_type,
int height, int num_channels, mjtColorSpace color_space, int width, int height,
const uint8_t* data, bool is_srgb) { int num_channels, const uint8_t* data)
if (num_channels != 1 && num_channels != 3 && num_channels != 4) { : engine_(engine) {
mju_error("Unsupported number of channels: %d", num_channels); const bool is_srgb = color_space == mjCOLORSPACE_SRGB;
return nullptr; if (texture_type == TextureType::kCube) {
} CreateCubeTexture(width, height, num_channels, data, is_srgb);
} else if (texture_type == TextureType::kNormal2d) {
filament::Texture::Builder builder; Create2dTexture(width, height, num_channels, data, is_srgb);
builder.width(width); } else if (texture_type == TextureType::kKtx) {
builder.height(height); CreateKtxTexture(data, width * height * num_channels);
builder.format(GetTextureInternalFormat(num_channels, is_srgb));
builder.sampler(filament::Texture::Sampler::SAMPLER_2D);
if (!is_srgb) {
builder.usage(filament::Texture::Usage::GEN_MIPMAPPABLE |
filament::Texture::Usage::SAMPLEABLE |
filament::Texture::Usage::UPLOADABLE);
}
filament::Texture* texture = builder.build(*engine);
if (data) {
const size_t num_bytes = width * height * sizeof(uint8_t) * num_channels;
const filament::Texture::Format format = GetTextureFormat(num_channels);
texture->setImage(
*engine, 0,
filament::Texture::PixelBufferDescriptor(
data, num_bytes, format, filament::Texture::Type::UBYTE));
if (!is_srgb) {
texture->generateMipmaps(*engine);
}
}
return texture;
}
filament::Texture* CreateCubeTexture(filament::Engine* engine, int width,
int height, int num_channels,
const uint8_t* data, bool is_srgb) {
if (num_channels != 3) {
mju_error("Only support RGB cubemaps.");
return nullptr;
}
const int kNumFacesPerCube = 6;
int face_height = height;
if (width != height) {
if (width * kNumFacesPerCube != height) {
mju_error("Cube maps must contain 6 square images.");
}
face_height = height / kNumFacesPerCube;
}
if (width != face_height) {
mju_error("Cube map faces must be square.");
}
filament::Texture::Builder builder;
builder.width(width);
builder.height(face_height);
builder.format(GetTextureInternalFormat(num_channels, is_srgb));
builder.sampler(filament::Texture::Sampler::SAMPLER_CUBEMAP);
if (!is_srgb) {
builder.usage(filament::Texture::Usage::GEN_MIPMAPPABLE |
filament::Texture::Usage::SAMPLEABLE |
filament::Texture::Usage::UPLOADABLE);
}
filament::Texture* texture = builder.build(*engine);
const int face_size = width * face_height * num_channels;
const int num_bytes = face_size * kNumFacesPerCube;
uint8_t* buffer = new uint8_t[num_bytes];
auto callback = +[](void* buffer, size_t size, void* user) {
delete [] reinterpret_cast<uint8_t*>(buffer);
};
filament::Texture::FaceOffsets offsets(face_size);
if (width == height) {
// Copy the image to all the faces.
for (int i = 0; i < kNumFacesPerCube; ++i) {
std::memcpy(buffer + (i * face_size), data, face_size);
}
} else { } else {
// Use the cubemap as is. mju_error("Unsupported texture type: %d", static_cast<int>(texture_type));
std::memcpy(buffer, data, num_bytes);
} }
if (data) {
filament::Texture::PixelBufferDescriptor desc(
buffer, num_bytes, filament::Texture::Format::RGB,
filament::Texture::Type::UBYTE, callback);
texture->setImage(*engine, 0, std::move(desc), offsets);
if (!is_srgb) {
texture->generateMipmaps(*engine);
}
}
return texture;
} }
filament::Texture* CreateRenderTargetTexture( Texture::Texture(filament::Engine* engine, RenderTargetTextureType type,
filament::Engine* engine, int width, int height, int width, int height) : engine_(engine) {
RenderTargetTextureType type) {
filament::Texture::Builder builder; filament::Texture::Builder builder;
builder.width(width); builder.width(width);
builder.height(height); builder.height(height);
@@ -198,36 +114,115 @@ filament::Texture* CreateRenderTargetTexture(
default: default:
mju_error("Unknown type: %d", static_cast<int>(type)); mju_error("Unknown type: %d", static_cast<int>(type));
} }
return builder.build(*engine); texture_ = builder.build(*engine);
} }
filament::Texture* CreateKtxTexture( void Texture::Create2dTexture(int width, int height, int num_channels,
filament::Engine* engine, const uint8_t* data, int size, const uint8_t* data, bool is_srgb) {
filament::math::float3* spherical_harmonics_out) { if (num_channels != 1 && num_channels != 3 && num_channels != 4) {
mju_error("Unsupported number of channels: %d", num_channels);
return;
}
filament::Texture::Builder builder;
builder.width(width);
builder.height(height);
builder.format(GetTextureInternalFormat(num_channels, is_srgb));
builder.sampler(filament::Texture::Sampler::SAMPLER_2D);
if (!is_srgb) {
builder.usage(filament::Texture::Usage::GEN_MIPMAPPABLE |
filament::Texture::Usage::SAMPLEABLE |
filament::Texture::Usage::UPLOADABLE);
}
texture_ = builder.build(*engine_);
if (data) {
const size_t num_bytes = width * height * sizeof(uint8_t) * num_channels;
const filament::Texture::Format format = GetTextureFormat(num_channels);
texture_->setImage(
*engine_, 0,
filament::Texture::PixelBufferDescriptor(
data, num_bytes, format, filament::Texture::Type::UBYTE));
if (!is_srgb) {
texture_->generateMipmaps(*engine_);
}
}
}
void Texture::CreateCubeTexture(int width, int height, int num_channels,
const uint8_t* data, bool is_srgb) {
if (num_channels != 3) {
mju_error("Only support RGB cubemaps.");
return;
}
const int kNumFacesPerCube = 6;
int face_height = height;
if (width != height) {
if (width * kNumFacesPerCube != height) {
mju_error("Cube maps must contain 6 square images.");
}
face_height = height / kNumFacesPerCube;
}
if (width != face_height) {
mju_error("Cube map faces must be square.");
}
filament::Texture::Builder builder;
builder.width(width);
builder.height(face_height);
builder.format(GetTextureInternalFormat(num_channels, is_srgb));
builder.sampler(filament::Texture::Sampler::SAMPLER_CUBEMAP);
if (!is_srgb) {
builder.usage(filament::Texture::Usage::GEN_MIPMAPPABLE |
filament::Texture::Usage::SAMPLEABLE |
filament::Texture::Usage::UPLOADABLE);
}
texture_ = builder.build(*engine_);
const int face_size = width * face_height * num_channels;
const int num_bytes = face_size * kNumFacesPerCube;
uint8_t* buffer = new uint8_t[num_bytes];
auto callback = +[](void* buffer, size_t size, void* user) {
delete [] reinterpret_cast<uint8_t*>(buffer);
};
filament::Texture::FaceOffsets offsets(face_size);
if (width == height) {
// Copy the image to all the faces.
for (int i = 0; i < kNumFacesPerCube; ++i) {
std::memcpy(buffer + (i * face_size), data, face_size);
}
} else {
// Use the cubemap as is.
std::memcpy(buffer, data, num_bytes);
}
if (data) {
filament::Texture::PixelBufferDescriptor desc(
buffer, num_bytes, filament::Texture::Format::RGB,
filament::Texture::Type::UBYTE, callback);
texture_->setImage(*engine_, 0, std::move(desc), offsets);
if (!is_srgb) {
texture_->generateMipmaps(*engine_);
}
}
}
void Texture::CreateKtxTexture(const uint8_t* data, int size) {
image::Ktx1Bundle* bundle = new image::Ktx1Bundle(data, size); image::Ktx1Bundle* bundle = new image::Ktx1Bundle(data, size);
if (spherical_harmonics_out) { has_spherical_harmonics_ = true;
bundle->getSphericalHarmonics(spherical_harmonics_out); bundle->getSphericalHarmonics(spherical_harmonics_);
}
const bool is_srgb = false; const bool is_srgb = false;
return ktxreader::Ktx1Reader::createTexture(engine, bundle, is_srgb); texture_ = ktxreader::Ktx1Reader::createTexture(engine_, bundle, is_srgb);
} }
filament::Texture* CreateTexture(filament::Engine* engine, const mjModel* model, Texture::~Texture() {
int id, TextureType texture_type) { if (texture_) {
if (id < 0 || id >= model->ntex) { engine_->destroy(texture_);
mju_error("Invalid texture index %d", id);
} }
const int width = model->tex_width[id];
const int height = model->tex_height[id];
const bool is_srgb = model->tex_colorspace[id] == mjCOLORSPACE_SRGB;
const int num_channels = model->tex_nchannel[id];
const mjtByte* data = model->tex_data + model->tex_adr[id];
filament::Texture* texture =
texture_type == TextureType::kNormal2d
? Create2dTexture(engine, width, height, num_channels, data, is_srgb)
: CreateCubeTexture(engine, width, height, num_channels, data,
is_srgb);
return texture;
} }
} // namespace mujoco } // namespace mujoco
@@ -40,30 +40,43 @@ enum class RenderTargetTextureType {
kReflectionColor, kReflectionColor,
}; };
// Creates a filament Texture for the given 2D texture. class Texture {
filament::Texture* Create2dTexture(filament::Engine* engine, int width, public:
int height, int num_channels, // Creates a texture with the given data.
const uint8_t* data, bool is_srgb); Texture(filament::Engine* engine, TextureType texture_type,
mjtColorSpace color_space, int width, int height, int num_channels,
const uint8_t* data);
// Creates a filament Texture for the given cube texture. // Creates a texture for use with a render target.
filament::Texture* CreateCubeTexture(filament::Engine* engine, int width, Texture(filament::Engine* engine, RenderTargetTextureType type, int width,
int height, int num_channels, int height);
const uint8_t* data, bool is_srgb);
// Creates a filament Texture for the given KTX payload. ~Texture();
filament::Texture* CreateKtxTexture(
filament::Engine* engine, const uint8_t* data, int size,
filament::math::float3* spherical_harmonics_out);
// Creates a filament Texture for the given texture in the mjModel. filament::Texture* GetFilamentTexture() const { return texture_; }
filament::Texture* CreateTexture(filament::Engine* engine, const mjModel* model,
int id, TextureType texture_type);
// Creates a filament Texture for the given render target. using SphericalHarmonics = filament::math::float3[9];
filament::Texture* CreateRenderTargetTexture(filament::Engine* engine,
int width, int height,
RenderTargetTextureType type);
const SphericalHarmonics* GetSphericalHarmonics() const {
return has_spherical_harmonics_ ? &spherical_harmonics_ : nullptr;
}
Texture(const Texture&) = delete;
Texture& operator=(const Texture&) = delete;
private:
void Create2dTexture(int width, int height, int num_channels,
const uint8_t* data, bool is_srgb);
void CreateCubeTexture(int width, int height, int num_channels,
const uint8_t* data, bool is_srgb);
void CreateKtxTexture(const uint8_t* data, int size);
filament::Engine* engine_ = nullptr;
filament::Texture* texture_ = nullptr;
SphericalHarmonics spherical_harmonics_;
bool has_spherical_harmonics_ = false;
};
} // namespace mujoco } // namespace mujoco
#endif // MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_TEXTURE_UTIL_H_ #endif // MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_TEXTURE_UTIL_H_