test updates

This commit is contained in:
Nick Fisher
2025-03-20 18:56:10 +08:00
parent e6bdcb687a
commit 1177a71f73
14 changed files with 1142 additions and 900 deletions

View File

@@ -7,21 +7,21 @@ void main() async {
final testHelper = TestHelper("assets");
await testHelper.setup();
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");
// });
// });
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");
});
});
test('load/remove ibl', () async {
await testHelper.withViewer((viewer) async {
@@ -35,39 +35,41 @@ void main() async {
}, 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");
// await viewer
// .loadIbl("file://${testHelper.testDir}/assets/default_env_ibl.ktx");
// await testHelper.capture(viewer.view, "asset_added");
// await viewer.removeFromScene(asset);
// await testHelper.capture(viewer.view, "asset_removed");
// }, cameraPosition: Vector3(0, 0, 5));
// });
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");
await viewer
.loadIbl("file://${testHelper.testDir}/assets/default_env_ibl.ktx");
await testHelper.capture(viewer.view, "gltf_loaded");
await viewer.removeFromScene(asset);
await testHelper.capture(viewer.view, "gltf_removed");
}, cameraPosition: Vector3(0, 0, 5));
});
// test('destroy assets', () async {
// await testHelper.withViewer((viewer) async {
// var asset = await viewer
// .loadGlb("file://${testHelper.testDir}/assets/cube.glb");
// await viewer
// .loadIbl("file://${testHelper.testDir}/assets/default_env_ibl.ktx");
// await testHelper.capture(viewer.view, "assets_present");
// await viewer.destroyAssets();
// await testHelper.capture(viewer.view, "assets_destroyed");
// }, 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");
await viewer
.loadIbl("file://${testHelper.testDir}/assets/default_env_ibl.ktx");
await testHelper.capture(viewer.view, "asset_added");
await viewer.removeFromScene(asset);
await testHelper.capture(viewer.view, "asset_removed");
}, cameraPosition: Vector3(0, 0, 5));
});
test('destroy assets', () async {
await testHelper.withViewer((viewer) async {
var asset = await viewer
.loadGlb("file://${testHelper.testDir}/assets/cube.glb");
await viewer
.loadIbl("file://${testHelper.testDir}/assets/default_env_ibl.ktx");
await testHelper.capture(viewer.view, "assets_present");
await viewer.destroyAssets();
await testHelper.capture(viewer.view, "assets_destroyed");
}, cameraPosition: Vector3(0, 0, 5));
});
// await viewer.destroyLights();
// await viewer.removeSkybox();
// await viewer.removeIbl();
// asset = await viewer
// .loadGlb("file://${testHelper.testDir}/assets/cube.glb");
// await testHelper.capture(viewer.view, "asset_reloaded");
});
}

Binary file not shown.

View File

@@ -0,0 +1,121 @@
{
"asset":{
"generator":"Khronos glTF Blender I/O v4.2.60",
"version":"2.0"
},
"scene":0,
"scenes":[
{
"name":"Scene",
"nodes":[
0
]
}
],
"nodes":[
{
"mesh":0,
"name":"Cube"
}
],
"materials":[
{
"doubleSided":true,
"name":"Material",
"pbrMetallicRoughness":{
"baseColorFactor":[
0.800000011920929,
0.800000011920929,
0.800000011920929,
1
],
"metallicFactor":0,
"roughnessFactor":0.5
}
}
],
"meshes":[
{
"name":"Cube",
"primitives":[
{
"attributes":{
"POSITION":0,
"NORMAL":1,
"TEXCOORD_0":2
},
"indices":3,
"material":0
}
]
}
],
"accessors":[
{
"bufferView":0,
"componentType":5126,
"count":24,
"max":[
1,
1,
1
],
"min":[
-1,
-1,
-1
],
"type":"VEC3"
},
{
"bufferView":1,
"componentType":5126,
"count":24,
"type":"VEC3"
},
{
"bufferView":2,
"componentType":5126,
"count":24,
"type":"VEC2"
},
{
"bufferView":3,
"componentType":5123,
"count":36,
"type":"SCALAR"
}
],
"bufferViews":[
{
"buffer":0,
"byteLength":288,
"byteOffset":0,
"target":34962
},
{
"buffer":0,
"byteLength":288,
"byteOffset":288,
"target":34962
},
{
"buffer":0,
"byteLength":192,
"byteOffset":576,
"target":34962
},
{
"buffer":0,
"byteLength":72,
"byteOffset":768,
"target":34963
}
],
"buffers":[
{
"byteLength":840,
"uri":"cube.bin"
}
]
}

View File

@@ -0,0 +1,24 @@
import 'package:test/test.dart';
import 'helpers.dart';
void main() async {
final testHelper = TestHelper("assets");
await testHelper.setup();
group("background", () {
test('set background color', () async {
await testHelper.withViewer((viewer) async {
await viewer.setBackgroundColor(0, 1, 0, 1);
await testHelper.capture(viewer.view, "background_green");
await viewer.setBackgroundColor(1, 0, 0, 1);
await testHelper.capture(viewer.view, "background_red");
});
});
test('set background image', () async {
await testHelper.withViewer((viewer) async {
await viewer.setBackgroundImage("file://${testHelper.testDir}/assets/cube_texture2_512x512.png");
await testHelper.capture(viewer.view, "background_image");
});
});
});
}

View File

