Planes should not receive shadows when rendered from behind.

Also refactors Renderables a bit to allow for additional use-cases.

PiperOrigin-RevId: 885527587
Change-Id: I4b17e097256de0356151a6d087bc01f11e3071b7
This commit is contained in:
Haroon Qureshi
2026-03-18 05:04:06 -07:00
committed by Copybara-Service
parent 3f77daa27a
commit b0c48ba846
4 changed files with 74 additions and 47 deletions
@@ -88,7 +88,8 @@ static bool IsBehind(const mjtNum* headpos, const float* pos, const float* mat)
Drawable::Drawable(ObjectManager* object_mgr, const mjvGeom& geom)
: material_(object_mgr), renderables_(object_mgr->GetEngine()) {
if (geom.category == mjCAT_DECOR) {
renderables_.DisableShadows();
renderables_.SetCastShadows(false);
renderables_.SetReceiveShadows(false);
}
switch ((mjtGeom)geom.type) {
@@ -346,8 +347,13 @@ void Drawable::UpdateMaterial(const mjvGeom& geom, bool use_segid_color,
const mjModel* model = object_mgr->GetModel();
float4 color = ReadFloat4(geom.rgba);
if (geom.type == mjGEOM_PLANE && IsBehind(headpos, geom.pos, geom.mat)) {
color[3] *= 0.3;
if (geom.type == mjGEOM_PLANE) {
if (IsBehind(headpos, geom.pos, geom.mat)) {
color[3] *= 0.3;
renderables_.SetReceiveShadows(false);
} else {
renderables_.SetReceiveShadows(true);
}
}
Material::Textures textures;
@@ -51,7 +51,6 @@ class Drawable {
// beginFrame/endFrame.
void SetDrawMode(Material::DrawMode mode);
private:
void AddMesh(int data_id);
void AddHeightField(int hfield_id);
@@ -14,6 +14,7 @@
#include "experimental/filament/filament/renderables.h"
#include <cstdint>
#include <optional>
#include <filament/Engine.h>
@@ -107,8 +108,9 @@ utils::Entity Renderables::CreateEntity(const FilamentBuffers& buffers) {
builder.boundingBox(buffers.bounds)
.culling(false)
.castShadows(cast_shadows_)
.receiveShadows(true)
.layerMask(1, visible_ ? 1 : 0)
.receiveShadows(receive_shadows_)
.layerMask(0xff, layer_mask_)
.priority(priority_)
.screenSpaceContactShadows(true);
builder.build(*engine_, entity);
@@ -180,23 +182,47 @@ void Renderables::SetMaterialInstance(
}
}
void Renderables::Hide() {
if (visible_) {
void Renderables::SetLayerMask(std::uint8_t mask) {
if (mask != layer_mask_) {
layer_mask_ = mask;
filament::RenderableManager& rm = engine_->getRenderableManager();
for (utils::Entity& entity : entities_) {
rm.setLayerMask(rm.getInstance(entity), 1, 0);
rm.setLayerMask(rm.getInstance(entity), 0xff, layer_mask_);
}
visible_ = false;
}
}
void Renderables::Show() {
if (!visible_) {
void Renderables::SetPriority(std::uint8_t priority) {
if (priority != priority_) {
priority_ = priority;
filament::RenderableManager& rm = engine_->getRenderableManager();
for (utils::Entity& entity : entities_) {
rm.setLayerMask(rm.getInstance(entity), 1, 1);
rm.setPriority(rm.getInstance(entity), priority_);
}
}
}
void Renderables::SetCastShadows(bool cast_shadows) {
if (cast_shadows_ != cast_shadows) {
cast_shadows_ = cast_shadows;
filament::RenderableManager& rm = engine_->getRenderableManager();
for (utils::Entity& entity : entities_) {
rm.setCastShadows(rm.getInstance(entity), cast_shadows_);
}
}
}
void Renderables::SetReceiveShadows(bool receive_shadows) {
if (receive_shadows_ != receive_shadows) {
receive_shadows_ = receive_shadows;
filament::RenderableManager& rm = engine_->getRenderableManager();
for (utils::Entity& entity : entities_) {
rm.setReceiveShadows(rm.getInstance(entity), receive_shadows_);
}
visible_ = true;
}
}
@@ -204,29 +230,19 @@ void Renderables::SetWireframe(bool wireframe) {
static constexpr auto kWireframeType =
filament::RenderableManager::PrimitiveType::LINES;
if (wireframe == wireframe_) {
return;
}
wireframe_ = wireframe;
if (wireframe != wireframe_) {
wireframe_ = wireframe;
filament::RenderableManager& rm = engine_->getRenderableManager();
for (int i = 0; i < entities_.size(); ++i) {
utils::Entity& entity = entities_[i];
FilamentBuffers& buffers = owned_buffers_[i].buffers;
rm.setGeometryAt(rm.getInstance(entity), 0,
wireframe ? kWireframeType : buffers.type,
buffers.vertex_buffer, buffers.index_buffer, 0,
buffers.index_buffer->getIndexCount());
filament::RenderableManager& rm = engine_->getRenderableManager();
for (int i = 0; i < entities_.size(); ++i) {
utils::Entity& entity = entities_[i];
FilamentBuffers& buffers = owned_buffers_[i].buffers;
rm.setGeometryAt(rm.getInstance(entity), 0,
wireframe_ ? kWireframeType : buffers.type,
buffers.vertex_buffer, buffers.index_buffer, 0,
buffers.index_buffer->getIndexCount());
}
}
}
void Renderables::DisableShadows() {
filament::RenderableManager& rm = engine_->getRenderableManager();
for (utils::Entity& entity : entities_) {
rm.setCastShadows(rm.getInstance(entity), false);
}
cast_shadows_ = false;
}
} // namespace mujoco
@@ -15,8 +15,8 @@
#ifndef MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_RENDERABLES_H_
#define MUJOCO_SRC_EXPERIMENTAL_FILAMENT_FILAMENT_RENDERABLES_H_
#include <cstdint>
#include <optional>
#include <span>
#include <vector>
#include <filament/Engine.h>
@@ -29,6 +29,10 @@ namespace mujoco {
// Manages a collection of related filament Renderable Entities.
class Renderables {
public:
// Default filament values for priority and layer mask.
static constexpr std::uint8_t kDefaultPriority = 4;
static constexpr std::uint8_t kDefaultLayerMask = 0x01;
Renderables(filament::Engine* engine);
~Renderables() noexcept;
@@ -53,16 +57,19 @@ class Renderables {
int GetNumEntities() const { return entities_.size(); }
// Hides all managed entities.
void Hide();
void SetLayerMask(std::uint8_t mask);
// Shows all managed entities.
void Show();
// Returns true if the entities are visible.
bool IsVisible() const { return visible_; }
// Sets the priority of all managed entities.
void SetPriority(std::uint8_t priority);
// Disables the renderables from casting shadows.
void DisableShadows();
void SetCastShadows(bool cast_shadows);
// Disables the renderables from receiving shadows.
void SetReceiveShadows(bool receive_shadows);
// If true, forces all entities to be rendered as lines.
void SetWireframe(bool wireframe);
// Adds all managed entities to the given filament Scene.
void AddToScene(filament::Scene* scene);
@@ -73,9 +80,6 @@ class Renderables {
// Sets the material instance for all managed entities.
void SetMaterialInstance(filament::MaterialInstance* material_instance);
// If true, forces all entities to be rendered as lines.
void SetWireframe(bool wireframe);
// Returns the filament Engine managing the entities in this collection.
filament::Engine* GetEngine() { return engine_; }
@@ -96,9 +100,11 @@ class Renderables {
filament::MaterialInstance* material_instance_ = nullptr;
std::vector<utils::Entity> entities_;
std::vector<OwnedBuffers> owned_buffers_;
bool visible_ = true;
std::uint8_t priority_ = kDefaultPriority;
std::uint8_t layer_mask_ = kDefaultLayerMask;
bool wireframe_ = false;
bool cast_shadows_ = true;
bool receive_shadows_ = true;
};
} // namespace mujoco