Introduce a Texture class that wraps filament::Texture.
PiperOrigin-RevId: 892839636 Change-Id: I3c08fba0a514cfb758ec2842d8510c6d88300874
This commit is contained in:
committed by
Copybara-Service
parent
6d32038417
commit
95666da039
@@ -37,6 +37,7 @@
|
||||
#include "experimental/filament/filament/math_util.h"
|
||||
#include "experimental/filament/filament/model_objects.h"
|
||||
#include "experimental/filament/filament/object_manager.h"
|
||||
#include "experimental/filament/filament/texture_util.h"
|
||||
|
||||
namespace mujoco {
|
||||
|
||||
@@ -226,7 +227,7 @@ void Drawable::SetDrawMode(Material::DrawMode mode) {
|
||||
renderables_.SetMaterialInstance(material_.GetMaterialInstance(mode));
|
||||
}
|
||||
|
||||
void Drawable::UpdateReflectionTexture(const filament::Texture* tex) {
|
||||
void Drawable::UpdateReflectionTexture(const Texture* tex) {
|
||||
material_.UpdateReflectionTexture(tex);
|
||||
}
|
||||
|
||||
@@ -422,7 +423,7 @@ void Drawable::UpdateMaterial(const mjvGeom& geom, bool use_segid_color,
|
||||
} else {
|
||||
material_.SetNormalMaterialType(ObjectManager::kPhongColor);
|
||||
}
|
||||
} else if (textures.color->getTarget() ==
|
||||
} else if (textures.color->GetFilamentTexture()->getTarget() ==
|
||||
filament::Texture::Sampler::SAMPLER_CUBEMAP) {
|
||||
if (color.a < 1.0f) {
|
||||
material_.SetNormalMaterialType(ObjectManager::kPhongCubeFade);
|
||||
@@ -490,7 +491,8 @@ void Drawable::UpdateMaterial(const mjvGeom& geom, bool use_segid_color,
|
||||
// the programmatic UVs.
|
||||
|
||||
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
|
||||
// image is repeated. The `tex_uniform` flag determines if the repetition
|
||||
// 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/object_manager.h"
|
||||
#include "experimental/filament/filament/renderables.h"
|
||||
#include "experimental/filament/filament/texture_util.h"
|
||||
|
||||
namespace mujoco {
|
||||
|
||||
@@ -68,7 +69,7 @@ class Drawable {
|
||||
// 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
|
||||
// to the material.
|
||||
void UpdateReflectionTexture(const filament::Texture* tex);
|
||||
void UpdateReflectionTexture(const Texture* tex);
|
||||
|
||||
private:
|
||||
void AddMesh(int data_id);
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <filament/TextureSampler.h>
|
||||
#include <mujoco/mjmodel.h>
|
||||
#include "experimental/filament/filament/object_manager.h"
|
||||
#include "experimental/filament/filament/texture_util.h"
|
||||
|
||||
namespace mujoco {
|
||||
|
||||
@@ -71,7 +72,7 @@ void Material::UpdateTextures(const Textures& textures) {
|
||||
UpdateMaterialInstances();
|
||||
}
|
||||
|
||||
void Material::UpdateReflectionTexture(const filament::Texture* tex) {
|
||||
void Material::UpdateReflectionTexture(const Texture* tex) {
|
||||
textures_.reflection = tex;
|
||||
UpdateMaterialInstances();
|
||||
}
|
||||
@@ -128,70 +129,26 @@ void Material::UpdateMaterialInstances() {
|
||||
sampler.setMinFilter(
|
||||
filament::TextureSampler::MinFilter::LINEAR_MIPMAP_LINEAR);
|
||||
|
||||
if (material->hasParameter("BaseColor")) {
|
||||
if (textures_.color) {
|
||||
instance->setParameter("BaseColor", textures_.color, sampler);
|
||||
} else {
|
||||
auto* fallback = object_mgr_->GetFallbackTexture(mjTEXROLE_RGB);
|
||||
instance->setParameter("BaseColor", fallback, sampler);
|
||||
auto TrySetTexture = [&](const char* name, const Texture* texture,
|
||||
mjtTextureRole role) {
|
||||
if (material->hasParameter(name)) {
|
||||
if (texture) {
|
||||
instance->setParameter(name, texture->GetFilamentTexture(), sampler);
|
||||
} else {
|
||||
auto* fallback = object_mgr_->GetFallbackTexture(role);
|
||||
instance->setParameter(name, fallback->GetFilamentTexture(), sampler);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (material->hasParameter("Normal")) {
|
||||
if (textures_.normal) {
|
||||
instance->setParameter("Normal", textures_.normal, sampler);
|
||||
} else {
|
||||
auto* fallback = object_mgr_->GetFallbackTexture(mjTEXROLE_NORMAL);
|
||||
instance->setParameter("Normal", fallback, sampler);
|
||||
}
|
||||
}
|
||||
if (material->hasParameter("Metallic")) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TrySetTexture("BaseColor", textures_.color, mjTEXROLE_RGB);
|
||||
TrySetTexture("Normal", textures_.normal, mjTEXROLE_NORMAL);
|
||||
TrySetTexture("Metallic", textures_.metallic, mjTEXROLE_METALLIC);
|
||||
TrySetTexture("Roughness", textures_.roughness, mjTEXROLE_ROUGHNESS);
|
||||
TrySetTexture("Occlusion", textures_.occlusion, mjTEXROLE_OCCLUSION);
|
||||
TrySetTexture("ORM", textures_.orm, mjTEXROLE_ORM);
|
||||
TrySetTexture("Emissive", textures_.emissive, mjTEXROLE_EMISSIVE);
|
||||
TrySetTexture("Reflection", textures_.reflection, mjTEXROLE_USER);
|
||||
}
|
||||
|
||||
} // namespace mujoco
|
||||
|
||||
@@ -17,11 +17,11 @@
|
||||
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/MaterialInstance.h>
|
||||
#include <filament/Texture.h>
|
||||
#include <math/vec2.h>
|
||||
#include <math/vec3.h>
|
||||
#include <math/vec4.h>
|
||||
#include "experimental/filament/filament/object_manager.h"
|
||||
#include "experimental/filament/filament/texture_util.h"
|
||||
|
||||
namespace mujoco {
|
||||
|
||||
@@ -39,14 +39,14 @@ class Material {
|
||||
|
||||
// The textures that can be assigned to the drawable's material.
|
||||
struct Textures {
|
||||
const filament::Texture* color = nullptr;
|
||||
const filament::Texture* normal = nullptr;
|
||||
const filament::Texture* metallic = nullptr;
|
||||
const filament::Texture* roughness = nullptr;
|
||||
const filament::Texture* occlusion = nullptr;
|
||||
const filament::Texture* orm = nullptr;
|
||||
const filament::Texture* emissive = nullptr;
|
||||
const filament::Texture* reflection = nullptr;
|
||||
const Texture* color = nullptr;
|
||||
const Texture* normal = nullptr;
|
||||
const Texture* metallic = nullptr;
|
||||
const Texture* roughness = nullptr;
|
||||
const Texture* occlusion = nullptr;
|
||||
const Texture* orm = nullptr;
|
||||
const Texture* emissive = nullptr;
|
||||
const Texture* reflection = nullptr;
|
||||
};
|
||||
|
||||
// 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
|
||||
// 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.
|
||||
filament::MaterialInstance* GetMaterialInstance(DrawMode mode) {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "experimental/filament/filament/model_objects.h"
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@@ -80,9 +81,7 @@ ModelObjects::~ModelObjects() {
|
||||
engine_->destroy(iter.vertex_buffer);
|
||||
engine_->destroy(iter.index_buffer);
|
||||
}
|
||||
for (auto& iter : textures_) {
|
||||
engine_->destroy(iter.second);
|
||||
}
|
||||
textures_.clear();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (auto iter = textures_.find(id); iter != textures_.end()) {
|
||||
engine_->destroy(iter->second);
|
||||
}
|
||||
const int width = model->tex_width[id];
|
||||
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];
|
||||
if (model->tex_height[id] == 1) {
|
||||
const mjtByte* bytes = model->tex_data + model->tex_adr[id];
|
||||
const int num_bytes = model->tex_width[id];
|
||||
textures_[id] =
|
||||
CreateKtxTexture(engine_, bytes, num_bytes, spherical_harmonics_[id]);
|
||||
} else if (texture_type == mjTEXTURE_2D) {
|
||||
textures_[id] = CreateTexture(engine_, model, id, TextureType::kNormal2d);
|
||||
} else if (texture_type == mjTEXTURE_CUBE) {
|
||||
textures_[id] = CreateTexture(engine_, model, id, TextureType::kCube);
|
||||
} else if (texture_type == mjTEXTURE_SKYBOX) {
|
||||
textures_[id] = CreateTexture(engine_, model, id, TextureType::kCube);
|
||||
} else {
|
||||
mju_error("Unsupported: Texture type: %d", texture_type);
|
||||
}
|
||||
const TextureType type = [&] {
|
||||
if (height == 1) {
|
||||
return TextureType::kKtx;
|
||||
} else if (tex_type == mjTEXTURE_2D) {
|
||||
return TextureType::kNormal2d;
|
||||
} else if (tex_type == mjTEXTURE_CUBE) {
|
||||
return TextureType::kCube;
|
||||
} else if (tex_type == mjTEXTURE_SKYBOX) {
|
||||
return TextureType::kCube;
|
||||
} else {
|
||||
mju_error("Unsupported texture type: %d", tex_type);
|
||||
return TextureType::kNormal2d;
|
||||
}
|
||||
}();
|
||||
|
||||
textures_[id] = std::make_unique<Texture>(engine_, type, color_space, width,
|
||||
height, num_channels, data);
|
||||
}
|
||||
|
||||
void ModelObjects::UploadHeightField(const mjModel* model, int id) {
|
||||
@@ -194,12 +198,12 @@ const FilamentBuffers* ModelObjects::GetShapeBuffer(ShapeType shape) const {
|
||||
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);
|
||||
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) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -210,15 +214,11 @@ const filament::Texture* ModelObjects::GetTexture(int mat_id, int role) const {
|
||||
filament::IndirectLight* ModelObjects::CreateIndirectLight(int tex_id,
|
||||
float intensity) {
|
||||
filament::Texture* texture = nullptr;
|
||||
const Texture::SphericalHarmonics* spherical_harmonics = nullptr;
|
||||
auto texture_iter = textures_.find(tex_id);
|
||||
if (texture_iter != textures_.end()) {
|
||||
texture = texture_iter->second;
|
||||
}
|
||||
|
||||
SphericalHarmonics* spherical_harmonics = nullptr;
|
||||
auto sh_iter = spherical_harmonics_.find(tex_id);
|
||||
if (sh_iter != spherical_harmonics_.end()) {
|
||||
spherical_harmonics = &sh_iter->second;
|
||||
texture = texture_iter->second->GetFilamentTexture();
|
||||
spherical_harmonics = texture_iter->second->GetSphericalHarmonics();
|
||||
}
|
||||
|
||||
filament::IndirectLight::Builder builder;
|
||||
@@ -240,7 +240,7 @@ filament::Skybox* ModelObjects::CreateSkybox() {
|
||||
for (auto& iter : textures_) {
|
||||
const int texture_type = model_->tex_type[iter.first];
|
||||
if (texture_type == mjTEXTURE_SKYBOX) {
|
||||
skybox_texture = iter.second;
|
||||
skybox_texture = iter.second->GetFilamentTexture();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#define MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_MODEL_OBJECTS_H_
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
@@ -25,6 +26,7 @@
|
||||
#include <math/vec3.h>
|
||||
#include <mujoco/mjmodel.h>
|
||||
#include "experimental/filament/filament/buffer_util.h"
|
||||
#include "experimental/filament/filament/texture_util.h"
|
||||
|
||||
namespace mujoco {
|
||||
|
||||
@@ -62,8 +64,8 @@ class ModelObjects {
|
||||
const FilamentBuffers* GetShapeBuffer(ShapeType shape) const;
|
||||
const FilamentBuffers* GetMeshBuffer(int data_id) const;
|
||||
const FilamentBuffers* GetHeightFieldBuffer(int hfield_id) const;
|
||||
const filament::Texture* GetTexture(int tex_id) const;
|
||||
const filament::Texture* GetTexture(int mat_id, int role) const;
|
||||
const Texture* GetTexture(int tex_id) const;
|
||||
const Texture* GetTexture(int mat_id, int role) const;
|
||||
|
||||
filament::Skybox* CreateSkybox();
|
||||
filament::IndirectLight* CreateIndirectLight(int tex_id, float intensity);
|
||||
@@ -78,8 +80,6 @@ class ModelObjects {
|
||||
ModelObjects& operator=(const ModelObjects&) = delete;
|
||||
|
||||
private:
|
||||
using SphericalHarmonics = filament::math::float3[9];
|
||||
|
||||
const mjModel* model_ = nullptr;
|
||||
filament::Engine* engine_ = nullptr;
|
||||
std::vector<filament::Skybox*> skyboxes_;
|
||||
@@ -88,8 +88,7 @@ class ModelObjects {
|
||||
std::unordered_map<int, FilamentBuffers> meshes_;
|
||||
std::unordered_map<int, FilamentBuffers> convex_hulls_;
|
||||
std::unordered_map<int, FilamentBuffers> height_fields_;
|
||||
std::unordered_map<int, filament::Texture*> textures_;
|
||||
std::unordered_map<int, SphericalHarmonics> spherical_harmonics_;
|
||||
std::unordered_map<int, std::unique_ptr<Texture>> textures_;
|
||||
float specular_multiplier_ = 0.2f;
|
||||
float shininess_multiplier_ = 0.1f;
|
||||
float emissive_multiplier_ = 0.3f;
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "experimental/filament/filament/object_manager.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
@@ -86,22 +87,27 @@ ObjectManager::ObjectManager(filament::Engine* engine)
|
||||
materials_[kUnlitUi] = LoadMaterial("unlit_ui.filamat");
|
||||
|
||||
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};
|
||||
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};
|
||||
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};
|
||||
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_RGB] = fallback_white_;
|
||||
fallback_textures_[mjTEXROLE_OCCLUSION] = fallback_white_;
|
||||
fallback_textures_[mjTEXROLE_ROUGHNESS] = fallback_white_;
|
||||
fallback_textures_[mjTEXROLE_METALLIC] = fallback_black_;
|
||||
fallback_textures_[mjTEXROLE_NORMAL] = fallback_normal_;
|
||||
fallback_textures_[mjTEXROLE_EMISSIVE] = fallback_black_;
|
||||
fallback_textures_[mjTEXROLE_ORM] = fallback_orm_;
|
||||
fallback_textures_[mjTEXROLE_USER] = fallback_black_.get();
|
||||
fallback_textures_[mjTEXROLE_RGB] = fallback_white_.get();
|
||||
fallback_textures_[mjTEXROLE_OCCLUSION] = fallback_white_.get();
|
||||
fallback_textures_[mjTEXROLE_ROUGHNESS] = fallback_white_.get();
|
||||
fallback_textures_[mjTEXROLE_METALLIC] = fallback_black_.get();
|
||||
fallback_textures_[mjTEXROLE_NORMAL] = fallback_normal_.get();
|
||||
fallback_textures_[mjTEXROLE_EMISSIVE] = fallback_black_.get();
|
||||
fallback_textures_[mjTEXROLE_ORM] = fallback_orm_.get();
|
||||
|
||||
LoadFallbackIndirectLight("ibl.ktx", 1.0f);
|
||||
}
|
||||
@@ -110,17 +116,10 @@ ObjectManager::~ObjectManager() {
|
||||
if (fallback_indirect_light_) {
|
||||
engine_->destroy(fallback_indirect_light_);
|
||||
}
|
||||
if (fallback_indirect_light_texture_) {
|
||||
engine_->destroy(fallback_indirect_light_texture_);
|
||||
}
|
||||
fallback_indirect_light_texture_.reset();
|
||||
for (auto& iter : materials_) {
|
||||
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 {
|
||||
@@ -130,7 +129,7 @@ filament::Material* ObjectManager::GetMaterial(MaterialType type) const {
|
||||
return materials_[type];
|
||||
}
|
||||
|
||||
const filament::Texture* ObjectManager::GetFallbackTexture(
|
||||
const Texture* ObjectManager::GetFallbackTexture(
|
||||
mjtTextureRole role) const {
|
||||
if (role < 0 || role >= mjNTEXROLE) {
|
||||
mju_error("Invalid texture role: %d", role);
|
||||
@@ -144,10 +143,7 @@ filament::IndirectLight* ObjectManager::GetFallbackIndirectLight() {
|
||||
|
||||
void ObjectManager::LoadFallbackIndirectLight(
|
||||
std::string_view filename, float intensity) {
|
||||
if (fallback_indirect_light_texture_ != nullptr) {
|
||||
engine_->destroy(fallback_indirect_light_texture_);
|
||||
fallback_indirect_light_texture_ = nullptr;
|
||||
}
|
||||
fallback_indirect_light_texture_.reset();
|
||||
if (fallback_indirect_light_ != nullptr) {
|
||||
engine_->destroy(fallback_indirect_light_);
|
||||
fallback_indirect_light_ = nullptr;
|
||||
@@ -158,18 +154,22 @@ void ObjectManager::LoadFallbackIndirectLight(
|
||||
return;
|
||||
}
|
||||
|
||||
filament::math::float3 spherical_harmonics[9];
|
||||
fallback_indirect_light_texture_ =
|
||||
CreateKtxTexture(engine_, reinterpret_cast<const uint8_t*>(asset.payload),
|
||||
asset.size, spherical_harmonics);
|
||||
fallback_indirect_light_texture_ = std::make_unique<Texture>(
|
||||
engine_, TextureType::kKtx, mjCOLORSPACE_AUTO, asset.size, 1, 1,
|
||||
reinterpret_cast<const uint8_t*>(asset.payload));
|
||||
if (fallback_indirect_light_texture_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const Texture::SphericalHarmonics* spherical_harmonics =
|
||||
fallback_indirect_light_texture_->GetSphericalHarmonics();
|
||||
|
||||
// Build the indirect light.
|
||||
filament::IndirectLight::Builder builder;
|
||||
builder.reflections(fallback_indirect_light_texture_);
|
||||
builder.irradiance(3, spherical_harmonics);
|
||||
builder.reflections(fallback_indirect_light_texture_->GetFilamentTexture());
|
||||
if (spherical_harmonics) {
|
||||
builder.irradiance(3, *spherical_harmonics);
|
||||
}
|
||||
builder.intensity(intensity);
|
||||
// Rotate the light to match mujoco's Z-up convention.
|
||||
builder.rotation(filament::math::mat3f::rotation(
|
||||
|
||||
@@ -16,12 +16,14 @@
|
||||
#define MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_OBJECT_MANAGER_H_
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/IndirectLight.h>
|
||||
#include <filament/Skybox.h>
|
||||
#include <mujoco/mujoco.h>
|
||||
#include "experimental/filament/filament/texture_util.h"
|
||||
|
||||
namespace mujoco {
|
||||
|
||||
@@ -60,7 +62,7 @@ class ObjectManager {
|
||||
filament::Material* GetMaterial(MaterialType type) const;
|
||||
|
||||
// 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.
|
||||
filament::IndirectLight* GetFallbackIndirectLight();
|
||||
@@ -74,12 +76,12 @@ class ObjectManager {
|
||||
private:
|
||||
filament::Engine* engine_ = nullptr;
|
||||
std::array<filament::Material*, kNumMaterials> materials_;
|
||||
std::array<filament::Texture*, mjNTEXROLE> fallback_textures_;
|
||||
filament::Texture* fallback_white_ = nullptr;
|
||||
filament::Texture* fallback_black_ = nullptr;
|
||||
filament::Texture* fallback_normal_ = nullptr;
|
||||
filament::Texture* fallback_orm_ = nullptr;
|
||||
filament::Texture* fallback_indirect_light_texture_ = nullptr;
|
||||
std::array<Texture*, mjNTEXROLE> fallback_textures_;
|
||||
std::unique_ptr<Texture> fallback_white_ = nullptr;
|
||||
std::unique_ptr<Texture> fallback_black_ = nullptr;
|
||||
std::unique_ptr<Texture> fallback_normal_ = nullptr;
|
||||
std::unique_ptr<Texture> fallback_orm_ = nullptr;
|
||||
std::unique_ptr<Texture> fallback_indirect_light_texture_ = nullptr;
|
||||
filament::IndirectLight* fallback_indirect_light_ = nullptr;
|
||||
};
|
||||
|
||||
|
||||
@@ -14,15 +14,15 @@
|
||||
|
||||
#include "experimental/filament/filament/render_target_util.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/RenderTarget.h>
|
||||
#include <filament/Texture.h>
|
||||
#include <mujoco/mujoco.h>
|
||||
#include "experimental/filament/filament/texture_util.h"
|
||||
|
||||
namespace mujoco {
|
||||
|
||||
|
||||
|
||||
RenderTargetAndTextures::RenderTargetAndTextures(filament::Engine* engine,
|
||||
RenderTargetTextureType color,
|
||||
RenderTargetTextureType depth)
|
||||
@@ -41,15 +41,15 @@ void RenderTargetAndTextures::Prepare(int width, int height) {
|
||||
height_ = height;
|
||||
|
||||
color_texture_ =
|
||||
CreateRenderTargetTexture(engine_, width, height, color_type_);
|
||||
std::make_unique<Texture>(engine_, color_type_, width, height);
|
||||
depth_texture_ =
|
||||
CreateRenderTargetTexture(engine_, width, height, depth_type_);
|
||||
std::make_unique<Texture>(engine_, depth_type_, width, height);
|
||||
|
||||
filament::RenderTarget::Builder builder;
|
||||
builder.texture(filament::RenderTarget::AttachmentPoint::COLOR,
|
||||
color_texture_);
|
||||
color_texture_->GetFilamentTexture());
|
||||
builder.texture(filament::RenderTarget::AttachmentPoint::DEPTH,
|
||||
depth_texture_);
|
||||
depth_texture_->GetFilamentTexture());
|
||||
render_target_ = builder.build(*engine_);
|
||||
}
|
||||
|
||||
@@ -58,14 +58,20 @@ void RenderTargetAndTextures::Destroy() {
|
||||
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;
|
||||
}
|
||||
color_texture_.reset();
|
||||
depth_texture_.reset();
|
||||
}
|
||||
|
||||
Texture* RenderTargetAndTextures::GetColorTexture() const {
|
||||
return color_texture_.get();
|
||||
}
|
||||
|
||||
Texture* RenderTargetAndTextures::GetDepthTexture() const {
|
||||
return depth_texture_.get();
|
||||
}
|
||||
|
||||
filament::RenderTarget* RenderTargetAndTextures::GetRenderTarget() const {
|
||||
return render_target_;
|
||||
}
|
||||
|
||||
} // namespace mujoco
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#ifndef 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/Texture.h>
|
||||
#include "experimental/filament/filament/texture_util.h"
|
||||
@@ -39,21 +41,21 @@ class RenderTargetAndTextures {
|
||||
void Prepare(int width, int height);
|
||||
|
||||
// Returns the color texture.
|
||||
filament::Texture* GetColorTexture() const { return color_texture_; }
|
||||
Texture* GetColorTexture() const;
|
||||
|
||||
// Returns the depth texture.
|
||||
filament::Texture* GetDepthTexture() const { return depth_texture_; }
|
||||
Texture* GetDepthTexture() const;
|
||||
|
||||
// Returns the render target.
|
||||
filament::RenderTarget* GetRenderTarget() const { return render_target_; }
|
||||
filament::RenderTarget* GetRenderTarget() const;
|
||||
|
||||
private:
|
||||
void Destroy();
|
||||
|
||||
filament::Engine* engine_ = nullptr;
|
||||
filament::Texture* color_texture_ = nullptr;
|
||||
filament::Texture* depth_texture_ = nullptr;
|
||||
filament::RenderTarget* render_target_ = nullptr;
|
||||
std::unique_ptr<Texture> color_texture_ = nullptr;
|
||||
std::unique_ptr<Texture> depth_texture_ = nullptr;
|
||||
RenderTargetTextureType color_type_;
|
||||
RenderTargetTextureType depth_type_;
|
||||
int width_ = 0;
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#include <filament/Texture.h>
|
||||
#include <image/Ktx1Bundle.h>
|
||||
#include <ktxreader/Ktx1Reader.h>
|
||||
#include <math/vec3.h>
|
||||
#include <mujoco/mujoco.h>
|
||||
|
||||
namespace mujoco {
|
||||
@@ -69,107 +68,24 @@ static filament::Texture::InternalFormat GetTextureInternalFormat(
|
||||
}
|
||||
}
|
||||
|
||||
filament::Texture* Create2dTexture(filament::Engine* engine, int width,
|
||||
int height, int num_channels,
|
||||
const uint8_t* data, bool is_srgb) {
|
||||
if (num_channels != 1 && num_channels != 3 && num_channels != 4) {
|
||||
mju_error("Unsupported number of channels: %d", num_channels);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
Texture::Texture(filament::Engine* engine, TextureType texture_type,
|
||||
mjtColorSpace color_space, int width, int height,
|
||||
int num_channels, const uint8_t* data)
|
||||
: engine_(engine) {
|
||||
const bool is_srgb = color_space == mjCOLORSPACE_SRGB;
|
||||
if (texture_type == TextureType::kCube) {
|
||||
CreateCubeTexture(width, height, num_channels, data, is_srgb);
|
||||
} else if (texture_type == TextureType::kNormal2d) {
|
||||
Create2dTexture(width, height, num_channels, data, is_srgb);
|
||||
} else if (texture_type == TextureType::kKtx) {
|
||||
CreateKtxTexture(data, width * height * num_channels);
|
||||
} else {
|
||||
// Use the cubemap as is.
|
||||
std::memcpy(buffer, data, num_bytes);
|
||||
mju_error("Unsupported texture type: %d", static_cast<int>(texture_type));
|
||||
}
|
||||
|
||||
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(
|
||||
filament::Engine* engine, int width, int height,
|
||||
RenderTargetTextureType type) {
|
||||
Texture::Texture(filament::Engine* engine, RenderTargetTextureType type,
|
||||
int width, int height) : engine_(engine) {
|
||||
filament::Texture::Builder builder;
|
||||
builder.width(width);
|
||||
builder.height(height);
|
||||
@@ -198,36 +114,115 @@ filament::Texture* CreateRenderTargetTexture(
|
||||
default:
|
||||
mju_error("Unknown type: %d", static_cast<int>(type));
|
||||
}
|
||||
return builder.build(*engine);
|
||||
texture_ = builder.build(*engine);
|
||||
}
|
||||
|
||||
filament::Texture* CreateKtxTexture(
|
||||
filament::Engine* engine, const uint8_t* data, int size,
|
||||
filament::math::float3* spherical_harmonics_out) {
|
||||
void Texture::Create2dTexture(int width, int height, int num_channels,
|
||||
const uint8_t* data, bool is_srgb) {
|
||||
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);
|
||||
if (spherical_harmonics_out) {
|
||||
bundle->getSphericalHarmonics(spherical_harmonics_out);
|
||||
}
|
||||
has_spherical_harmonics_ = true;
|
||||
bundle->getSphericalHarmonics(spherical_harmonics_);
|
||||
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,
|
||||
int id, TextureType texture_type) {
|
||||
if (id < 0 || id >= model->ntex) {
|
||||
mju_error("Invalid texture index %d", id);
|
||||
Texture::~Texture() {
|
||||
if (texture_) {
|
||||
engine_->destroy(texture_);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@@ -40,30 +40,43 @@ enum class RenderTargetTextureType {
|
||||
kReflectionColor,
|
||||
};
|
||||
|
||||
// Creates a filament Texture for the given 2D texture.
|
||||
filament::Texture* Create2dTexture(filament::Engine* engine, int width,
|
||||
int height, int num_channels,
|
||||
const uint8_t* data, bool is_srgb);
|
||||
class Texture {
|
||||
public:
|
||||
// Creates a texture with the given data.
|
||||
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.
|
||||
filament::Texture* CreateCubeTexture(filament::Engine* engine, int width,
|
||||
int height, int num_channels,
|
||||
const uint8_t* data, bool is_srgb);
|
||||
// Creates a texture for use with a render target.
|
||||
Texture(filament::Engine* engine, RenderTargetTextureType type, int width,
|
||||
int height);
|
||||
|
||||
// Creates a filament Texture for the given KTX payload.
|
||||
filament::Texture* CreateKtxTexture(
|
||||
filament::Engine* engine, const uint8_t* data, int size,
|
||||
filament::math::float3* spherical_harmonics_out);
|
||||
~Texture();
|
||||
|
||||
// Creates a filament Texture for the given texture in the mjModel.
|
||||
filament::Texture* CreateTexture(filament::Engine* engine, const mjModel* model,
|
||||
int id, TextureType texture_type);
|
||||
filament::Texture* GetFilamentTexture() const { return texture_; }
|
||||
|
||||
// Creates a filament Texture for the given render target.
|
||||
filament::Texture* CreateRenderTargetTexture(filament::Engine* engine,
|
||||
int width, int height,
|
||||
RenderTargetTextureType type);
|
||||
using SphericalHarmonics = filament::math::float3[9];
|
||||
|
||||
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
|
||||
|
||||
#endif // MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_TEXTURE_UTIL_H_
|
||||
|
||||
Reference in New Issue
Block a user