@@ -1,240 +1,235 @@
// ignore_for_file: unused_local_variable
import 'dart:math';
import 'package:thermion_dart/thermion_dart.dart';
import 'package:test/test.dart';
import 'package:vector_math/vector_math_64.dart';
import 'helpers.dart';
void main() async {
final testHelper = TestHelper("integration");
final testHelper = TestHelper("camera");
await testHelper.setup();
group('camera', () {
test('model matrix', () async {
await testHelper.withViewer((viewer) async {
var matrix = await viewer.getCameraModelMatrix();
expect(matrix.trace(), 4);
await viewer.setCameraPosition(2.0, 2.0, 2.0);
matrix = await viewer.getCameraModelMatrix();
var position = matrix.getColumn(3).xyz;
final camera = await viewer.getActiveCamera();
await camera.setModelMatrix(Matrix4.translation(Vector3.all(4.0)));
var matrix = await camera.getModelMatrix();
await camera.lookAt(Vector3(2.0, 2.0, 2.0));
matrix = await camera.getModelMatrix();
var position = await camera.getPosition();
expect(position.x, 2.0);
expect(position.y, 2.0);
expect(position.z, 2.0);
position = await viewer.getCameraPosition();
expect(position.x, 2.0);
expect(position.y, 2.0);
expect(position.z, 2.0);
});
});
test('getCameraViewMatrix', () async {
await testHelper.withViewer((viewer) async {
await viewer.setCameraModelMatrix4(Matrix4.identity());
var modelMatrix = await viewer.getCameraModelMatrix();
var viewMatrix = await viewer.getCameraViewMatrix();
// test('getCameraViewMatrix', () async {
// await testHelper.withViewer((viewer) async {
// await viewer.setCameraModelMatrix4(Matrix4.identity());
// var modelMatrix = await camera.getModelMatrix();
// var viewMatrix = await viewer.getCameraViewMatrix();
// The view matrix should be the inverse of the model matrix
var identity = modelMatrix * viewMatrix;
expect(identity.isIdentity(), isTrue);
var camera = await viewer.getMainCamera();
identity = modelMatrix * (await camera.getViewMatrix());
expect(identity.isIdentity(), isTrue);
// // The view matrix should be the inverse of the model matrix
// var identity = modelMatrix * viewMatrix;
// expect(identity.isIdentity(), isTrue);
// var camera = await viewer.getMainCamera();
// identity = modelMatrix * (await camera.getViewMatrix());
// expect(identity.isIdentity(), isTrue);
// Check that moving the camera affects the view matrix
await viewer.setCameraPosition(3.0, 4.0, 5.0);
viewMatrix = await viewer.getCameraViewMatrix();
var invertedView = viewMatrix.clone()..invert();
var position = invertedView.getColumn(3).xyz;
expect(position.x, closeTo(3.0, 1e-6));
expect(position.y, closeTo(4.0, 1e-6));
expect(position.z, closeTo(5.0, 1e-6));
});
});
// // Check that moving the camera affects the view matrix
// await viewer.setCameraPosition(3.0, 4.0, 5.0);
// viewMatrix = await viewer.getCameraViewMatrix();
// var invertedView = viewMatrix.clone()..invert();
// var position = invertedView.getColumn(3).xyz;
// expect(position.x, closeTo(3.0, 1e-6));
// expect(position.y, closeTo(4.0, 1e-6));
// expect(position.z, closeTo(5.0, 1e-6));
// });
// });
test('getCameraProjectionMatrix', () async {
await testHelper.withViewer((viewer) async {
var projectionMatrix = await viewer.getCameraProjectionMatrix();
print(projectionMatrix);
});
});
// test('getCameraProjectionMatrix', () async {
// await testHelper.withViewer((viewer) async {
// var projectionMatrix = await viewer.getCameraProjectionMatrix();
// print(projectionMatrix);
// });
// });
test('getCameraCullingProjectionMatrix', () async {
await testHelper.withViewer((viewer) async {
// ignore: dead_code
var viewer = await testHelper.createViewer();
var matrix = await viewer.getCameraCullingProjectionMatrix();
print(matrix);
});
});
// test('getCameraCullingProjectionMatrix', () async {
// await testHelper.withViewer((viewer) async {
// // ignore: dead_code
// var viewer = await testHelper.createViewer();
// var matrix = await viewer.getCameraCullingProjectionMatrix();
// print(matrix);
// });
// });
test('getCameraFrustum', () async {
await testHelper.withViewer((viewer) async {
var frustum = await viewer.getCameraFrustum();
print(frustum.plane5.normal);
print(frustum.plane5.constant);
// test('getCameraFrustum', () async {
// await testHelper.withViewer((viewer) async {
// var frustum = await viewer.getCameraFrustum();
// print(frustum.plane5.normal);
// print(frustum.plane5.constant);
var camera = await viewer.getMainCamera();
// var camera = await viewer.getMainCamera();
await camera.setLensProjection(
near: 10.0, far: 1000.0, aspect: 1.0, focalLength: 28.0);
frustum = await viewer.getCameraFrustum();
print(frustum.plane5.normal);
print(frustum.plane5.constant);
});
});
// await camera.setLensProjection(
// near: 10.0, far: 1000.0, aspect: 1.0, focalLength: 28.0);
// frustum = await viewer.getCameraFrustum();
// print(frustum.plane5.normal);
// print(frustum.plane5.constant);
// });
// });
test('set orthographic projection', () async {
await testHelper.withViewer((viewer) async {
var camera = await viewer.getMainCamera();
await viewer.createGeometry(GeometryHelper.cube());
// test('set orthographic projection', () async {
// await testHelper.withViewer((viewer) async {
// var camera = await viewer.getMainCamera();
// await viewer.createGeometry(GeometryHelper.cube());
await camera.setProjection(
Projection.Orthographic, -0.05, 0.05, -0.05, 0.05, 0.05, 10000);
await testHelper.capture(viewer, "camera_set_orthographic_projection");
});
});
// await camera.setProjection(
// Projection.Orthographic, -0.05, 0.05, -0.05, 0.05, 0.05, 10000);
// await testHelper.capture(viewer, "camera_set_orthographic_projection");
// });
// });
test('set perspective projection/culling matrix', () async {
await testHelper.withViewer((viewer) async {
var camera = await viewer.getMainCamera();
final cube = await viewer.createGeometry(GeometryHelper.cube());
// test('set perspective projection/culling matrix', () async {
// await testHelper.withViewer((viewer) async {
// var camera = await viewer.getMainCamera();
// final cube = await viewer.createGeometry(GeometryHelper.cube());
var fovY = pi / 2;
await camera.setProjectionMatrixWithCulling(
makePerspectiveMatrix(fovY, 1.0, 0.05, 10000), 0.05, 10000);
// var fovY = pi / 2;
// await camera.setProjectionMatrixWithCulling(
// makePerspectiveMatrix(fovY, 1.0, 0.05, 10000), 0.05, 10000);
await testHelper.capture(viewer,
"camera_set_perspective_projection_culling_matrix_object_fov90");
// await testHelper.capture(viewer,
// "camera_set_perspective_projection_culling_matrix_object_fov90");
// cube no longer visible when the far plane is moved closer to camera so cube is outside
fovY = 2 * (pi / 3);
await camera.setProjectionMatrixWithCulling(
makePerspectiveMatrix(fovY, 1.0, 0.05, 10000), 0.05, 10000);
// // cube no longer visible when the far plane is moved closer to camera so cube is outside
// fovY = 2 * (pi / 3);
// await camera.setProjectionMatrixWithCulling(
// makePerspectiveMatrix(fovY, 1.0, 0.05, 10000), 0.05, 10000);
await testHelper.capture(viewer,
"camera_set_perspective_projection_culling_matrix_object_fov120");
});
});
// await testHelper.capture(viewer,
// "camera_set_perspective_projection_culling_matrix_object_fov120");
// });
// });
test('set custom projection/culling matrix (orthographic)', () async {
await testHelper.withViewer((viewer) async {
var camera = await viewer.getMainCamera();
final cube = await viewer.createGeometry(GeometryHelper.cube());
// test('set custom projection/culling matrix (orthographic)', () async {
// await testHelper.withViewer((viewer) async {
// var camera = await viewer.getMainCamera();
// final cube = await viewer.createGeometry(GeometryHelper.cube());
// cube is visible when inside the frustum, cube is visible
var projectionMatrix =
makeOrthographicMatrix(-10.0, 10.0, -10.0, 10.0, 0.05, 10000);
await camera.setProjectionMatrixWithCulling(
projectionMatrix, 0.05, 10000);
// // cube is visible when inside the frustum, cube is visible
// var projectionMatrix =
// makeOrthographicMatrix(-10.0, 10.0, -10.0, 10.0, 0.05, 10000);
// await camera.setProjectionMatrixWithCulling(
// projectionMatrix, 0.05, 10000);
await testHelper.capture(
viewer, "camera_projection_culling_matrix_object_in_frustum");
// await testHelper.capture(
// viewer, "camera_projection_culling_matrix_object_in_frustum");
// cube no longer visible when the far plane is moved closer to camera so cube is outside
projectionMatrix =
makeOrthographicMatrix(-10.0, 10.0, -10.0, 10.0, 0.05, 1);
await camera.setProjectionMatrixWithCulling(projectionMatrix, 0.05, 1);
await testHelper.capture(
viewer, "camera_projection_culling_matrix_object_outside_frustum");
});
});
// // cube no longer visible when the far plane is moved closer to camera so cube is outside
// projectionMatrix =
// makeOrthographicMatrix(-10.0, 10.0, -10.0, 10.0, 0.05, 1);
// await camera.setProjectionMatrixWithCulling(projectionMatrix, 0.05, 1);
// await testHelper.capture(
// viewer, "camera_projection_culling_matrix_object_outside_frustum");
// });
// });
test('setting transform on camera updates model matrix (no parent)',
() async {
await testHelper.withViewer((viewer) async {
var cameraEntity = await viewer.getMainCameraEntity();
var camera = await viewer.getMainCamera();
// test('setting transform on camera updates model matrix (no parent)',
// () async {
// await testHelper.withViewer((viewer) async {
// var cameraEntity = await viewer.getMainCameraEntity();
// var camera = await viewer.getMainCamera();
await viewer.setTransform(
cameraEntity, Matrix4.translation(Vector3.all(1)));
// await viewer.setTransform(
// cameraEntity, Matrix4.translation(Vector3.all(1)));
var modelMatrix = await viewer.getCameraModelMatrix();
expect(modelMatrix.getColumn(3).x, 1.0);
expect(modelMatrix.getColumn(3).y, 1.0);
expect(modelMatrix.getColumn(3).z, 1.0);
expect(modelMatrix.getColumn(3).w, 1.0);
});
});
// var modelMatrix = await camera.getModelMatrix();
// expect(modelMatrix.getColumn(3).x, 1.0);
// expect(modelMatrix.getColumn(3).y, 1.0);
// expect(modelMatrix.getColumn(3).z, 1.0);
// expect(modelMatrix.getColumn(3).w, 1.0);
// });
// });
test('setting transform on camera updates model matrix (with parent)',
() async {
await testHelper.withViewer((viewer) async {
var cameraEntity = await viewer.getMainCameraEntity();
var camera = await viewer.getMainCamera();
// test('setting transform on camera updates model matrix (with parent)',
// () async {
// await testHelper.withViewer((viewer) async {
// var cameraEntity = await viewer.getMainCameraEntity();
// var camera = await viewer.getMainCamera();
var parent = await viewer.createGeometry(GeometryHelper.cube());
// var parent = await viewer.createGeometry(GeometryHelper.cube());
await viewer.setParent(camera.getEntity(), parent.entity);
await viewer.setTransform(
cameraEntity, Matrix4.translation(Vector3(1, 0, 0)));
// await viewer.setParent(camera.getEntity(), parent.entity);
// await viewer.setTransform(
// cameraEntity, Matrix4.translation(Vector3(1, 0, 0)));
var modelMatrix = await viewer.getCameraModelMatrix();
expect(modelMatrix.getColumn(3).x, 1.0);
expect(modelMatrix.getColumn(3).y, 0.0);
expect(modelMatrix.getColumn(3).z, 0.0);
expect(modelMatrix.getColumn(3).w, 1.0);
// var modelMatrix = await camera.getModelMatrix();
// expect(modelMatrix.getColumn(3).x, 1.0);
// expect(modelMatrix.getColumn(3).y, 0.0);
// expect(modelMatrix.getColumn(3).z, 0.0);
// expect(modelMatrix.getColumn(3).w, 1.0);
await viewer.setTransform(
parent.entity, Matrix4.translation(Vector3(0, 1, 0)));
modelMatrix = await viewer.getCameraModelMatrix();
expect(modelMatrix.getColumn(3).x, 1.0);
expect(modelMatrix.getColumn(3).y, 1.0);
expect(modelMatrix.getColumn(3).z, 0.0);
expect(modelMatrix.getColumn(3).w, 1.0);
});
});
// await viewer.setTransform(
// parent.entity, Matrix4.translation(Vector3(0, 1, 0)));
// modelMatrix = await camera.getModelMatrix();
// expect(modelMatrix.getColumn(3).x, 1.0);
// expect(modelMatrix.getColumn(3).y, 1.0);
// expect(modelMatrix.getColumn(3).z, 0.0);
// expect(modelMatrix.getColumn(3).w, 1.0);
// });
// });
test(
'when a camera is the parent of another entity, setting the model matrix updates the parent transform ',
() async {
await testHelper.withViewer((viewer) async {
var camera = await viewer.createCamera();
// test(
// 'when a camera is the parent of another entity, setting the model matrix updates the parent transform ',
// () async {
// await testHelper.withViewer((viewer) async {
// var camera = await viewer.createCamera();
var child = await viewer
.createGeometry(GeometryHelper.cube(normals: false, uvs: false));
await viewer.setParent(child.entity, camera.getEntity());
// var child = await viewer
// .createGeometry(GeometryHelper.cube(normals: false, uvs: false));
// await viewer.setParent(child.entity, camera.getEntity());
await testHelper.capture(viewer, "camera_as_parent1");
// await testHelper.capture(viewer, "camera_as_parent1");
await camera.setModelMatrix(Matrix4.translation(Vector3(1, 0, 0)));
// await camera.setModelMatrix(Matrix4.translation(Vector3(1, 0, 0)));
await testHelper.capture(viewer, "camera_as_parent2");
}, bg: kRed, cameraPosition: Vector3(0, 0, 10));
});
// await testHelper.capture(viewer, "camera_as_parent2");
// }, bg: kRed, cameraPosition: Vector3(0, 0, 10));
// });
test('create camera', () async {
await testHelper.withViewer((viewer) async {
await viewer.setCameraPosition(0, 0, 5);
await viewer.setBackgroundColor(1.0, 0.0, 1.0, 1.0);
await viewer
.createGeometry(GeometryHelper.cube(normals: false, uvs: false));
await testHelper.capture(viewer, "create_camera_main_camera");
// test('create camera', () async {
// await testHelper.withViewer((viewer) async {
// await viewer.setCameraPosition(0, 0, 5);
// await viewer.setBackgroundColor(1.0, 0.0, 1.0, 1.0);
// await viewer
// .createGeometry(GeometryHelper.cube(normals: false, uvs: false));
// await testHelper.capture(viewer, "create_camera_main_camera");
expect(viewer.getCameraCount(), 1);
var newCamera = await viewer.createCamera();
expect(viewer.getCameraCount(), 2);
await newCamera.setTransform(Matrix4.translation(Vector3(0, 0, 4)));
newCamera.setLensProjection();
await viewer.setActiveCamera(newCamera);
// expect(viewer.getCameraCount(), 1);
// var newCamera = await viewer.createCamera();
// expect(viewer.getCameraCount(), 2);
// await newCamera.setTransform(Matrix4.translation(Vector3(0, 0, 4)));
// newCamera.setLensProjection();
// await viewer.setActiveCamera(newCamera);
expect(await viewer.getActiveCamera(), newCamera);
// expect(await viewer.getActiveCamera(), newCamera);
await testHelper.capture(viewer, "create_camera_new_camera");
// await testHelper.capture(viewer, "create_camera_new_camera");
final mainCamera = await viewer.getMainCamera();
await viewer.setActiveCamera(mainCamera);
expect(await viewer.getActiveCamera(), mainCamera);
await testHelper.capture(viewer, "create_camera_back_to_main");
// final mainCamera = await viewer.getMainCamera();
// await viewer.setActiveCamera(mainCamera);
// expect(await viewer.getActiveCamera(), mainCamera);
// await testHelper.capture(viewer, "create_camera_back_to_main");
expect(viewer.getCameraCount(), 2);
expect(viewer.getCameraAt(0), await viewer.getMainCamera());
expect(viewer.getCameraAt(1), newCamera);
await expectLater(
() => viewer.getCameraAt(2), throwsA(isA<Exception>()));
});
});
// expect(viewer.getCameraCount(), 2);
// expect(viewer.getCameraAt(0), await viewer.getMainCamera());
// expect(viewer.getCameraAt(1), newCamera);
// await expectLater(
// () => viewer.getCameraAt(2), throwsA(isA<Exception>()));
// });
// });
});
}

