Files
cup_edit/thermion_dart/test/depth_tests.dart
2025-03-28 10:01:00 +08:00

393 lines
16 KiB
Dart

@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<TCamera>((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<TCamera>((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);
// }
// });
// });
// });
// });
// });
// }