add missing setExposure methods + reinstate camera tests

This commit is contained in:
Nick Fisher
2025-05-24 10:51:56 +08:00
parent 60cfe32672
commit 4505cbe325
4 changed files with 87 additions and 44 deletions

View File

@@ -195,7 +195,7 @@ class FFICamera extends Camera {
Engine_destroyCamera(app.engine, camera); Engine_destroyCamera(app.engine, camera);
} }
Future setCameraExposure( Future setExposure(
double aperture, double shutterSpeed, double sensitivity) async { double aperture, double shutterSpeed, double sensitivity) async {
Camera_setExposure(camera, aperture, shutterSpeed, sensitivity); Camera_setExposure(camera, aperture, shutterSpeed, sensitivity);
} }

View File

@@ -4,12 +4,17 @@ import 'package:thermion_dart/thermion_dart.dart';
enum Projection { Perspective, Orthographic } enum Projection { Perspective, Orthographic }
abstract class Camera { abstract class Camera {
///
///
///
Future<Vector3> getPosition() async { Future<Vector3> getPosition() async {
final modelMatrix = await getModelMatrix(); final modelMatrix = await getModelMatrix();
return modelMatrix.getTranslation(); return modelMatrix.getTranslation();
} }
///
///
///
Future lookAt(Vector3 position, {Vector3? focus, Vector3? up}) async { Future lookAt(Vector3 position, {Vector3? focus, Vector3? up}) async {
focus ??= Vector3.zero(); focus ??= Vector3.zero();
up ??= Vector3(0, 1, 0); up ??= Vector3(0, 1, 0);
@@ -19,9 +24,30 @@ abstract class Camera {
} }
/// ///
/// Sets the camera exposure. /// From Camera.h:
/// ///
Future setCameraExposure( /// Sets this camera's exposure (default is f/16, 1/125s, 100 ISO)
///
/// The exposure ultimately controls the scene's brightness, just like with a real camera.
/// The default values provide adequate exposure for a camera placed outdoors on a sunny day
/// with the sun at the zenith.
///
/// @param aperture Aperture in f-stops, clamped between 0.5 and 64.
/// A lower \p aperture value ///increases/// the exposure, leading to
/// a brighter scene. Realistic values are between 0.95 and 32.
///
/// @param shutterSpeed Shutter speed in seconds, clamped between 1/25,000 and 60.
/// A lower shutter speed increases the exposure. Realistic values are
/// between 1/8000 and 30.
///
/// @param sensitivity Sensitivity in ISO, clamped between 10 and 204,800.
/// A higher \p sensitivity increases the exposure. Realistic values are
/// between 50 and 25600.
///
/// @note
/// With the default parameters, the scene must contain at least one Light of intensity
/// similar to the sun (e.g.: a 100,000 lux directional light).
Future setExposure(
double aperture, double shutterSpeed, double sensitivity); double aperture, double shutterSpeed, double sensitivity);
Future setProjection(Projection projection, double left, double right, Future setProjection(Projection projection, double left, double right,
@@ -52,5 +78,7 @@ abstract class Camera {
Future setFocusDistance(double focusDistance); Future setFocusDistance(double focusDistance);
Future<double> getHorizontalFieldOfView(); Future<double> getHorizontalFieldOfView();
Future<double> getVerticalFieldOfView(); Future<double> getVerticalFieldOfView();
Future<Frustum> getFrustum();
Future destroy(); Future destroy();
} }

View File

@@ -52,6 +52,12 @@ namespace thermion
camera->setLensProjection(focalLength, aspect, near, far); camera->setLensProjection(focalLength, aspect, near, far);
} }
EMSCRIPTEN_KEEPALIVE void Camera_setExposure(TCamera *tCamera, float aperture, float shutterSpeed, float sensitivity) {
TRACE("Setting exposure %f %f %f", aperture, shutterSpeed, sensitivity);
auto *camera = reinterpret_cast<Camera *>(tCamera);
camera->setExposure(aperture, shutterSpeed, sensitivity);
}
EMSCRIPTEN_KEEPALIVE void Camera_setModelMatrix(TCamera *tCamera, double *tModelMatrix) { EMSCRIPTEN_KEEPALIVE void Camera_setModelMatrix(TCamera *tCamera, double *tModelMatrix) {
auto *camera = reinterpret_cast<Camera *>(tCamera); auto *camera = reinterpret_cast<Camera *>(tCamera);
auto modelMatrix = convert_double_to_mat4f(tModelMatrix); auto modelMatrix = convert_double_to_mat4f(tModelMatrix);

View File

@@ -1,6 +1,5 @@
// ignore_for_file: unused_local_variable // ignore_for_file: unused_local_variable
import 'dart:math';
import 'package:thermion_dart/thermion_dart.dart'; import 'package:thermion_dart/thermion_dart.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'helpers.dart'; import 'helpers.dart';
@@ -8,7 +7,7 @@ import 'helpers.dart';
void main() async { void main() async {
final testHelper = TestHelper("camera"); final testHelper = TestHelper("camera");
await testHelper.setup(); await testHelper.setup();
group('camera', () {
test('create/destroy camera', () async { test('create/destroy camera', () async {
await testHelper.withViewer((viewer) async { await testHelper.withViewer((viewer) async {
final camera = await viewer.createCamera(); final camera = await viewer.createCamera();
@@ -16,7 +15,7 @@ void main() async {
}); });
}); });
test('model matrix', () async { test('set model matrix', () async {
await testHelper.withViewer((viewer) async { await testHelper.withViewer((viewer) async {
final camera = await viewer.getActiveCamera(); final camera = await viewer.getActiveCamera();
await camera.setModelMatrix(Matrix4.translation(Vector3.all(4.0))); await camera.setModelMatrix(Matrix4.translation(Vector3.all(4.0)));
@@ -31,6 +30,15 @@ void main() async {
}); });
}); });
test('set exposure', () async {
await testHelper.withViewer((viewer) async {
final camera = await viewer.getActiveCamera();
await testHelper.capture(viewer.view, "camera_default_exposure");
await camera.setExposure(16.0, 1.0 / 125.0, 200.0);
await testHelper.capture(viewer.view, "camera_iso_200");
}, addSkybox: true);
});
// test('getCameraViewMatrix', () async { // test('getCameraViewMatrix', () async {
// await testHelper.withViewer((viewer) async { // await testHelper.withViewer((viewer) async {
// await viewer.setCameraModelMatrix4(Matrix4.identity()); // await viewer.setCameraModelMatrix4(Matrix4.identity());
@@ -55,48 +63,49 @@ void main() async {
// }); // });
// }); // });
// test('getCameraProjectionMatrix', () async { test('getCameraProjectionMatrix', () async {
// await testHelper.withViewer((viewer) async { await testHelper.withViewer((viewer) async {
// var projectionMatrix = await viewer.getCameraProjectionMatrix(); var camera = await viewer.getActiveCamera();
// print(projectionMatrix); var projectionMatrix = await camera.getProjectionMatrix();
// }); print(projectionMatrix);
// }); });
});
// test('getCameraCullingProjectionMatrix', () async { test('getCameraCullingProjectionMatrix', () async {
// await testHelper.withViewer((viewer) async { await testHelper.withViewer((viewer) async {
// // ignore: dead_code var camera = await viewer.getActiveCamera();
// var viewer = await testHelper.createViewer(); var matrix = await camera.getCullingProjectionMatrix();
// var matrix = await viewer.getCameraCullingProjectionMatrix(); print(matrix);
// print(matrix); });
// }); });
// });
// test('getCameraFrustum', () async { test('getCameraFrustum', () async {
// await testHelper.withViewer((viewer) async { await testHelper.withViewer((viewer) async {
// var frustum = await viewer.getCameraFrustum(); var camera = await viewer.getActiveCamera();
// print(frustum.plane5.normal); var frustum = await camera.getFrustum();
// print(frustum.plane5.constant);
// var camera = await viewer.getMainCamera(); print(frustum.plane5.normal);
print(frustum.plane5.constant);
// await camera.setLensProjection( await camera.setLensProjection(
// near: 10.0, far: 1000.0, aspect: 1.0, focalLength: 28.0); near: 10.0, far: 1000.0, aspect: 1.0, focalLength: 28.0);
// frustum = await viewer.getCameraFrustum(); frustum = await camera.getFrustum();
// print(frustum.plane5.normal); print(frustum.plane5.normal);
// print(frustum.plane5.constant); print(frustum.plane5.constant);
// }); });
// }); });
// test('set orthographic projection', () async { test('set orthographic projection', () async {
// await testHelper.withViewer((viewer) async { await testHelper.withViewer((viewer) async {
// var camera = await viewer.getMainCamera(); var camera = await viewer.getActiveCamera();
// await viewer.createGeometry(GeometryHelper.cube());
// await camera.setProjection( await viewer.createGeometry(GeometryHelper.cube());
// 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.view, "camera_set_orthographic_projection");
});
});
// test('set perspective projection/culling matrix', () async { // test('set perspective projection/culling matrix', () async {
// await testHelper.withViewer((viewer) async { // await testHelper.withViewer((viewer) async {
@@ -237,5 +246,5 @@ void main() async {
// () => viewer.getCameraAt(2), throwsA(isA<Exception>())); // () => viewer.getCameraAt(2), throwsA(isA<Exception>()));
// }); // });
// }); // });
});
} }