feat: ignore grid overlay and gizmo center when picking, implement highlighting

This commit is contained in:
Nick Fisher
2024-08-24 16:17:34 +08:00
parent 2e1f2cd56d
commit 11756fcedd

View File

@@ -88,6 +88,7 @@
#include <filesystem> #include <filesystem>
#include <mutex> #include <mutex>
#include <iomanip> #include <iomanip>
#include <unordered_set>
#include "Log.hpp" #include "Log.hpp"
@@ -115,10 +116,6 @@ namespace thermion_filament
using std::string; using std::string;
// const float kAperture = 1.0f;
// const float kShutterSpeed = 1.0f;
// const float kSensitivity = 50.0f;
static constexpr float4 sFullScreenTriangleVertices[3] = { static constexpr float4 sFullScreenTriangleVertices[3] = {
{-1.0f, -1.0f, 1.0f, 1.0f}, {-1.0f, -1.0f, 1.0f, 1.0f},
{3.0f, -1.0f, 1.0f, 1.0f}, {3.0f, -1.0f, 1.0f, 1.0f},
@@ -129,7 +126,7 @@ namespace thermion_filament
FilamentViewer::FilamentViewer(const void *sharedContext, const ResourceLoaderWrapperImpl *const resourceLoader, void *const platform, const char *uberArchivePath) FilamentViewer::FilamentViewer(const void *sharedContext, const ResourceLoaderWrapperImpl *const resourceLoader, void *const platform, const char *uberArchivePath)
: _resourceLoaderWrapper(resourceLoader) : _resourceLoaderWrapper(resourceLoader)
{ {
_context = (void*) sharedContext; _context = (void *)sharedContext;
ASSERT_POSTCONDITION(_resourceLoaderWrapper != nullptr, "Resource loader must be non-null"); ASSERT_POSTCONDITION(_resourceLoaderWrapper != nullptr, "Resource loader must be non-null");
#if TARGET_OS_IPHONE #if TARGET_OS_IPHONE
@@ -147,14 +144,11 @@ namespace thermion_filament
#else #else
_engine = Engine::create(Engine::Backend::OPENGL, (backend::Platform *)platform, (void *)sharedContext, nullptr); _engine = Engine::create(Engine::Backend::OPENGL, (backend::Platform *)platform, (void *)sharedContext, nullptr);
#endif #endif
Log("Created engine");
_engine->setAutomaticInstancingEnabled(true); _engine->setAutomaticInstancingEnabled(true);
_renderer = _engine->createRenderer(); _renderer = _engine->createRenderer();
Log("Created renderer");
_frameInterval = 1000.0f / 60.0f; _frameInterval = 1000.0f / 60.0f;
setFrameInterval(_frameInterval); setFrameInterval(_frameInterval);
@@ -180,9 +174,9 @@ namespace thermion_filament
_view->setAmbientOcclusionOptions({.enabled = false}); _view->setAmbientOcclusionOptions({.enabled = false});
_view->setDynamicResolutionOptions({.enabled = false}); _view->setDynamicResolutionOptions({.enabled = false});
#if defined(_WIN32) #if defined(_WIN32)
_view->setStereoscopicOptions({.enabled = true}); _view->setStereoscopicOptions({.enabled = true});
#endif #endif
_view->setDithering(filament::Dithering::NONE); _view->setDithering(filament::Dithering::NONE);
setAntiAliasing(false, false, false); setAntiAliasing(false, false, false);
@@ -196,8 +190,7 @@ namespace thermion_filament
_cameraFocalLength = 28.0f; _cameraFocalLength = 28.0f;
_mainCamera->setLensProjection(_cameraFocalLength, 1.0f, _near, _mainCamera->setLensProjection(_cameraFocalLength, 1.0f, _near,
_far); _far);
// _mainCamera->setExposure(kAperture, kShutterSpeed, kSensitivity);
Log("View created");
const float aperture = _mainCamera->getAperture(); const float aperture = _mainCamera->getAperture();
const float shutterSpeed = _mainCamera->getShutterSpeed(); const float shutterSpeed = _mainCamera->getShutterSpeed();
const float sens = _mainCamera->getSensitivity(); const float sens = _mainCamera->getSensitivity();
@@ -207,13 +200,11 @@ namespace thermion_filament
EntityManager &em = EntityManager::get(); EntityManager &em = EntityManager::get();
_sceneManager = new SceneManager( _sceneManager = new SceneManager(
_view,
_resourceLoaderWrapper, _resourceLoaderWrapper,
_engine, _engine,
_scene, _scene,
uberArchivePath); uberArchivePath);
Log("Created scene maager");
} }
void FilamentViewer::setAntiAliasing(bool msaa, bool fxaa, bool taa) void FilamentViewer::setAntiAliasing(bool msaa, bool fxaa, bool taa)
@@ -243,22 +234,22 @@ namespace thermion_filament
_view->setShadowType(shadowType); _view->setShadowType(shadowType);
} }
void FilamentViewer::setSoftShadowOptions(float penumbraScale, float penumbraRatioScale) { void FilamentViewer::setSoftShadowOptions(float penumbraScale, float penumbraRatioScale)
{
SoftShadowOptions opts; SoftShadowOptions opts;
opts.penumbraRatioScale = penumbraRatioScale; opts.penumbraRatioScale = penumbraRatioScale;
opts.penumbraScale = penumbraScale; opts.penumbraScale = penumbraScale;
_view->setSoftShadowOptions(opts); _view->setSoftShadowOptions(opts);
} }
void FilamentViewer::setBloom(float strength) void FilamentViewer::setBloom(float strength)
{ {
#ifndef __EMSCRIPTEN__ #ifndef __EMSCRIPTEN__
decltype(_view->getBloomOptions()) opts; decltype(_view->getBloomOptions()) opts;
opts.enabled = true; opts.enabled = true;
opts.strength = strength; opts.strength = strength;
_view->setBloomOptions(opts); _view->setBloomOptions(opts);
#endif #endif
} }
void FilamentViewer::setToneMapping(ToneMapping toneMapping) void FilamentViewer::setToneMapping(ToneMapping toneMapping)
@@ -301,22 +292,22 @@ namespace thermion_filament
} }
EntityId FilamentViewer::addLight( EntityId FilamentViewer::addLight(
LightManager::Type t, LightManager::Type t,
float colour, float colour,
float intensity, float intensity,
float posX, float posX,
float posY, float posY,
float posZ, float posZ,
float dirX, float dirX,
float dirY, float dirY,
float dirZ, float dirZ,
float falloffRadius, float falloffRadius,
float spotLightConeInner, float spotLightConeInner,
float spotLightConeOuter, float spotLightConeOuter,
float sunAngularRadius, float sunAngularRadius,
float sunHaloSize, float sunHaloSize,
float sunHaloFallof, float sunHaloFallof,
bool shadows) bool shadows)
{ {
auto light = EntityManager::get().create(); auto light = EntityManager::get().create();
auto &transformManager = _engine->getTransformManager(); auto &transformManager = _engine->getTransformManager();
@@ -324,20 +315,23 @@ namespace thermion_filament
auto parent = transformManager.getInstance(light); auto parent = transformManager.getInstance(light);
auto result = LightManager::Builder(t) auto result = LightManager::Builder(t)
.color(Color::cct(colour)) .color(Color::cct(colour))
.intensity(intensity) .intensity(intensity)
.falloff(falloffRadius) .falloff(falloffRadius)
.spotLightCone(spotLightConeInner, spotLightConeOuter) .spotLightCone(spotLightConeInner, spotLightConeOuter)
.sunAngularRadius(sunAngularRadius) .sunAngularRadius(sunAngularRadius)
.sunHaloSize(sunHaloSize) .sunHaloSize(sunHaloSize)
.sunHaloFalloff(sunHaloFallof) .sunHaloFalloff(sunHaloFallof)
.position(math::float3(posX, posY, posZ)) .position(math::float3(posX, posY, posZ))
.direction(math::float3(dirX, dirY, dirZ)) .direction(math::float3(dirX, dirY, dirZ))
.castShadows(shadows) .castShadows(shadows)
.build(*_engine, light); .build(*_engine, light);
if(result != LightManager::Builder::Result::Success) { if (result != LightManager::Builder::Result::Success)
{
Log("ERROR : failed to create light"); Log("ERROR : failed to create light");
} else { }
else
{
_scene->addEntity(light); _scene->addEntity(light);
_lights.push_back(light); _lights.push_back(light);
} }
@@ -507,7 +501,8 @@ namespace thermion_filament
{ {
std::lock_guard lock(_imageMutex); std::lock_guard lock(_imageMutex);
if(_imageEntity.isNull()) { if (_imageEntity.isNull())
{
createBackgroundImage(); createBackgroundImage();
} }
_imageMaterial->setDefaultParameter("showImage", 0); _imageMaterial->setDefaultParameter("showImage", 0);
@@ -515,15 +510,16 @@ namespace thermion_filament
_imageMaterial->setDefaultParameter("transform", _imageScale); _imageMaterial->setDefaultParameter("transform", _imageScale);
} }
void FilamentViewer::createBackgroundImage() { void FilamentViewer::createBackgroundImage()
{
_dummyImageTexture = Texture::Builder() _dummyImageTexture = Texture::Builder()
.width(1) .width(1)
.height(1) .height(1)
.levels(0x01) .levels(0x01)
.format(Texture::InternalFormat::RGB16F) .format(Texture::InternalFormat::RGB16F)
.sampler(Texture::Sampler::SAMPLER_2D) .sampler(Texture::Sampler::SAMPLER_2D)
.build(*_engine); .build(*_engine);
try try
{ {
_imageMaterial = _imageMaterial =
@@ -561,7 +557,7 @@ namespace thermion_filament
_imageIb->setBuffer(*_engine, {sFullScreenTriangleIndices, _imageIb->setBuffer(*_engine, {sFullScreenTriangleIndices,
sizeof(sFullScreenTriangleIndices)}); sizeof(sFullScreenTriangleIndices)});
auto & em = EntityManager::get(); auto &em = EntityManager::get();
_imageEntity = em.create(); _imageEntity = em.create();
RenderableManager::Builder(1) RenderableManager::Builder(1)
.boundingBox({{}, {1.0f, 1.0f, 1.0f}}) .boundingBox({{}, {1.0f, 1.0f, 1.0f}})
@@ -577,7 +573,8 @@ namespace thermion_filament
{ {
std::lock_guard lock(_imageMutex); std::lock_guard lock(_imageMutex);
if(_imageEntity.isNull()) { if (_imageEntity.isNull())
{
createBackgroundImage(); createBackgroundImage();
} }
_imageMaterial->setDefaultParameter("image", _dummyImageTexture, _imageSampler); _imageMaterial->setDefaultParameter("image", _dummyImageTexture, _imageSampler);
@@ -595,7 +592,8 @@ namespace thermion_filament
std::lock_guard lock(_imageMutex); std::lock_guard lock(_imageMutex);
if(_imageEntity.isNull()) { if (_imageEntity.isNull())
{
createBackgroundImage(); createBackgroundImage();
} }
@@ -610,7 +608,7 @@ namespace thermion_filament
// This currently just anchors the image at the bottom left of the viewport at its original size // This currently just anchors the image at the bottom left of the viewport at its original size
// TODO - implement stretch/etc // TODO - implement stretch/etc
const Viewport &vp = _view->getViewport(); const Viewport &vp = _view->getViewport();
Log("Image width %d height %d vp width %d height %d", _imageWidth, _imageHeight, vp.width, vp.height); // Log("Image width %d height %d vp width %d height %d", _imageWidth, _imageHeight, vp.width, vp.height);
float xScale = float(vp.width) / float(_imageWidth); float xScale = float(vp.width) / float(_imageWidth);
@@ -641,7 +639,8 @@ namespace thermion_filament
{ {
std::lock_guard lock(_imageMutex); std::lock_guard lock(_imageMutex);
if(_imageEntity.isNull()) { if (_imageEntity.isNull())
{
createBackgroundImage(); createBackgroundImage();
} }
@@ -724,7 +723,8 @@ namespace thermion_filament
{ {
clearLights(); clearLights();
destroySwapChain(); destroySwapChain();
if(!_imageEntity.isNull()) { if (!_imageEntity.isNull())
{
_engine->destroy(_imageEntity); _engine->destroy(_imageEntity);
_engine->destroy(_imageTexture); _engine->destroy(_imageTexture);
_engine->destroy(_imageVb); _engine->destroy(_imageVb);
@@ -735,6 +735,7 @@ namespace thermion_filament
_engine->destroyCameraComponent(_mainCamera->getEntity()); _engine->destroyCameraComponent(_mainCamera->getEntity());
_mainCamera = nullptr; _mainCamera = nullptr;
_engine->destroy(_view); _engine->destroy(_view);
_engine->destroy(_scene); _engine->destroy(_scene);
_engine->destroy(_renderer); _engine->destroy(_renderer);
Engine::destroy(&_engine); Engine::destroy(&_engine);
@@ -806,11 +807,11 @@ namespace thermion_filament
_swapChain = nullptr; _swapChain = nullptr;
Log("Swapchain destroyed."); Log("Swapchain destroyed.");
} }
#ifdef __EMSCRIPTEN__ #ifdef __EMSCRIPTEN__
_engine->execute(); _engine->execute();
#else #else
_engine->flushAndWait(); _engine->flushAndWait();
#endif #endif
} }
void FilamentViewer::clearEntities() void FilamentViewer::clearEntities()
@@ -821,8 +822,6 @@ namespace thermion_filament
void FilamentViewer::removeEntity(EntityId asset) void FilamentViewer::removeEntity(EntityId asset)
{ {
Log("Removing asset from scene");
mtx.lock(); mtx.lock();
// todo - what if we are using a camera from this asset? // todo - what if we are using a camera from this asset?
_sceneManager->remove(asset); _sceneManager->remove(asset);
@@ -835,7 +834,6 @@ namespace thermion_filament
void FilamentViewer::setCameraExposure(float aperture, float shutterSpeed, float sensitivity) void FilamentViewer::setCameraExposure(float aperture, float shutterSpeed, float sensitivity)
{ {
Camera &cam = _view->getCamera(); Camera &cam = _view->getCamera();
Log("Setting aperture (%03f) shutterSpeed (%03f) and sensitivity (%03f)", aperture, shutterSpeed, sensitivity);
cam.setExposure(aperture, shutterSpeed, sensitivity); cam.setExposure(aperture, shutterSpeed, sensitivity);
} }
@@ -846,7 +844,15 @@ namespace thermion_filament
{ {
Camera &cam = _view->getCamera(); Camera &cam = _view->getCamera();
_cameraFocalLength = focalLength; _cameraFocalLength = focalLength;
cam.setLensProjection(_cameraFocalLength, 1.0f, _near, const auto &vp = _view->getViewport();
if (vp.height == 0)
{
Log("Viewport height has not yet been set, returning");
return;
}
auto aspect = vp.width / vp.height;
cam.setLensProjection(_cameraFocalLength, aspect, _near,
_far); _far);
} }
@@ -858,8 +864,9 @@ namespace thermion_filament
Camera &cam = _view->getCamera(); Camera &cam = _view->getCamera();
_near = near; _near = near;
_far = far; _far = far;
cam.setLensProjection(_cameraFocalLength, 1.0f, _near, _far); const auto &vp = _view->getViewport();
Log("Set lens projection to focal length %f, near %f and far %f", _cameraFocalLength, _near, _far); auto aspect = vp.width / vp.height;
cam.setLensProjection(_cameraFocalLength, aspect, _near, _far);
} }
double FilamentViewer::getCameraCullingNear() double FilamentViewer::getCameraCullingNear()
@@ -1005,8 +1012,7 @@ namespace thermion_filament
ResourceBuffer* rb = (ResourceBuffer*) vec->at(1); ResourceBuffer* rb = (ResourceBuffer*) vec->at(1);
loader->free(*rb); loader->free(*rb);
delete rb; delete rb;
delete vec; delete vec; },
},
callbackData); callbackData);
_skybox = _skybox =
filament::Skybox::Builder().environment(_skyboxTexture).build(*_engine); filament::Skybox::Builder().environment(_skyboxTexture).build(*_engine);
@@ -1148,12 +1154,11 @@ namespace thermion_filament
_skippedFrames++; _skippedFrames++;
} }
// beginFrame = true;
if (beginFrame) if (beginFrame)
{ {
_renderer->render(_view); _renderer->render(_view);
_frameCount++; _frameCount++;
if (_recording) if (_recording)
@@ -1185,53 +1190,54 @@ namespace thermion_filament
} }
_renderer->endFrame(); _renderer->endFrame();
} }
#ifdef __EMSCRIPTEN__ #ifdef __EMSCRIPTEN__
_engine->execute(); _engine->execute();
#endif #endif
} }
void FilamentViewer::capture(uint8_t *out, void (*onComplete)()) { void FilamentViewer::capture(uint8_t *out, void (*onComplete)())
{
Viewport const &vp = _view->getViewport(); Viewport const &vp = _view->getViewport();
size_t pixelBufferSize = vp.width * vp.height * 4; size_t pixelBufferSize = vp.width * vp.height * 4;
auto *pixelBuffer = new uint8_t[pixelBufferSize]; auto *pixelBuffer = new uint8_t[pixelBufferSize];
auto callback = [](void *buf, size_t size, void *data) auto callback = [](void *buf, size_t size, void *data)
{ {
auto frameCallbackData = (std::vector<void *> *)data;
uint8_t *out = (uint8_t *)(frameCallbackData->at(0));
void *callbackPtr = frameCallbackData->at(1);
auto frameCallbackData = (std::vector<void*>*)data; void (*callback)(void) = (void (*)(void))callbackPtr;
uint8_t *out = (uint8_t *)(frameCallbackData->at(0)); memcpy(out, buf, size);
void* callbackPtr = frameCallbackData->at(1); delete frameCallbackData;
callback();
};
void (*callback)(void) = (void (*)(void))callbackPtr; auto userData = new std::vector<void *>{out, (void *)onComplete};
memcpy(out, buf, size);
delete frameCallbackData;
callback();
};
auto userData = new std::vector<void*> { out, (void*)onComplete } ; auto pbd = Texture::PixelBufferDescriptor(
pixelBuffer, pixelBufferSize,
Texture::Format::RGBA,
Texture::Type::UBYTE, nullptr, callback, userData);
_renderer->beginFrame(_swapChain, 0);
auto pbd = Texture::PixelBufferDescriptor( _renderer->render(_view);
pixelBuffer, pixelBufferSize,
Texture::Format::RGBA,
Texture::Type::UBYTE, nullptr, callback, userData);
_renderer->beginFrame(_swapChain, 0);
_renderer->render(_view); if (_rt)
{
if(_rt) { _renderer->readPixels(_rt, 0, 0, vp.width, vp.height, std::move(pbd));
_renderer->readPixels(_rt, 0, 0, vp.width, vp.height, std::move(pbd));
} else {
_renderer->readPixels(0, 0, vp.width, vp.height, std::move(pbd));
}
_renderer->endFrame();
#ifdef __EMSCRIPTEN__
_engine->execute();
emscripten_webgl_commit_frame();
#endif
} }
else
{
_renderer->readPixels(0, 0, vp.width, vp.height, std::move(pbd));
}
_renderer->endFrame();
#ifdef __EMSCRIPTEN__
_engine->execute();
emscripten_webgl_commit_frame();
#endif
}
void FilamentViewer::savePng(void *buf, size_t size, int frameNumber) void FilamentViewer::savePng(void *buf, size_t size, int frameNumber)
{ {
@@ -1319,10 +1325,14 @@ namespace thermion_filament
const double aspect = (double)width / height; const double aspect = (double)width / height;
Camera &cam = _view->getCamera(); Camera &cam = _view->getCamera();
cam.setLensProjection(_cameraFocalLength, 1.0f, _near,
cam.setLensProjection(_cameraFocalLength, aspect, _near,
_far); _far);
cam.setScaling({1.0 / aspect, 1.0}); // cam.setScaling({1.0 / aspect, 1.0});
// Camera &gizmoCam = _gizmoView->getCamera();
// gizmoCam.setScaling({1.0 / aspect, 1.0});
Log("Set viewport to width: %d height: %d aspect %f scaleFactor : %f", width, height, aspect, Log("Set viewport to width: %d height: %d aspect %f scaleFactor : %f", width, height, aspect,
contentScaleFactor); contentScaleFactor);
@@ -1333,11 +1343,18 @@ namespace thermion_filament
_view->setFrustumCullingEnabled(enabled); _view->setFrustumCullingEnabled(enabled);
} }
void FilamentViewer::setCameraFov(double fovInDegrees, double aspect) float FilamentViewer::getCameraFov(bool horizontal)
{ {
Camera &cam = _view->getCamera(); Camera &cam = _view->getCamera();
cam.setProjection(fovInDegrees, aspect, _near, _far, Camera::Fov::HORIZONTAL); return cam.getFieldOfViewInDegrees(horizontal ? Camera::Fov::HORIZONTAL : Camera::Fov::VERTICAL);
Log("Set camera projection fov to %f", fovInDegrees); }
void FilamentViewer::setCameraFov(double fovInDegrees, bool horizontal)
{
Camera &cam = _view->getCamera();
const auto &vp = _view->getViewport();
auto aspect = vp.width / vp.height;
cam.setProjection(fovInDegrees, aspect, _near, _far, horizontal ? Camera::Fov::HORIZONTAL : Camera::Fov::VERTICAL);
} }
void FilamentViewer::setCameraPosition(float x, float y, float z) void FilamentViewer::setCameraPosition(float x, float y, float z)
@@ -1494,14 +1511,14 @@ namespace thermion_filament
{ {
_createManipulator(); _createManipulator();
} }
if (pan) // if (pan)
{ // {
Log("Beginning pan at %f %f", x, y); // Log("Beginning pan at %f %f", x, y);
} // }
else // else
{ // {
Log("Beginning rotate at %f %f", x, y); // Log("Beginning rotate at %f %f", x, y);
} // }
_manipulator->grabBegin(x, y, pan); _manipulator->grabBegin(x, y, pan);
} }
@@ -1574,9 +1591,26 @@ namespace thermion_filament
_view->pick(x, y, [=](filament::View::PickingQueryResult const &result) _view->pick(x, y, [=](filament::View::PickingQueryResult const &result)
{ {
if(result.renderable != _imageEntity) {
callback(Entity::smuggle(result.renderable), x, y); Log("Picked entity %d at screen space (%f,%f,(%f))", result.renderable, result.fragCoords.x, result.fragCoords.y, result.fragCoords.z);
} }); auto* gizmo = _sceneManager->gizmo;
std::unordered_set<Entity, Entity::Hasher> nonPickableEntities = {
_imageEntity,
gizmo->center(),
_sceneManager->_gridOverlay->sphere(),
_sceneManager->_gridOverlay->grid(),
};
if(result.renderable == gizmo->x() || result.renderable == gizmo->y() || result.renderable == gizmo->z()) {
gizmo->highlight(result.renderable);
} else {
gizmo->unhighlight();
}
if (nonPickableEntities.find(result.renderable) == nonPickableEntities.end()) {
callback(Entity::smuggle(result.renderable), x, y);
} else {
Log("Ignored");
} });
} }
EntityId FilamentViewer::createGeometry(float *vertices, uint32_t numVertices, uint16_t *indices, uint32_t numIndices, RenderableManager::PrimitiveType primitiveType, const char *materialPath) EntityId FilamentViewer::createGeometry(float *vertices, uint32_t numVertices, uint16_t *indices, uint32_t numIndices, RenderableManager::PrimitiveType primitiveType, const char *materialPath)