use decompose/composeMatrix for transforms and add mouse controls for rotation
This commit is contained in:
@@ -39,7 +39,7 @@ namespace polyvox
|
||||
inline void updateTransform(EntityId e);
|
||||
void setScale(EntityId e, float scale);
|
||||
void setPosition(EntityId e, float x, float y, float z, bool relative);
|
||||
void setRotation(EntityId e, float rads, float x, float y, float z);
|
||||
void setRotation(EntityId e, float rads, float x, float y, float z, float w, bool relative);
|
||||
const utils::Entity *getCameraEntities(EntityId e);
|
||||
size_t getCameraEntityCount(EntityId e);
|
||||
const utils::Entity *getLightEntities(EntityId e) const noexcept;
|
||||
@@ -119,7 +119,5 @@ namespace polyvox
|
||||
SceneAsset asset,
|
||||
const char *entityName);
|
||||
|
||||
inline void updateTransform(SceneAsset &asset);
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ extern "C"
|
||||
FLUTTER_PLUGIN_EXPORT bool set_material_color(void *assetManager, EntityId asset, const char *meshName, int materialIndex, const float r, const float g, const float b, const float a);
|
||||
FLUTTER_PLUGIN_EXPORT void transform_to_unit_cube(void *assetManager, EntityId asset);
|
||||
FLUTTER_PLUGIN_EXPORT void set_position(void *assetManager, EntityId asset, float x, float y, float z, bool relative);
|
||||
FLUTTER_PLUGIN_EXPORT void set_rotation(void *assetManager, EntityId asset, float rads, float x, float y, float z);
|
||||
FLUTTER_PLUGIN_EXPORT void set_rotation(void *assetManager, EntityId asset, float rads, float x, float y, float z, float w, bool relative);
|
||||
FLUTTER_PLUGIN_EXPORT void set_scale(void *assetManager, EntityId asset, float scale);
|
||||
|
||||
// Camera methods
|
||||
|
||||
@@ -86,14 +86,6 @@ namespace polyvox {
|
||||
// a slot to preload textures
|
||||
filament::Texture* texture = nullptr;
|
||||
|
||||
// initialized to identity
|
||||
math::mat4f position;
|
||||
|
||||
// initialized to identity
|
||||
math::mat4f rotation;
|
||||
|
||||
float mScale = 1;
|
||||
|
||||
SceneAsset(
|
||||
FilamentAsset* asset
|
||||
) : asset(asset) {}
|
||||
|
||||
@@ -360,7 +360,7 @@ namespace polyvox
|
||||
asset.asset->getInstance()->getAnimator()->updateBoneMatrices();
|
||||
}
|
||||
|
||||
for (int i = asset.morphAnimations.size() - 1; i >= 0; i--) {
|
||||
for (int i = (int)asset.morphAnimations.size() - 1; i >= 0; i--) {
|
||||
|
||||
auto animationStatus = asset.morphAnimations[i];
|
||||
|
||||
@@ -392,7 +392,7 @@ namespace polyvox
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = asset.boneAnimations.size() - 1; i >= 0; i--) {
|
||||
for (int i = (int)asset.boneAnimations.size() - 1; i >= 0; i--) {
|
||||
auto animationStatus = asset.boneAnimations[i];
|
||||
|
||||
auto elapsedInSecs = float(std::chrono::duration_cast<std::chrono::milliseconds>(now - animationStatus.start).count()) / 1000.0f;
|
||||
@@ -493,7 +493,7 @@ namespace polyvox
|
||||
Log("WARNING - skin count > 1 not currently implemented. This will probably not work");
|
||||
}
|
||||
|
||||
int numJoints = filamentInstance->getJointCountAt(skinIndex);
|
||||
size_t numJoints = filamentInstance->getJointCountAt(skinIndex);
|
||||
auto joints = filamentInstance->getJointsAt(skinIndex);
|
||||
int boneIndex = -1;
|
||||
for (int i = 0; i < numJoints; i++)
|
||||
@@ -830,7 +830,7 @@ namespace polyvox
|
||||
}
|
||||
|
||||
animation.frameData.clear();
|
||||
const auto& tm = _engine->getTransformManager();
|
||||
|
||||
const auto& inverseBindMatrix = filamentInstance->getInverseBindMatricesAt(skinIndex)[animation.boneIndex];
|
||||
const auto& bindMatrix = inverse(inverseBindMatrix);
|
||||
math::float3 trans;
|
||||
@@ -1163,15 +1163,7 @@ namespace polyvox
|
||||
tm.setTransform(tm.getInstance(inst->getRoot()), transform);
|
||||
}
|
||||
|
||||
void AssetManager::updateTransform(SceneAsset &asset)
|
||||
{
|
||||
auto &tm = _engine->getTransformManager();
|
||||
auto transform =
|
||||
asset.position * asset.rotation * math::mat4f::scaling(asset.mScale);
|
||||
tm.setTransform(tm.getInstance(asset.asset->getRoot()), transform);
|
||||
}
|
||||
|
||||
void AssetManager::setScale(EntityId entity, float scale)
|
||||
void AssetManager::setScale(EntityId entity, float newScale)
|
||||
{
|
||||
const auto &pos = _entityIdLookup.find(entity);
|
||||
if (pos == _entityIdLookup.end())
|
||||
@@ -1180,8 +1172,22 @@ namespace polyvox
|
||||
return;
|
||||
}
|
||||
auto &asset = _assets[pos->second];
|
||||
asset.mScale = scale;
|
||||
updateTransform(asset);
|
||||
|
||||
auto &tm = _engine->getTransformManager();
|
||||
auto transformInstance = tm.getInstance(asset.asset->getRoot());
|
||||
|
||||
auto transform = tm.getTransform(transformInstance);
|
||||
|
||||
math::float3 translation;
|
||||
math::quatf rotation;
|
||||
math::float3 scale;
|
||||
|
||||
decomposeMatrix(transform, &translation, &rotation, &scale);
|
||||
scale = { newScale, newScale, newScale};
|
||||
|
||||
transform = composeMatrix(translation, rotation, scale);
|
||||
tm.setTransform(transformInstance, transform);
|
||||
|
||||
}
|
||||
|
||||
void AssetManager::setPosition(EntityId entity, float x, float y, float z, bool relative)
|
||||
@@ -1193,18 +1199,29 @@ namespace polyvox
|
||||
return;
|
||||
}
|
||||
auto &asset = _assets[pos->second];
|
||||
if(relative) {
|
||||
asset.position[3][0] += x;
|
||||
asset.position[3][1] += y;
|
||||
asset.position[3][2] += z;
|
||||
} else {
|
||||
asset.position = math::mat4f::translation(math::float3(x, y, z));
|
||||
}
|
||||
|
||||
updateTransform(asset);
|
||||
auto &tm = _engine->getTransformManager();
|
||||
auto transformInstance = tm.getInstance(asset.asset->getRoot());
|
||||
|
||||
auto transform = tm.getTransform(transformInstance);
|
||||
|
||||
math::float3 translation;
|
||||
math::quatf rotation;
|
||||
math::float3 scale;
|
||||
|
||||
decomposeMatrix(transform, &translation, &rotation, &scale);
|
||||
if(relative) {
|
||||
translation += math::float3( x, y, z );
|
||||
} else {
|
||||
translation = math::float3(x,y,z);
|
||||
}
|
||||
|
||||
transform = composeMatrix(translation, rotation, scale);
|
||||
tm.setTransform(transformInstance, transform);
|
||||
|
||||
}
|
||||
|
||||
void AssetManager::setRotation(EntityId entity, float rads, float x, float y, float z)
|
||||
void AssetManager::setRotation(EntityId entity, float rads, float x, float y, float z, float w, bool relative)
|
||||
{
|
||||
const auto &pos = _entityIdLookup.find(entity);
|
||||
if (pos == _entityIdLookup.end())
|
||||
@@ -1213,8 +1230,27 @@ namespace polyvox
|
||||
return;
|
||||
}
|
||||
auto &asset = _assets[pos->second];
|
||||
asset.rotation = math::mat4f::rotation(rads, math::float3(x, y, z));
|
||||
updateTransform(asset);
|
||||
|
||||
auto &tm = _engine->getTransformManager();
|
||||
auto transformInstance = tm.getInstance(asset.asset->getRoot());
|
||||
|
||||
auto transform = tm.getTransform(transformInstance);
|
||||
|
||||
math::float3 translation;
|
||||
math::quatf rotation;
|
||||
math::float3 scale;
|
||||
|
||||
decomposeMatrix(transform, &translation, &rotation, &scale);
|
||||
|
||||
if(relative) {
|
||||
rotation = normalize(rotation * math::quatf(w,x,y,z));
|
||||
} else {
|
||||
rotation = math::quatf(w,x,y,z);
|
||||
}
|
||||
|
||||
transform = composeMatrix(translation, rotation, scale);
|
||||
tm.setTransform(transformInstance, transform);
|
||||
|
||||
}
|
||||
|
||||
const utils::Entity *AssetManager::getCameraEntities(EntityId entity)
|
||||
|
||||
@@ -475,9 +475,9 @@ extern "C"
|
||||
((AssetManager *)assetManager)->setPosition(asset, x, y, z, relative);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_rotation(void *assetManager, EntityId asset, float rads, float x, float y, float z)
|
||||
FLUTTER_PLUGIN_EXPORT void set_rotation(void *assetManager, EntityId asset, float rads, float x, float y, float z, float w, bool relative)
|
||||
{
|
||||
((AssetManager *)assetManager)->setRotation(asset, rads, x, y, z);
|
||||
((AssetManager *)assetManager)->setRotation(asset, rads, x, y, z, w, relative);
|
||||
}
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void set_scale(void *assetManager, EntityId asset, float scale)
|
||||
|
||||
@@ -19,54 +19,103 @@ class EntityTransformController {
|
||||
bool _back = false;
|
||||
bool _rotateLeft = false;
|
||||
bool _rotateRight = false;
|
||||
double _rotY = 0;
|
||||
|
||||
int? forwardAnimationIndex;
|
||||
int? backwardAnimationIndex;
|
||||
int? strafeLeftAnimationIndex;
|
||||
int? strafeRightAnimationIndex;
|
||||
|
||||
EntityTransformController(this.controller, this._entity,
|
||||
{this.translationSpeed = 1, this.rotationRadsPerSecond = pi / 2}) {
|
||||
{this.translationSpeed = 1,
|
||||
this.rotationRadsPerSecond = pi / 2,
|
||||
this.forwardAnimationIndex,
|
||||
this.backwardAnimationIndex,
|
||||
this.strafeLeftAnimationIndex,
|
||||
this.strafeRightAnimationIndex}) {
|
||||
var translationSpeedPerTick = translationSpeed / (1000 / 16.667);
|
||||
var rotationRadsPerTick = rotationRadsPerSecond / (1000 / 16.667);
|
||||
_ticker = Timer.periodic(const Duration(milliseconds: 16), (timer) {
|
||||
_update(translationSpeedPerTick);
|
||||
_update(translationSpeedPerTick, rotationRadsPerTick);
|
||||
});
|
||||
}
|
||||
|
||||
void _update(double translationSpeedPerTick) async {
|
||||
bool _enabled = true;
|
||||
void enable() {
|
||||
_enabled = true;
|
||||
}
|
||||
|
||||
void disable() {
|
||||
_enabled = false;
|
||||
}
|
||||
|
||||
void _update(
|
||||
double translationSpeedPerTick, double rotationRadsPerTick) async {
|
||||
if (!_enabled) {
|
||||
return;
|
||||
}
|
||||
var _position = v.Vector3.zero();
|
||||
var _rotation = v.Quaternion.identity();
|
||||
bool requiresUpdate = false;
|
||||
bool updateTranslation = false;
|
||||
if (_forward) {
|
||||
_position.add(v.Vector3(0, 0, -translationSpeedPerTick));
|
||||
requiresUpdate = true;
|
||||
updateTranslation = true;
|
||||
}
|
||||
if (_back) {
|
||||
_position.add(v.Vector3(0, 0, translationSpeedPerTick));
|
||||
requiresUpdate = true;
|
||||
updateTranslation = true;
|
||||
}
|
||||
if (_strafeLeft) {
|
||||
_position.add(v.Vector3(-translationSpeedPerTick, 0, 0));
|
||||
requiresUpdate = true;
|
||||
updateTranslation = true;
|
||||
}
|
||||
if (_strafeRight) {
|
||||
_position.add(v.Vector3(translationSpeedPerTick, 0, 0));
|
||||
requiresUpdate = true;
|
||||
updateTranslation = true;
|
||||
}
|
||||
|
||||
// todo - better to use pitch/yaw/roll
|
||||
if (_rotateLeft) {}
|
||||
if (_rotateRight) {}
|
||||
bool updateRotation = false;
|
||||
var _rotation = v.Quaternion.identity();
|
||||
|
||||
if (requiresUpdate) {
|
||||
double rads = 0.0;
|
||||
if (_rotY != 0) {
|
||||
rads = _rotY! * pi / 1000;
|
||||
var rotY = v.Quaternion.axisAngle(v.Vector3(0, 1, 0), rads).normalized();
|
||||
_rotation = rotY;
|
||||
updateRotation = true;
|
||||
_rotY = 0;
|
||||
}
|
||||
|
||||
if (updateTranslation) {
|
||||
await controller.setPosition(
|
||||
_entity, _position.x, _position.y, _position.z,
|
||||
relative: true);
|
||||
}
|
||||
if (updateRotation) {
|
||||
var axis = _rotation.axis;
|
||||
await controller.setRotationQuat(_entity, _rotation, relative: true);
|
||||
}
|
||||
}
|
||||
|
||||
void look(double deltaX) async {
|
||||
_rotY -= deltaX;
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
_ticker.cancel();
|
||||
}
|
||||
|
||||
void forwardPressed() {
|
||||
print("forward");
|
||||
bool _playingForwardAnimation = false;
|
||||
|
||||
void forwardPressed() async {
|
||||
_forward = true;
|
||||
if (forwardAnimationIndex != null) {
|
||||
if (!_playingForwardAnimation) {
|
||||
await controller.playAnimation(_entity, forwardAnimationIndex!,
|
||||
loop: true);
|
||||
_playingForwardAnimation = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer? _forwardTimer;
|
||||
@@ -76,8 +125,12 @@ class EntityTransformController {
|
||||
|
||||
void forwardReleased() async {
|
||||
_forwardTimer?.cancel();
|
||||
_forwardTimer = Timer(Duration(milliseconds: 50), () {
|
||||
_forwardTimer = Timer(Duration(milliseconds: 50), () async {
|
||||
_forward = false;
|
||||
_playingForwardAnimation = false;
|
||||
if (forwardAnimationIndex != null) {
|
||||
await controller.stopAnimation(_entity, forwardAnimationIndex!);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import 'dart:ui' as ui;
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'package:flutter_filament/animations/animation_data.dart';
|
||||
import 'package:flutter_filament/entities/entity_transform_controller.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
// a handle that can be safely passed back to the rendering layer to manipulate an Entity
|
||||
@@ -467,7 +468,14 @@ abstract class FilamentController {
|
||||
/// Sets the rotation for [entity] to [rads] around the axis {x,y,z}.
|
||||
///
|
||||
Future setRotation(
|
||||
FilamentEntity entity, double rads, double x, double y, double z);
|
||||
FilamentEntity entity, double rads, double x, double y, double z,
|
||||
{bool relative = false});
|
||||
|
||||
///
|
||||
/// Sets the rotation for [entity] to the specified quaternion.
|
||||
///
|
||||
Future setRotationQuat(FilamentEntity entity, Quaternion rotation,
|
||||
{bool relative = false});
|
||||
|
||||
///
|
||||
/// Reveal the node [meshName] under [entity]. Only applicable if [hide] had previously been called; this is a no-op otherwise.
|
||||
@@ -528,5 +536,6 @@ abstract class FilamentController {
|
||||
// Stream get keyboardFocusRequested;
|
||||
// void requestKeyboardFocus();
|
||||
|
||||
void control(FilamentEntity entity, {double? translationSpeed});
|
||||
Future<EntityTransformController> control(FilamentEntity entity,
|
||||
{double? translationSpeed, String? forwardAnimation});
|
||||
}
|
||||
|
||||
@@ -1069,11 +1069,23 @@ class FilamentControllerFFI extends FilamentController {
|
||||
|
||||
@override
|
||||
Future setRotation(
|
||||
FilamentEntity entity, double rads, double x, double y, double z) async {
|
||||
FilamentEntity entity, double rads, double x, double y, double z,
|
||||
{bool relative = false}) async {
|
||||
if (_viewer == null) {
|
||||
throw Exception("No viewer available, ignoring");
|
||||
}
|
||||
set_rotation(_assetManager!, entity, rads, x, y, z);
|
||||
var quat = Quaternion.axisAngle(Vector3(x, y, z), rads);
|
||||
await setRotationQuat(entity, quat, relative: relative);
|
||||
}
|
||||
|
||||
@override
|
||||
Future setRotationQuat(FilamentEntity entity, Quaternion rotation,
|
||||
{bool relative = false}) async {
|
||||
if (_viewer == null) {
|
||||
throw Exception("No viewer available, ignoring");
|
||||
}
|
||||
set_rotation(_assetManager!, entity, rotation.radians, rotation.x,
|
||||
rotation.y, rotation.z, rotation.w, relative);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -1325,10 +1337,23 @@ class FilamentControllerFFI extends FilamentController {
|
||||
}
|
||||
|
||||
HardwareKeyboardListener? _keyboardListener;
|
||||
void control(FilamentEntity entity, {double? translationSpeed}) {
|
||||
Future<EntityTransformController> control(FilamentEntity entity,
|
||||
{double? translationSpeed, String? forwardAnimation}) async {
|
||||
int? forwardAnimationIndex;
|
||||
if (forwardAnimation != null) {
|
||||
final animationNames = await getAnimationNames(entity);
|
||||
forwardAnimationIndex = animationNames.indexOf(forwardAnimation);
|
||||
}
|
||||
|
||||
if (forwardAnimationIndex == -1) {
|
||||
throw Exception("Invalid animation : $forwardAnimation");
|
||||
}
|
||||
|
||||
_keyboardListener?.dispose();
|
||||
_keyboardListener = HardwareKeyboardListener(EntityTransformController(
|
||||
this, entity,
|
||||
translationSpeed: translationSpeed ?? 1.0));
|
||||
var transformController = EntityTransformController(this, entity,
|
||||
translationSpeed: translationSpeed ?? 1.0,
|
||||
forwardAnimationIndex: forwardAnimationIndex);
|
||||
_keyboardListener = HardwareKeyboardListener(transformController);
|
||||
return transformController;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -564,7 +564,9 @@ external void set_position(
|
||||
ffi.Float,
|
||||
ffi.Float,
|
||||
ffi.Float,
|
||||
ffi.Float)>(symbol: 'set_rotation', assetId: 'flutter_filament_plugin')
|
||||
ffi.Float,
|
||||
ffi.Float,
|
||||
ffi.Bool)>(symbol: 'set_rotation', assetId: 'flutter_filament_plugin')
|
||||
external void set_rotation(
|
||||
ffi.Pointer<ffi.Void> assetManager,
|
||||
int asset,
|
||||
@@ -572,6 +574,8 @@ external void set_rotation(
|
||||
double x,
|
||||
double y,
|
||||
double z,
|
||||
double w,
|
||||
bool relative,
|
||||
);
|
||||
|
||||
@ffi.Native<ffi.Void Function(ffi.Pointer<ffi.Void>, EntityId, ffi.Float)>(
|
||||
|
||||
23
lib/widgets/entity_controller_mouse_widget.dart
Normal file
23
lib/widgets/entity_controller_mouse_widget.dart
Normal file
@@ -0,0 +1,23 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_filament/entities/entity_transform_controller.dart';
|
||||
|
||||
///
|
||||
/// A widget that translates mouse gestures to zoom/pan/rotate actions.
|
||||
///
|
||||
class EntityTransformMouseControllerWidget extends StatelessWidget {
|
||||
final EntityTransformController? transformController;
|
||||
final Widget? child;
|
||||
|
||||
const EntityTransformMouseControllerWidget(
|
||||
{Key? key, required this.transformController, this.child})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Listener(
|
||||
onPointerHover: (event) {
|
||||
transformController?.look(event.delta.dx);
|
||||
},
|
||||
child: child);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user