add ThirdPersonCameraDelegate
This commit is contained in:
@@ -0,0 +1,194 @@
|
||||
import 'dart:async';
|
||||
import 'dart:math';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
import '../../../viewer/viewer.dart';
|
||||
import '../delegates.dart';
|
||||
import '../input_handler.dart';
|
||||
|
||||
class OverTheShoulderCameraDelegate implements InputHandlerDelegate {
|
||||
final ThermionViewer viewer;
|
||||
|
||||
late ThermionEntity player;
|
||||
late Camera camera;
|
||||
|
||||
final double rotationSensitivity;
|
||||
final double movementSensitivity;
|
||||
final double zoomSensitivity;
|
||||
final double panSensitivity;
|
||||
final double? clampY;
|
||||
|
||||
static final _up = Vector3(0, 1, 0);
|
||||
static final _forward = Vector3(0, 0, -1);
|
||||
static final Vector3 _right = Vector3(1, 0, 0);
|
||||
|
||||
Vector2 _queuedRotationDelta = Vector2.zero();
|
||||
double _queuedZoomDelta = 0.0;
|
||||
Vector3 _queuedMoveDelta = Vector3.zero();
|
||||
|
||||
final cameraPosition = Vector3(-0.5, 2.5, -3);
|
||||
final cameraUp = Vector3(0, 1, 0);
|
||||
var cameraLookAt = Vector3(0, 0.5, 3);
|
||||
|
||||
OverTheShoulderCameraDelegate(this.viewer, this.player, this.camera,
|
||||
{this.rotationSensitivity = 0.001,
|
||||
this.movementSensitivity = 0.1,
|
||||
this.zoomSensitivity = 0.1,
|
||||
this.panSensitivity = 0.1,
|
||||
this.clampY,
|
||||
ThermionEntity? entity}) {}
|
||||
|
||||
@override
|
||||
Future<void> queue(InputAction action, Vector3? delta) async {
|
||||
if (delta == null) return;
|
||||
|
||||
switch (action) {
|
||||
case InputAction.ROTATE:
|
||||
_queuedRotationDelta += Vector2(delta.x, delta.y);
|
||||
break;
|
||||
case InputAction.TRANSLATE:
|
||||
_queuedMoveDelta += delta;
|
||||
break;
|
||||
case InputAction.PICK:
|
||||
_queuedZoomDelta += delta.z;
|
||||
break;
|
||||
case InputAction.NONE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool _executing = false;
|
||||
static bool get executing => _executing;
|
||||
|
||||
@override
|
||||
Future<void> execute() async {
|
||||
if (_executing) {
|
||||
return;
|
||||
}
|
||||
|
||||
_executing = true;
|
||||
|
||||
if (_queuedRotationDelta.length2 == 0.0 &&
|
||||
_queuedZoomDelta == 0.0 &&
|
||||
_queuedMoveDelta.length2 == 0.0) {
|
||||
_executing = false;
|
||||
return;
|
||||
}
|
||||
|
||||
Matrix4 currentPlayerTransform = await viewer.getWorldTransform(player);
|
||||
|
||||
// first we need to convert the move vector to player space
|
||||
var newTransform =
|
||||
Matrix4.translation(_queuedMoveDelta * movementSensitivity);
|
||||
|
||||
_queuedMoveDelta = Vector3.zero();
|
||||
Matrix4 newPlayerTransform = newTransform * currentPlayerTransform;
|
||||
await viewer.setTransform(player, newPlayerTransform);
|
||||
|
||||
if (_queuedZoomDelta != 0.0) {
|
||||
// Ignore zoom
|
||||
}
|
||||
|
||||
var inverted = newPlayerTransform.clone()..invert();
|
||||
|
||||
// camera is always looking at -Z, whereas models generally face towards +Z
|
||||
// therefore
|
||||
if (_queuedRotationDelta.length2 > 0.0) {
|
||||
double deltaX =
|
||||
_queuedRotationDelta.x * rotationSensitivity * viewer.pixelRatio;
|
||||
double deltaY =
|
||||
_queuedRotationDelta.y * rotationSensitivity * viewer.pixelRatio;
|
||||
|
||||
cameraLookAt = Matrix4.rotationY(-deltaX) * Matrix4.rotationX(-deltaY) * cameraLookAt;
|
||||
_queuedRotationDelta = Vector2.zero();
|
||||
}
|
||||
|
||||
var newCameraViewMatrix =
|
||||
makeViewMatrix(cameraPosition, cameraLookAt, cameraUp);
|
||||
newCameraViewMatrix.invert();
|
||||
var newCameraTransform = newPlayerTransform * newCameraViewMatrix;
|
||||
await camera.setTransform(newCameraTransform);
|
||||
|
||||
await viewer.queueTransformUpdates(
|
||||
[camera.getEntity(), player], [newCameraTransform, newPlayerTransform]);
|
||||
|
||||
_executing = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Quaternion relativeCameraRotation = Quaternion.identity();
|
||||
|
||||
// // Apply rotation
|
||||
|
||||
|
||||
// // transform the translation from player space to world space
|
||||
// var rotation = (await camera.getModelMatrix()).getRotation();
|
||||
// // Extract yaw angle from the original matrix
|
||||
// double yaw = atan2(rotation.entry(2, 0), rotation.entry(0, 0));
|
||||
|
||||
// // Create a new matrix with only the yaw rotation
|
||||
// double cosYaw = cos(yaw);
|
||||
// double sinYaw = sin(yaw);
|
||||
|
||||
// rotation = Matrix3(cosYaw, 0, sinYaw, 0, 1, 0, -sinYaw, 0, cosYaw);
|
||||
|
||||
// relativeTranslation = rotation * relativeTranslation;
|
||||
|
||||
// // Compose relative transform
|
||||
// relativeTransform =
|
||||
// Matrix4.compose(relativeTranslation, currentRotation, Vector3(1, 1, 1));
|
||||
|
||||
// // Apply relative transform to current transform
|
||||
// Matrix4 newTransform = currentTransform * relativeTransform;
|
||||
|
||||
// // Extract new position and constrain it
|
||||
// Vector3 newPosition = newTransform.getTranslation();
|
||||
|
||||
// // Recompose final transform with constrained position
|
||||
// Matrix4 finalTransform = Matrix4.compose(newPosition,
|
||||
// Quaternion.fromRotation(newTransform.getRotation()), Vector3(1, 1, 1));
|
||||
|
||||
// Quaternion relativeCameraRotation = Quaternion.identity();
|
||||
|
||||
// // Apply rotation
|
||||
// if (_queuedRotationDelta.length2 > 0.0) {
|
||||
// double deltaX =
|
||||
// _queuedRotationDelta.x * rotationSensitivity * viewer.pixelRatio;
|
||||
// double deltaY =
|
||||
// _queuedRotationDelta.y * rotationSensitivity * viewer.pixelRatio;
|
||||
|
||||
// Quaternion yawRotation = Quaternion.axisAngle(_up, -deltaX);
|
||||
// Quaternion pitchRotation = Quaternion.axisAngle(_right, -deltaY);
|
||||
|
||||
// relativeCameraRotation = pitchRotation * yawRotation;
|
||||
// _queuedRotationDelta = Vector2.zero();
|
||||
// }
|
||||
|
||||
// // transform the translation from player space to world space
|
||||
// var rotation = (await camera.getModelMatrix()).getRotation();
|
||||
// // Extract yaw angle from the original matrix
|
||||
// double yaw = atan2(rotation.entry(2, 0), rotation.entry(0, 0));
|
||||
|
||||
// // Create a new matrix with only the yaw rotation
|
||||
// double cosYaw = cos(yaw);
|
||||
// double sinYaw = sin(yaw);
|
||||
|
||||
// rotation = Matrix3(cosYaw, 0, sinYaw, 0, 1, 0, -sinYaw, 0, cosYaw);
|
||||
|
||||
// relativeTranslation = rotation * relativeTranslation;
|
||||
|
||||
// // Compose relative transform
|
||||
// relativeTransform =
|
||||
// Matrix4.compose(relativeTranslation, currentRotation, Vector3(1, 1, 1));
|
||||
|
||||
// // Apply relative transform to current transform
|
||||
// Matrix4 newTransform = currentTransform * relativeTransform;
|
||||
|
||||
// // Extract new position and constrain it
|
||||
// Vector3 newPosition = newTransform.getTranslation();
|
||||
|
||||
// // Recompose final transform with constrained position
|
||||
// Matrix4 finalTransform = Matrix4.compose(newPosition,
|
||||
// Quaternion.fromRotation(newTransform.getRotation()), Vector3(1, 1, 1));
|
||||
|
||||
// // Update camera
|
||||
Reference in New Issue
Block a user