diff --git a/thermion_dart/lib/src/viewer/src/ffi/src/ffi_asset.dart b/thermion_dart/lib/src/viewer/src/ffi/src/ffi_asset.dart index fceaa67a..002c6d72 100644 --- a/thermion_dart/lib/src/viewer/src/ffi/src/ffi_asset.dart +++ b/thermion_dart/lib/src/viewer/src/ffi/src/ffi_asset.dart @@ -122,7 +122,7 @@ class FFIAsset extends ThermionAsset { } var sourceMaterialInstance = ThermionFFIMaterialInstance( RenderableManager_getMaterialInstanceAt( - renderableManager, targetEntity, 0)); + renderableManager, targetEntity, 0), sceneManager); await sourceMaterialInstance.setStencilWriteEnabled(true); await sourceMaterialInstance.setDepthWriteEnabled(true); @@ -138,7 +138,7 @@ class FFIAsset extends ThermionAsset { _unlitMaterialProvider, key.address, cb); }); final highlightMaterialInstance = - ThermionFFIMaterialInstance(materialInstancePtr); + ThermionFFIMaterialInstance(materialInstancePtr, sceneManager); await highlightMaterialInstance .setStencilCompareFunction(SamplerCompareFunction.NE); await highlightMaterialInstance.setStencilReferenceValue(1); diff --git a/thermion_dart/lib/src/viewer/src/ffi/src/ffi_material_instance.dart b/thermion_dart/lib/src/viewer/src/ffi/src/ffi_material_instance.dart index 7d918935..81266a4c 100644 --- a/thermion_dart/lib/src/viewer/src/ffi/src/ffi_material_instance.dart +++ b/thermion_dart/lib/src/viewer/src/ffi/src/ffi_material_instance.dart @@ -6,8 +6,9 @@ import 'package:thermion_dart/thermion_dart.dart'; class ThermionFFIMaterialInstance extends MaterialInstance { final Pointer pointer; + final Pointer sceneManager; - ThermionFFIMaterialInstance(this.pointer) { + ThermionFFIMaterialInstance(this.pointer, this.sceneManager) { if (pointer == nullptr) { throw Exception("MaterialInstance not found"); } @@ -50,14 +51,17 @@ class ThermionFFIMaterialInstance extends MaterialInstance { @override Future setDepthFunc(SamplerCompareFunction depthFunc) async { - MaterialInstance_setDepthFunc(pointer, TSamplerCompareFunc.values[depthFunc.index]); + MaterialInstance_setDepthFunc( + pointer, TSamplerCompareFunc.values[depthFunc.index]); } @override Future setStencilCompareFunction(SamplerCompareFunction func, [StencilFace face = StencilFace.FRONT_AND_BACK]) async { MaterialInstance_setStencilCompareFunction( - pointer, TSamplerCompareFunc.values[func.index], TStencilFace.values[face.index]); + pointer, + TSamplerCompareFunc.values[func.index], + TStencilFace.values[face.index]); } @override @@ -113,4 +117,8 @@ class ThermionFFIMaterialInstance extends MaterialInstance { Future setStencilWriteMask(int mask) async { MaterialInstance_setStencilWriteMask(pointer, mask); } + + Future dispose() async { + SceneManager_destroyMaterialInstance(sceneManager, pointer); + } } diff --git a/thermion_dart/lib/src/viewer/src/ffi/src/thermion_viewer_ffi.dart b/thermion_dart/lib/src/viewer/src/ffi/src/thermion_viewer_ffi.dart index 3f9d704f..f734cb0f 100644 --- a/thermion_dart/lib/src/viewer/src/ffi/src/thermion_viewer_ffi.dart +++ b/thermion_dart/lib/src/viewer/src/ffi/src/thermion_viewer_ffi.dart @@ -282,6 +282,8 @@ class ThermionViewerFFI extends ThermionViewer { final _onDispose = []; bool _disposing = false; + final _materialInstances = []; + /// /// /// @@ -291,12 +293,13 @@ class ThermionViewerFFI extends ThermionViewer { throw Exception("Viewer has already been disposed."); } _disposing = true; - await setRendering(false); await clearEntities(); + for (final mInstance in _materialInstances) { + await mInstance.dispose(); + } await clearLights(); - // await _sceneUpdateEventController.close(); Viewer_destroyOnRenderThread(_viewer!); _sceneManager = null; _viewer = null; @@ -984,9 +987,6 @@ class ThermionViewerFFI extends ThermionViewer { _sceneManager!, asset.pointer, callback)); } - /// - /// - /// /// /// /// @@ -1880,7 +1880,10 @@ class ThermionViewerFFI extends ThermionViewer { throw Exception("Failed to create material instance"); } - return ThermionFFIMaterialInstance(materialInstance); + var instance = + ThermionFFIMaterialInstance(materialInstance, _sceneManager!); + _materialInstances.add(instance); + return instance; } /// @@ -1888,21 +1891,20 @@ class ThermionViewerFFI extends ThermionViewer { /// Future destroyMaterialInstance( ThermionFFIMaterialInstance materialInstance) async { - SceneManager_destroyMaterialInstance( - _sceneManager!, materialInstance.pointer); + await materialInstance.dispose(); + _materialInstances.remove(materialInstance); } /// /// /// Future createUnlitMaterialInstance() async { - var instance = await withPointerCallback((cb) { + var instancePtr = await withPointerCallback((cb) { SceneManager_createUnlitMaterialInstanceRenderThread(_sceneManager!, cb); }); - if (instance == nullptr) { - throw Exception("Failed to create material instance"); - } - return ThermionFFIMaterialInstance(instance); + final instance = ThermionFFIMaterialInstance(instancePtr, _sceneManager!); + _materialInstances.add(instance); + return instance; } /// @@ -1910,14 +1912,13 @@ class ThermionViewerFFI extends ThermionViewer { /// Future createUnlitFixedSizeMaterialInstance() async { - var instance = await withPointerCallback((cb) { + var instancePtr = await withPointerCallback((cb) { SceneManager_createUnlitFixedSizeMaterialInstanceRenderThread( _sceneManager!, cb); }); - if (instance == nullptr) { - throw Exception("Failed to create material instance"); - } - return ThermionFFIMaterialInstance(instance); + final instance = ThermionFFIMaterialInstance(instancePtr, _sceneManager!); + _materialInstances.add(instance); + return instance; } /// @@ -1925,12 +1926,11 @@ class ThermionViewerFFI extends ThermionViewer { /// Future getMaterialInstanceAt( ThermionEntity entity, int index) async { - final instance = RenderableManager_getMaterialInstanceAt( + final instancePtr = RenderableManager_getMaterialInstanceAt( _renderableManager!, entity, index); - if (instance == nullptr) { - throw Exception("Failed to get material instance"); - } - return ThermionFFIMaterialInstance(instance); + + final instance = ThermionFFIMaterialInstance(instancePtr, _sceneManager!); + return instance; } @override @@ -2036,8 +2036,8 @@ class ThermionViewerFFI extends ThermionViewer { SceneManager_getOverlayEntityCount(_sceneManager!); final overlayEntities = List.generate(overlayEntityCount, (i) => SceneManager_getOverlayEntityAt(_sceneManager!, i)).toSet(); - return FFIGizmo( - view, gizmo.cast(), _sceneManager!, _engine!, nullptr, overlayEntities); + return FFIGizmo(view, gizmo.cast(), _sceneManager!, _engine!, + nullptr, overlayEntities); } } diff --git a/thermion_dart/lib/src/viewer/src/shared_types/material.dart b/thermion_dart/lib/src/viewer/src/shared_types/material.dart index 333bc4df..38cd5abc 100644 --- a/thermion_dart/lib/src/viewer/src/shared_types/material.dart +++ b/thermion_dart/lib/src/viewer/src/shared_types/material.dart @@ -67,7 +67,7 @@ enum StencilFace { BACK, /// Both front and back faces - FRONT_AND_BACK + FRONT_AND_BACK } enum AlphaMode { OPAQUE, MASK, BLEND } @@ -109,4 +109,5 @@ abstract class MaterialInstance { Future setStencilReadMask(int mask); Future setStencilWriteMask(int mask); + } diff --git a/thermion_dart/lib/src/viewer/src/thermion_viewer_base.dart b/thermion_dart/lib/src/viewer/src/thermion_viewer_base.dart index 1d7325ee..5b80a58d 100644 --- a/thermion_dart/lib/src/viewer/src/thermion_viewer_base.dart +++ b/thermion_dart/lib/src/viewer/src/thermion_viewer_base.dart @@ -792,28 +792,28 @@ abstract class ThermionViewer { AlphaMode alphaMode = AlphaMode.OPAQUE, bool enableDiagnostics = false, bool hasMetallicRoughnessTexture = false, - int metallicRoughnessUV = 0, - int baseColorUV = 0, + int metallicRoughnessUV = -1, + int baseColorUV = -1, bool hasClearCoatTexture = false, - int clearCoatUV = 0, + int clearCoatUV = -1, bool hasClearCoatRoughnessTexture = false, - int clearCoatRoughnessUV = 0, + int clearCoatRoughnessUV = -1, bool hasClearCoatNormalTexture = false, - int clearCoatNormalUV = 0, + int clearCoatNormalUV = -1, bool hasClearCoat = false, bool hasTransmission = false, bool hasTextureTransforms = false, - int emissiveUV = 0, - int aoUV = 0, - int normalUV = 0, + int emissiveUV = -1, + int aoUV = -1, + int normalUV = -1, bool hasTransmissionTexture = false, - int transmissionUV = 0, + int transmissionUV = -1, bool hasSheenColorTexture = false, - int sheenColorUV = 0, + int sheenColorUV = -1, bool hasSheenRoughnessTexture = false, - int sheenRoughnessUV = 0, + int sheenRoughnessUV = -1, bool hasVolumeThicknessTexture = false, - int volumeThicknessUV = 0, + int volumeThicknessUV = -1, bool hasSheen = false, bool hasIOR = false, bool hasVolume = false, diff --git a/thermion_dart/native/src/scene/SceneManager.cpp b/thermion_dart/native/src/scene/SceneManager.cpp index 5cb859c6..ef0712c1 100644 --- a/thermion_dart/native/src/scene/SceneManager.cpp +++ b/thermion_dart/native/src/scene/SceneManager.cpp @@ -41,9 +41,6 @@ #include "scene/GeometrySceneAssetBuilder.hpp" #include "UnprojectTexture.hpp" - - - extern "C" { #include "material/image.h" @@ -130,11 +127,12 @@ namespace thermion _engine->getEntityManager().destroy(entity); } + destroyAll(); + _engine->destroy(_unlitFixedSizeMaterial); _cameras.clear(); _gridOverlay->destroy(); - destroyAll(); _gltfResourceLoader->asyncCancelLoad(); _ubershaderProvider->destroyMaterials(); @@ -153,7 +151,7 @@ namespace thermion Gizmo *SceneManager::createGizmo(View *view, Scene *scene) { auto gizmo = std::make_unique(_engine, view, scene, _unlitFixedSizeMaterial); - auto *raw =gizmo.get(); + auto *raw = gizmo.get(); _sceneAssets.push_back(std::move(gizmo)); return raw; } @@ -682,7 +680,6 @@ namespace thermion math::float4 entityPlaneInClipSpace = Camera::inverseProjection(camera.getProjectionMatrix()) * ndcEntityPlanePos; auto entityPlaneInCameraSpace = entityPlaneInClipSpace / entityPlaneInClipSpace.w; auto entityPlaneInWorldSpace = camera.getModelMatrix() * entityPlaneInCameraSpace; - } void SceneManager::queueTransformUpdates(EntityId *entities, math::mat4 *transforms, int numEntities) diff --git a/thermion_dart/test/geometry_tests.dart b/thermion_dart/test/geometry_tests.dart index e08562cf..1b13cf4a 100644 --- a/thermion_dart/test/geometry_tests.dart +++ b/thermion_dart/test/geometry_tests.dart @@ -13,16 +13,30 @@ import 'helpers.dart'; void main() async { final testHelper = TestHelper("geometry"); group("custom geometry", () { - test('create cube', () async { + test('create cube (no normals/uvs)', () async { await testHelper.withViewer((viewer) async { final cube = await viewer .createGeometry(GeometryHelper.cube(normals: false, uvs: false)); - await testHelper.capture(viewer, "geometry_add_cube"); + await testHelper.capture(viewer, "geometry_cube_no_normals_uvs"); await viewer.removeEntity(cube); await testHelper.capture(viewer, "geometry_remove_cube"); }); }); + test('create cube with unlit ubershader material (no normals/uvs)', + () async { + await testHelper.withViewer((viewer) async { + final materialInstance = + await viewer.createUbershaderMaterialInstance(unlit: true); + await materialInstance.setParameterFloat4( + "baseColorFactor", 1.0, 0.0, 0.0, 1.0); + final cube = await viewer.createGeometry( + GeometryHelper.cube(normals: false, uvs: false), + materialInstances: [materialInstance]); + await testHelper.capture(viewer, "geometry_cube_ubershader"); + }); + }); + test('create cube (with normals)', () async { var viewer = await testHelper.createViewer(); await viewer @@ -30,6 +44,36 @@ void main() async { await testHelper.capture(viewer, "geometry_cube_with_normals"); }); + test('create cube with lit ubershader material (normals/ no uvs)', + () async { + await testHelper.withViewer((viewer) async { + final materialInstance = + await viewer.createUbershaderMaterialInstance( + unlit: false, + alphaMode: AlphaMode.BLEND, + hasVertexColors:false); + await materialInstance.setParameterFloat4( + "baseColorFactor", 1.0, 0.0, 0.0, 1.0); + final cube = await viewer.createGeometry( + GeometryHelper.cube(normals: true, uvs: false), + materialInstances: [materialInstance] + ); + + await viewer.addDirectLight(DirectLight.sun( + intensity: 100000, + castShadows: false, + direction: Vector3(0,-0.5,-1))); + // await viewer.addDirectLight(DirectLight.spot( + // intensity: 1000000, + // position: Vector3(0,3,3), + // direction: Vector3(0,-1.5,-1), + // falloffRadius: 10)); + await materialInstance.setParameterFloat4( + "baseColorFactor", 1.0, 0.0, 0.0, 1.0); + await testHelper.capture(viewer, "geometry_cube_lit_ubershader"); + }); + }); + test('create instance', () async { await testHelper.withViewer((viewer) async { final cube = await viewer