From cd1c2f38279155cf35e9aa2b26c48d4667a86cae Mon Sep 17 00:00:00 2001 From: Nick Fisher Date: Fri, 28 Mar 2025 10:01:00 +0800 Subject: [PATCH] projection work + tests --- materials/capture_uv.mat | 4 +- materials/vdtm.mat | 63 +-- thermion_dart/test/asset_tests.dart | 46 +- thermion_dart/test/assets/cube_texture2.svg | 181 ++++++++ .../test/assets/cube_texture2_512x512.png | Bin 0 -> 6021 bytes .../assets/cube_texture2_512x512_flipped.png | Bin 0 -> 6079 bytes thermion_dart/test/depth_tests.dart | 392 ++++++++++++++++++ thermion_dart/test/postprocessing_tests.dart | 40 ++ 8 files changed, 687 insertions(+), 39 deletions(-) create mode 100644 thermion_dart/test/assets/cube_texture2.svg create mode 100644 thermion_dart/test/assets/cube_texture2_512x512.png create mode 100644 thermion_dart/test/assets/cube_texture2_512x512_flipped.png create mode 100644 thermion_dart/test/depth_tests.dart create mode 100644 thermion_dart/test/postprocessing_tests.dart diff --git a/materials/capture_uv.mat b/materials/capture_uv.mat index bda2c47d..a44f7f66 100644 --- a/materials/capture_uv.mat +++ b/materials/capture_uv.mat @@ -100,8 +100,8 @@ fragment { //material.baseColor = vec4(sampledDepth.r, 0.0, 0.0, 1.0); //material.baseColor = vec4(vertexDepth, 0.0, 0.0, 1.0); - if(materialParams.useDepth && abs(vertexDepth - sampledDepth.r) > 0.001) { - discard; + if(materialParams.useDepth && (sampledDepth.r < 0.0001 || abs(vertexDepth - sampledDepth.r) > 0.001)) { + material.baseColor = vec4(0.0, 0.0, 0.0, 0.0); } else { vec2 texSize = vec2(textureSize(materialParams_color, 0)); vec4 color = textureLod(materialParams_color, uvToRenderTargetUV(deviceCoords.xy), 0.0f); diff --git a/materials/vdtm.mat b/materials/vdtm.mat index e00c7e90..a0720a26 100644 --- a/materials/vdtm.mat +++ b/materials/vdtm.mat @@ -8,7 +8,7 @@ material { }, { type : float3[3], - name : cameraPositions + name : cameraForwardVectors }, { type : bool, @@ -17,8 +17,8 @@ material { ], variables : [ { - type : float3, - name : blendWeights, + type : float, + name : samplerCoord, } ], requires : [ position, uv0 ], @@ -43,42 +43,57 @@ material { // Parameters: // - perspectives: 3D texture containing different perspective views of the object // - cameraPositions: Array of camera positions used to render each perspective slice - vertex { void materialVertex(inout MaterialVertexInputs material) { - vec3 worldCameraPos = getWorldCameraPosition(); - vec4 currentCameraPos = getUserWorldFromWorldMatrix() * vec4(worldCameraPos, 1.0); + vec3 forward = -(normalize(getWorldFromViewMatrix()[2].xyz)); + + vec3 weights = vec3(0.0, 0.0, 0.0); + int idxMax = 0; + float weightMax = 0.0; + for(int i = 0; i < 3; i++) { + weights[i] = dot(forward, materialParams.cameraForwardVectors[i]); + if(weights[i] > weightMax) { + weightMax = weights[i]; + idxMax = i; + } + } + + if(idxMax == 0) { + float z = (weights.y * 0.5) + (weights.z * 1.0); + } + + //weights /= (weights.x + weights.y + weights.z); - material.blendWeights.xyz = vec3(0.0f); - float totalWeight = 0.0; - - for (int i = 0; i < 3; i++) { - vec3 cameraPos = materialParams.cameraPositions[i]; - float dist = distance(currentCameraPos.xyz, cameraPos); - material.blendWeights[i] = exp(-dist); - totalWeight += material.blendWeights[i]; - } - if (totalWeight > 0.0) { - material.blendWeights /= totalWeight; - } - //material.blendWeights.x = exp(-distance(currentCameraPos.xyz, materialParams.cameraPositions[0])); + + material.samplerCoord.x = z; } } fragment { + void useMax(vec3 forward) { + float maxIdx = 0.0f; + float maxWeight = 0.0f; + for(int i =0; i < 3; i++) { + float weight = dot(forward, materialParams.cameraForwardVectors[i]); + if(weight > maxWeight) { + maxWeight = weight; + maxIdx = float(i) / 2.0f; + } + } + + float z = maxIdx; + + } void material(inout MaterialInputs material) { prepareMaterial(material); - - vec3 weights = variable_blendWeights.xyz; - - float z = (weights.x * 0.0) + (weights.y * 0.5) + (weights.z * 1.0); vec2 uv = getUV0(); if(materialParams.flipUVs) { uv = uvToRenderTargetUV(uv); } - vec3 texCoord = vec3(uv, z); + vec3 texCoord = vec3(uv, variable_samplerCoord.x); material.baseColor = texture(materialParams_perspectives, texCoord); + } } \ No newline at end of file diff --git a/thermion_dart/test/asset_tests.dart b/thermion_dart/test/asset_tests.dart index 270bf541..9093f587 100644 --- a/thermion_dart/test/asset_tests.dart +++ b/thermion_dart/test/asset_tests.dart @@ -9,24 +9,28 @@ void main() async { group("assets", () { test('load/clear skybox', () async { await testHelper.withViewer((viewer) async { - final camera = await viewer.getActiveCamera(); - print(await camera.getModelMatrix()); - print(await camera.getViewMatrix()); - print(await camera.getProjectionMatrix()); - await camera.lookAt(Vector3(0, 0, 10), - focus: Vector3.zero(), up: Vector3(0, 1, 0)); await viewer.loadSkybox( "file://${testHelper.testDir}/assets/default_env_skybox.ktx"); await testHelper.capture(viewer.view, "load_skybox"); await viewer.removeSkybox(); await testHelper.capture(viewer.view, "remove_skybox"); - }); + + await viewer.setPostProcessing(true); + await viewer.setBloom(false, 0.01); + await viewer.loadSkybox( + "file://${testHelper.testDir}/assets/default_env_skybox.ktx"); + await testHelper.capture( + viewer.view, "load_skybox_with_postprocessing"); + await viewer.removeSkybox(); + await testHelper.capture( + viewer.view, "remove_skybox_with_postprocessing"); + }, createRenderTarget: true); }); test('load/remove ibl', () async { await testHelper.withViewer((viewer) async { var asset = await viewer - .loadGlb("file://${testHelper.testDir}/assets/cube.glb"); + .loadGltf("file://${testHelper.testDir}/assets/cube.glb"); await viewer .loadIbl("file://${testHelper.testDir}/assets/default_env_ibl.ktx"); await testHelper.capture(viewer.view, "ibl_loaded"); @@ -37,8 +41,9 @@ void main() async { test('load/remove gltf', () async { await testHelper.withViewer((viewer) async { - var asset = await viewer - .loadGlb("file://${testHelper.testDir}/assets/cube.gltf", relativeResourcePath: "${testHelper.testDir}/assets"); + var asset = await viewer.loadGltf( + "file://${testHelper.testDir}/assets/cube.gltf", + relativeResourcePath: "${testHelper.testDir}/assets"); await viewer .loadIbl("file://${testHelper.testDir}/assets/default_env_ibl.ktx"); await testHelper.capture(viewer.view, "gltf_loaded"); @@ -47,10 +52,26 @@ void main() async { }, cameraPosition: Vector3(0, 0, 5)); }); + test('transform gltf to unit cube', () async { + await testHelper.withViewer((viewer) async { + var asset = await viewer.loadGltf( + "file://${testHelper.testDir}/assets/cube.gltf", + relativeResourcePath: "${testHelper.testDir}/assets"); + + await viewer + .loadIbl("file://${testHelper.testDir}/assets/default_env_ibl.ktx"); + await asset.setTransform(Matrix4.compose( + Vector3.zero(), Quaternion.identity(), Vector3.all(2))); + await testHelper.capture(viewer.view, "gltf_before_unit_cube"); + await asset.transformToUnitCube(); + await testHelper.capture(viewer.view, "gltf_after_unit_cube"); + }, cameraPosition: Vector3(0, 0, 5)); + }); + test('add/remove asset from scene ', () async { await testHelper.withViewer((viewer) async { var asset = await viewer - .loadGlb("file://${testHelper.testDir}/assets/cube.glb"); + .loadGltf("file://${testHelper.testDir}/assets/cube.glb"); await viewer .loadIbl("file://${testHelper.testDir}/assets/default_env_ibl.ktx"); await testHelper.capture(viewer.view, "asset_added"); @@ -62,7 +83,7 @@ void main() async { test('destroy assets', () async { await testHelper.withViewer((viewer) async { var asset = await viewer - .loadGlb("file://${testHelper.testDir}/assets/cube.glb"); + .loadGltf("file://${testHelper.testDir}/assets/cube.glb"); await viewer .loadIbl("file://${testHelper.testDir}/assets/default_env_ibl.ktx"); await testHelper.capture(viewer.view, "assets_present"); @@ -70,6 +91,5 @@ void main() async { await testHelper.capture(viewer.view, "assets_destroyed"); }, cameraPosition: Vector3(0, 0, 5)); }); - }); } diff --git a/thermion_dart/test/assets/cube_texture2.svg b/thermion_dart/test/assets/cube_texture2.svg new file mode 100644 index 00000000..3d5282bd --- /dev/null +++ b/thermion_dart/test/assets/cube_texture2.svg @@ -0,0 +1,181 @@ + + + + + + + + + + + + + + Front + + + Back + + + Top + + + Bottom + + + Right + + + Left + diff --git a/thermion_dart/test/assets/cube_texture2_512x512.png b/thermion_dart/test/assets/cube_texture2_512x512.png new file mode 100644 index 0000000000000000000000000000000000000000..e38900539d722aca15310f507a2c4b8e316f8001 GIT binary patch literal 6021 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 literal 0 HcmV?d00001 diff --git a/thermion_dart/test/assets/cube_texture2_512x512_flipped.png b/thermion_dart/test/assets/cube_texture2_512x512_flipped.png new file mode 100644 index 0000000000000000000000000000000000000000..9c1fa5c703030b12336a32a7330859f522be3471 GIT binary patch literal 6079 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 S*Kq^i0gttfwHh=WUi}XXowbSp literal 0 HcmV?d00001 diff --git a/thermion_dart/test/depth_tests.dart b/thermion_dart/test/depth_tests.dart new file mode 100644 index 00000000..fafe4d1b --- /dev/null +++ b/thermion_dart/test/depth_tests.dart @@ -0,0 +1,392 @@ +@Timeout(const Duration(seconds: 600)) +import 'dart:async'; +import 'dart:io'; +import 'dart:math'; +import 'dart:typed_data'; +import 'package:test/test.dart'; +import 'package:thermion_dart/src/viewer/src/ffi/src/callbacks.dart'; +import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_asset.dart'; +import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_camera.dart'; +import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_filament_app.dart'; +import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_material.dart'; +import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_render_target.dart'; +import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_scene.dart'; +import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_swapchain.dart'; +import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_view.dart'; +import 'package:thermion_dart/thermion_dart.dart'; +import 'helpers.dart'; + +void checkMinMaxPixelValues(Float32List pixelBuffer, int width, int height) { + var minVal = 99999.0; + var maxVal = 0.0; + for (var y = 0; y < height; y++) { + for (var x = 0; x < width; x++) { + for (int i = 0; i < 3; i++) { + final srcIndex = (y * width * 4) + (x * 4) + i; + if (pixelBuffer[srcIndex] == 0) { + continue; + } + minVal = min(minVal, pixelBuffer[srcIndex]); + maxVal = max(maxVal, pixelBuffer[srcIndex]); + } + } + } + print("minVal $minVal maxVal $maxVal"); +} + +void main() async { + final testHelper = TestHelper("depth"); + await testHelper.setup(); + + test('write depth value to R32F texture', () async { + final viewportDimensions = (width: 512, height: 512); + var swapChain = await FilamentApp.instance!.createHeadlessSwapChain( + viewportDimensions.width, viewportDimensions.height) as FFISwapChain; + + var color = await FilamentApp.instance! + .createTexture(viewportDimensions.width, viewportDimensions.height, + flags: { + TextureUsage.TEXTURE_USAGE_BLIT_SRC, + TextureUsage.TEXTURE_USAGE_COLOR_ATTACHMENT, + TextureUsage.TEXTURE_USAGE_SAMPLEABLE + }, + textureFormat: TextureFormat.R32F); + + var renderTarget = await FilamentApp.instance!.createRenderTarget( + viewportDimensions.width, viewportDimensions.height, color: color) + as FFIRenderTarget; + + var view = await FilamentApp.instance!.createView() as FFIView; + await view.setPostProcessing(false); + await view.setRenderTarget(renderTarget); + + await FilamentApp.instance!.setClearOptions(0.0, 1.0, 0.0, 1.0); + var scene = await FilamentApp.instance!.createScene() as FFIScene; + + await view.setScene(scene); + await view.setViewport(viewportDimensions.width, viewportDimensions.height); + final camera = FFICamera( + await withPointerCallback((cb) => + Engine_createCameraRenderThread(FilamentApp.instance!.engine, cb)), + FilamentApp.instance! as FFIFilamentApp); + + await camera.setLensProjection(); + + await view.setCamera(camera); + + await view.setFrustumCullingEnabled(false); + await camera.setLensProjection(near: 0.5, far: 10); + final dist = 2.0; + await camera.lookAt( + Vector3( + -0.5, + dist, + dist, + ), + ); + + var mat = await FilamentApp.instance!.createMaterial( + File( + "/Users/nickfisher/Documents/thermion/materials/linear_depth.filamat", + ).readAsBytesSync(), + ); + var mi = await mat.createInstance(); + await mi.setDepthCullingEnabled(true); + await mi.setDepthWriteEnabled(true); + await mi.setCullingMode(CullingMode.BACK); + + var umi = await FilamentApp.instance! + .createUbershaderMaterialInstance(unlit: true); + var cube = await FilamentApp.instance! + .createGeometry(GeometryHelper.cube(), nullptr); + await scene.add(cube as FFIAsset); + await umi.setParameterFloat4("baseColorFactor", 1, 1, 1, 0); + + await cube.setTransform( + Matrix4.compose(Vector3.zero(), Quaternion.identity(), Vector3.all(1))); + await cube.setMaterialInstanceAt(mi as FFIMaterialInstance); + await FilamentApp.instance!.register(swapChain, view); + var pixelBuffers = await testHelper.capture(null, "linear_depth", + swapChain: swapChain, pixelDataFormat: PixelDataFormat.R); + checkMinMaxPixelValues(pixelBuffers[view]!.buffer.asFloat32List(), + viewportDimensions.width, viewportDimensions.height); + }); + + test('check NDC depth value', () async { + final viewportDimensions = (width: 512, height: 512); + var swapChain = await FilamentApp.instance!.createHeadlessSwapChain( + viewportDimensions.width, viewportDimensions.height) as FFISwapChain; + + var color = await FilamentApp.instance! + .createTexture(viewportDimensions.width, viewportDimensions.height, + flags: { + TextureUsage.TEXTURE_USAGE_BLIT_SRC, + TextureUsage.TEXTURE_USAGE_COLOR_ATTACHMENT, + TextureUsage.TEXTURE_USAGE_SAMPLEABLE + }, + textureFormat: TextureFormat.R32F); + + var renderTarget = await FilamentApp.instance!.createRenderTarget( + viewportDimensions.width, viewportDimensions.height, color: color) + as FFIRenderTarget; + + var view = await FilamentApp.instance!.createView() as FFIView; + await view.setPostProcessing(false); + await view.setRenderTarget(renderTarget); + + await FilamentApp.instance!.setClearOptions(0.0, 1.0, 0.0, 1.0); + var scene = await FilamentApp.instance!.createScene() as FFIScene; + + await view.setScene(scene); + await view.setViewport(viewportDimensions.width, viewportDimensions.height); + final camera = FFICamera( + await withPointerCallback((cb) => + Engine_createCameraRenderThread(FilamentApp.instance!.engine, cb)), + FilamentApp.instance! as FFIFilamentApp); + + await camera.setLensProjection(); + + await view.setCamera(camera); + + await view.setFrustumCullingEnabled(false); + await camera.setLensProjection(near: 0.5, far: 10); + final dist = 3.0; + await camera.lookAt( + Vector3( + -0.5, + dist, + dist, + ), + ); + + var mat = await FilamentApp.instance!.createMaterial( + File( + "/Users/nickfisher/Documents/thermion/materials/ndc_depth.filamat", + ).readAsBytesSync(), + ); + var mi = await mat.createInstance(); + await mi.setDepthCullingEnabled(true); + await mi.setDepthWriteEnabled(true); + await mi.setCullingMode(CullingMode.BACK); + + var umi = await FilamentApp.instance! + .createUbershaderMaterialInstance(unlit: true); + var cube = await FilamentApp.instance! + .createGeometry(GeometryHelper.cube(), nullptr); + await scene.add(cube as FFIAsset); + await umi.setParameterFloat4("baseColorFactor", 1, 1, 1, 0); + + await cube.setTransform( + Matrix4.compose(Vector3.zero(), Quaternion.identity(), Vector3.all(1))); + await cube.setMaterialInstanceAt(mi as FFIMaterialInstance); + await FilamentApp.instance!.register(swapChain, view); + var pixelBuffers = await testHelper.capture(null, "ndc_depth", + swapChain: swapChain, pixelDataFormat: PixelDataFormat.R); + checkMinMaxPixelValues(pixelBuffers[view]!.buffer.asFloat32List(), + viewportDimensions.width, viewportDimensions.height); + }); + + group('depth sampling', () { + test("depth sampling", () async { + await testHelper.withViewer((viewer) async { + await FilamentApp.instance!.setClearOptions(0, 0, 0, 1, + clearStencil: 0, discard: false, clear: true); + final camera = await viewer.getActiveCamera(); + await camera.lookAt(Vector3(3, 3, 6)); + + final view = await testHelper.createView(testHelper.swapChain); + await testHelper.withCube( + viewer, + (cube) async { + var mat = await FilamentApp.instance!.createMaterial( + File( + "/Users/nickfisher/Documents/thermion/materials/depth_sampler.filamat", + ).readAsBytesSync(), + ); + final mi = await mat.createInstance(); + + await viewer.addToScene(cube); + final secondScene = await view.getScene(); + await secondScene.add(cube); + + final sampler = await FilamentApp.instance!.createTextureSampler(); + final rt = await view.getRenderTarget(); + final color = await rt!.getColorTexture(); + final depth = await rt!.getDepthTexture(); + await mi.setParameterTexture( + "depth", + depth, + await FilamentApp.instance!.createTextureSampler( + compareMode: TextureCompareMode.COMPARE_TO_TEXTURE, + ), + ); + await cube.setMaterialInstanceAt(mi); + + await testHelper.capture(null, "depth_sampling1"); + }, + ); + }, createRenderTarget: true); + }); + }); +} + + + // group('projection', () { + // test('project texture & UV unwrap', () async { + // await testHelper.withViewer((viewer) async { + // final camera = await viewer.getActiveCamera(); + // await viewer.view.setFrustumCullingEnabled(false); + // await camera.setLensProjection(near: 0.01, far: 100); + // final dist = 26.0; + // await camera.lookAt( + // Vector3( + // -0.5, + // dist, + // dist, + // ), + // ); + // await FilamentApp.instance! + // .unregister(testHelper.swapChain, viewer.view); + + // await withView(testHelper.swapChain, viewer, (linearDepthView) async { + // await withView(testHelper.swapChain, viewer, (manualDepthView) async { + // await manualDepthView.setRenderOrder(1); + // await linearDepthView.setRenderOrder(0); + + // await viewer.view.setRenderOrder(2); + // await withManualDepthMaterial(testHelper, viewer, ( + // manualDepthMi, + // ) async { + // await withSampledDepthMaterial(testHelper, viewer, ( + // sampledDepthMi, + // ) async { + // await sampledDepthMi.setParameterTexture( + // "depth", + // await (await manualDepthView.getRenderTarget())! + // .getColorTexture(), + // await FilamentApp.instance!.createTextureSampler()); + + // await withLinearDepthMaterial(testHelper, viewer, ( + // linearDepthMi, + // ) async { + // await withProjectionMaterial(testHelper, viewer, ( + // projectMi, + // ) async { + // await FilamentApp.instance!.setClearOptions(0, 0, 0, 1, + // clearStencil: 0, discard: false, clear: true); + // await testHelper.withCube(viewer, (cube2) async { + // var ubershader = await cube2.getMaterialInstanceAt(); + // (await manualDepthView.getScene()).remove(cube2); + // await ubershader.setParameterFloat4( + // "baseColorFactor", 0.0, 1.0, 0.0, 1.0); + // await cube2.setTransform(Matrix4.compose( + // Vector3(-0.5, 0, -0.5), + // Quaternion.identity(), + // Vector3.all(1))); + // await testHelper.withCube(viewer, (cube) async { + // await cube.setTransform(Matrix4.compose(Vector3.zero(), + // Quaternion.identity(), Vector3.all(1))); + // var divisions = 1; + // var ubershader = await cube.getMaterialInstanceAt(); + // await ubershader.setDepthCullingEnabled(true); + // await ubershader.setDepthWriteEnabled(true); + // await ubershader.setCullingMode(CullingMode.BACK); + // await ubershader.setParameterInt("baseColorIndex", 0); + + // await ubershader.setParameterTexture( + // "baseColorMap", + // await createTextureFromImage(testHelper), + // await FilamentApp.instance!.createTextureSampler()); + + // // final color = await (await linearDepthView.getRenderTarget())! + // // .getColorTexture(); + // // final depth = await (await manualDepthView.getRenderTarget())! + // // .getColorTexture(); + + // // await projectMi.setParameterTexture("color", color, + // // await FilamentApp.instance!.createTextureSampler()); + // // await projectMi.setParameterTexture("depth", depth, + // // await FilamentApp.instance!.createTextureSampler()); + // // await projectMi.setDepthCullingEnabled(true); + // // await projectMi.setParameterBool("useDepth", true); + + // // for (int i = 0; i < divisions; i++) { + // // await camera.lookAt( + // // Vector3( + // // sin(i / divisions * pi) * dist, + // // dist, + // // cos(i / divisions * pi) * dist, + // // ), + // // ); + // // await cube.setMaterialInstanceAt(manualDepthMi); + + // var pixelBuffers = await testHelper + // .capture(null, "project_texture_color", + // beforeRender: (view) async { + // if (view == linearDepthView) { + // await cube.setMaterialInstanceAt(linearDepthMi); + // } else if (view == manualDepthView) { + // await cube.setMaterialInstanceAt(manualDepthMi); + // } else { + // throw Exception(); + // } + // }); + // // var comparison = comparePixelBuffers( + // // pixelBuffers[1], pixelBuffers[2], 512, 512); + // // savePixelBufferToBmp(comparison, 512, 512, "cmparison"); + // // await cube.setMaterialInstanceAt(ubershader); + // checkRedFromRGBAPixelBuffer( + // pixelBuffers[manualDepthView]! + // .buffer + // .asFloat32List(), + // 512, + // 512); + // // } + // }); + // }); + // }); + // }); + // }); + // }); + // }); + // }); + // }, createRenderTarget: true); + // }); + // }); +// } + +// final projectedImage = await viewer.createImage(512, 512, 4); +// final data = await projectedImage.getData(); +// data.setRange(0, data.length, floatPixelBuffer); +// final projectedTexture = await FilamentApp.instance!.createTexture( +// 512, +// 512, +// textureFormat: TextureFormat.RGBA32F, +// ); +// await projectedTexture.setLinearImage( +// projectedImage, +// PixelDataFormat.RGBA, +// PixelDataType.FLOAT, +// ); + +// await ubershader.setParameterTexture( +// "baseColorMap", +// projectedTexture, +// sampler, +// ); +// await object.setMaterialInstanceAt(ubershader); +// await testHelper.capture( +// viewer, +// "retextured_${key}_$i", +// renderTarget: rt, +// ); +// await resetMaterial(); +// } +// await viewer.destroyAsset(object); +// } +// }); +// }); +// }); +// }); +// }); +// } diff --git a/thermion_dart/test/postprocessing_tests.dart b/thermion_dart/test/postprocessing_tests.dart new file mode 100644 index 00000000..0f38b59b --- /dev/null +++ b/thermion_dart/test/postprocessing_tests.dart @@ -0,0 +1,40 @@ +@Timeout(const Duration(seconds: 600)) +import 'package:test/test.dart'; +import 'package:thermion_dart/src/filament/src/light_options.dart'; +import 'package:thermion_dart/thermion_dart.dart'; + +import 'helpers.dart'; + +void main() async { + final testHelper = TestHelper("postprocessing"); + await testHelper.setup(); + group("assets", () { + test('enable/disable postprocessing', () async { + await testHelper.withViewer((viewer) async { + await viewer.setBackgroundColor(1.0, 0.0, 0.0, 1.0); + await testHelper.capture(viewer.view, "empty_scene_no_postprocessing"); + await viewer.setPostProcessing(true); + await testHelper.capture(viewer.view, "empty_scene_postprocessing"); + }, postProcessing: false, createRenderTarget: true); + }); + + test('bloom', () async { + await testHelper.withViewer((viewer) async { + await FilamentApp.instance!.setClearOptions(1, 1, 1, 1, clear: false); + var asset = await viewer + .loadGltf("file://${testHelper.testDir}/assets/cube.glb"); + var light = await viewer.addDirectLight( + DirectLight.point(intensity: 1000000, falloffRadius: 10)); + await viewer.setLightPosition(light, 1, 2, 2); + await viewer.setBloom(false, 0.5); + await testHelper.capture(viewer.view, "postprocessing_no_bloom"); + await viewer.setBloom(true, 0.5); + await testHelper.capture(viewer.view, "postprocessing_bloom_0.5"); + await viewer.setBloom(true, 1.0); + await testHelper.capture(viewer.view, "postprocessing_bloom_1.0"); + }, postProcessing: true, createRenderTarget: true, bg: kBlue); + }); + + + }); +}