culling fixes for HighlightOverlay

This commit is contained in:
Nick Fisher
2024-09-13 10:34:47 +08:00
parent 44078ba2e0
commit 90827ff012

View File

@@ -4,54 +4,62 @@
#include "SceneManager.hpp" #include "SceneManager.hpp"
namespace thermion_filament { namespace thermion_filament
{
SceneManager::HighlightOverlay::HighlightOverlay( SceneManager::HighlightOverlay::HighlightOverlay(
EntityId entityId, EntityId entityId,
SceneManager* const sceneManager, SceneManager *const sceneManager,
Engine* engine, Engine *engine,
float r, float r,
float g, float g,
float b) : _sceneManager(sceneManager), _engine(engine) { float b) : _sceneManager(sceneManager), _engine(engine)
{
auto& rm = engine->getRenderableManager();
auto &rm = engine->getRenderableManager();
auto& tm = engine->getTransformManager();
auto &tm = engine->getTransformManager();
// Create the outline/highlight material instance // Create the outline/highlight material instance
filament::gltfio::MaterialKey dummyKey; // We're not using the key for this simple material filament::gltfio::MaterialKey dummyKey; // We're not using the key for this simple material
filament::gltfio::UvMap dummyUvMap; // We're not using UV mapping for this simple material filament::gltfio::UvMap dummyUvMap; // We're not using UV mapping for this simple material
auto materialProvider = sceneManager->unlitMaterialProvider(); auto materialProvider = sceneManager->unlitMaterialProvider();
_highlightMaterialInstance = materialProvider->createMaterialInstance(&dummyKey, &dummyUvMap); _highlightMaterialInstance = materialProvider->createMaterialInstance(&dummyKey, &dummyUvMap);
_highlightMaterialInstance->setDoubleSided(false);
_highlightMaterialInstance->setStencilOpStencilFail(filament::backend::StencilOperation::KEEP); _highlightMaterialInstance->setStencilOpStencilFail(filament::backend::StencilOperation::KEEP);
_highlightMaterialInstance->setStencilOpDepthFail(filament::backend::StencilOperation::KEEP); _highlightMaterialInstance->setStencilOpDepthFail(filament::backend::StencilOperation::KEEP);
_highlightMaterialInstance->setStencilOpDepthStencilPass(filament::backend::StencilOperation::KEEP); _highlightMaterialInstance->setStencilOpDepthStencilPass(filament::backend::StencilOperation::REPLACE);
_highlightMaterialInstance->setStencilCompareFunction(filament::backend::SamplerCompareFunc::NE); _highlightMaterialInstance->setStencilCompareFunction(filament::backend::SamplerCompareFunc::NE);
_highlightMaterialInstance->setStencilReferenceValue(1); _highlightMaterialInstance->setStencilReferenceValue(1);
_highlightMaterialInstance->setParameter("color", filament::math::float3 { r, g, b });
_highlightMaterialInstance->setParameter("scale", 1.05f); _highlightMaterialInstance->setParameter("color", filament::math::float3{r, g, b});
_highlightMaterialInstance->setParameter("scale", 1.04f);
_highlightMaterialInstance->setCullingMode(filament::backend::CullingMode::FRONT);
auto scene = sceneManager->getScene(); auto scene = sceneManager->getScene();
_isGeometryEntity = sceneManager->isGeometryEntity(entityId); _isGeometryEntity = sceneManager->isGeometryEntity(entityId);
_isGltfAsset = sceneManager->isGltfAsset(entityId); _isGltfAsset = sceneManager->isGltfAsset(entityId);
if(!(_isGeometryEntity || _isGltfAsset)) { if (!(_isGeometryEntity || _isGltfAsset))
{
Log("Failed to set stencil outline for entity %d: the entity is a child of another entity. " Log("Failed to set stencil outline for entity %d: the entity is a child of another entity. "
"Currently, we only support outlining top-level entities." "Currently, we only support outlining top-level entities."
"Call getAncestor() to get the ancestor of this entity, then set on that", entityId); "Call getAncestor() to get the ancestor of this entity, then set on that",
entityId);
return; return;
} }
if(_isGeometryEntity) { if (_isGeometryEntity)
{
Log("Entity %d is geometry", entityId); Log("Entity %d is geometry", entityId);
auto geometryEntity = Entity::import(entityId); auto geometryEntity = Entity::import(entityId);
auto renderable = rm.getInstance(geometryEntity); auto renderable = rm.getInstance(geometryEntity);
auto materialInstance = rm.getMaterialInstanceAt(renderable, 0); auto materialInstance = rm.getMaterialInstanceAt(renderable, 0);
@@ -60,37 +68,40 @@ namespace thermion_filament {
materialInstance->setDepthWrite(true); materialInstance->setDepthWrite(true);
materialInstance->setStencilReferenceValue(1); materialInstance->setStencilReferenceValue(1);
materialInstance->setStencilOpStencilFail(filament::backend::StencilOperation::KEEP); materialInstance->setStencilOpStencilFail(filament::backend::StencilOperation::KEEP);
materialInstance->setStencilOpDepthFail(filament::backend::StencilOperation::REPLACE); materialInstance->setStencilOpDepthFail(filament::backend::StencilOperation::KEEP);
materialInstance->setStencilOpDepthStencilPass(filament::backend::StencilOperation::REPLACE); materialInstance->setStencilOpDepthStencilPass(filament::backend::StencilOperation::KEEP);
materialInstance->setStencilCompareFunction(filament::backend::SamplerCompareFunc::A); materialInstance->setStencilCompareFunction(filament::backend::SamplerCompareFunc::A);
// materialInstance->setCullingMode(filament::MaterialInstance::CullingMode::BACK);
auto geometry = sceneManager->getGeometry(entityId); auto geometry = sceneManager->getGeometry(entityId);
_entity = utils::EntityManager::get().create(); _entity = utils::EntityManager::get().create();
RenderableManager::Builder builder(1); RenderableManager::Builder builder(1);
builder.boundingBox(geometry->getBoundingBox()) builder.boundingBox(geometry->getBoundingBox())
.geometry(0, geometry->primitiveType, geometry->vertexBuffer(), geometry->indexBuffer(), 0, geometry->numIndices) .geometry(0, geometry->primitiveType, geometry->vertexBuffer(), geometry->indexBuffer(), 0, geometry->numIndices)
.culling(true) .culling(true)
.material(0, _highlightMaterialInstance) .material(0, _highlightMaterialInstance)
.receiveShadows(false) .priority(0)
.castShadows(false); .receiveShadows(false)
.castShadows(false);
builder.build(*engine, _entity); builder.build(*engine, _entity);
scene->addEntity(_entity); scene->addEntity(_entity);
auto outlineTransformInstance = tm.getInstance(_entity); auto outlineTransformInstance = tm.getInstance(_entity);
auto entityTransformInstance = tm.getInstance(geometryEntity); auto entityTransformInstance = tm.getInstance(geometryEntity);
tm.setParent(outlineTransformInstance, entityTransformInstance); tm.setParent(outlineTransformInstance, entityTransformInstance);
} else if(_isGltfAsset) { }
else if (_isGltfAsset)
{
Log("Entity %d is gltf", entityId); Log("Entity %d is gltf", entityId);
auto *asset = sceneManager->getAssetByEntityId(entityId); auto *asset = sceneManager->getAssetByEntityId(entityId);
if (asset) if (asset)
{ {
Log("Found glTF FilamentAsset with %d material instances", asset->getInstance()->getMaterialInstanceCount()); Log("Found glTF FilamentAsset with %d material instances", asset->getInstance()->getMaterialInstanceCount());
auto materialInstance = asset->getInstance()->getMaterialInstances()[0]; auto materialInstance = asset->getInstance()->getMaterialInstances()[0];
// set stencil write on the existing material // set stencil write on the existing material
@@ -108,55 +119,66 @@ namespace thermion_filament {
auto newTransformInstance = tm.getInstance(_entity); auto newTransformInstance = tm.getInstance(_entity);
auto entityTransformInstance = tm.getInstance(asset->getRoot()); auto entityTransformInstance = tm.getInstance(asset->getRoot());
tm.setParent(newTransformInstance, entityTransformInstance); tm.setParent(newTransformInstance, entityTransformInstance);
if(!_newInstance) { if (!_newInstance)
{
Log("Couldn't create new instance"); Log("Couldn't create new instance");
} else { }
for(int i = 0; i < _newInstance->getEntityCount(); i++) { else
{
for (int i = 0; i < _newInstance->getEntityCount(); i++)
{
auto entity = _newInstance->getEntities()[i]; auto entity = _newInstance->getEntities()[i];
auto renderableInstance = rm.getInstance(entity); auto renderableInstance = rm.getInstance(entity);
rm.setPriority(renderableInstance, 7); rm.setPriority(renderableInstance, 7);
if(renderableInstance.isValid()) { if (renderableInstance.isValid())
for(int primitiveIndex = 0; primitiveIndex < rm.getPrimitiveCount(renderableInstance); primitiveIndex++) { {
for (int primitiveIndex = 0; primitiveIndex < rm.getPrimitiveCount(renderableInstance); primitiveIndex++)
{
rm.setMaterialInstanceAt(renderableInstance, primitiveIndex, _highlightMaterialInstance); rm.setMaterialInstanceAt(renderableInstance, primitiveIndex, _highlightMaterialInstance);
} }
} else { }
else
{
Log("Not renderable, ignoring"); Log("Not renderable, ignoring");
} }
} }
scene->addEntities(_newInstance->getEntities(), _newInstance->getEntityCount()); scene->addEntities(_newInstance->getEntities(), _newInstance->getEntityCount());
} }
} else { }
else
{
Log("Not FilamentAsset"); Log("Not FilamentAsset");
} }
} }
}
SceneManager::HighlightOverlay::~HighlightOverlay()
} {
if (_entity.isNull())
SceneManager::HighlightOverlay::~HighlightOverlay() { {
Log("Destructor"); Log("Null entity");
if (_entity.isNull()) { return;
Log("Null entity"); }
return;
} if (_isGltfAsset)
if (_isGltfAsset)
{ {
Log("Erasing new instance");
_sceneManager->getScene()->removeEntities(_newInstance->getEntities(), _newInstance->getEntityCount()); _sceneManager->getScene()->removeEntities(_newInstance->getEntities(), _newInstance->getEntityCount());
_newInstance->detachMaterialInstances(); _newInstance->detachMaterialInstances();
_engine->destroy(_highlightMaterialInstance); _engine->destroy(_highlightMaterialInstance);
} else if(_isGeometryEntity) { }
Log("Erasing new geometry"); else if (_isGeometryEntity)
auto& tm = _engine->getTransformManager(); {
auto &tm = _engine->getTransformManager();
auto transformInstance = tm.getInstance(_entity); auto transformInstance = tm.getInstance(_entity);
_sceneManager->getScene()->remove(_entity); _sceneManager->getScene()->remove(_entity);
utils::EntityManager::get().destroy(_entity); utils::EntityManager::get().destroy(_entity);
_engine->destroy(_entity); _engine->destroy(_entity);
_engine->destroy(_highlightMaterialInstance); _engine->destroy(_highlightMaterialInstance);
} else { }
else
{
Log("FATAL: Unknown highlight overlay entity type"); Log("FATAL: Unknown highlight overlay entity type");
} }
} }