View File

@@ -1,18 +1,21 @@
// ignore_for_file: unused_local_variable
import 'dart:io';
import 'dart:math';
import 'package:thermion_dart/src/viewer/src/ffi/src/thermion_viewer_ffi.dart';
import 'package:thermion_dart/thermion_dart.dart';
import 'package:test/test.dart';
import 'package:vector_math/vector_math_64.dart';
import 'helpers.dart';
void main() async {
final testHelper = TestHelper("geometry");
await testHelper.setup();
group("custom geometry", () {
test('create cube (uvs only)', () async {
var viewer = await testHelper.createViewer();
await viewer
.createGeometry(GeometryHelper.cube(normals: false, uvs: true));
await testHelper.capture(viewer, "geometry_cube_with_uvs");
});
test('create cube with normals & uvs', () async {
var viewer = await testHelper.createViewer();
await viewer
@@ -185,15 +188,18 @@ void main() async {
final cube = await viewer.createGeometry(
GeometryHelper.cube(uvs: true, normals: true),
materialInstances: [materialInstance]);
var textureData =
final image = await viewer.decodeImage(
File("${testHelper.testDir}/assets/cube_texture_512x512.png")
.readAsBytesSync();
var texture = await viewer.createTexture(textureData);
await viewer.applyTexture(texture as ThermionFFITexture, cube.entity);
.readAsBytesSync());
var texture = await viewer.createTexture(
await image.getWidth(), await image.getHeight());
await texture.setLinearImage(
image, PixelDataFormat.RGBA, PixelDataType.FLOAT);
await testHelper.capture(
viewer, "geometry_cube_with_custom_material_ubershader_texture");
await viewer.destroyAsset(cube);
await viewer.destroyTexture(texture);
await texture.dispose();
await image.destroy();
});
test('unlit material with color only', () async {
@@ -216,11 +222,14 @@ void main() async {
materialInstances: [materialInstance]);
await materialInstance.setParameterInt("baseColorIndex", 0);
var textureData =
final image = await viewer.decodeImage(
File("${testHelper.testDir}/assets/cube_texture_512x512.png")
.readAsBytesSync();
var texture = await viewer.createTexture(textureData);
await viewer.applyTexture(texture, cube.entity);
.readAsBytesSync());
var texture = await viewer.createTexture(
await image.getWidth(), await image.getHeight());
await texture.setLinearImage(
image, PixelDataFormat.RGBA, PixelDataType.FLOAT);
await testHelper.capture(viewer, "unlit_material_texture_only");
await viewer.destroyAsset(cube);
});
@@ -237,24 +246,26 @@ void main() async {
cube2.entity, Matrix4.translation(Vector3(1, 1, 1)));
await materialInstance.setParameterInt("baseColorIndex", 0);
var textureData =
final image = await viewer.decodeImage(
File("${testHelper.testDir}/assets/cube_texture_512x512.png")
.readAsBytesSync();
var texture = await viewer.createTexture(textureData);
await viewer.applyTexture(texture, cube1.entity);
await viewer.applyTexture(texture, cube2.entity);
.readAsBytesSync());
var texture = await viewer.createTexture(
await image.getWidth(), await image.getHeight());
await texture.setLinearImage(
image, PixelDataFormat.RGBA, PixelDataType.FLOAT);
await testHelper.capture(viewer, "unlit_material_shared");
await viewer.destroyTexture(texture);
await texture.dispose();
await image.destroy();
});
});
test('create sphere (no normals)', () async {
var viewer = await testHelper.createViewer();
await viewer.setBackgroundColor(0.0, 0.0, 1.0, 1.0);
await viewer.setCameraPosition(0, 0, 6);
await viewer
.createGeometry(GeometryHelper.sphere(normals: false, uvs: false));
await testHelper.capture(viewer, "geometry_sphere_no_normals");
await testHelper.withViewer((viewer) async {
await viewer
.createGeometry(GeometryHelper.sphere(normals: false, uvs: false));
await testHelper.capture(viewer, "geometry_sphere_no_normals");
}, bg: kBlue, cameraPosition: Vector3(0, 0, 6));
});
test('create multiple (non-instanced) geometry', () async {

View File

@@ -1,153 +1,153 @@
// ignore_for_file: unused_local_variable
// // ignore_for_file: unused_local_variable
import 'dart:io';
import 'package:thermion_dart/thermion_dart.dart';
import 'package:test/test.dart';
// import 'dart:io';
// import 'package:thermion_dart/thermion_dart.dart';
// import 'package:test/test.dart';
import 'package:vector_math/vector_math_64.dart';
// import 'package:vector_math/vector_math_64.dart';
import 'helpers.dart';
// import 'helpers.dart';
void main() async {
final testHelper = TestHelper("gltf");
group("gltf", () {
test('load glb from file', () async {
await testHelper.withViewer((viewer) async {
var model = await viewer
.loadGlb("file://${testHelper.testDir}/assets/cube.glb");
await testHelper.capture(viewer, "load_glb_from_file");
await viewer.destroyAsset(model);
});
});
// void main() async {
// final testHelper = TestHelper("gltf");
// group("gltf", () {
// test('load glb from file', () async {
// await testHelper.withViewer((viewer) async {
// var model = await viewer
// .loadGlb("file://${testHelper.testDir}/assets/cube.glb");
// await testHelper.capture(viewer, "load_glb_from_file");
// await viewer.destroyAsset(model);
// });
// });
test('load glb from buffer', () async {
await testHelper.withViewer((viewer) async {
var buffer =
File("${testHelper.testDir}/assets/cube.glb").readAsBytesSync();
var model = await viewer.loadGlbFromBuffer(buffer);
await testHelper.capture(viewer, "load_glb_from_buffer");
});
});
// test('load glb from buffer', () async {
// await testHelper.withViewer((viewer) async {
// var buffer =
// File("${testHelper.testDir}/assets/cube.glb").readAsBytesSync();
// var model = await viewer.loadGlbFromBuffer(buffer);
// await testHelper.capture(viewer, "load_glb_from_buffer");
// });
// });
test('load glb from buffer with instances', () async {
await testHelper.withViewer((viewer) async {
var buffer =
File("${testHelper.testDir}/assets/cube.glb").readAsBytesSync();
var model = await viewer.loadGlbFromBuffer(buffer, numInstances: 2);
var instance = await model.createInstance();
await instance.addToScene();
await viewer.setTransform(
instance.entity, Matrix4.translation(Vector3(1, 0, 0)));
// test('load glb from buffer with instances', () async {
// await testHelper.withViewer((viewer) async {
// var buffer =
// File("${testHelper.testDir}/assets/cube.glb").readAsBytesSync();
// var model = await viewer.loadGlbFromBuffer(buffer, numInstances: 2);
// var instance = await model.createInstance();
// await instance.addToScene();
// await viewer.setTransform(
// instance.entity, Matrix4.translation(Vector3(1, 0, 0)));
await testHelper.capture(viewer, "load_glb_from_buffer_with_instances");
// await testHelper.capture(viewer, "load_glb_from_buffer_with_instances");
await viewer.destroyAsset(instance);
// await viewer.destroyAsset(instance);
await testHelper.capture(
viewer, "load_glb_from_buffer_instance_removed");
// await testHelper.capture(
// viewer, "load_glb_from_buffer_instance_removed");
await viewer.destroyAsset(model);
// await viewer.destroyAsset(model);
await testHelper.capture(
viewer, "load_glb_from_buffer_original_removed");
}, bg: kRed);
});
// await testHelper.capture(
// viewer, "load_glb_from_buffer_original_removed");
// }, bg: kRed);
// });
test('load glb from buffer with priority', () async {
await testHelper.withViewer((viewer) async {
viewer.addDirectLight(DirectLight.sun());
var buffer =
File("${testHelper.testDir}/assets/cube.glb").readAsBytesSync();
// test('load glb from buffer with priority', () async {
// await testHelper.withViewer((viewer) async {
// viewer.addDirectLight(DirectLight.sun());
// var buffer =
// File("${testHelper.testDir}/assets/cube.glb").readAsBytesSync();
// priority 0 gets drawn first
var greenModel = await viewer.loadGlbFromBuffer(buffer, priority: 0);
for (final entity in await viewer.getChildEntities(greenModel)) {
final material = await viewer.getMaterialInstanceAt(entity, 0);
await material!.setParameterFloat4("baseColorFactor", 0, 1, 0.0, 1.0);
}
// // priority 0 gets drawn first
// var greenModel = await viewer.loadGlbFromBuffer(buffer, priority: 0);
// for (final entity in await viewer.getChildEntities(greenModel)) {
// final material = await viewer.getMaterialInstanceAt(entity, 0);
// await material!.setParameterFloat4("baseColorFactor", 0, 1, 0.0, 1.0);
// }
// priority 7 gets drawn last
var blueModel = await viewer.loadGlbFromBuffer(buffer, priority: 7);
for (final entity in await viewer.getChildEntities(blueModel)) {
final material = await viewer.getMaterialInstanceAt(entity, 0);
await material!.setParameterFloat4("baseColorFactor", 0, 0, 1.0, 1.0);
}
// // priority 7 gets drawn last
// var blueModel = await viewer.loadGlbFromBuffer(buffer, priority: 7);
// for (final entity in await viewer.getChildEntities(blueModel)) {
// final material = await viewer.getMaterialInstanceAt(entity, 0);
// await material!.setParameterFloat4("baseColorFactor", 0, 0, 1.0, 1.0);
// }
// blue model rendered in front
await testHelper.capture(viewer, "load_glb_from_buffer_with_priority");
});
});
// // blue model rendered in front
// await testHelper.capture(viewer, "load_glb_from_buffer_with_priority");
// });
// });
test('create instance from gltf', () async {
await testHelper.withViewer((viewer) async {
var model = await viewer.loadGlb(
"file://${testHelper.testDir}/assets/cube.glb",
numInstances: 32);
await testHelper.capture(viewer, "gltf_create_instance_0");
var instance = await model.createInstance();
await instance.addToScene();
await viewer.setRendering(true);
// test('create instance from gltf', () async {
// await testHelper.withViewer((viewer) async {
// var model = await viewer.loadGlb(
// "file://${testHelper.testDir}/assets/cube.glb",
// numInstances: 32);
// await testHelper.capture(viewer, "gltf_create_instance_0");
// var instance = await model.createInstance();
// await instance.addToScene();
// await viewer.setRendering(true);
await viewer.setTransform(
instance.entity, Matrix4.translation(Vector3.all(1)));
await testHelper.capture(viewer, "gltf_create_instance_1");
});
});
// await viewer.setTransform(
// instance.entity, Matrix4.translation(Vector3.all(1)));
// await testHelper.capture(viewer, "gltf_create_instance_1");
// });
// });
test('create instance from gltf with new material', () async {
await testHelper.withViewer((viewer) async {
var model = await viewer.loadGlb(
"file://${testHelper.testDir}/assets/cube.glb",
numInstances: 2);
await testHelper.capture(
viewer, "gltf_create_instance_with_material_0");
// test('create instance from gltf with new material', () async {
// await testHelper.withViewer((viewer) async {
// var model = await viewer.loadGlb(
// "file://${testHelper.testDir}/assets/cube.glb",
// numInstances: 2);
// await testHelper.capture(
// viewer, "gltf_create_instance_with_material_0");
final materialInstance = await viewer.createUnlitMaterialInstance();
await materialInstance.setParameterFloat4(
"baseColorFactor", 1.0, 0.0, 0.0, 1.0);
var instance =
await model.createInstance(materialInstances: [materialInstance]);
await instance.addToScene();
// final materialInstance = await viewer.createUnlitMaterialInstance();
// await materialInstance.setParameterFloat4(
// "baseColorFactor", 1.0, 0.0, 0.0, 1.0);
// var instance =
// await model.createInstance(materialInstances: [materialInstance]);
// await instance.addToScene();
await viewer.setTransform(
instance.entity, Matrix4.translation(Vector3.all(1)));
await testHelper.capture(
viewer, "gltf_create_instance_with_material_1");
await viewer.destroyMaterialInstance(materialInstance);
});
});
// await viewer.setTransform(
// instance.entity, Matrix4.translation(Vector3.all(1)));
// await testHelper.capture(
// viewer, "gltf_create_instance_with_material_1");
// await viewer.destroyMaterialInstance(materialInstance);
// });
// });
test('replace material instance with unlit material', () async {
await testHelper.withViewer((viewer) async {
var model = await viewer
.loadGlb("file://${testHelper.testDir}/assets/cube.glb");
await testHelper.capture(viewer, "gltf_default_material_instance");
var materialInstance = await viewer.createUnlitMaterialInstance();
await materialInstance.setParameterFloat4(
"baseColorFactor", 1.0, 1.0, 0.0, 1.0);
await model.setMaterialInstanceAt(materialInstance);
await testHelper.capture(
viewer, "gltf_replace_material_instance_unlit");
await viewer.destroyAsset(model);
await viewer.destroyMaterialInstance(materialInstance);
});
});
// test('replace material instance with unlit material', () async {
// await testHelper.withViewer((viewer) async {
// var model = await viewer
// .loadGlb("file://${testHelper.testDir}/assets/cube.glb");
// await testHelper.capture(viewer, "gltf_default_material_instance");
// var materialInstance = await viewer.createUnlitMaterialInstance();
// await materialInstance.setParameterFloat4(
// "baseColorFactor", 1.0, 1.0, 0.0, 1.0);
// await model.setMaterialInstanceAt(materialInstance);
// await testHelper.capture(
// viewer, "gltf_replace_material_instance_unlit");
// await viewer.destroyAsset(model);
// await viewer.destroyMaterialInstance(materialInstance);
// });
// });
test('replace material instance with ubershader material', () async {
await testHelper.withViewer((viewer) async {
var model = await viewer
.loadGlb("file://${testHelper.testDir}/assets/cube.glb");
await viewer
.loadIbl("file://${testHelper.testDir}/assets/default_env_ibl.ktx");
var materialInstance = await viewer.createUbershaderMaterialInstance();
await materialInstance.setParameterFloat4(
"baseColorFactor", 1.0, 1.0, 0.0, 1.0);
await model.setMaterialInstanceAt(materialInstance);
await testHelper.capture(
viewer, "gltf_replace_material_instance_ubershader");
await viewer.destroyAsset(model);
await viewer.destroyMaterialInstance(materialInstance);
}, bg: kRed);
});
});
}
// test('replace material instance with ubershader material', () async {
// await testHelper.withViewer((viewer) async {
// var model = await viewer
// .loadGlb("file://${testHelper.testDir}/assets/cube.glb");
// await viewer
// .loadIbl("file://${testHelper.testDir}/assets/default_env_ibl.ktx");
// var materialInstance = await viewer.createUbershaderMaterialInstance();
// await materialInstance.setParameterFloat4(
// "baseColorFactor", 1.0, 1.0, 0.0, 1.0);
// await model.setMaterialInstanceAt(materialInstance);
// await testHelper.capture(
// viewer, "gltf_replace_material_instance_ubershader");
// await viewer.destroyAsset(model);
// await viewer.destroyMaterialInstance(materialInstance);
// }, bg: kRed);
// });
// });
// }

View File

@@ -1,15 +1,17 @@
// ignore_for_file: unused_local_variable
import 'dart:ffi';
import 'dart:io';
import 'dart:math';
import 'package:image/image.dart' as img;
import 'dart:typed_data';
import 'package:ffi/ffi.dart';
import 'package:image/image.dart';
import 'swift/swift_bindings.g.dart';
import 'package:thermion_dart/src/filament/src/layers.dart';
import 'package:thermion_dart/src/swift/swift_bindings.g.dart';
import 'package:thermion_dart/src/utils/src/dart_resources.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/callbacks.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_filament_app.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_render_target.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_swapchain.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/thermion_dart.g.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/thermion_viewer_ffi.dart';
import 'package:thermion_dart/src/viewer/src/ffi/thermion_viewer_ffi.dart';
@@ -32,7 +34,7 @@ Color kBlue = ColorFloat32(4)..setRgba(0.0, 0.0, 1.0, 1.0);
Uri findPackageRoot(String packageName) {
final script = Platform.script;
final fileName = script.name;
if (fileName.endsWith('_test.dart')) {
if (fileName.contains('_test')) {
// We're likely running from source.
var directory = script.resolve('.');
while (true) {
@@ -69,73 +71,88 @@ Future<Uint8List> savePixelBufferToBmp(
return data;
}
Future<Uint8List> savePixelBufferToPng(
Uint8List pixelBuffer, int width, int height, String outputPath) async {
var data = await pixelBufferToPng(pixelBuffer, width, height);
File(outputPath).writeAsBytesSync(data);
print("Wrote bitmap to ${outputPath}");
return data;
}
class TestHelper {
late SwapChain swapChain;
late FFISwapChain swapChain;
late Directory outDir;
late String testDir;
TestHelper(String dir) {
final packageUri = findPackageRoot('thermion_dart');
print("Package URIL $packageUri");
testDir = Directory("${packageUri.toFilePath()}/test").path;
print("Test dir : $packageUri");
final packageUri = findPackageRoot('thermion_dart').toFilePath();
testDir = Directory("${packageUri}test").path;
outDir = Directory("$testDir/output/${dir}");
print("Out dir : $packageUri");
outDir.createSync(recursive: true);
print("Created out dir : $packageUri");
if (Platform.isMacOS) {
DynamicLibrary.open('${testDir}/libThermionTextureSwift.dylib');
}
}
Future capture(ThermionViewer viewer, String outputFilename,
{View? view, SwapChain? swapChain, RenderTarget? renderTarget}) async {
await Future.delayed(Duration(milliseconds: 10));
var outPath = p.join(outDir.path, "$outputFilename.bmp");
var pixelBuffer = await viewer.capture(
view: view,
swapChain: swapChain ?? this.swapChain,
renderTarget: renderTarget);
await viewer.render();
view ??= await viewer.getViewAt(0);
///
///
///
Future<Uint8List> capture(View view, String? outputFilename) async {
final rt = await view.getRenderTarget();
var pixelBuffer = await FilamentApp.instance!
.capture(view, captureRenderTarget: rt != null);
var vp = await view.getViewport();
await savePixelBufferToBmp(pixelBuffer, vp.width, vp.height, outPath);
if (outputFilename != null) {
var outPath = p.join(outDir.path, "$outputFilename.png");
await savePixelBufferToPng(pixelBuffer, vp.width, vp.height, outPath);
}
return pixelBuffer;
}
Future<ThermionTextureSwift> createTexture(int width, int height) async {
///
///
///
Future<List<Uint8List>> captureMultiple(
ThermionViewer viewer,
String? outputFilename, {
View? view,
SwapChain? swapChain,
RenderTarget? renderTarget,
}) async {
throw UnimplementedError();
// view ??= await viewer.view;
// final targets = [
// (view: view!, swapChain: swapChain, renderTarget: renderTarget)
// ];
// var pixelBuffers = await viewer.capture(targets);
// for (final entry in targets) {
// var vp = await entry.view.getViewport();
// if (outputFilename != null) {
// var outPath = p.join(outDir.path, "$outputFilename.png");
// await savePixelBufferToPng(
// pixelBuffers[targets.indexOf(entry)], vp.width, vp.height, outPath);
// }
// }
// return pixelBuffers;
}
///
///
///
Future<ThermionTextureSwift> createTexture(int width, int height,
{bool depth = false}) async {
final object = ThermionTextureSwift.new1();
object.initWithWidth_height_(width, height);
object.initWithWidth_height_isDepth_(width, height, depth);
return object;
}
Future withViewer(Future Function(ThermionViewer viewer) fn,
{img.Color? bg,
Vector3? cameraPosition,
viewportDimensions = (width: 500, height: 500),
bool postProcessing = false}) async {
var viewer = await createViewer(
bg: bg,
cameraPosition: cameraPosition,
viewportDimensions: viewportDimensions,
postProcessing: postProcessing);
await fn.call(viewer);
await viewer.dispose();
}
Future<ThermionViewer> createViewer(
{img.Color? bg,
Vector3? cameraPosition,
bool postProcessing = false,
viewportDimensions = (width: 500, height: 500)}) async {
Future setup() async {
final resourceLoader = calloc<ResourceLoaderWrapper>(1);
cameraPosition ??= Vector3(0, 2, 6);
var loadToOut = NativeCallable<
Void Function(Pointer<Char>,
Pointer<ResourceBuffer>)>.listener(DartResourceLoader.loadResource);
@@ -146,96 +163,88 @@ class TestHelper {
DartResourceLoader.freeResource);
resourceLoader.ref.freeResource = freeResource.nativeFunction;
await FFIFilamentApp.create();
var viewer = ThermionViewerFFI(resourceLoader: resourceLoader.cast<Void>());
await FilamentApp.instance!.setClearColor(0, 0, 0, 1);
}
///
///
///
Future withViewer(Future Function(ThermionViewer viewer) fn,
{img.Color? bg,
Vector3? cameraPosition,
({int width, int height}) viewportDimensions = (width: 500, height: 500),
bool postProcessing = false,
bool createRenderTarget = false}) async {
cameraPosition ??= Vector3(0, 2, 6);
var swapChain = await FilamentApp.instance!.createHeadlessSwapChain(
viewportDimensions.width, viewportDimensions.height) as FFISwapChain;
FFIRenderTarget? renderTarget;
if (createRenderTarget) {
var metalColorTexture = await createTexture(
viewportDimensions.width, viewportDimensions.height);
var metalDepthTexture = await createTexture(
viewportDimensions.width, viewportDimensions.height,
depth: true);
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.RGB32F,
importedTextureHandle: metalColorTexture.metalTextureAddress);
var depth = await FilamentApp.instance!
.createTexture(viewportDimensions.width, viewportDimensions.height,
flags: {
TextureUsage.TEXTURE_USAGE_BLIT_SRC,
TextureUsage.TEXTURE_USAGE_DEPTH_ATTACHMENT,
TextureUsage.TEXTURE_USAGE_SAMPLEABLE,
},
textureFormat: TextureFormat.DEPTH32F,
importedTextureHandle: metalDepthTexture.metalTextureAddress);
renderTarget = await FilamentApp.instance!.createRenderTarget(
viewportDimensions.width, viewportDimensions.height,
color: color, depth: depth) as FFIRenderTarget;
}
var viewer = ThermionViewerFFI(
loadAssetFromUri: (path) async =>
File(path.replaceAll("file://", "")).readAsBytesSync(),
renderTarget: renderTarget);
await viewer.initialized;
swapChain = await viewer.createHeadlessSwapChain(
viewportDimensions.width, viewportDimensions.height);
await FilamentApp.instance!.register(swapChain, viewer.view);
await viewer.updateViewportAndCameraProjection(
viewportDimensions.width.toDouble(),
viewportDimensions.height.toDouble());
await viewer.view
.setViewport(viewportDimensions.width, viewportDimensions.height);
await viewer.view.setBloom(false, 0);
if (bg != null) {
await viewer.setBackgroundColor(
bg.r.toDouble(), bg.g.toDouble(), bg.b.toDouble(), bg.a.toDouble());
}
await viewer.setCameraPosition(
cameraPosition.x, cameraPosition.y, cameraPosition.z);
final camera = await viewer.getActiveCamera();
await camera.setLensProjection(
near: kNear, far: kFar, aspect: 1.0, focalLength: kFocalLength);
await camera.lookAt(cameraPosition);
await viewer.setPostProcessing(postProcessing);
await viewer.setToneMapping(ToneMapper.LINEAR);
return viewer;
}
}
Future<Uint8List> pixelsToPng(Uint8List pixelBuffer, int width, int height,
{bool linearToSrgb = false, bool invertAces = false}) async {
final image = img.Image(width: width, height: height);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
final int pixelIndex = (y * width + x) * 4;
double r = pixelBuffer[pixelIndex] / 255.0;
double g = pixelBuffer[pixelIndex + 1] / 255.0;
double b = pixelBuffer[pixelIndex + 2] / 255.0;
int a = pixelBuffer[pixelIndex + 3];
// Apply inverse ACES tone mapping
if (invertAces) {
r = _inverseACESToneMapping(r);
g = _inverseACESToneMapping(g);
b = _inverseACESToneMapping(b);
}
if (linearToSrgb) {
// Convert from linear to sRGB
image.setPixel(
x,
y,
img.ColorUint8(4)
..setRgba(
_linearToSRGB(r), _linearToSRGB(g), _linearToSRGB(b), 1.0));
} else {
image.setPixel(
x,
y,
img.ColorUint8(4)
..setRgba((r * 255).toInt(), (g * 255).toInt(), (b * 255).toInt(),
1.0));
}
}
}
return img.encodePng(image);
}
double _inverseACESToneMapping(double x) {
const double a = 2.51;
const double b = 0.03;
const double c = 2.43;
const double d = 0.59;
const double e = 0.14;
// Ensure x is in the valid range [0, 1]
x = x.clamp(0.0, 1.0);
// Inverse ACES filmic tone mapping function
return (x * (x * a + b)) / (x * (x * c + d) + e);
}
int _linearToSRGB(double linearValue) {
if (linearValue <= 0.0031308) {
return (linearValue * 12.92 * 255.0).round().clamp(0, 255);
} else {
return ((1.055 * pow(linearValue, 1.0 / 2.4) - 0.055) * 255.0)
.round()
.clamp(0, 255);
await fn.call(viewer);
await viewer.dispose();
}
}

View File

@@ -10,7 +10,7 @@ import 'package:animation_tools_dart/animation_tools_dart.dart' as _i9;
import 'package:mockito/mockito.dart' as _i1;
import 'package:thermion_dart/src/utils/src/gizmo.dart' as _i4;
import 'package:thermion_dart/src/viewer/src/events.dart' as _i7;
import 'package:thermion_dart/src/viewer/src/shared_types/shared_types.dart'
import 'package:thermion_dart/src/filament/src/shared_types.dart'
as _i2;
import 'package:thermion_dart/src/viewer/src/thermion_viewer_base.dart' as _i5;
import 'package:vector_math/vector_math_64.dart' as _i3;

View File

@@ -1,12 +1,9 @@
import 'dart:io';
import 'dart:math';
import 'dart:typed_data';
import 'package:thermion_dart/src/viewer/src/ffi/src/thermion_viewer_ffi.dart';
import 'package:thermion_dart/thermion_dart.dart';
import 'package:test/test.dart';
import 'package:vector_math/vector_math_64.dart';
import 'helpers.dart';
Future<
@@ -43,8 +40,8 @@ Future<
void main() async {
final testHelper = TestHelper("material");
group("unlit material tests", () {
test('unlit material with color only', () async {
group("unlit material", () {
test('unlit + baseColorFactor', () async {
await testHelper.withViewer((viewer) async {
await viewer.setPostProcessing(true);
await viewer.setToneMapping(ToneMapper.LINEAR);
@@ -62,6 +59,116 @@ void main() async {
}, bg: kRed);
});
test('unlit + baseColorMap', () async {
await testHelper.withViewer((viewer) async {
var materialInstance = await viewer.createUnlitMaterialInstance();
var cube = await viewer.createGeometry(GeometryHelper.cube(),
materialInstances: [materialInstance]);
await materialInstance.setParameterFloat4(
"baseColorFactor", 1.0, 1.0, 1.0, 1.0);
await materialInstance.setParameterFloat2("uvScale", 1.0, 1.0);
await materialInstance.setParameterInt("baseColorIndex", 0);
var data =
File("${testHelper.testDir}/assets/cube_texture2_512x512.png")
.readAsBytesSync();
final image = await viewer.decodeImage(data);
final texture = await viewer.createTexture(
await image.getWidth(), await image.getHeight(),
textureFormat: TextureFormat.RGBA32F);
await texture.setLinearImage(
image, PixelDataFormat.RGBA, PixelDataType.FLOAT);
final sampler = await viewer.createTextureSampler();
await materialInstance.setParameterTexture(
"baseColorMap", texture, sampler);
await testHelper.capture(viewer, "unlit_baseColorMap");
await image.destroy();
await texture.dispose();
await sampler.dispose();
await viewer.destroyMaterialInstance(materialInstance);
});
});
test('unlit + baseColorMap (apply material after creation)', () async {
await testHelper.withViewer((viewer) async {
var cube = await viewer
.createGeometry(GeometryHelper.cube(), materialInstances: []);
var materialInstance = await viewer.createUnlitMaterialInstance();
await materialInstance.setParameterFloat4(
"baseColorFactor", 1.0, 1.0, 1.0, 1.0);
await materialInstance.setParameterFloat2("uvScale", 1.0, 1.0);
await materialInstance.setParameterInt("baseColorIndex", 0);
var data =
File("${testHelper.testDir}/assets/cube_texture2_512x512.png")
.readAsBytesSync();
final image = await viewer.decodeImage(data);
final texture = await viewer.createTexture(
await image.getWidth(), await image.getHeight(),
textureFormat: TextureFormat.RGBA32F);
await texture.setLinearImage(
image, PixelDataFormat.RGBA, PixelDataType.FLOAT);
final sampler = await viewer.createTextureSampler();
await materialInstance.setParameterTexture(
"baseColorMap", texture, sampler);
await cube.setMaterialInstanceAt(materialInstance);
await testHelper.capture(
viewer, "unlit_baseColorMap_material_created_after");
await image.destroy();
await texture.dispose();
await sampler.dispose();
await viewer.destroyMaterialInstance(materialInstance);
});
});
test('unlit + baseColorMap (fetch material after creation)', () async {
await testHelper.withViewer((viewer) async {
var materialInstance = await viewer.createUnlitMaterialInstance();
var cube = await viewer.createGeometry(GeometryHelper.cube(),
materialInstances: [materialInstance]);
materialInstance = await viewer.getMaterialInstanceAt(cube.entity, 0);
await materialInstance.setParameterFloat4(
"baseColorFactor", 1.0, 1.0, 1.0, 1.0);
await materialInstance.setParameterInt("baseColorIndex", 0);
var data =
File("${testHelper.testDir}/assets/cube_texture2_512x512.png")
.readAsBytesSync();
final image = await viewer.decodeImage(data);
final texture = await viewer.createTexture(
await image.getWidth(), await image.getHeight(),
textureFormat: TextureFormat.RGBA32F);
await texture.setLinearImage(
image, PixelDataFormat.RGBA, PixelDataType.FLOAT);
final sampler = await viewer.createTextureSampler();
await materialInstance.setParameterTexture(
"baseColorMap", texture, sampler);
await cube.setMaterialInstanceAt(materialInstance);
await testHelper.capture(
viewer, "unlit_baseColorMap_fetch_material");
await image.destroy();
await texture.dispose();
await sampler.dispose();
await viewer.destroyMaterialInstance(materialInstance);
});
});
test('unlit material with color + alpha', () async {
await testHelper.withViewer((viewer) async {
await viewer.setPostProcessing(true);
@@ -123,18 +230,13 @@ void main() async {
}, bg: kRed, postProcessing: true);
});
test('set ubershader texture', () async {
test('ubershader + baseColorMap texture', () async {
await testHelper.withViewer((viewer) async {
await viewer.addLight(LightType.SUN, 6500, 1000000, 0, 0, 0, 0, 0, -1);
await viewer.setCameraPosition(0, 2, 6);
await viewer
.setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -pi / 8));
var materialInstance = await viewer.createUbershaderMaterialInstance();
var materialInstance = await viewer.createUbershaderMaterialInstance(unlit: true);
final cube = await viewer.createGeometry(
GeometryHelper.cube(uvs: true, normals: true),
GeometryHelper.cube(),
materialInstances: [materialInstance]);
var data = File("${testHelper.testDir}/assets/cube_texture_512x512.png")
var data = File("${testHelper.testDir}/assets/cube_texture2_512x512_flipped.png")
.readAsBytesSync();
final image = await viewer.decodeImage(data);
final texture = await viewer.createTexture(
@@ -153,7 +255,7 @@ void main() async {
viewer, "geometry_cube_with_custom_material_ubershader_texture");
await viewer.destroyAsset(cube);
await viewer.destroyMaterialInstance(materialInstance);
await viewer.destroyTexture(texture);
await texture.dispose();
});
});
@@ -340,159 +442,6 @@ void main() async {
}, postProcessing: true);
});
});
group('projection', () {
test('apply projection material', () async {
await testHelper.withViewer((viewer) async {
await viewer
.setCameraModelMatrix4(Matrix4.translation(Vector3(0, 0, 5)));
// // Rotate the camera in 30-degree increments and capture at each position
// for (int i = 0; i <= 180; i += 30) {
// int i = 60;
// final angle = i * (pi / 180); // Convert to radians
// // Calculate camera position
// // Start at (0, 1, 5) (facing the sphere from +z) and rotate around to (-5, 1, 0)
// final radius = 5.0;
// final x = -radius * sin(angle);
// final z = radius * cos(angle);
// // Create view matrix for this camera position
// final matrix = makeViewMatrix(
// Vector3(x, 1, z),
// Vector3.zero(), // Looking at origin
// Vector3(0, 1, 0) // Up vector
// )
// ..invert();
// await viewer.setCameraModelMatrix4(matrix);
// // Take a snapshot at this position
// await testHelper.capture(viewer, "projection_${i}deg");
// }
final view = await viewer.getViewAt(0);
final rtTextureHandle = await testHelper.createTexture(512, 512);
final rt = await viewer.createRenderTarget(
512, 512, rtTextureHandle.metalTextureAddress);
await view.setRenderTarget(rt);
final rtTexture = await rt.getColorTexture();
final ppuvMaterial = await viewer.createMaterial(File(
"/Users/nickfisher/Documents/thermion/materials/postprocess_uv.filamat")
.readAsBytesSync());
final ppuvInstance = await ppuvMaterial.createInstance();
// Setup the scene (lighting, materials, etc.)
await viewer.loadIbl(
"file://${testHelper.testDir}/assets/default_env_ibl.ktx",
intensity: 1000);
await viewer.addDirectLight(DirectLight.sun(
intensity: 500000,
castShadows: true,
direction: Vector3(1, -0.5, 0).normalized()));
// input texture
var inputTextureData =
File("${testHelper.testDir}/assets/cube_texture_512x512.png")
.readAsBytesSync();
var inputImage = await viewer.decodeImage(inputTextureData);
var inputTexture = await viewer.createTexture(
await inputImage.getWidth(), await inputImage.getHeight(),
textureFormat: TextureFormat.RGBA32F);
await inputTexture.setLinearImage(
inputImage, PixelDataFormat.RGBA, PixelDataType.FLOAT);
var captureUvMaterial = await viewer.createMaterial(File(
"/Users/nickfisher/Documents/thermion/materials/capture_uv.filamat")
.readAsBytesSync());
var captureUvMaterialInstance =
await captureUvMaterial.createInstance();
var sampler = await viewer.createTextureSampler();
// Create sphere and plane
final sphere = await viewer.createGeometry(
GeometryHelper.sphere(normals: true, uvs: true),
materialInstances: []);
// await viewer.setTransform(
// sphere.entity, Matrix4.compose(Vector3(2, 1, -1), Quaternion.identity(), Vector3(1.0,1.0,1.0)));
await sphere.addToScene();
await testHelper.capture(viewer, "color", renderTarget: rt);
await captureUvMaterialInstance.setParameterTexture(
"color", rtTexture, sampler);
await sphere.setMaterialInstanceAt(captureUvMaterialInstance);
await testHelper.capture(viewer, "uv_capture", renderTarget: rt);
// await ppuvInstance.setParameterTexture("uvTexture", rtTexture, sampler);
await sphere.setMaterialInstanceAt(ppuvInstance);
await testHelper.capture(viewer, "ppuv", renderTarget: rt);
// final quad = await viewer.createGeometry(
// GeometryHelper.plane(width: 100.0, height: 100.0),
// materialInstances: [materialInstance]);
// await viewer.setTransform(
// quad.entity, Matrix4.translation(Vector3(0, -1, 0)));
// await quad.addToScene();
var bytePixelBuffer = await viewer.capture(renderTarget: rt);
var floatPixelBuffer = Float32List.fromList(
bytePixelBuffer.map((p) => p.toDouble() / 255.0).toList());
print("pixelBuffer ${floatPixelBuffer.lengthInBytes} bytes");
var output = unprojectTexture(
renderTarget: await inputImage.getData(),
uvCoordinates: floatPixelBuffer,
renderTargetWidth: 512,
renderTargetHeight: 512,
renderTargetChannels: 4,
uvWidth: 512,
uvHeight: 512,
uvChannels: 4,
outputWidth: 512,
outputHeight: 512);
var byteOutput =
Uint8List.fromList(output.map((o) => (o * 255.0).toInt()).toList());
await savePixelBufferToBmp(byteOutput, 512, 512, "/tmp/foo.bmp");
final reappliedImage = await viewer.createImage(512, 512, 4);
final data = await reappliedImage.getData();
data.setRange(0, data.length, output);
final reappliedTexture = await viewer.createTexture(512, 512,
textureFormat: TextureFormat.RGBA32F);
await reappliedTexture.setLinearImage(
reappliedImage, PixelDataFormat.RGBA, PixelDataType.FLOAT);
var newMaterialInstance =
await viewer.createUbershaderMaterialInstance(unlit: true);
await newMaterialInstance.setParameterInt("baseColorIndex", 0);
await newMaterialInstance.setParameterTexture(
"baseColorMap",
reappliedTexture,
// inputTexture,
sampler);
await newMaterialInstance.setParameterFloat4(
"baseColorFactor", 1.0, 1.0, 1.0, 1.0);
await sphere.setMaterialInstanceAt(newMaterialInstance);
await testHelper.capture(viewer, "capture2");
// final view = await viewer.getViewAt(0);
// final renderTargetTexture = await testHelper.createTexture(512, 512);
// final rt = await viewer.createRenderTarget(
// 512, 512, renderTargetTexture.metalTextureAddress);
// await view.setRenderTarget(rt);
// pixelBuffer = await viewer.capture(renderTarget: rt);
}, viewportDimensions: (width: 512, height: 512));
});
});
}
Float32List unprojectTexture({

View File

@@ -0,0 +1,44 @@
import 'dart:async';
import 'dart:ffi';
import 'package:test/test.dart';
import 'package:thermion_dart/thermion_dart.dart';
import 'helpers.dart';
void main() async {
final testHelper = TestHelper("render_thread");
await testHelper.setup();
group("render thread/capture", () {
test("request frame on render thread", () async {
await testHelper.withViewer((viewer) async {
var metalTexture = await testHelper.createTexture(500, 500);
var texture = await FilamentApp.instance!.createTexture(
500, 500,
importedTextureHandle: metalTexture.metalTextureAddress,
flags: {
TextureUsage.TEXTURE_USAGE_BLIT_DST,
TextureUsage.TEXTURE_USAGE_SAMPLEABLE,
TextureUsage.TEXTURE_USAGE_COLOR_ATTACHMENT
});
var renderTarget = await FilamentApp.instance!
.createRenderTarget(500, 500, color: texture);
await viewer.view.setRenderTarget(renderTarget);
await viewer.render();
await Future.delayed(Duration(milliseconds: 1));
var data = metalTexture.getTextureBytes()!;
var pixels = data.bytes.cast<Uint8>().asTypedList(data.length);
savePixelBufferToBmp(
pixels, 500, 500, "${testHelper.testDir}/request_frame.bmp");
await viewer.dispose();
});
});
});
}

View File

@@ -316,7 +316,13 @@ void main() async {
test('depth visualization', () async {
RenderLoop_create();
final engine = await withPointerCallback<TEngine>(
(cb) => Engine_createRenderThread(TBackend.BACKEND_METAL.index, cb));
(cb) => Engine_createRenderThread(TBackend.BACKEND_METAL.index, nullptr, nullptr, 1, false, cb));
final gltfResourceLoader = await withPointerCallback<TGltfResourceLoader>(
(cb) => GltfResourceLoader_createRenderThread(engine, cb));
final gltfAssetLoader = await withPointerCallback<TGltfAssetLoader>(
(cb) => GltfAssetLoader_createRenderThread(engine, nullptr, cb));
final renderer = await withPointerCallback<TRenderer>(
(cb) => Engine_createRendererRenderThread(engine, cb));
final swapchain = await withPointerCallback<TSwapChain>((cb) =>
@@ -328,20 +334,63 @@ void main() async {
cb));
final camera = await withPointerCallback<TCamera>(
(cb) => Engine_createCameraRenderThread(engine, cb));
final offscreenView = await withPointerCallback<TView>(
(cb) => Engine_createViewRenderThread(engine, cb));
final view = await withPointerCallback<TView>(
(cb) => Engine_createViewRenderThread(engine, cb));
final colorTexture = await withPointerCallback<TTexture>((cb) =>
Texture_buildRenderThread(
engine,
500,
500,
1,
1,
TTextureUsage.TEXTURE_USAGE_COLOR_ATTACHMENT.value |
TTextureUsage.TEXTURE_USAGE_SAMPLEABLE.value |
TTextureUsage.TEXTURE_USAGE_BLIT_SRC.value,
0,
TTextureSamplerType.SAMPLER_2D,
TTextureFormat.TEXTUREFORMAT_RGBA8,
cb));
final depthTexture = await withPointerCallback<TTexture>((cb) =>
Texture_buildRenderThread(
engine,
500,
500,
1,
1,
TTextureUsage.TEXTURE_USAGE_DEPTH_ATTACHMENT.value |
TTextureUsage.TEXTURE_USAGE_SAMPLEABLE.value,
0,
TTextureSamplerType.SAMPLER_2D,
TTextureFormat.TEXTUREFORMAT_DEPTH32F,
cb));
final renderTarget = await withPointerCallback<TRenderTarget>((cb) =>
RenderTarget_createRenderThread(
engine, 500, 500, colorTexture, depthTexture, cb));
View_setRenderTarget(offscreenView, renderTarget);
final offscreenScene = Engine_createScene(engine);
final scene = Engine_createScene(engine);
await withVoidCallback((cb) {
Renderer_setClearOptionsRenderThread(
renderer, 1.0, 0.0, 1.0, 1.0, 0, true, true, cb);
});
View_setFrustumCullingEnabled(offscreenView, false);
View_setFrustumCullingEnabled(view, false);
View_setScene(offscreenView, offscreenScene);
View_setScene(view, scene);
View_setCamera(offscreenView, camera);
View_setCamera(view, camera);
View_setViewport(offscreenView, 500, 500);
View_setViewport(view, 500, 500);
final eye = Struct.create<double3>()
..x = 0.0
..y = 0.0
..x = 5.0
..y = 1.0
..z = 5.0;
Camera_lookAt(
camera,
@@ -354,11 +403,21 @@ void main() async {
..x = 0.0
..y = 1.0
..z = 0.0);
View_setBloomRenderThread(view, false, 0.0);
View_setBloomRenderThread(offscreenView, false, 0.0);
Camera_setLensProjection(camera, 0.05, 100000, 1.0, kFocalLength);
View_setPostProcessing(offscreenView, false);
View_setPostProcessing(view, false);
final iblData = File("${testHelper.testDir}/assets/default_env_ibl.ktx")
.readAsBytesSync();
final ibl = await withPointerCallback<TIndirectLight>((cb) =>
Engine_buildIndirectLightRenderThread(
engine, iblData.address, iblData.length, 30000, cb, nullptr));
Scene_setIndirectLight(offscreenScene, ibl);
Scene_setIndirectLight(scene, ibl);
final skyboxData =
File("${testHelper.testDir}/assets/default_env_skybox.ktx")
.readAsBytesSync();
@@ -367,25 +426,98 @@ void main() async {
Engine_buildSkyboxRenderThread(
engine, skyboxData.address, skyboxData.length, cb, nullptr));
Scene_setSkybox(offscreenScene, skybox);
Scene_setSkybox(scene, skybox);
final cubeData = GeometryHelper.cube();
final cube = await withPointerCallback<TSceneAsset>((cb) =>
SceneAsset_createGeometryRenderThread(
// final cubeData = GeometryHelper.cube();
// final cube = await withPointerCallback<TSceneAsset>((cb) =>
// SceneAsset_createGeometryRenderThread(
// engine,
// cubeData.vertices.address,
// cubeData.vertices.length,
// cubeData.normals.address,
// cubeData.normals.length,
// cubeData.uvs.address,
// cubeData.uvs.length,
// cubeData.indices.address,
// cubeData.indices.length,
// TPrimitiveType.PRIMITIVETYPE_POINTS,
// nullptr,
// 0,
// cb));
// Scene_addEntity(offscreenScene, SceneAsset_getEntity(cube));
var cube =
File("${testHelper.testDir}/assets/cube.glb").readAsBytesSync();
final filamentAsset = await withPointerCallback<TFilamentAsset>((cb) =>
GltfAssetLoader_loadRenderThread(gltfAssetLoader,
cube.address, cube.length, 1, cb));
var entities = Int32List(FilamentAsset_getEntityCount(filamentAsset));
FilamentAsset_getEntities(filamentAsset, entities.address);
final unlitMaData =
File("/Users/nickfisher/Documents/thermion/materials/unlit.filamat")
.readAsBytesSync();
final unlitMa =
Engine_buildMaterial(engine, unlitMaData.address, unlitMaData.length);
final unlitMi = await withPointerCallback<TMaterialInstance>(
(cb) => Material_createInstanceRenderThread(unlitMa, cb));
MaterialInstance_setParameterFloat2(
unlitMi, "uvScale".toNativeUtf8().cast<Char>(), 1.0, 1.0);
MaterialInstance_setParameterFloat4(unlitMi,
"baseColorFactor".toNativeUtf8().cast<Char>(), 1.0, 1.0, 0.0, 1.0);
MaterialInstance_setParameterInt(
unlitMi, "baseColorIndex".toNativeUtf8().cast<Char>(), -1);
for (int i = 0; i < entities.length; i++) {
RenderableManager_setMaterialInstanceAt(
Engine_getRenderableManager(engine), entities[i], 0, unlitMi);
}
// final materialInstance = GltfAssetLoader_getMaterialInstance(
// Engine_getRenderableManager(engine), filamentAsset);
// MaterialInstance_setParameterFloat4(materialInstance,
// "baseColorFactor".toNativeUtf8().cast<Char>(), 1.0, 0, 0, 1);
final imageData =
File("${testHelper.testDir}/assets/cube_texture2_512x512.png")
.readAsBytesSync();
final image = await Image_decode(imageData.address, imageData.length,
"unused".toNativeUtf8().cast<Char>());
final texture = await withPointerCallback<TTexture>((cb) =>
Texture_buildRenderThread(
engine,
cubeData.vertices.address,
cubeData.vertices.length,
cubeData.normals.address,
cubeData.normals.length,
cubeData.uvs.address,
cubeData.uvs.length,
cubeData.indices.address,
cubeData.indices.length,
TPrimitiveType.PRIMITIVETYPE_POINTS,
nullptr,
Image_getWidth(image),
Image_getHeight(image),
1,
1,
TTextureUsage.TEXTURE_USAGE_SAMPLEABLE.index,
0,
TTextureSamplerType.SAMPLER_2D,
TTextureFormat.TEXTUREFORMAT_RGBA32F,
cb));
Scene_addEntity(scene, SceneAsset_getEntity(cube));
await withBoolCallback((cb) => Texture_loadImageRenderThread(
engine,
texture,
image,
TPixelDataFormat.PIXELDATAFORMAT_RGBA,
TPixelDataType.PIXELDATATYPE_FLOAT,
cb));
MaterialInstance_setParameterInt(
unlitMi, "baseColorIndex".toNativeUtf8().cast<Char>(), 0);
MaterialInstance_setParameterTexture(
unlitMi,
"baseColorMap".toNativeUtf8().cast<Char>(),
RenderTarget_getDepthTexture(renderTarget),
// texture,
TextureSampler_create());
await withVoidCallback((cb) {
Scene_addFilamentAssetRenderThread(offscreenScene, filamentAsset, cb);
});
await withVoidCallback((cb) {
Scene_addFilamentAssetRenderThread(scene, filamentAsset, cb);
});
await withVoidCallback((cb) {
Engine_flushAndWaitRenderThead(engine, cb);
@@ -400,13 +532,29 @@ void main() async {
);
});
// for (int i = 0; i < 10; i++) {
await withVoidCallback((cb) {
Renderer_renderRenderThread(renderer, view, cb);
});
// }
await withVoidCallback((cb) {
Renderer_renderRenderThread(renderer, offscreenView, cb);
});
var view1Out = Uint8List(500 * 500 * 4);
await withVoidCallback((cb) {
Renderer_renderRenderThread(renderer, view, cb);
});
var offscreenViewOut = Uint8List(500 * 500 * 4);
await withVoidCallback((cb) {
Renderer_readPixelsRenderThread(
renderer,
offscreenView,
renderTarget,
TPixelDataFormat.PIXELDATAFORMAT_RGBA,
TPixelDataType.PIXELDATATYPE_UBYTE,
offscreenViewOut.address,
cb,
);
});
var swapchainOut = Uint8List(500 * 500 * 4);
await withVoidCallback((cb) {
Renderer_readPixelsRenderThread(
@@ -415,7 +563,7 @@ void main() async {
nullptr,
TPixelDataFormat.PIXELDATAFORMAT_RGBA,
TPixelDataType.PIXELDATATYPE_UBYTE,
view1Out.address,
swapchainOut.address,
cb,
);
});
@@ -425,72 +573,23 @@ void main() async {
});
await savePixelBufferToPng(
view1Out,
offscreenViewOut,
500,
500,
"/tmp/view1.png",
);
await savePixelBufferToPng(
swapchainOut,
500,
500,
"/tmp/sc1.png",
);
await withVoidCallback((cb) => Engine_destroyIndirectLightRenderThread(engine, ibl, cb));
await withVoidCallback((cb) => Engine_destroySkyboxRenderThread(engine, skybox, cb));
RenderLoop_destroy();
// await camera.lookAt(Vector3(100, 1500, 1500));
// // first view just renders a normal unlit cube, but into a render target
// final vp = await (await viewer.getViewAt(0)).getViewport();
// FFIView view = await viewer.createView()
// as FFIView; // await viewer.getViewAt(0) as FFIView;
// await view.setViewport(vp.width, vp.height);
// await view.setCamera(camera);
// await view.setFrustumCullingEnabled(false);
// var scene1 = Engine_createScene(engine);
// View_setScene(view.view, scene1);
// Scene_setSkybox(scene1, skybox);
// await view.setPostProcessing(false);
// await viewer.setClearOptions(Vector4(0, 0, 1, 0), 1, false, false);
// final colorTextureHandle = await testHelper.createTexture(
// vp.width,
// vp.height,
// );
// final rt = await viewer.createRenderTarget(
// vp.width,
// vp.height,
// // colorTextureHandle.metalTextureAddress,
// ) as FFIRenderTarget;
// await view.setRenderTarget(rt);
// final unlit = await viewer.createUnlitMaterialInstance();
// await unlit.setParameterInt("baseColorIndex", -1);
// await unlit.setParameterFloat4("baseColorFactor", 1.0, 0, 0, 1);
// await unlit.setDepthWriteEnabled(true);
// final cube = await viewer
// .createGeometry(GeometryHelper.cube(), materialInstances: [unlit]);
// Scene_addEntity(scene1, cube.entity);
// final cube2 = await viewer
// .createGeometry(GeometryHelper.cube(), materialInstances: [unlit]);
// Scene_addEntity(scene1, cube2.entity);
// await viewer.setTransform(
// cube.entity,
// Matrix4.compose(
// Vector3.zero(),
// Quaternion.identity(),
// Vector3(950, 950, 500),
// ),
// );
// await viewer.setTransform(
// cube2.entity,
// Matrix4.compose(
// Vector3(-500, -500, -2000),
// Quaternion.identity(),
// Vector3(500, 500, 500),
// ),
// );
// final mirrorMaterial = await viewer.createMaterial(
// File(
// "/Users/nickfisher/Documents/thermion/materials/mirror.filamat",
@@ -524,15 +623,6 @@ void main() async {
// await view2.setCamera(camera);
// await view2.setFrustumCullingEnabled(false);
// final image = await viewer.decodeImage(
// File("${testHelper.testDir}/assets/cube_texture2_512x512.png")
// .readAsBytesSync());
// final texture = await viewer.createTexture(
// await image.getWidth(), await image.getHeight(),
// textureFormat: TextureFormat.RGBA32F);
// await texture.setLinearImage(
// image, PixelDataFormat.RGBA, PixelDataType.FLOAT);
// await mirrorMi.setParameterTexture(
// "albedo",
// // texture as FFITexture,

View File

@@ -2,9 +2,6 @@
import 'package:thermion_dart/thermion_dart.dart';
import 'package:test/test.dart';
import 'package:vector_math/vector_math_64.dart';
import 'helpers.dart';
void main() async {

View File

@@ -1,157 +1,157 @@
// ignore_for_file: unused_local_variable
// // ignore_for_file: unused_local_variable
import 'dart:async';
// import 'dart:async';
import 'package:test/test.dart';
import 'package:thermion_dart/thermion_dart.dart';
import 'package:vector_math/vector_math_64.dart';
import 'helpers.dart';
// import 'package:test/test.dart';
// import 'package:thermion_dart/thermion_dart.dart';
// import 'package:vector_math/vector_math_64.dart';
// import 'helpers.dart';
void main() async {
final testHelper = TestHelper("view");
// void main() async {
// final testHelper = TestHelper("view");
group('view tests', () {
test('get camera from view', () async {
await testHelper.withViewer((viewer) async {
var view = await viewer.getViewAt(0);
expect(await view.getCamera(), isNotNull);
});
});
// group('view tests', () {
// test('get camera from view', () async {
// await testHelper.withViewer((viewer) async {
// var view = await viewer.getViewAt(0);
// expect(await view.getCamera(), isNotNull);
// });
// });
test('one swapchain, render view to render target', () async {
await testHelper.withViewer((viewer) async {
final texture = await testHelper.createTexture(500, 500);
final renderTarget = await viewer.createRenderTarget(
500, 500, texture.metalTextureAddress);
final view = await viewer.getViewAt(0);
await view.setRenderTarget(renderTarget);
// test('one swapchain, render view to render target', () async {
// await testHelper.withViewer((viewer) async {
// final texture = await testHelper.createTexture(500, 500);
// final renderTarget = await viewer.createRenderTarget(
// 500, 500, texture.metalTextureAddress);
// final view = await viewer.getViewAt(0);
// await view.setRenderTarget(renderTarget);
await viewer.setBackgroundColor(1.0, 0, 0, 1);
final cube = await viewer
.createGeometry(GeometryHelper.cube(normals: false, uvs: false));
// await viewer.setBackgroundColor(1.0, 0, 0, 1);
// final cube = await viewer
// .createGeometry(GeometryHelper.cube(normals: false, uvs: false));
var mainCamera = await viewer.getMainCamera();
mainCamera.setTransform(Matrix4.translation(Vector3(0, 0, 5)));
await testHelper.capture(
viewer,
renderTarget: renderTarget,
"default_swapchain_default_view_render_target");
});
});
// var mainCamera = await viewer.getMainCamera();
// mainCamera.setTransform(Matrix4.translation(Vector3(0, 0, 5)));
// await testHelper.capture(
// viewer,
// renderTarget: renderTarget,
// "default_swapchain_default_view_render_target");
// });
// });
test('create secondary view, default swapchain', () async {
await testHelper.withViewer((viewer) async {
final cube = await viewer
.createGeometry(GeometryHelper.cube(normals: false, uvs: false));
// test('create secondary view, default swapchain', () async {
// await testHelper.withViewer((viewer) async {
// final cube = await viewer
// .createGeometry(GeometryHelper.cube(normals: false, uvs: false));
var mainCamera = await viewer.getMainCamera();
mainCamera.setTransform(Matrix4.translation(Vector3(0, 0, 5)));
await testHelper.capture(viewer, "default_swapchain_default_view");
// var mainCamera = await viewer.getMainCamera();
// mainCamera.setTransform(Matrix4.translation(Vector3(0, 0, 5)));
// await testHelper.capture(viewer, "default_swapchain_default_view");
final view = await viewer.createView();
view.updateViewport(500, 500);
view.setCamera(mainCamera);
await testHelper.capture(
viewer,
"default_swapchain_new_view_with_main_camera",
view: view,
);
// final view = await viewer.createView();
// view.setViewport(500, 500);
// view.setCamera(mainCamera);
// await testHelper.capture(
// viewer,
// "default_swapchain_new_view_with_main_camera",
// view: view,
// );
var newCamera = await viewer.createCamera();
newCamera.setTransform(Matrix4.translation(Vector3(0.0, 0.0, 10.0)));
newCamera.setLensProjection();
view.setCamera(newCamera);
// var newCamera = await viewer.createCamera();
// newCamera.setTransform(Matrix4.translation(Vector3(0.0, 0.0, 10.0)));
// newCamera.setLensProjection();
// view.setCamera(newCamera);
await testHelper.capture(
viewer,
"default_swapchain_new_view_new_camera",
view: view,
);
// await testHelper.capture(
// viewer,
// "default_swapchain_new_view_new_camera",
// view: view,
// );
await testHelper.capture(
viewer,
"default_swapchain_default_view_main_camera_no_change",
);
});
});
// await testHelper.capture(
// viewer,
// "default_swapchain_default_view_main_camera_no_change",
// );
// });
// });
test('create secondary view, different swapchain', () async {
await testHelper.withViewer((viewer) async {
final cube = await viewer.createGeometry(GeometryHelper.cube());
// test('create secondary view, different swapchain', () async {
// await testHelper.withViewer((viewer) async {
// final cube = await viewer.createGeometry(GeometryHelper.cube());
var mainCamera = await viewer.getMainCamera();
mainCamera.setTransform(Matrix4.translation(Vector3(0, 0, 5)));
final swapChain = await viewer.createHeadlessSwapChain(1, 1);
await testHelper.capture(
viewer, "create_swapchain_default_view_default_swapchain");
// var mainCamera = await viewer.getMainCamera();
// mainCamera.setTransform(Matrix4.translation(Vector3(0, 0, 5)));
// final swapChain = await viewer.createHeadlessSwapChain(1, 1);
// await testHelper.capture(
// viewer, "create_swapchain_default_view_default_swapchain");
final view = await viewer.createView();
// final view = await viewer.createView();
final texture = await testHelper.createTexture(200, 400);
final renderTarget = await viewer.createRenderTarget(
200, 400, texture.metalTextureAddress);
await view.setRenderTarget(renderTarget);
// final texture = await testHelper.createTexture(200, 400);
// final renderTarget = await viewer.createRenderTarget(
// 200, 400, texture.metalTextureAddress);
// await view.setRenderTarget(renderTarget);
await view.updateViewport(200, 400);
view.setCamera(mainCamera);
mainCamera.setLensProjection(aspect: 0.5);
// await view.setViewport(200, 400);
// view.setCamera(mainCamera);
// mainCamera.setLensProjection(aspect: 0.5);
await testHelper.capture(
viewer,
view: view,
swapChain: swapChain,
renderTarget: renderTarget,
"create_swapchain_secondary_view_new_swapchain",
);
});
});
// await testHelper.capture(
// viewer,
// view: view,
// swapChain: swapChain,
// renderTarget: renderTarget,
// "create_swapchain_secondary_view_new_swapchain",
// );
// });
// });
test('pick', () async {
await testHelper.withViewer((viewer) async {
final view = await viewer.getViewAt(0);
// test('pick', () async {
// await testHelper.withViewer((viewer) async {
// final view = await viewer.getViewAt(0);
await view.setRenderable(true, testHelper.swapChain);
// await view.setRenderable(true, testHelper.swapChain);
final cube = await viewer
.createGeometry(GeometryHelper.cube(normals: false, uvs: false));
// final cube = await viewer
// .createGeometry(GeometryHelper.cube(normals: false, uvs: false));
await testHelper.capture(viewer, "view_pick");
// await testHelper.capture(viewer, "view_pick");
final completer = Completer();
// final completer = Completer();
await viewer.pick(250, 250, (result) {
completer.complete(result.entity);
print(
"Pick result : ${result.fragX} ${result.fragY} ${result.fragZ}");
});
// await viewer.pick(250, 250, (result) {
// completer.complete(result.entity);
// print(
// "Pick result : ${result.fragX} ${result.fragY} ${result.fragZ}");
// });
for (int i = 0; i < 10; i++) {
await testHelper.capture(viewer, "view_pick");
if (completer.isCompleted) {
break;
}
}
// for (int i = 0; i < 10; i++) {
// await testHelper.capture(viewer, "view_pick");
// if (completer.isCompleted) {
// break;
// }
// }
expect(completer.isCompleted, true);
expect(await completer.future, cube.entity);
}, cameraPosition: Vector3(0, 0, 3));
});
// expect(completer.isCompleted, true);
// expect(await completer.future, cube.entity);
// }, cameraPosition: Vector3(0, 0, 3));
// });
test('dithering', () async {
await testHelper.withViewer((viewer) async {
final view = await viewer.getViewAt(0);
// test('dithering', () async {
// await testHelper.withViewer((viewer) async {
// final view = await viewer.getViewAt(0);
expect(await view.isDitheringEnabled(), true);
// expect(await view.isDitheringEnabled(), true);
final cube = await viewer
.createGeometry(GeometryHelper.cube(normals: false, uvs: false));
// final cube = await viewer
// .createGeometry(GeometryHelper.cube(normals: false, uvs: false));
await testHelper.capture(viewer, "dithering_enabled");
// await testHelper.capture(viewer, "dithering_enabled");
await view.setDithering(false);
expect(await view.isDitheringEnabled(), false);
await testHelper.capture(viewer, "dithering_disabled");
}, cameraPosition: Vector3(0, 0, 3));
});
});
}
// await view.setDithering(false);
// expect(await view.isDitheringEnabled(), false);
// await testHelper.capture(viewer, "dithering_disabled");
// }, cameraPosition: Vector3(0, 0, 3));
// });
// });
// }