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);
}
Future setCameraExposure(
Future setExposure(
double aperture, double shutterSpeed, double sensitivity) async {
Camera_setExposure(camera, aperture, shutterSpeed, sensitivity);
}

View File

@@ -4,12 +4,17 @@ import 'package:thermion_dart/thermion_dart.dart';
enum Projection { Perspective, Orthographic }
abstract class Camera {
///
///
///
Future<Vector3> getPosition() async {
final modelMatrix = await getModelMatrix();
return modelMatrix.getTranslation();
}
///
///
///
Future lookAt(Vector3 position, {Vector3? focus, Vector3? up}) async {
focus ??= Vector3.zero();
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);
Future setProjection(Projection projection, double left, double right,
@@ -52,5 +78,7 @@ abstract class Camera {
Future setFocusDistance(double focusDistance);
Future<double> getHorizontalFieldOfView();
Future<double> getVerticalFieldOfView();
Future<Frustum> getFrustum();
Future destroy();
}

View File

@@ -52,6 +52,12 @@ namespace thermion
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) {
auto *camera = reinterpret_cast<Camera *>(tCamera);
auto modelMatrix = convert_double_to_mat4f(tModelMatrix);

View File

@@ -1,6 +1,5 @@
// ignore_for_file: unused_local_variable
import 'dart:math';
import 'package:thermion_dart/thermion_dart.dart';
import 'package:test/test.dart';
import 'helpers.dart';
@@ -8,7 +7,7 @@ import 'helpers.dart';
void main() async {
final testHelper = TestHelper("camera");
await testHelper.setup();
group('camera', () {
test('create/destroy camera', () async {
await testHelper.withViewer((viewer) async {
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 {
final camera = await viewer.getActiveCamera();
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 {
// await testHelper.withViewer((viewer) async {
// await viewer.setCameraModelMatrix4(Matrix4.identity());
@@ -55,48 +63,49 @@ void main() async {
// });
// });
// test('getCameraProjectionMatrix', () async {
// await testHelper.withViewer((viewer) async {
// var projectionMatrix = await viewer.getCameraProjectionMatrix();
// print(projectionMatrix);
// });
// });
test('getCameraProjectionMatrix', () async {
await testHelper.withViewer((viewer) async {
var camera = await viewer.getActiveCamera();
var projectionMatrix = await camera.getProjectionMatrix();
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 {
var camera = await viewer.getActiveCamera();
var matrix = await camera.getCullingProjectionMatrix();
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 camera = await viewer.getActiveCamera();
var frustum = await camera.getFrustum();
// var camera = await viewer.getMainCamera();
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);
// });
// });
await camera.setLensProjection(
near: 10.0, far: 1000.0, aspect: 1.0, focalLength: 28.0);
frustum = await camera.getFrustum();
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.getActiveCamera();
// 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 viewer.createGeometry(GeometryHelper.cube());
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 {
// await testHelper.withViewer((viewer) async {
@@ -237,5 +246,5 @@ void main() async {
// () => viewer.getCameraAt(2), throwsA(isA<Exception>()));
// });
// });
});
}