From 908710acab1ea4292ac8d7924aba3c669e193eab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Thu, 29 Feb 2024 08:58:54 +0100 Subject: [PATCH 01/21] restructure js code --- package/src/FilamentView.tsx | 43 ++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/package/src/FilamentView.tsx b/package/src/FilamentView.tsx index 0fd3420f..2b5f6406 100644 --- a/package/src/FilamentView.tsx +++ b/package/src/FilamentView.tsx @@ -1,6 +1,6 @@ import React from 'react' import { findNodeHandle, NativeMethods, Platform } from 'react-native' -import { FilamentProxy, Listener } from './native/FilamentProxy' +import { FilamentProxy } from './native/FilamentProxy' import { FilamentNativeView, NativeProps } from './native/FilamentNativeView' type FilamentViewProps = NativeProps @@ -9,12 +9,13 @@ type RefType = React.Component & Readonly export class FilamentView extends React.PureComponent { private readonly ref: React.RefObject - private readonly choreographer = FilamentProxy.createChoreographer() - private choreographerListener: Listener | null = null + private readonly engine = FilamentProxy.createEngine() constructor(props: FilamentViewProps) { super(props) this.ref = React.createRef() + + this.setup3dScene() } // TODO: Does this also work for Fabric? @@ -30,32 +31,18 @@ export class FilamentView extends React.PureComponent { componentDidMount() { // TODO: lets get rid of this timeout setTimeout(() => { - this.setup3dScene() + this.setupSurface() }, 100) } - componentWillUnmount(): void { - this.choreographer.stop() - if (this.choreographerListener != null) { - this.choreographerListener.remove() - } - } - setup3dScene = () => { - // Get Surface: - const fView = FilamentProxy.findFilamentView(this.handle) - const surfaceProvider = fView.getSurfaceProvider() - - // Create engine: - const engine = FilamentProxy.createEngine() - // Load a model into the scene: const modelPath = Platform.select({ android: 'custom/pengu.glb', ios: 'pengu.glb', }) const modelBuffer = FilamentProxy.getAssetByteBuffer(modelPath!) - engine.loadAsset(modelBuffer) + this.engine.loadAsset(modelBuffer) // Create a default light: const indirectLightPath = Platform.select({ @@ -63,15 +50,23 @@ export class FilamentView extends React.PureComponent { ios: 'default_env_ibl.ktx', }) const indirectLightBuffer = FilamentProxy.getAssetByteBuffer(indirectLightPath!) - engine.createDefaultLight(indirectLightBuffer) + this.engine.createDefaultLight(indirectLightBuffer) + } + + renderCallback = () => { + this.engine.getCamera().lookAt(this.engine.getCameraManipulator()) + } + + setupSurface = () => { + // Get Surface: + const fView = FilamentProxy.findFilamentView(this.handle) + const surfaceProvider = fView.getSurfaceProvider() // Link the surface with the engine: - engine.setSurfaceProvider(surfaceProvider) + this.engine.setSurfaceProvider(surfaceProvider) // Callback for rendering every frame - engine.setRenderCallback(() => { - engine.getCamera().lookAt(engine.getCameraManipulator()) - }) + this.engine.setRenderCallback(this.renderCallback) } /** @internal */ From 14463f031998e0f4ec271710db2d4df044ee0fc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Thu, 29 Feb 2024 09:43:10 +0100 Subject: [PATCH 02/21] wip: separarte light creation --- package/cpp/core/EngineWrapper.cpp | 24 +++++++------- package/cpp/core/EngineWrapper.h | 8 ++++- package/cpp/core/LightEnum.h | 51 ++++++++++++++++++++++++++++++ package/src/FilamentView.tsx | 6 +++- package/src/types/Engine.ts | 15 ++++++++- 5 files changed, 90 insertions(+), 14 deletions(-) create mode 100644 package/cpp/core/LightEnum.h diff --git a/package/cpp/core/EngineWrapper.cpp b/package/cpp/core/EngineWrapper.cpp index ee4fedd1..bec084bd 100644 --- a/package/cpp/core/EngineWrapper.cpp +++ b/package/cpp/core/EngineWrapper.cpp @@ -58,7 +58,7 @@ EngineWrapper::~EngineWrapper() { void EngineWrapper::loadHybridMethods() { registerHybridMethod("setSurfaceProvider", &EngineWrapper::setSurfaceProvider, this); registerHybridMethod("setRenderCallback", &EngineWrapper::setRenderCallback, this); - registerHybridMethod("createDefaultLight", &EngineWrapper::createDefaultLight, this); + registerHybridMethod("setIndirectLight", &EngineWrapper::setIndirectLight, this); registerHybridMethod("loadAsset", &EngineWrapper::loadAsset, this); @@ -68,6 +68,7 @@ void EngineWrapper::loadHybridMethods() { registerHybridMethod("getView", &EngineWrapper::getView, this); registerHybridMethod("getCamera", &EngineWrapper::getCamera, this); registerHybridMethod("getCameraManipulator", &EngineWrapper::getCameraManipulator, this); + registerHybridMethod("createLightEntity", &EngineWrapper::createLightEntity, this); } void EngineWrapper::setSurfaceProvider(std::shared_ptr surfaceProvider) { @@ -226,7 +227,7 @@ void EngineWrapper::loadAsset(std::shared_ptr modelBuffer) { } // Default light is a directional light for shadows + a default IBL -void EngineWrapper::createDefaultLight(std::shared_ptr iblBuffer) { +void EngineWrapper::setIndirectLight(std::shared_ptr iblBuffer) { if (!_scene) { throw std::runtime_error("Scene not initialized"); } @@ -254,17 +255,18 @@ void EngineWrapper::createDefaultLight(std::shared_ptr iblBuffer IndirectLight::Builder().reflections(cubemap).irradiance(3, harmonics).intensity(30000.0f).build(*_engine); _scene->getScene()->setIndirectLight(_indirectLight); +} - // Add directional light for supporting shadows +std::shared_ptr EngineWrapper::createLightEntity(LightManager::Type type, float colorFahrenheit, float intensity, + float directionX, float directionY, float directionZ, bool castShadows) { auto lightEntity = _engine->getEntityManager().create(); - LightManager::Builder(LightManager::Type::DIRECTIONAL) - .color(Color::cct(6500.0f)) - .intensity(10000) - .direction({0, -1, 0}) - .castShadows(true) - .build(*_engine, lightEntity); - - _scene->getScene()->addEntity(lightEntity); + LightManager::Builder(type) + .color(Color::cct(colorFahrenheit)) + .intensity(intensity) + .direction({directionX, directionY, directionZ}) + .castShadows(castShadows) + .build(*_engine, lightEntity); + return std::make_shared(lightEntity); } std::shared_ptr EngineWrapper::createCameraManipulator(int width, int height) { diff --git a/package/cpp/core/EngineWrapper.h b/package/cpp/core/EngineWrapper.h index eaba2f98..b9c0ce57 100644 --- a/package/cpp/core/EngineWrapper.h +++ b/package/cpp/core/EngineWrapper.h @@ -6,6 +6,7 @@ #include "Surface.h" #include "SurfaceProvider.h" +#include "LightEnum.h" #include #include #include @@ -24,6 +25,7 @@ #include #include #include +#include namespace margelo { @@ -50,10 +52,14 @@ class EngineWrapper : public HybridObject { void transformToUnitCube(gltfio::FilamentAsset* asset); void loadAsset(std::shared_ptr modelBuffer); - void createDefaultLight(std::shared_ptr modelBuffer); + void setIndirectLight(std::shared_ptr modelBuffer); + void updateCameraProjection(); void synchronizePendingFrames(); + std::shared_ptr createLightEntity(LightManager::Type type, float colorFahrenheit, float intensity, float directionX, + float directionY, float directionZ, bool castShadows); + private: std::shared_ptr _engine; std::shared_ptr _surfaceProvider; diff --git a/package/cpp/core/LightEnum.h b/package/cpp/core/LightEnum.h new file mode 100644 index 00000000..4c2dc0f4 --- /dev/null +++ b/package/cpp/core/LightEnum.h @@ -0,0 +1,51 @@ +// +// Created by Hanno Gödecke on 29.02.24. +// + +#pragma once + +#include "jsi/EnumMapper.h" +#include + +namespace margelo { + +namespace EnumMapper { + using namespace filament; + + static void convertJSUnionToEnum(const std::string& inUnion, LightManager::Type* outEnum) { + if (inUnion == "directional") + *outEnum = LightManager::Type::DIRECTIONAL; + else if (inUnion == "spot") + *outEnum = LightManager::Type::SPOT; + else if (inUnion == "point") + *outEnum = LightManager::Type::POINT; + else if (inUnion == "focused_sport") + *outEnum = LightManager::Type::FOCUSED_SPOT; + else if (inUnion == "sun") + *outEnum = LightManager::Type::SUN; + else + throw invalidUnion(inUnion); + } + static void convertEnumToJSUnion(LightManager::Type inEnum, std::string* outUnion) { + switch (inEnum) { + case LightManager::Type::DIRECTIONAL: + *outUnion = "directional"; + break; + case LightManager::Type::SPOT: + *outUnion = "spot"; + break; + case LightManager::Type::POINT: + *outUnion = "point"; + break; + case LightManager::Type::FOCUSED_SPOT: + *outUnion = "focused_sport"; + break; + case LightManager::Type::SUN: + *outUnion = "sun"; + break; + default: + throw invalidEnum(static_cast(inEnum)); + } + } +} // namespace EnumMapper +} // namespace margelo diff --git a/package/src/FilamentView.tsx b/package/src/FilamentView.tsx index 2b5f6406..2619b967 100644 --- a/package/src/FilamentView.tsx +++ b/package/src/FilamentView.tsx @@ -50,7 +50,11 @@ export class FilamentView extends React.PureComponent { ios: 'default_env_ibl.ktx', }) const indirectLightBuffer = FilamentProxy.getAssetByteBuffer(indirectLightPath!) - this.engine.createDefaultLight(indirectLightBuffer) + this.engine.setIndirectLight(indirectLightBuffer) + + // Create a directional light for supporting shadows + const light = this.engine.createLightEntity(1, 0.98, 100000, 0.5, -1, 0.5, true) + this.engine.getScene().addEntity(light) } renderCallback = () => { diff --git a/package/src/types/Engine.ts b/package/src/types/Engine.ts index b97c62b3..02d774c8 100644 --- a/package/src/types/Engine.ts +++ b/package/src/types/Engine.ts @@ -5,17 +5,30 @@ import { Renderer } from './Renderer' import { Scene } from './Scene' import { View } from './View' import { FilamentBuffer } from '../native/FilamentBuffer' +import { Entity } from './Entity' export interface Engine { setSurfaceProvider(surfaceProvider: SurfaceProvider): void setRenderCallback(callback: (engine: Engine) => void): void loadAsset(buffer: FilamentBuffer): void - createDefaultLight(iblBuffer: FilamentBuffer): void + setIndirectLight(iblBuffer: FilamentBuffer): void getRenderer(): Renderer getScene(): Scene getCamera(): Camera getView(): View getCameraManipulator(): Manipulator + + // std::shared_ptr createLightEntity(LightManager::Type type, float colorFahrenheit, float intensity, float directionX, + // float directionY, float directionZ, bool castShadows); + createLightEntity( + type: number, + colorFahrenheit: number, + intensity: number, + directionX: number, + directionY: number, + directionZ: number, + castShadows: boolean, + ): Entity } From 53cb2298f77d8395d80a371c17c98f22ec4f7af5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Thu, 29 Feb 2024 10:08:35 +0100 Subject: [PATCH 03/21] use double instead of float --- package/cpp/core/EngineWrapper.cpp | 9 +++++---- package/cpp/core/EngineWrapper.h | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/package/cpp/core/EngineWrapper.cpp b/package/cpp/core/EngineWrapper.cpp index 1e8078a5..c759888f 100644 --- a/package/cpp/core/EngineWrapper.cpp +++ b/package/cpp/core/EngineWrapper.cpp @@ -5,6 +5,7 @@ #include "EngineWrapper.h" #include "References.h" + #include #include #include @@ -262,12 +263,12 @@ void EngineWrapper::setIndirectLight(std::shared_ptr iblBuffer) _scene->getScene()->setIndirectLight(_indirectLight); } -std::shared_ptr EngineWrapper::createLightEntity(LightManager::Type type, float colorFahrenheit, float intensity, - float directionX, float directionY, float directionZ, bool castShadows) { +std::shared_ptr EngineWrapper::createLightEntity(LightManager::Type type, double colorFahrenheit, double intensity, + double directionX, double directionY, double directionZ, bool castShadows) { auto lightEntity = _engine->getEntityManager().create(); LightManager::Builder(type) - .color(Color::cct(colorFahrenheit)) - .intensity(intensity) + .color(Color::cct(static_cast(colorFahrenheit))) + .intensity(static_cast(intensity)) .direction({directionX, directionY, directionZ}) .castShadows(castShadows) .build(*_engine, lightEntity); diff --git a/package/cpp/core/EngineWrapper.h b/package/cpp/core/EngineWrapper.h index b9c0ce57..1c76e721 100644 --- a/package/cpp/core/EngineWrapper.h +++ b/package/cpp/core/EngineWrapper.h @@ -57,8 +57,8 @@ class EngineWrapper : public HybridObject { void updateCameraProjection(); void synchronizePendingFrames(); - std::shared_ptr createLightEntity(LightManager::Type type, float colorFahrenheit, float intensity, float directionX, - float directionY, float directionZ, bool castShadows); + std::shared_ptr createLightEntity(LightManager::Type type, double colorFahrenheit, double intensity, double directionX, + double directionY, double directionZ, bool castShadows); private: std::shared_ptr _engine; From 2efe5a896d6e591994eabda9c8f127a52bb6d7d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Thu, 29 Feb 2024 10:24:56 +0100 Subject: [PATCH 04/21] remove cast --- package/cpp/core/LightEnum.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/cpp/core/LightEnum.h b/package/cpp/core/LightEnum.h index 4c2dc0f4..c0d0e80e 100644 --- a/package/cpp/core/LightEnum.h +++ b/package/cpp/core/LightEnum.h @@ -44,7 +44,7 @@ namespace EnumMapper { *outUnion = "sun"; break; default: - throw invalidEnum(static_cast(inEnum)); + throw invalidEnum(inEnum); } } } // namespace EnumMapper From 958fa4a8508e4f23819db55e3f81278fa8322c22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Thu, 29 Feb 2024 10:43:46 +0100 Subject: [PATCH 05/21] create correct light in JS --- package/cpp/core/EngineWrapper.cpp | 10 +++++----- package/src/FilamentView.tsx | 2 +- package/src/types/Engine.ts | 4 +--- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/package/cpp/core/EngineWrapper.cpp b/package/cpp/core/EngineWrapper.cpp index c759888f..ab27c188 100644 --- a/package/cpp/core/EngineWrapper.cpp +++ b/package/cpp/core/EngineWrapper.cpp @@ -267,11 +267,11 @@ std::shared_ptr EngineWrapper::createLightEntity(LightManager::Ty double directionX, double directionY, double directionZ, bool castShadows) { auto lightEntity = _engine->getEntityManager().create(); LightManager::Builder(type) - .color(Color::cct(static_cast(colorFahrenheit))) - .intensity(static_cast(intensity)) - .direction({directionX, directionY, directionZ}) - .castShadows(castShadows) - .build(*_engine, lightEntity); + .color(Color::cct(static_cast(colorFahrenheit))) + .intensity(static_cast(intensity)) + .direction({directionX, directionY, directionZ}) + .castShadows(castShadows) + .build(*_engine, lightEntity); return std::make_shared(lightEntity); } diff --git a/package/src/FilamentView.tsx b/package/src/FilamentView.tsx index 2619b967..dc236199 100644 --- a/package/src/FilamentView.tsx +++ b/package/src/FilamentView.tsx @@ -53,7 +53,7 @@ export class FilamentView extends React.PureComponent { this.engine.setIndirectLight(indirectLightBuffer) // Create a directional light for supporting shadows - const light = this.engine.createLightEntity(1, 0.98, 100000, 0.5, -1, 0.5, true) + const light = this.engine.createLightEntity('directional', 6500, 10000, 0, -1, 0, true) this.engine.getScene().addEntity(light) } diff --git a/package/src/types/Engine.ts b/package/src/types/Engine.ts index 02d774c8..9dcf2243 100644 --- a/package/src/types/Engine.ts +++ b/package/src/types/Engine.ts @@ -20,10 +20,8 @@ export interface Engine { getView(): View getCameraManipulator(): Manipulator - // std::shared_ptr createLightEntity(LightManager::Type type, float colorFahrenheit, float intensity, float directionX, - // float directionY, float directionZ, bool castShadows); createLightEntity( - type: number, + type: 'directional' | 'spot' | 'point' | 'focused_point' | 'sun', colorFahrenheit: number, intensity: number, directionX: number, From a178794bbbfe0399f8f0d57b444e536363e2189e Mon Sep 17 00:00:00 2001 From: Marc Rousavy Date: Thu, 29 Feb 2024 10:55:15 +0100 Subject: [PATCH 06/21] fix: Fix enums not converting properly (#19) --- package/cpp/core/EngineWrapper.cpp | 1 + package/cpp/core/EngineWrapper.h | 2 +- package/cpp/core/LightEnum.h | 2 +- package/cpp/jsi/EnumMapper.h | 25 ++++++++++++++++++++----- package/cpp/jsi/JSIConverter.h | 2 +- package/cpp/test/TestEnum.h | 2 +- package/src/types/Engine.ts | 2 +- 7 files changed, 26 insertions(+), 10 deletions(-) diff --git a/package/cpp/core/EngineWrapper.cpp b/package/cpp/core/EngineWrapper.cpp index ab27c188..dadb272c 100644 --- a/package/cpp/core/EngineWrapper.cpp +++ b/package/cpp/core/EngineWrapper.cpp @@ -6,6 +6,7 @@ #include "References.h" +#include "LightEnum.h" #include #include #include diff --git a/package/cpp/core/EngineWrapper.h b/package/cpp/core/EngineWrapper.h index 1c76e721..ef2e38b7 100644 --- a/package/cpp/core/EngineWrapper.h +++ b/package/cpp/core/EngineWrapper.h @@ -4,9 +4,9 @@ #pragma once +#include "LightEnum.h" #include "Surface.h" #include "SurfaceProvider.h" -#include "LightEnum.h" #include #include #include diff --git a/package/cpp/core/LightEnum.h b/package/cpp/core/LightEnum.h index c0d0e80e..f878ac59 100644 --- a/package/cpp/core/LightEnum.h +++ b/package/cpp/core/LightEnum.h @@ -24,7 +24,7 @@ namespace EnumMapper { else if (inUnion == "sun") *outEnum = LightManager::Type::SUN; else - throw invalidUnion(inUnion); + throw invalidUnion(inUnion); } static void convertEnumToJSUnion(LightManager::Type inEnum, std::string* outUnion) { switch (inEnum) { diff --git a/package/cpp/jsi/EnumMapper.h b/package/cpp/jsi/EnumMapper.h index 7f2a7513..931a026a 100644 --- a/package/cpp/jsi/EnumMapper.h +++ b/package/cpp/jsi/EnumMapper.h @@ -14,20 +14,35 @@ namespace EnumMapper { // 1. `static void convertJSUnionToEnum(const std::string& inUnion, Enum* outEnum)` // 2. `static void convertEnumToJSUnion(Enum inEnum, std::string* outUnion)` - static std::runtime_error invalidUnion(const std::string& passedUnion) { + template static std::runtime_error invalidUnion(const std::string& passedUnion) { return std::runtime_error("Cannot convert JS Value to Enum: Invalid Union value passed! (\"" + std::string(passedUnion) + "\")"); } + template static std::runtime_error invalidEnum(T passedEnum) { return std::runtime_error("Cannot convert Enum to JS Value: Invalid Enum passed! (Value #" + std::to_string(static_cast(passedEnum)) + ")"); } - static void convertJSUnionToEnum(const std::string& inUnion, int*) { - throw invalidUnion(inUnion); + // Trait to check if a convertJSUnionToEnum function for enum type T exists + template struct has_js_union_to_enum : std::false_type {}; + template + struct has_js_union_to_enum(), std::declval()))>> + : std::true_type {}; + + // Trait to check if a convertEnumToJSUnion function for enum type T exists + template struct has_enum_to_js_union : std::false_type {}; + template + struct has_enum_to_js_union(), std::declval()))>> + : std::true_type {}; + + template static void convertJSUnionToEnum(const std::string&, TEnum*) { + static_assert(has_js_union_to_enum::value, + "Cannot convert a JS union to this enum type. Did you implement EnumMapper::convertJSUnionToEnum(...)?"); } - static void convertEnumToJSUnion(int inEnum, std::string*) { - throw invalidEnum(inEnum); + template static void convertEnumToJSUnion(TEnum, std::string*) { + static_assert(has_enum_to_js_union::value, + "Cannot convert this enum type to a JS union. Did you implement EnumMapper::convertEnumToJSUnion(...)?"); } } // namespace EnumMapper diff --git a/package/cpp/jsi/JSIConverter.h b/package/cpp/jsi/JSIConverter.h index 20094973..036f4329 100644 --- a/package/cpp/jsi/JSIConverter.h +++ b/package/cpp/jsi/JSIConverter.h @@ -108,7 +108,7 @@ template struct JSIConverter(inUnion); } static void convertEnumToJSUnion(TestEnum inEnum, std::string* outUnion) { switch (inEnum) { diff --git a/package/src/types/Engine.ts b/package/src/types/Engine.ts index 9dcf2243..a158521f 100644 --- a/package/src/types/Engine.ts +++ b/package/src/types/Engine.ts @@ -27,6 +27,6 @@ export interface Engine { directionX: number, directionY: number, directionZ: number, - castShadows: boolean, + castShadows: boolean ): Entity } From c27be15e92d313355b2535a916bc255f9b600df2 Mon Sep 17 00:00:00 2001 From: Marc Rousavy Date: Thu, 29 Feb 2024 10:57:32 +0100 Subject: [PATCH 07/21] fix: Remove unneeded template --- package/cpp/jsi/EnumMapper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/cpp/jsi/EnumMapper.h b/package/cpp/jsi/EnumMapper.h index 931a026a..67153bf3 100644 --- a/package/cpp/jsi/EnumMapper.h +++ b/package/cpp/jsi/EnumMapper.h @@ -14,7 +14,7 @@ namespace EnumMapper { // 1. `static void convertJSUnionToEnum(const std::string& inUnion, Enum* outEnum)` // 2. `static void convertEnumToJSUnion(Enum inEnum, std::string* outUnion)` - template static std::runtime_error invalidUnion(const std::string& passedUnion) { + static std::runtime_error invalidUnion(const std::string& passedUnion) { return std::runtime_error("Cannot convert JS Value to Enum: Invalid Union value passed! (\"" + std::string(passedUnion) + "\")"); } From b335d8015cd079396928205e38a36aa19fde1023 Mon Sep 17 00:00:00 2001 From: Marc Rousavy Date: Thu, 29 Feb 2024 11:32:38 +0100 Subject: [PATCH 08/21] fix: Fix invalidUnion template arg --- package/cpp/core/LightEnum.h | 2 +- package/cpp/test/TestEnum.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package/cpp/core/LightEnum.h b/package/cpp/core/LightEnum.h index f878ac59..c0d0e80e 100644 --- a/package/cpp/core/LightEnum.h +++ b/package/cpp/core/LightEnum.h @@ -24,7 +24,7 @@ namespace EnumMapper { else if (inUnion == "sun") *outEnum = LightManager::Type::SUN; else - throw invalidUnion(inUnion); + throw invalidUnion(inUnion); } static void convertEnumToJSUnion(LightManager::Type inEnum, std::string* outUnion) { switch (inEnum) { diff --git a/package/cpp/test/TestEnum.h b/package/cpp/test/TestEnum.h index c084be71..053c71bd 100644 --- a/package/cpp/test/TestEnum.h +++ b/package/cpp/test/TestEnum.h @@ -19,7 +19,7 @@ namespace EnumMapper { else if (inUnion == "third") *outEnum = TestEnum::THIRD; else - throw invalidUnion(inUnion); + throw invalidUnion(inUnion); } static void convertEnumToJSUnion(TestEnum inEnum, std::string* outUnion) { switch (inEnum) { From b947cc762c52916cb9c449bd280eaa81658c0ee8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Thu, 29 Feb 2024 15:48:33 +0100 Subject: [PATCH 09/21] wip: restructure --- package/android/CMakeLists.txt | 1 + package/cpp/core/EngineWrapper.cpp | 22 ++++++-------- package/cpp/core/EngineWrapper.h | 35 ++++++++++++----------- package/cpp/core/FilamentAssetWrapper.cpp | 25 ++++++++++++++++ package/cpp/core/FilamentAssetWrapper.h | 23 +++++++++++++++ 5 files changed, 76 insertions(+), 30 deletions(-) create mode 100644 package/cpp/core/FilamentAssetWrapper.cpp create mode 100644 package/cpp/core/FilamentAssetWrapper.h diff --git a/package/android/CMakeLists.txt b/package/android/CMakeLists.txt index 0c545e10..a97a215d 100644 --- a/package/android/CMakeLists.txt +++ b/package/android/CMakeLists.txt @@ -36,6 +36,7 @@ add_library( ../cpp/core/CameraWrapper.cpp ../cpp/core/ViewWrapper.cpp ../cpp/core/SwapChainWrapper.cpp + ../cpp/core/FilamentAssetWrapper.cpp # Filament Utils ../cpp/core/utils/EntityWrapper.cpp diff --git a/package/cpp/core/EngineWrapper.cpp b/package/cpp/core/EngineWrapper.cpp index dadb272c..8a81c224 100644 --- a/package/cpp/core/EngineWrapper.cpp +++ b/package/cpp/core/EngineWrapper.cpp @@ -5,8 +5,8 @@ #include "EngineWrapper.h" #include "References.h" - #include "LightEnum.h" + #include #include #include @@ -211,8 +211,8 @@ std::shared_ptr EngineWrapper::createCamera() { return std::make_shared(camera); } -void EngineWrapper::loadAsset(std::shared_ptr modelBuffer) { - filament::gltfio::FilamentAsset* asset = _assetLoader->createAsset(modelBuffer->getData(), modelBuffer->getSize()); +std::shared_ptr EngineWrapper::loadAsset(std::shared_ptr modelBuffer) { + gltfio::FilamentAsset* asset = _assetLoader->createAsset(modelBuffer->getData(), modelBuffer->getSize()); if (asset == nullptr) { throw std::runtime_error("Failed to load asset"); } @@ -230,7 +230,10 @@ void EngineWrapper::loadAsset(std::shared_ptr modelBuffer) { _animator = asset->getInstance()->getAnimator(); asset->releaseSourceData(); - transformToUnitCube(asset); + auto sharedPtr = std::shared_ptr(asset, [](gltfio::FilamentAsset* asset) { + // TODO: destroy the asset + }); + return std::make_shared(sharedPtr); } // Default light is a directional light for shadows + a default IBL @@ -290,16 +293,9 @@ std::shared_ptr EngineWrapper::createCameraManipulator(int w /** * Sets up a root transform on the current model to make it fit into a unit cube. */ -void EngineWrapper::transformToUnitCube(filament::gltfio::FilamentAsset* asset) { +void EngineWrapper::transformToUnitCube(const std::shared_ptr& asset) { TransformManager& tm = _engine->getTransformManager(); - Aabb aabb = asset->getBoundingBox(); - math::details::TVec3 center = aabb.center(); - math::details::TVec3 halfExtent = aabb.extent(); - float maxExtent = max(halfExtent) * 2.0f; - float scaleFactor = 2.0f / maxExtent; - math::mat4f transform = math::mat4f::scaling(scaleFactor) * math::mat4f::translation(-center); - EntityInstance transformInstance = tm.getInstance(asset->getRoot()); - tm.setTransform(transformInstance, transform); + asset->transformToUnitCube(tm); } void EngineWrapper::updateCameraProjection() { diff --git a/package/cpp/core/EngineWrapper.h b/package/cpp/core/EngineWrapper.h index ef2e38b7..f966b676 100644 --- a/package/cpp/core/EngineWrapper.h +++ b/package/cpp/core/EngineWrapper.h @@ -4,28 +4,29 @@ #pragma once -#include "LightEnum.h" -#include "Surface.h" -#include "SurfaceProvider.h" -#include -#include -#include -#include -#include -#include -#include +#include "jsi/HybridObject.h" #include "CameraWrapper.h" +#include "Choreographer.h" +#include "FilamentAssetWrapper.h" +#include "FilamentBuffer.h" #include "RendererWrapper.h" #include "SceneWrapper.h" +#include "Surface.h" +#include "SurfaceProvider.h" #include "SwapChainWrapper.h" #include "ViewWrapper.h" -#include "jsi/HybridObject.h" -#include -#include +#include "core/utils/EntityWrapper.h" +#include "core/utils/ManipulatorWrapper.h" + #include -#include +#include #include +#include +#include +#include +#include +#include namespace margelo { @@ -50,8 +51,8 @@ class EngineWrapper : public HybridObject { void setRenderCallback(std::function)> callback); void renderFrame(double timestamp); - void transformToUnitCube(gltfio::FilamentAsset* asset); - void loadAsset(std::shared_ptr modelBuffer); + void transformToUnitCube(const std::shared_ptr& asset); + std::shared_ptr loadAsset(std::shared_ptr modelBuffer); void setIndirectLight(std::shared_ptr modelBuffer); void updateCameraProjection(); @@ -77,7 +78,7 @@ class EngineWrapper : public HybridObject { gltfio::ResourceLoader* _resourceLoader; const math::float3 defaultObjectPosition = {0.0f, 0.0f, 0.0f}; - const math::float3 defaultCameraPosition = {0.0f, 0.0f, 5.0f}; + const math::float3 defaultCameraPosition = {0.0f, 0.0f, 0.0f}; private: // Internals we create, but share the access with the user diff --git a/package/cpp/core/FilamentAssetWrapper.cpp b/package/cpp/core/FilamentAssetWrapper.cpp new file mode 100644 index 00000000..beadf70d --- /dev/null +++ b/package/cpp/core/FilamentAssetWrapper.cpp @@ -0,0 +1,25 @@ +#include "FilamentAssetWrapper.h" + +#include + +namespace margelo { + +using namespace utils; + +void FilamentAssetWrapper::loadHybridMethods() {} + +/** + * Sets up a root transform on the current model to make it fit into a unit cube. + */ +void FilamentAssetWrapper::transformToUnitCube(TransformManager& transformManager) { + Aabb aabb = _asset->getBoundingBox(); + math::details::TVec3 center = aabb.center(); + math::details::TVec3 halfExtent = aabb.extent(); + float maxExtent = max(halfExtent) * 2.0f; + float scaleFactor = 2.0f / maxExtent; + math::mat4f transform = math::mat4f::scaling(scaleFactor) * math::mat4f::translation(-center); + EntityInstance transformInstance = transformManager.getInstance(_asset->getRoot()); + transformManager.setTransform(transformInstance, transform); +} + +} // namespace margelo \ No newline at end of file diff --git a/package/cpp/core/FilamentAssetWrapper.h b/package/cpp/core/FilamentAssetWrapper.h new file mode 100644 index 00000000..ca07580c --- /dev/null +++ b/package/cpp/core/FilamentAssetWrapper.h @@ -0,0 +1,23 @@ +#pragma once + +#include "jsi/HybridObject.h" +#include +#include + +namespace margelo { + +using namespace filament; + +class FilamentAssetWrapper : public HybridObject { +public: + explicit FilamentAssetWrapper(std::shared_ptr asset) : _asset(asset) {} + + void loadHybridMethods() override; + + void transformToUnitCube(TransformManager& transformManager); + +private: + std::shared_ptr _asset; +}; + +} // namespace margelo From 6ba1383084e5fcb911bd7b261f53dc86376cad49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Thu, 29 Feb 2024 15:52:56 +0100 Subject: [PATCH 10/21] temp --- package/cpp/core/EngineWrapper.cpp | 8 ++++++-- package/cpp/core/EngineWrapper.h | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/package/cpp/core/EngineWrapper.cpp b/package/cpp/core/EngineWrapper.cpp index 8a81c224..4221fd21 100644 --- a/package/cpp/core/EngineWrapper.cpp +++ b/package/cpp/core/EngineWrapper.cpp @@ -267,10 +267,14 @@ void EngineWrapper::setIndirectLight(std::shared_ptr iblBuffer) _scene->getScene()->setIndirectLight(_indirectLight); } -std::shared_ptr EngineWrapper::createLightEntity(LightManager::Type type, double colorFahrenheit, double intensity, +std::shared_ptr EngineWrapper::createLightEntity(const std::string& type, double colorFahrenheit, double intensity, double directionX, double directionY, double directionZ, bool castShadows) { auto lightEntity = _engine->getEntityManager().create(); - LightManager::Builder(type) + + LightManager::Type outLightType; + EnumMapper::convertJSUnionToEnum(type, &outLightType); + + LightManager::Builder(outLightType) .color(Color::cct(static_cast(colorFahrenheit))) .intensity(static_cast(intensity)) .direction({directionX, directionY, directionZ}) diff --git a/package/cpp/core/EngineWrapper.h b/package/cpp/core/EngineWrapper.h index f966b676..9d131b0e 100644 --- a/package/cpp/core/EngineWrapper.h +++ b/package/cpp/core/EngineWrapper.h @@ -58,7 +58,7 @@ class EngineWrapper : public HybridObject { void updateCameraProjection(); void synchronizePendingFrames(); - std::shared_ptr createLightEntity(LightManager::Type type, double colorFahrenheit, double intensity, double directionX, + std::shared_ptr createLightEntity(const std::string& type, double colorFahrenheit, double intensity, double directionX, double directionY, double directionZ, bool castShadows); private: From 4c995b06c09adfbcef0b17135990a1ae8c7a11bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Thu, 29 Feb 2024 16:05:45 +0100 Subject: [PATCH 11/21] use string for now --- package/cpp/core/EngineWrapper.cpp | 9 +++++---- package/cpp/core/EngineWrapper.h | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/package/cpp/core/EngineWrapper.cpp b/package/cpp/core/EngineWrapper.cpp index 4221fd21..36a494d1 100644 --- a/package/cpp/core/EngineWrapper.cpp +++ b/package/cpp/core/EngineWrapper.cpp @@ -267,14 +267,15 @@ void EngineWrapper::setIndirectLight(std::shared_ptr iblBuffer) _scene->getScene()->setIndirectLight(_indirectLight); } -std::shared_ptr EngineWrapper::createLightEntity(const std::string& type, double colorFahrenheit, double intensity, +std::shared_ptr EngineWrapper::createLightEntity(std::string lightTypeStr, double colorFahrenheit, double intensity, double directionX, double directionY, double directionZ, bool castShadows) { auto lightEntity = _engine->getEntityManager().create(); - LightManager::Type outLightType; - EnumMapper::convertJSUnionToEnum(type, &outLightType); + // TODO(Marc): Fix enum converter + LightManager::Type lightType; + EnumMapper::convertJSUnionToEnum(lightTypeStr, &lightType); - LightManager::Builder(outLightType) + LightManager::Builder(lightType) .color(Color::cct(static_cast(colorFahrenheit))) .intensity(static_cast(intensity)) .direction({directionX, directionY, directionZ}) diff --git a/package/cpp/core/EngineWrapper.h b/package/cpp/core/EngineWrapper.h index 9d131b0e..e6e47977 100644 --- a/package/cpp/core/EngineWrapper.h +++ b/package/cpp/core/EngineWrapper.h @@ -58,7 +58,7 @@ class EngineWrapper : public HybridObject { void updateCameraProjection(); void synchronizePendingFrames(); - std::shared_ptr createLightEntity(const std::string& type, double colorFahrenheit, double intensity, double directionX, + std::shared_ptr createLightEntity(std::string lightTypeStr, double colorFahrenheit, double intensity, double directionX, double directionY, double directionZ, bool castShadows); private: From d71bdd01748081fa9a708b8afd64387978246ccd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Thu, 29 Feb 2024 16:11:22 +0100 Subject: [PATCH 12/21] expose transform to unit cube --- package/cpp/core/EngineWrapper.cpp | 3 ++- package/cpp/core/EngineWrapper.h | 2 +- package/src/FilamentView.tsx | 3 ++- package/src/types/Engine.ts | 7 +++++-- package/src/types/FilamentAsset.ts | 5 +++++ 5 files changed, 15 insertions(+), 5 deletions(-) create mode 100644 package/src/types/FilamentAsset.ts diff --git a/package/cpp/core/EngineWrapper.cpp b/package/cpp/core/EngineWrapper.cpp index 36a494d1..97163b01 100644 --- a/package/cpp/core/EngineWrapper.cpp +++ b/package/cpp/core/EngineWrapper.cpp @@ -76,6 +76,7 @@ void EngineWrapper::loadHybridMethods() { registerHybridMethod("getCamera", &EngineWrapper::getCamera, this); registerHybridMethod("getCameraManipulator", &EngineWrapper::getCameraManipulator, this); registerHybridMethod("createLightEntity", &EngineWrapper::createLightEntity, this); + registerHybridMethod("transformToUnitCube", &EngineWrapper::transformToUnitCube, this); } void EngineWrapper::setSurfaceProvider(std::shared_ptr surfaceProvider) { @@ -298,7 +299,7 @@ std::shared_ptr EngineWrapper::createCameraManipulator(int w /** * Sets up a root transform on the current model to make it fit into a unit cube. */ -void EngineWrapper::transformToUnitCube(const std::shared_ptr& asset) { +void EngineWrapper::transformToUnitCube(std::shared_ptr asset) { TransformManager& tm = _engine->getTransformManager(); asset->transformToUnitCube(tm); } diff --git a/package/cpp/core/EngineWrapper.h b/package/cpp/core/EngineWrapper.h index e6e47977..2fdebe28 100644 --- a/package/cpp/core/EngineWrapper.h +++ b/package/cpp/core/EngineWrapper.h @@ -51,7 +51,7 @@ class EngineWrapper : public HybridObject { void setRenderCallback(std::function)> callback); void renderFrame(double timestamp); - void transformToUnitCube(const std::shared_ptr& asset); + void transformToUnitCube(std::shared_ptr asset); std::shared_ptr loadAsset(std::shared_ptr modelBuffer); void setIndirectLight(std::shared_ptr modelBuffer); diff --git a/package/src/FilamentView.tsx b/package/src/FilamentView.tsx index dc236199..f860d12d 100644 --- a/package/src/FilamentView.tsx +++ b/package/src/FilamentView.tsx @@ -42,7 +42,8 @@ export class FilamentView extends React.PureComponent { ios: 'pengu.glb', }) const modelBuffer = FilamentProxy.getAssetByteBuffer(modelPath!) - this.engine.loadAsset(modelBuffer) + const penguAsset = this.engine.loadAsset(modelBuffer) + this.engine.transformToUnitCube(penguAsset) // Create a default light: const indirectLightPath = Platform.select({ diff --git a/package/src/types/Engine.ts b/package/src/types/Engine.ts index a158521f..626fd066 100644 --- a/package/src/types/Engine.ts +++ b/package/src/types/Engine.ts @@ -6,12 +6,13 @@ import { Scene } from './Scene' import { View } from './View' import { FilamentBuffer } from '../native/FilamentBuffer' import { Entity } from './Entity' +import { FilamentAsset } from './FilamentAsset' export interface Engine { setSurfaceProvider(surfaceProvider: SurfaceProvider): void setRenderCallback(callback: (engine: Engine) => void): void - loadAsset(buffer: FilamentBuffer): void + loadAsset(buffer: FilamentBuffer): FilamentAsset setIndirectLight(iblBuffer: FilamentBuffer): void getRenderer(): Renderer @@ -27,6 +28,8 @@ export interface Engine { directionX: number, directionY: number, directionZ: number, - castShadows: boolean + castShadows: boolean, ): Entity + + transformToUnitCube(entity: FilamentAsset): void } diff --git a/package/src/types/FilamentAsset.ts b/package/src/types/FilamentAsset.ts new file mode 100644 index 00000000..f3d11e03 --- /dev/null +++ b/package/src/types/FilamentAsset.ts @@ -0,0 +1,5 @@ +import type { Entity } from './Entity' + +export interface FilamentAsset { + getRoot(): Entity +} From de2b1b7f5f5f75dafd7d75b43ddffbe8c8acf487 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Thu, 29 Feb 2024 16:43:25 +0100 Subject: [PATCH 13/21] camera look at --- package/cpp/core/CameraWrapper.cpp | 12 ++++++++++-- package/cpp/core/CameraWrapper.h | 3 ++- package/src/FilamentView.tsx | 27 +++++++++++++++++---------- package/src/types/Camera.ts | 12 ++++++++++-- package/src/types/float3.ts | 4 ++++ 5 files changed, 43 insertions(+), 15 deletions(-) create mode 100644 package/src/types/float3.ts diff --git a/package/cpp/core/CameraWrapper.cpp b/package/cpp/core/CameraWrapper.cpp index e10d417b..44628345 100644 --- a/package/cpp/core/CameraWrapper.cpp +++ b/package/cpp/core/CameraWrapper.cpp @@ -1,10 +1,11 @@ #include "CameraWrapper.h" void margelo::CameraWrapper::loadHybridMethods() { - registerHybridMethod("lookAt", &CameraWrapper::lookAt, this); + registerHybridMethod("lookAtCameraManipulator", &CameraWrapper::lookAtCameraManipulator, this); + registerHybridMethod("lookAt", &CameraWrapper::lookAt, this); } -void margelo::CameraWrapper::lookAt(std::shared_ptr cameraManipulator) { +void margelo::CameraWrapper::lookAtCameraManipulator(std::shared_ptr cameraManipulator) { if (!cameraManipulator) { throw std::invalid_argument("CameraManipulator is null"); } @@ -13,3 +14,10 @@ void margelo::CameraWrapper::lookAt(std::shared_ptr cameraMa cameraManipulator->getManipulator()->getLookAt(&eye, ¢er, &up); _camera->lookAt(eye, center, up); } + +void margelo::CameraWrapper::lookAt(std::vector eye, std::vector center, std::vector up) { + math::float3 eyeVec = {static_cast(eye[0]), static_cast(eye[1]), static_cast(eye[2])}; + math::float3 centerVec = {static_cast(center[0]), static_cast(center[1]), static_cast(center[2])}; + math::float3 upVec = {static_cast(up[0]), static_cast(up[1]), static_cast(up[2])}; + _camera->lookAt(eyeVec, centerVec, upVec); +} diff --git a/package/cpp/core/CameraWrapper.h b/package/cpp/core/CameraWrapper.h index b2c9bc88..ae5876eb 100644 --- a/package/cpp/core/CameraWrapper.h +++ b/package/cpp/core/CameraWrapper.h @@ -22,7 +22,8 @@ class CameraWrapper : public HybridObject { std::shared_ptr _camera; private: + void lookAt(std::vector eye, std::vector center, std::vector up); // Convenience methods - void lookAt(std::shared_ptr cameraManipulator); + void lookAtCameraManipulator(std::shared_ptr cameraManipulator); }; } // namespace margelo \ No newline at end of file diff --git a/package/src/FilamentView.tsx b/package/src/FilamentView.tsx index f860d12d..16497a28 100644 --- a/package/src/FilamentView.tsx +++ b/package/src/FilamentView.tsx @@ -2,11 +2,22 @@ import React from 'react' import { findNodeHandle, NativeMethods, Platform } from 'react-native' import { FilamentProxy } from './native/FilamentProxy' import { FilamentNativeView, NativeProps } from './native/FilamentNativeView' +import type { Float3 } from './types/float3' type FilamentViewProps = NativeProps type RefType = React.Component & Readonly +const penguModelPath = Platform.select({ + android: 'custom/pengu.glb', + ios: 'pengu.glb', +}) + +const indirectLightPath = Platform.select({ + android: 'custom/default_env_ibl.ktx', + ios: 'default_env_ibl.ktx', +}) + export class FilamentView extends React.PureComponent { private readonly ref: React.RefObject private readonly engine = FilamentProxy.createEngine() @@ -37,19 +48,11 @@ export class FilamentView extends React.PureComponent { setup3dScene = () => { // Load a model into the scene: - const modelPath = Platform.select({ - android: 'custom/pengu.glb', - ios: 'pengu.glb', - }) - const modelBuffer = FilamentProxy.getAssetByteBuffer(modelPath!) + const modelBuffer = FilamentProxy.getAssetByteBuffer(penguModelPath!) const penguAsset = this.engine.loadAsset(modelBuffer) this.engine.transformToUnitCube(penguAsset) // Create a default light: - const indirectLightPath = Platform.select({ - android: 'custom/default_env_ibl.ktx', - ios: 'default_env_ibl.ktx', - }) const indirectLightBuffer = FilamentProxy.getAssetByteBuffer(indirectLightPath!) this.engine.setIndirectLight(indirectLightBuffer) @@ -59,7 +62,11 @@ export class FilamentView extends React.PureComponent { } renderCallback = () => { - this.engine.getCamera().lookAt(this.engine.getCameraManipulator()) + const cameraPosition: Float3 = [0, 0, 5] + const cameraTarget: Float3 = [0, 0, 0] + const cameraUp: Float3 = [0, 1, 0] + + this.engine.getCamera().lookAt(cameraPosition, cameraTarget, cameraUp) } setupSurface = () => { diff --git a/package/src/types/Camera.ts b/package/src/types/Camera.ts index 1a6f4903..974442e2 100644 --- a/package/src/types/Camera.ts +++ b/package/src/types/Camera.ts @@ -1,4 +1,5 @@ import { Manipulator } from './Manipulator' +import { Float3 } from './float3' /** * Camera represents the eye through which the scene is viewed. @@ -79,6 +80,13 @@ import { Manipulator } from './Manipulator' */ export interface Camera { - // Convenience method. The original method works slightly different, this is a simplification, so we don't have to deal with out params. - lookAt(cameraManipulator: Manipulator): void + // Convenience method + lookAtCameraManipulator(cameraManipulator: Manipulator): void + /** + * + * @param eye The position of the camera in space + * @param center The target position to look at + * @param up The up vector of the camera (Usually (0, 1, 0)) + */ + lookAt(eye: Float3, center: Float3, up: Float3): void } diff --git a/package/src/types/float3.ts b/package/src/types/float3.ts new file mode 100644 index 00000000..fb7f75d5 --- /dev/null +++ b/package/src/types/float3.ts @@ -0,0 +1,4 @@ +/** + * A 3D float vector (x, y, z). + */ +export type Float3 = [number, number, number] From 2ee53b40e6c38c1956199563fd354d1294872726 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Thu, 29 Feb 2024 17:00:09 +0100 Subject: [PATCH 14/21] configure camera dynamically --- package/cpp/core/CameraFovEnum.h | 35 ++++++++++++++++++++++++++++++ package/cpp/core/CameraWrapper.cpp | 17 ++++++++++++++- package/cpp/core/CameraWrapper.h | 3 +++ package/cpp/core/EngineWrapper.cpp | 30 ++++++++++++------------- package/cpp/core/EngineWrapper.h | 2 +- package/cpp/core/ViewWrapper.cpp | 8 +++++++ package/cpp/core/ViewWrapper.h | 1 + package/src/FilamentView.tsx | 10 +++++++++ package/src/types/Camera.ts | 23 ++++++++++++++++++++ package/src/types/View.ts | 1 + 10 files changed, 113 insertions(+), 17 deletions(-) create mode 100644 package/cpp/core/CameraFovEnum.h diff --git a/package/cpp/core/CameraFovEnum.h b/package/cpp/core/CameraFovEnum.h new file mode 100644 index 00000000..d5603ead --- /dev/null +++ b/package/cpp/core/CameraFovEnum.h @@ -0,0 +1,35 @@ +// +// Created by Marc Rousavy on 22.02.24. +// + +#pragma once + +#include "jsi/EnumMapper.h" +#include + +namespace margelo { + using namespace filament; + + namespace EnumMapper { + static void convertJSUnionToEnum(const std::string& inUnion, Camera::Fov* outEnum) { + if (inUnion == "horizontal") + *outEnum = Camera::Fov::HORIZONTAL; + else if (inUnion == "vertical") + *outEnum = Camera::Fov::VERTICAL; + else + throw invalidUnion(inUnion); + } + static void convertEnumToJSUnion(Camera::Fov inEnum, std::string* outUnion) { + switch (inEnum) { + case filament::Camera::Fov::HORIZONTAL: + *outUnion = "horizontal"; + break; + case filament::Camera::Fov::VERTICAL: + *outUnion = "vertical"; + break; + default: + throw invalidEnum(inEnum); + } + } + } // namespace EnumMapper +} // namespace margelo \ No newline at end of file diff --git a/package/cpp/core/CameraWrapper.cpp b/package/cpp/core/CameraWrapper.cpp index 44628345..48a07b1c 100644 --- a/package/cpp/core/CameraWrapper.cpp +++ b/package/cpp/core/CameraWrapper.cpp @@ -1,8 +1,11 @@ #include "CameraWrapper.h" +#include "CameraFovEnum.h" void margelo::CameraWrapper::loadHybridMethods() { registerHybridMethod("lookAtCameraManipulator", &CameraWrapper::lookAtCameraManipulator, this); - registerHybridMethod("lookAt", &CameraWrapper::lookAt, this); + registerHybridMethod("lookAt", &CameraWrapper::lookAt, this); + registerHybridMethod("setLensProjection", &CameraWrapper::setLensProjection, this); + registerHybridMethod("setProjection", &CameraWrapper::setProjection, this); } void margelo::CameraWrapper::lookAtCameraManipulator(std::shared_ptr cameraManipulator) { @@ -21,3 +24,15 @@ void margelo::CameraWrapper::lookAt(std::vector eye, std::vector math::float3 upVec = {static_cast(up[0]), static_cast(up[1]), static_cast(up[2])}; _camera->lookAt(eyeVec, centerVec, upVec); } + +void margelo::CameraWrapper::setLensProjection(double fov, double aspect, double near, double far) { + _camera->setLensProjection(static_cast(fov), static_cast(aspect), static_cast(near), static_cast(far)); +} + +void margelo::CameraWrapper::setProjection(double fovInDegrees, double aspect, double near, double far, std::string directionStr = "vertical") { + Camera::Fov direction; + EnumMapper::convertJSUnionToEnum(directionStr, &direction); + + _camera->setProjection(static_cast(fovInDegrees), static_cast(aspect), static_cast(near), static_cast(far), direction); +} + diff --git a/package/cpp/core/CameraWrapper.h b/package/cpp/core/CameraWrapper.h index ae5876eb..574604f0 100644 --- a/package/cpp/core/CameraWrapper.h +++ b/package/cpp/core/CameraWrapper.h @@ -23,6 +23,9 @@ class CameraWrapper : public HybridObject { private: void lookAt(std::vector eye, std::vector center, std::vector up); + void setLensProjection(double fov, double aspect, double near, double far); + // TODO(Hanno): Add directionStr , Camera::Fov directionStr = Camera::Fov::VERTICAL + void setProjection(double fovInDegrees, double aspect, double near, double far, std::string directionStr); // Convenience methods void lookAtCameraManipulator(std::shared_ptr cameraManipulator); }; diff --git a/package/cpp/core/EngineWrapper.cpp b/package/cpp/core/EngineWrapper.cpp index 97163b01..6d832bfc 100644 --- a/package/cpp/core/EngineWrapper.cpp +++ b/package/cpp/core/EngineWrapper.cpp @@ -121,7 +121,7 @@ void EngineWrapper::surfaceSizeChanged(int width, int height) { _view->setViewport(0, 0, width, height); } - updateCameraProjection(); +// updateCameraProjection(); } void EngineWrapper::destroySurface() { @@ -304,20 +304,20 @@ void EngineWrapper::transformToUnitCube(std::shared_ptr as asset->transformToUnitCube(tm); } -void EngineWrapper::updateCameraProjection() { - if (!_view) { - throw std::runtime_error("View not initialized"); - } - if (!_camera) { - throw std::runtime_error("Camera not initialized"); - } - - const double aspect = (double)_view->getView()->getViewport().width / _view->getView()->getViewport().height; - double focalLength = 28.0; - double near = 0.05; // 5cm - double far = 1000.0; // 1km - _camera->getCamera()->setLensProjection(focalLength, aspect, near, far); -} +//void EngineWrapper::updateCameraProjection() { +// if (!_view) { +// throw std::runtime_error("View not initialized"); +// } +// if (!_camera) { +// throw std::runtime_error("Camera not initialized"); +// } +// +// const double aspect = (double)_view->getView()->getViewport().width / _view->getView()->getViewport().height; +// double focalLength = 28.0; +// double near = 0.05; // 5cm +// double far = 1000.0; // 1km +// _camera->getCamera()->setLensProjection(focalLength, aspect, near, far); +//} void EngineWrapper::synchronizePendingFrames() { if (!_engine) { diff --git a/package/cpp/core/EngineWrapper.h b/package/cpp/core/EngineWrapper.h index 2fdebe28..62f14dfa 100644 --- a/package/cpp/core/EngineWrapper.h +++ b/package/cpp/core/EngineWrapper.h @@ -55,7 +55,7 @@ class EngineWrapper : public HybridObject { std::shared_ptr loadAsset(std::shared_ptr modelBuffer); void setIndirectLight(std::shared_ptr modelBuffer); - void updateCameraProjection(); +// void updateCameraProjection(); void synchronizePendingFrames(); std::shared_ptr createLightEntity(std::string lightTypeStr, double colorFahrenheit, double intensity, double directionX, diff --git a/package/cpp/core/ViewWrapper.cpp b/package/cpp/core/ViewWrapper.cpp index 4551443c..99aa03fa 100644 --- a/package/cpp/core/ViewWrapper.cpp +++ b/package/cpp/core/ViewWrapper.cpp @@ -8,6 +8,7 @@ void ViewWrapper::loadHybridMethods() { registerHybridSetter("camera", &ViewWrapper::setCamera, this); registerHybridGetter("camera", &ViewWrapper::getCamera, this); registerHybridMethod("setViewport", &ViewWrapper::setViewport, this); + registerHybridGetter("aspectRatio", &ViewWrapper::getAspectRatio, this); } void ViewWrapper::setScene(std::shared_ptr scene) { @@ -48,4 +49,11 @@ void ViewWrapper::setViewport(int x, int y, int width, int height) { _view->setViewport({x, y, static_cast(width), static_cast(height)}); } + double ViewWrapper::getAspectRatio() { + if (!_view) { + throw std::invalid_argument("View is null"); + } + return (double)_view->getViewport().width / _view->getViewport().height; + } + } // namespace margelo diff --git a/package/cpp/core/ViewWrapper.h b/package/cpp/core/ViewWrapper.h index 01d60cf0..816e4d66 100644 --- a/package/cpp/core/ViewWrapper.h +++ b/package/cpp/core/ViewWrapper.h @@ -27,6 +27,7 @@ class ViewWrapper : public HybridObject { std::shared_ptr getScene(); void setCamera(std::shared_ptr camera); std::shared_ptr getCamera(); + double getAspectRatio(); private: std::shared_ptr _view; diff --git a/package/src/FilamentView.tsx b/package/src/FilamentView.tsx index 16497a28..7ead183b 100644 --- a/package/src/FilamentView.tsx +++ b/package/src/FilamentView.tsx @@ -77,6 +77,16 @@ export class FilamentView extends React.PureComponent { // Link the surface with the engine: this.engine.setSurfaceProvider(surfaceProvider) + // Configure camera lens (Important, do so after linking the surface) + const view = this.engine.getView() + const aspectRatio = view.aspectRatio + const focalLengthInMillimeters = 28 + const near = 0.1 + const far = 1000 + this.engine.getCamera().setLensProjection(focalLengthInMillimeters, aspectRatio, near, far) + console.log('aspectRatio', aspectRatio) + // Alternatively setProjection can be used + // Callback for rendering every frame this.engine.setRenderCallback(this.renderCallback) } diff --git a/package/src/types/Camera.ts b/package/src/types/Camera.ts index 974442e2..88666040 100644 --- a/package/src/types/Camera.ts +++ b/package/src/types/Camera.ts @@ -89,4 +89,27 @@ export interface Camera { * @param up The up vector of the camera (Usually (0, 1, 0)) */ lookAt(eye: Float3, center: Float3, up: Float3): void + + /** Utility to set the projection matrix from the focal length. + * + * @param focalLengthInMillimeters lens's focal length in millimeters.focalLength > 0. + * @param aspect aspect ratio (You can use view.aspectRatio) + * @param near distance in world units from the camera to the near plane. near > 0. + * @param far distance in world units from the camera to the far plane. far > near. + */ + setLensProjection(focalLengthInMillimeters: number, aspect: number, near: number, far: number): void + + //TODO(Hanno): This also accepts a last parameter called direction. Implement once custom enums are fixed + /** + * Utility to set the projection matrix from the field-of-view. + * + * @param fovInDegrees full field-of-view in degrees. 0 < \p fov < 180. + * @param aspect aspect ratio \f$ \frac{width}{height} \f$. \p aspect > 0. + * @param near distance in world units from the camera to the near plane. \p near > 0. + * @param far distance in world units from the camera to the far plane. \p far > \p near. + * @param direction direction of the \p fovInDegrees parameter. + * + * @see Fov. + */ + setProjection(fov: number, aspect: number, near: number, far: number): void } diff --git a/package/src/types/View.ts b/package/src/types/View.ts index ec7ce907..25eece32 100644 --- a/package/src/types/View.ts +++ b/package/src/types/View.ts @@ -23,5 +23,6 @@ import { Scene } from './Scene' export interface View { camera: Camera scene: Scene + aspectRatio: number setViewport(x: number, y: number, width: number, height: number): void } From 680f32fe7bb66d0ff12489c892dc7899a4a67838 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Thu, 29 Feb 2024 17:03:09 +0100 Subject: [PATCH 15/21] check-all --- package/cpp/core/CameraFovEnum.h | 46 ++++++++++++------------- package/cpp/core/CameraWrapper.cpp | 19 +++++----- package/cpp/core/EngineWrapper.cpp | 20 ++--------- package/cpp/core/EngineWrapper.h | 1 - package/cpp/core/FilamentAssetWrapper.h | 2 +- package/cpp/core/ViewWrapper.cpp | 12 +++---- package/src/types/Engine.ts | 2 +- 7 files changed, 44 insertions(+), 58 deletions(-) diff --git a/package/cpp/core/CameraFovEnum.h b/package/cpp/core/CameraFovEnum.h index d5603ead..3883d72d 100644 --- a/package/cpp/core/CameraFovEnum.h +++ b/package/cpp/core/CameraFovEnum.h @@ -8,28 +8,28 @@ #include namespace margelo { - using namespace filament; +using namespace filament; - namespace EnumMapper { - static void convertJSUnionToEnum(const std::string& inUnion, Camera::Fov* outEnum) { - if (inUnion == "horizontal") - *outEnum = Camera::Fov::HORIZONTAL; - else if (inUnion == "vertical") - *outEnum = Camera::Fov::VERTICAL; - else - throw invalidUnion(inUnion); - } - static void convertEnumToJSUnion(Camera::Fov inEnum, std::string* outUnion) { - switch (inEnum) { - case filament::Camera::Fov::HORIZONTAL: - *outUnion = "horizontal"; - break; - case filament::Camera::Fov::VERTICAL: - *outUnion = "vertical"; - break; - default: - throw invalidEnum(inEnum); - } - } - } // namespace EnumMapper +namespace EnumMapper { + static void convertJSUnionToEnum(const std::string& inUnion, Camera::Fov* outEnum) { + if (inUnion == "horizontal") + *outEnum = Camera::Fov::HORIZONTAL; + else if (inUnion == "vertical") + *outEnum = Camera::Fov::VERTICAL; + else + throw invalidUnion(inUnion); + } + static void convertEnumToJSUnion(Camera::Fov inEnum, std::string* outUnion) { + switch (inEnum) { + case filament::Camera::Fov::HORIZONTAL: + *outUnion = "horizontal"; + break; + case filament::Camera::Fov::VERTICAL: + *outUnion = "vertical"; + break; + default: + throw invalidEnum(inEnum); + } + } +} // namespace EnumMapper } // namespace margelo \ No newline at end of file diff --git a/package/cpp/core/CameraWrapper.cpp b/package/cpp/core/CameraWrapper.cpp index 48a07b1c..7c47d654 100644 --- a/package/cpp/core/CameraWrapper.cpp +++ b/package/cpp/core/CameraWrapper.cpp @@ -19,20 +19,21 @@ void margelo::CameraWrapper::lookAtCameraManipulator(std::shared_ptr eye, std::vector center, std::vector up) { - math::float3 eyeVec = {static_cast(eye[0]), static_cast(eye[1]), static_cast(eye[2])}; - math::float3 centerVec = {static_cast(center[0]), static_cast(center[1]), static_cast(center[2])}; - math::float3 upVec = {static_cast(up[0]), static_cast(up[1]), static_cast(up[2])}; - _camera->lookAt(eyeVec, centerVec, upVec); + math::float3 eyeVec = {static_cast(eye[0]), static_cast(eye[1]), static_cast(eye[2])}; + math::float3 centerVec = {static_cast(center[0]), static_cast(center[1]), static_cast(center[2])}; + math::float3 upVec = {static_cast(up[0]), static_cast(up[1]), static_cast(up[2])}; + _camera->lookAt(eyeVec, centerVec, upVec); } void margelo::CameraWrapper::setLensProjection(double fov, double aspect, double near, double far) { _camera->setLensProjection(static_cast(fov), static_cast(aspect), static_cast(near), static_cast(far)); } -void margelo::CameraWrapper::setProjection(double fovInDegrees, double aspect, double near, double far, std::string directionStr = "vertical") { - Camera::Fov direction; - EnumMapper::convertJSUnionToEnum(directionStr, &direction); +void margelo::CameraWrapper::setProjection(double fovInDegrees, double aspect, double near, double far, + std::string directionStr = "vertical") { + Camera::Fov direction; + EnumMapper::convertJSUnionToEnum(directionStr, &direction); - _camera->setProjection(static_cast(fovInDegrees), static_cast(aspect), static_cast(near), static_cast(far), direction); + _camera->setProjection(static_cast(fovInDegrees), static_cast(aspect), static_cast(near), static_cast(far), + direction); } - diff --git a/package/cpp/core/EngineWrapper.cpp b/package/cpp/core/EngineWrapper.cpp index 6d832bfc..ab90ae5e 100644 --- a/package/cpp/core/EngineWrapper.cpp +++ b/package/cpp/core/EngineWrapper.cpp @@ -4,8 +4,8 @@ #include "EngineWrapper.h" -#include "References.h" #include "LightEnum.h" +#include "References.h" #include #include @@ -121,7 +121,8 @@ void EngineWrapper::surfaceSizeChanged(int width, int height) { _view->setViewport(0, 0, width, height); } -// updateCameraProjection(); + // TODO: when the surface resizes we need to update the camera projection, but that one is owned by JS now. + // updateCameraProjection(); } void EngineWrapper::destroySurface() { @@ -304,21 +305,6 @@ void EngineWrapper::transformToUnitCube(std::shared_ptr as asset->transformToUnitCube(tm); } -//void EngineWrapper::updateCameraProjection() { -// if (!_view) { -// throw std::runtime_error("View not initialized"); -// } -// if (!_camera) { -// throw std::runtime_error("Camera not initialized"); -// } -// -// const double aspect = (double)_view->getView()->getViewport().width / _view->getView()->getViewport().height; -// double focalLength = 28.0; -// double near = 0.05; // 5cm -// double far = 1000.0; // 1km -// _camera->getCamera()->setLensProjection(focalLength, aspect, near, far); -//} - void EngineWrapper::synchronizePendingFrames() { if (!_engine) { throw std::runtime_error("Engine not initialized"); diff --git a/package/cpp/core/EngineWrapper.h b/package/cpp/core/EngineWrapper.h index 62f14dfa..de77e097 100644 --- a/package/cpp/core/EngineWrapper.h +++ b/package/cpp/core/EngineWrapper.h @@ -55,7 +55,6 @@ class EngineWrapper : public HybridObject { std::shared_ptr loadAsset(std::shared_ptr modelBuffer); void setIndirectLight(std::shared_ptr modelBuffer); -// void updateCameraProjection(); void synchronizePendingFrames(); std::shared_ptr createLightEntity(std::string lightTypeStr, double colorFahrenheit, double intensity, double directionX, diff --git a/package/cpp/core/FilamentAssetWrapper.h b/package/cpp/core/FilamentAssetWrapper.h index ca07580c..a930a4ca 100644 --- a/package/cpp/core/FilamentAssetWrapper.h +++ b/package/cpp/core/FilamentAssetWrapper.h @@ -1,8 +1,8 @@ #pragma once #include "jsi/HybridObject.h" -#include #include +#include namespace margelo { diff --git a/package/cpp/core/ViewWrapper.cpp b/package/cpp/core/ViewWrapper.cpp index 99aa03fa..b13eb5c9 100644 --- a/package/cpp/core/ViewWrapper.cpp +++ b/package/cpp/core/ViewWrapper.cpp @@ -49,11 +49,11 @@ void ViewWrapper::setViewport(int x, int y, int width, int height) { _view->setViewport({x, y, static_cast(width), static_cast(height)}); } - double ViewWrapper::getAspectRatio() { - if (!_view) { - throw std::invalid_argument("View is null"); - } - return (double)_view->getViewport().width / _view->getViewport().height; - } +double ViewWrapper::getAspectRatio() { + if (!_view) { + throw std::invalid_argument("View is null"); + } + return (double)_view->getViewport().width / _view->getViewport().height; +} } // namespace margelo diff --git a/package/src/types/Engine.ts b/package/src/types/Engine.ts index 626fd066..267c7288 100644 --- a/package/src/types/Engine.ts +++ b/package/src/types/Engine.ts @@ -28,7 +28,7 @@ export interface Engine { directionX: number, directionY: number, directionZ: number, - castShadows: boolean, + castShadows: boolean ): Entity transformToUnitCube(entity: FilamentAsset): void From 8ba2e3cd2e8c4a361d78f1963ccc71e21e05c193 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Thu, 29 Feb 2024 17:03:49 +0100 Subject: [PATCH 16/21] remove unnecessary checks --- package/cpp/core/ViewWrapper.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/package/cpp/core/ViewWrapper.cpp b/package/cpp/core/ViewWrapper.cpp index b13eb5c9..36793d0d 100644 --- a/package/cpp/core/ViewWrapper.cpp +++ b/package/cpp/core/ViewWrapper.cpp @@ -42,17 +42,10 @@ void ViewWrapper::setViewport(int x, int y, int width, int height) { throw std::invalid_argument("Invalid viewport size"); } - if (!_view) { - throw std::invalid_argument("View is null"); - } - _view->setViewport({x, y, static_cast(width), static_cast(height)}); } double ViewWrapper::getAspectRatio() { - if (!_view) { - throw std::invalid_argument("View is null"); - } return (double)_view->getViewport().width / _view->getViewport().height; } From ca28ecab3e8aad76d32d3b241960cff09367db7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Thu, 29 Feb 2024 17:42:42 +0100 Subject: [PATCH 17/21] wip: translate system --- package/cpp/core/EngineWrapper.cpp | 56 +++++++++++++++++++++++ package/cpp/core/EngineWrapper.h | 5 ++ package/cpp/core/FilamentAssetWrapper.cpp | 10 +++- package/cpp/core/FilamentAssetWrapper.h | 4 ++ package/src/FilamentView.tsx | 9 +++- package/src/types/Engine.ts | 5 ++ 6 files changed, 87 insertions(+), 2 deletions(-) diff --git a/package/cpp/core/EngineWrapper.cpp b/package/cpp/core/EngineWrapper.cpp index ab90ae5e..0665d05b 100644 --- a/package/cpp/core/EngineWrapper.cpp +++ b/package/cpp/core/EngineWrapper.cpp @@ -77,6 +77,10 @@ void EngineWrapper::loadHybridMethods() { registerHybridMethod("getCameraManipulator", &EngineWrapper::getCameraManipulator, this); registerHybridMethod("createLightEntity", &EngineWrapper::createLightEntity, this); registerHybridMethod("transformToUnitCube", &EngineWrapper::transformToUnitCube, this); + registerHybridMethod("setEntityPosition", &EngineWrapper::setEntityPosition, this); + registerHybridMethod("setEntityRotation", &EngineWrapper::setEntityRotation, this); + registerHybridMethod("setEntityScale", &EngineWrapper::setEntityScale, this); + registerHybridMethod("translateEntityPosition", &EngineWrapper::translateEntityPosition, this); } void EngineWrapper::setSurfaceProvider(std::shared_ptr surfaceProvider) { @@ -317,4 +321,56 @@ void EngineWrapper::synchronizePendingFrames() { _engine->destroy(fence); } +// TODO(Marc): Ideally i want to do this in the entity wrapper, but i dont have access to the transform manager there +void EngineWrapper::setEntityPosition(std::shared_ptr entity, double x, double y, double z) { + if (!entity) { + throw std::invalid_argument("Entity is null"); + } + + math::float3 position = math::float3(x, y, z); + TransformManager& tm = _engine->getTransformManager(); + EntityInstance entityInstance = tm.getInstance(entity->getEntity()); + auto translationMatrix = math::mat4::translation(position); + tm.setTransform(entityInstance, math::mat4::translation(position)); +} + +void EngineWrapper::setEntityRotation(std::shared_ptr entity, double angleRadians, double x, double y, double z) { + if (!entity) { + throw std::invalid_argument("Entity is null"); + } + + math::float3 axis = math::float3(x, y, z); + float angle = static_cast(angleRadians); + + TransformManager& tm = _engine->getTransformManager(); + EntityInstance entityInstance = tm.getInstance(entity->getEntity()); + auto rotationMatrix = math::mat4::rotation(angle, axis); + tm.setTransform(entityInstance, rotationMatrix); +} + +void EngineWrapper::setEntityScale(std::shared_ptr entity, double x, double y, double z) { + if (!entity) { + throw std::invalid_argument("Entity is null"); + } + + math::float3 scale = math::float3(x, y, z); + TransformManager& tm = _engine->getTransformManager(); + EntityInstance entityInstance = tm.getInstance(entity->getEntity()); + tm.setTransform(entityInstance, math::mat4::scaling(scale)); +} + +void EngineWrapper::translateEntityPosition(std::shared_ptr entity, double x, double y, double z) { + if (!entity) { + throw std::invalid_argument("Entity is null"); + } + + math::float3 position = math::float3(x, y, z); + TransformManager& tm = _engine->getTransformManager(); + EntityInstance entityInstance = tm.getInstance(entity->getEntity()); + auto translationMatrix = math::mat4::translation(position); + auto currentTransform = tm.getTransform(entityInstance); + auto newTransform = currentTransform * translationMatrix; + tm.setTransform(entityInstance, newTransform); +} + } // namespace margelo diff --git a/package/cpp/core/EngineWrapper.h b/package/cpp/core/EngineWrapper.h index de77e097..b6678d11 100644 --- a/package/cpp/core/EngineWrapper.h +++ b/package/cpp/core/EngineWrapper.h @@ -60,6 +60,11 @@ class EngineWrapper : public HybridObject { std::shared_ptr createLightEntity(std::string lightTypeStr, double colorFahrenheit, double intensity, double directionX, double directionY, double directionZ, bool castShadows); + void setEntityPosition(std::shared_ptr entity, double x, double y, double z); + void setEntityRotation(std::shared_ptr entity, double angleRadians, double x, double y, double z); + void setEntityScale(std::shared_ptr entity, double x, double y, double z); + void translateEntityPosition(std::shared_ptr entity, double x, double y, double z); + private: std::shared_ptr _engine; std::shared_ptr _surfaceProvider; diff --git a/package/cpp/core/FilamentAssetWrapper.cpp b/package/cpp/core/FilamentAssetWrapper.cpp index beadf70d..e49b125c 100644 --- a/package/cpp/core/FilamentAssetWrapper.cpp +++ b/package/cpp/core/FilamentAssetWrapper.cpp @@ -1,12 +1,15 @@ #include "FilamentAssetWrapper.h" +#include #include namespace margelo { using namespace utils; -void FilamentAssetWrapper::loadHybridMethods() {} +void FilamentAssetWrapper::loadHybridMethods() { + registerHybridMethod("getRoot", &FilamentAssetWrapper::getRoot, this); +} /** * Sets up a root transform on the current model to make it fit into a unit cube. @@ -22,4 +25,9 @@ void FilamentAssetWrapper::transformToUnitCube(TransformManager& transformManage transformManager.setTransform(transformInstance, transform); } +std::shared_ptr FilamentAssetWrapper::getRoot() { + Entity rootEntity = _asset->getRoot(); + return std::make_shared(rootEntity); +} + } // namespace margelo \ No newline at end of file diff --git a/package/cpp/core/FilamentAssetWrapper.h b/package/cpp/core/FilamentAssetWrapper.h index a930a4ca..dd63f9f8 100644 --- a/package/cpp/core/FilamentAssetWrapper.h +++ b/package/cpp/core/FilamentAssetWrapper.h @@ -1,5 +1,6 @@ #pragma once +#include "core/utils/EntityWrapper.h" #include "jsi/HybridObject.h" #include #include @@ -16,6 +17,9 @@ class FilamentAssetWrapper : public HybridObject { void transformToUnitCube(TransformManager& transformManager); +private: + std::shared_ptr getRoot(); + private: std::shared_ptr _asset; }; diff --git a/package/src/FilamentView.tsx b/package/src/FilamentView.tsx index 7ead183b..66481f65 100644 --- a/package/src/FilamentView.tsx +++ b/package/src/FilamentView.tsx @@ -50,7 +50,14 @@ export class FilamentView extends React.PureComponent { // Load a model into the scene: const modelBuffer = FilamentProxy.getAssetByteBuffer(penguModelPath!) const penguAsset = this.engine.loadAsset(modelBuffer) - this.engine.transformToUnitCube(penguAsset) + // By default all assets get added to the origin at 0,0,0, + // we transform it to fit into a unit cube at the origin using this utility: + // this.engine.transformToUnitCube(penguAsset) + + // We can also change the pengus position, rotation and scale: + const penguEntity = penguAsset.getRoot() + // this.engine.setEntityRotation(penguEntity, Math.PI / 2, 0, 1, 0) + this.engine.translateEntityPosition(penguEntity, 0, 2, 0) // Create a default light: const indirectLightBuffer = FilamentProxy.getAssetByteBuffer(indirectLightPath!) diff --git a/package/src/types/Engine.ts b/package/src/types/Engine.ts index 267c7288..817f1438 100644 --- a/package/src/types/Engine.ts +++ b/package/src/types/Engine.ts @@ -32,4 +32,9 @@ export interface Engine { ): Entity transformToUnitCube(entity: FilamentAsset): void + + setEntityPosition(entity: Entity, x: number, y: number, z: number): void + setEntityRotation(entity: Entity, angleRadians: number, x: number, y: number, z: number): void + setEntityScale(entity: Entity, x: number, y: number, z: number): void + translateEntityPosition(entity: Entity, x: number, y: number, z: number): void } From 9b1e7b9079fa7d555334fa9b8d427efe43d846ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Thu, 29 Feb 2024 17:43:01 +0100 Subject: [PATCH 18/21] wip --- package/src/FilamentView.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package/src/FilamentView.tsx b/package/src/FilamentView.tsx index 66481f65..00311989 100644 --- a/package/src/FilamentView.tsx +++ b/package/src/FilamentView.tsx @@ -56,8 +56,7 @@ export class FilamentView extends React.PureComponent { // We can also change the pengus position, rotation and scale: const penguEntity = penguAsset.getRoot() - // this.engine.setEntityRotation(penguEntity, Math.PI / 2, 0, 1, 0) - this.engine.translateEntityPosition(penguEntity, 0, 2, 0) + this.engine.translateEntityPosition(penguEntity, 0, 1, 0) // Move the pengu up by 1 unit // Create a default light: const indirectLightBuffer = FilamentProxy.getAssetByteBuffer(indirectLightPath!) From ceb5e87945ea12ad6a526d38fceb217405130405 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Thu, 29 Feb 2024 20:46:11 +0100 Subject: [PATCH 19/21] transform API --- package/cpp/core/EngineWrapper.cpp | 64 ++++++++++++------------------ package/cpp/core/EngineWrapper.h | 8 ++-- package/cpp/core/utils/Converter.h | 21 ++++++++++ package/src/FilamentView.tsx | 4 +- package/src/types/Engine.ts | 8 ++-- 5 files changed, 56 insertions(+), 49 deletions(-) create mode 100644 package/cpp/core/utils/Converter.h diff --git a/package/cpp/core/EngineWrapper.cpp b/package/cpp/core/EngineWrapper.cpp index 0665d05b..fbb94942 100644 --- a/package/cpp/core/EngineWrapper.cpp +++ b/package/cpp/core/EngineWrapper.cpp @@ -6,6 +6,7 @@ #include "LightEnum.h" #include "References.h" +#include "utils/Converter.h" #include #include @@ -80,7 +81,6 @@ void EngineWrapper::loadHybridMethods() { registerHybridMethod("setEntityPosition", &EngineWrapper::setEntityPosition, this); registerHybridMethod("setEntityRotation", &EngineWrapper::setEntityRotation, this); registerHybridMethod("setEntityScale", &EngineWrapper::setEntityScale, this); - registerHybridMethod("translateEntityPosition", &EngineWrapper::translateEntityPosition, this); } void EngineWrapper::setSurfaceProvider(std::shared_ptr surfaceProvider) { @@ -321,56 +321,42 @@ void EngineWrapper::synchronizePendingFrames() { _engine->destroy(fence); } -// TODO(Marc): Ideally i want to do this in the entity wrapper, but i dont have access to the transform manager there -void EngineWrapper::setEntityPosition(std::shared_ptr entity, double x, double y, double z) { +/** + * Internal method that will help updating the transform of an entity. + * @param transform The transform matrix to apply + * @param entity The entity to apply the transform to + * @param multiplyCurrent If true, the current transform will be multiplied with the new transform, otherwise it will be replaced + */ +void EngineWrapper::updateTransform(math::mat4 transform, std::shared_ptr entity, bool multiplyCurrent) { if (!entity) { throw std::invalid_argument("Entity is null"); } - math::float3 position = math::float3(x, y, z); TransformManager& tm = _engine->getTransformManager(); EntityInstance entityInstance = tm.getInstance(entity->getEntity()); - auto translationMatrix = math::mat4::translation(position); - tm.setTransform(entityInstance, math::mat4::translation(position)); + auto currentTransform = tm.getTransform(entityInstance); + auto newTransform = multiplyCurrent ? (currentTransform * transform) : transform; + tm.setTransform(entityInstance, newTransform); } -void EngineWrapper::setEntityRotation(std::shared_ptr entity, double angleRadians, double x, double y, double z) { - if (!entity) { - throw std::invalid_argument("Entity is null"); - } - - math::float3 axis = math::float3(x, y, z); - float angle = static_cast(angleRadians); - - TransformManager& tm = _engine->getTransformManager(); - EntityInstance entityInstance = tm.getInstance(entity->getEntity()); - auto rotationMatrix = math::mat4::rotation(angle, axis); - tm.setTransform(entityInstance, rotationMatrix); +// TODO(Marc): Ideally i want to do this in the entity wrapper, but i dont have access to the transform manager there +void EngineWrapper::setEntityPosition(std::shared_ptr entity, std::vector positionVec, bool multiplyCurrent) { + math::float3 position = Converter::VecToFloat3(positionVec); + auto translationMatrix = math::mat4::translation(position); + updateTransform(translationMatrix, entity, multiplyCurrent); } -void EngineWrapper::setEntityScale(std::shared_ptr entity, double x, double y, double z) { - if (!entity) { - throw std::invalid_argument("Entity is null"); - } - - math::float3 scale = math::float3(x, y, z); - TransformManager& tm = _engine->getTransformManager(); - EntityInstance entityInstance = tm.getInstance(entity->getEntity()); - tm.setTransform(entityInstance, math::mat4::scaling(scale)); +void EngineWrapper::setEntityRotation(std::shared_ptr entity, double angleRadians, std::vector axisVec, + bool multiplyCurrent) { + math::float3 axis = Converter::VecToFloat3(axisVec); + auto rotationMatrix = math::mat4::rotation(angleRadians, axis); + updateTransform(rotationMatrix, entity, multiplyCurrent); } -void EngineWrapper::translateEntityPosition(std::shared_ptr entity, double x, double y, double z) { - if (!entity) { - throw std::invalid_argument("Entity is null"); - } - - math::float3 position = math::float3(x, y, z); - TransformManager& tm = _engine->getTransformManager(); - EntityInstance entityInstance = tm.getInstance(entity->getEntity()); - auto translationMatrix = math::mat4::translation(position); - auto currentTransform = tm.getTransform(entityInstance); - auto newTransform = currentTransform * translationMatrix; - tm.setTransform(entityInstance, newTransform); +void EngineWrapper::setEntityScale(std::shared_ptr entity, std::vector scaleVec, bool multiplyCurrent) { + math::float3 scale = Converter::VecToFloat3(scaleVec); + auto scaleMatrix = math::mat4::scaling(scale); + updateTransform(scaleMatrix, entity, multiplyCurrent); } } // namespace margelo diff --git a/package/cpp/core/EngineWrapper.h b/package/cpp/core/EngineWrapper.h index b6678d11..c785e026 100644 --- a/package/cpp/core/EngineWrapper.h +++ b/package/cpp/core/EngineWrapper.h @@ -60,10 +60,10 @@ class EngineWrapper : public HybridObject { std::shared_ptr createLightEntity(std::string lightTypeStr, double colorFahrenheit, double intensity, double directionX, double directionY, double directionZ, bool castShadows); - void setEntityPosition(std::shared_ptr entity, double x, double y, double z); - void setEntityRotation(std::shared_ptr entity, double angleRadians, double x, double y, double z); - void setEntityScale(std::shared_ptr entity, double x, double y, double z); - void translateEntityPosition(std::shared_ptr entity, double x, double y, double z); + void updateTransform(math::mat4 transform, std::shared_ptr entity, bool multiplyCurrent); + void setEntityPosition(std::shared_ptr entity, std::vector positionVec, bool multiplyCurrent); + void setEntityRotation(std::shared_ptr entity, double angleRadians, std::vector axisVec, bool multiplyCurrent); + void setEntityScale(std::shared_ptr entity, std::vector scaleVec, bool multiplyCurrent); private: std::shared_ptr _engine; diff --git a/package/cpp/core/utils/Converter.h b/package/cpp/core/utils/Converter.h new file mode 100644 index 00000000..de9541f8 --- /dev/null +++ b/package/cpp/core/utils/Converter.h @@ -0,0 +1,21 @@ +// +// Created by Hanno Gödecke on 29.02.24. +// + +#pragma once + +#include + +namespace margelo { + +class Converter { +public: + static math::float3 VecToFloat3(std::vector vec) { + if (vec.size() != 3) { + throw std::invalid_argument("Point must have 3 elements"); + } + + return math::float3(vec[0], vec[1], vec[2]); + } +}; +} // namespace margelo diff --git a/package/src/FilamentView.tsx b/package/src/FilamentView.tsx index 00311989..472c081d 100644 --- a/package/src/FilamentView.tsx +++ b/package/src/FilamentView.tsx @@ -52,11 +52,11 @@ export class FilamentView extends React.PureComponent { const penguAsset = this.engine.loadAsset(modelBuffer) // By default all assets get added to the origin at 0,0,0, // we transform it to fit into a unit cube at the origin using this utility: - // this.engine.transformToUnitCube(penguAsset) + this.engine.transformToUnitCube(penguAsset) // We can also change the pengus position, rotation and scale: const penguEntity = penguAsset.getRoot() - this.engine.translateEntityPosition(penguEntity, 0, 1, 0) // Move the pengu up by 1 unit + this.engine.setEntityPosition(penguEntity, [0, 2, 0], true) // Move the pengu up by 2 units // Create a default light: const indirectLightBuffer = FilamentProxy.getAssetByteBuffer(indirectLightPath!) diff --git a/package/src/types/Engine.ts b/package/src/types/Engine.ts index 817f1438..9b63af23 100644 --- a/package/src/types/Engine.ts +++ b/package/src/types/Engine.ts @@ -7,6 +7,7 @@ import { View } from './View' import { FilamentBuffer } from '../native/FilamentBuffer' import { Entity } from './Entity' import { FilamentAsset } from './FilamentAsset' +import { Float3 } from './float3' export interface Engine { setSurfaceProvider(surfaceProvider: SurfaceProvider): void @@ -33,8 +34,7 @@ export interface Engine { transformToUnitCube(entity: FilamentAsset): void - setEntityPosition(entity: Entity, x: number, y: number, z: number): void - setEntityRotation(entity: Entity, angleRadians: number, x: number, y: number, z: number): void - setEntityScale(entity: Entity, x: number, y: number, z: number): void - translateEntityPosition(entity: Entity, x: number, y: number, z: number): void + setEntityPosition(entity: Entity, position: Float3, multiplyCurrent: boolean): void + setEntityRotation(entity: Entity, angleRadians: number, axis: Float3, multiplyCurrent: boolean): void + setEntityScale(entity: Entity, scale: Float3, multiplyCurrent: boolean): void } From 1741f9c2f45a1975dcc57fdbd26671d853434679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Thu, 29 Feb 2024 20:54:46 +0100 Subject: [PATCH 20/21] docs --- package/src/types/Engine.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/package/src/types/Engine.ts b/package/src/types/Engine.ts index 9b63af23..599a3b3f 100644 --- a/package/src/types/Engine.ts +++ b/package/src/types/Engine.ts @@ -13,7 +13,16 @@ export interface Engine { setSurfaceProvider(surfaceProvider: SurfaceProvider): void setRenderCallback(callback: (engine: Engine) => void): void + /** + * Given a @see FilamentBuffer (e.g. from a .glb file), load the asset into the engine. + * This will by default add all entities from the asset to the attached default scene. + */ loadAsset(buffer: FilamentBuffer): FilamentAsset + + /** + * Set the indirect light for the scene. + * @param iblBuffer A buffer containing the IBL data (e.g. from a .ktx file) + */ setIndirectLight(iblBuffer: FilamentBuffer): void getRenderer(): Renderer @@ -29,9 +38,13 @@ export interface Engine { directionX: number, directionY: number, directionZ: number, - castShadows: boolean + castShadows: boolean, ): Entity + /** + * Transforms the given entity to fit into a unit cube at the origin (0,0,0). + * @param entity The entity to transform + */ transformToUnitCube(entity: FilamentAsset): void setEntityPosition(entity: Entity, position: Float3, multiplyCurrent: boolean): void From 08786e3f48fe019795bf13036085f61f366fefa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Thu, 29 Feb 2024 20:57:27 +0100 Subject: [PATCH 21/21] clean --- package/src/FilamentView.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package/src/FilamentView.tsx b/package/src/FilamentView.tsx index 472c081d..5298eefb 100644 --- a/package/src/FilamentView.tsx +++ b/package/src/FilamentView.tsx @@ -11,12 +11,12 @@ type RefType = React.Component & Readonly const penguModelPath = Platform.select({ android: 'custom/pengu.glb', ios: 'pengu.glb', -}) +})! const indirectLightPath = Platform.select({ android: 'custom/default_env_ibl.ktx', ios: 'default_env_ibl.ktx', -}) +})! export class FilamentView extends React.PureComponent { private readonly ref: React.RefObject @@ -48,7 +48,7 @@ export class FilamentView extends React.PureComponent { setup3dScene = () => { // Load a model into the scene: - const modelBuffer = FilamentProxy.getAssetByteBuffer(penguModelPath!) + const modelBuffer = FilamentProxy.getAssetByteBuffer(penguModelPath) const penguAsset = this.engine.loadAsset(modelBuffer) // By default all assets get added to the origin at 0,0,0, // we transform it to fit into a unit cube at the origin using this utility: @@ -59,7 +59,7 @@ export class FilamentView extends React.PureComponent { this.engine.setEntityPosition(penguEntity, [0, 2, 0], true) // Move the pengu up by 2 units // Create a default light: - const indirectLightBuffer = FilamentProxy.getAssetByteBuffer(indirectLightPath!) + const indirectLightBuffer = FilamentProxy.getAssetByteBuffer(indirectLightPath) this.engine.setIndirectLight(indirectLightBuffer) // Create a directional light for supporting shadows