refactoring

This commit is contained in:
Nick Fisher
2025-03-21 14:56:20 +08:00
parent 1177a71f73
commit 255c0edd49
38 changed files with 1521 additions and 1207 deletions

View File

@@ -20,4 +20,5 @@ class ThermionFlutterPlugin {
return viewer;
}
}

View File

@@ -1,98 +1,98 @@
import 'dart:math';
// import 'dart:math';
import 'package:flutter/material.dart';
import 'package:thermion_flutter/thermion_flutter.dart';
import 'package:vector_math/vector_math_64.dart' as v64;
// import 'package:flutter/material.dart';
// import 'package:thermion_flutter/thermion_flutter.dart';
// import 'package:vector_math/vector_math_64.dart' as v64;
class CameraOrientationWidget extends StatefulWidget {
final ThermionViewer viewer;
// class CameraOrientationWidget extends StatefulWidget {
// final ThermionViewer viewer;
const CameraOrientationWidget({Key? key, required this.viewer})
: super(key: key);
// const CameraOrientationWidget({Key? key, required this.viewer})
// : super(key: key);
@override
_CameraOrientationWidgetState createState() =>
_CameraOrientationWidgetState();
}
// @override
// _CameraOrientationWidgetState createState() =>
// _CameraOrientationWidgetState();
// }
class _CameraOrientationWidgetState extends State<CameraOrientationWidget>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
v64.Vector3? _position;
v64.Matrix3? _rotation;
// class _CameraOrientationWidgetState extends State<CameraOrientationWidget>
// with SingleTickerProviderStateMixin {
// late AnimationController _controller;
// v64.Vector3? _position;
// v64.Matrix3? _rotation;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 16), // ~60 FPS
)..repeat();
// @override
// void initState() {
// super.initState();
// _controller = AnimationController(
// vsync: this,
// duration: const Duration(milliseconds: 16), // ~60 FPS
// )..repeat();
_controller.addListener(_updateCameraInfo);
}
// _controller.addListener(_updateCameraInfo);
// }
void _updateCameraInfo() async {
final camera = await widget.viewer.getActiveCamera();
final position = await widget.viewer.getCameraPosition();
final rotation = await widget.viewer.getCameraRotation();
setState(() {
_position = position;
_rotation = rotation;
});
}
// void _updateCameraInfo() async {
// final camera = await widget.viewer.getActiveCamera();
// final position = await widget.viewer.getCameraPosition();
// final rotation = await widget.viewer.getCameraRotation();
// setState(() {
// _position = position;
// _rotation = rotation;
// });
// }
@override
void dispose() {
_controller.dispose();
super.dispose();
}
// @override
// void dispose() {
// _controller.dispose();
// super.dispose();
// }
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(8.0),
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.7),
borderRadius: BorderRadius.circular(8.0),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
'Position: ${_formatVector(_position)}',
style: const TextStyle(color: Colors.white),
),
const SizedBox(height: 4),
Text(
'Rotation: ${_formatMatrix(_rotation)}',
style: const TextStyle(color: Colors.white),
),
],
),
);
}
// @override
// Widget build(BuildContext context) {
// return Container(
// padding: const EdgeInsets.all(8.0),
// decoration: BoxDecoration(
// color: Colors.black.withOpacity(0.7),
// borderRadius: BorderRadius.circular(8.0),
// ),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// mainAxisSize: MainAxisSize.min,
// children: [
// Text(
// 'Position: ${_formatVector(_position)}',
// style: const TextStyle(color: Colors.white),
// ),
// const SizedBox(height: 4),
// Text(
// 'Rotation: ${_formatMatrix(_rotation)}',
// style: const TextStyle(color: Colors.white),
// ),
// ],
// ),
// );
// }
String _formatVector(v64.Vector3? vector) {
if (vector == null) return 'N/A';
return '(${vector.x.toStringAsFixed(2)}, ${vector.y.toStringAsFixed(2)}, ${vector.z.toStringAsFixed(2)})';
}
// String _formatVector(v64.Vector3? vector) {
// if (vector == null) return 'N/A';
// return '(${vector.x.toStringAsFixed(2)}, ${vector.y.toStringAsFixed(2)}, ${vector.z.toStringAsFixed(2)})';
// }
String _formatMatrix(v64.Matrix3? matrix) {
if (matrix == null) return 'N/A';
return 'Yaw: ${_getYaw(matrix).toStringAsFixed(2)}°, Pitch: ${_getPitch(matrix).toStringAsFixed(2)}°, Roll: ${_getRoll(matrix).toStringAsFixed(2)}°';
}
// String _formatMatrix(v64.Matrix3? matrix) {
// if (matrix == null) return 'N/A';
// return 'Yaw: ${_getYaw(matrix).toStringAsFixed(2)}°, Pitch: ${_getPitch(matrix).toStringAsFixed(2)}°, Roll: ${_getRoll(matrix).toStringAsFixed(2)}°';
// }
double _getYaw(v64.Matrix3 matrix) {
return -atan2(matrix[2], matrix[0]) * 180 / pi;
}
// double _getYaw(v64.Matrix3 matrix) {
// return -atan2(matrix[2], matrix[0]) * 180 / pi;
// }
double _getPitch(v64.Matrix3 matrix) {
return -asin(matrix[5]) * 180 / pi;
}
// double _getPitch(v64.Matrix3 matrix) {
// return -asin(matrix[5]) * 180 / pi;
// }
double _getRoll(v64.Matrix3 matrix) {
return atan2(matrix[3], matrix[4]) * 180 / pi;
}
}
// double _getRoll(v64.Matrix3 matrix) {
// return atan2(matrix[3], matrix[4]) * 180 / pi;
// }
// }

View File

@@ -1,79 +1,79 @@
import 'package:flutter/material.dart';
import 'package:thermion_dart/thermion_dart.dart';
// import 'package:flutter/material.dart';
// import 'package:thermion_dart/thermion_dart.dart';
class CameraSelectorWidget extends StatefulWidget {
final ThermionViewer viewer;
// class CameraSelectorWidget extends StatefulWidget {
// final ThermionViewer viewer;
const CameraSelectorWidget({Key? key, required this.viewer}) : super(key: key);
// const CameraSelectorWidget({Key? key, required this.viewer}) : super(key: key);
@override
_CameraSelectorWidgetState createState() => _CameraSelectorWidgetState();
}
// @override
// _CameraSelectorWidgetState createState() => _CameraSelectorWidgetState();
// }
class _CameraSelectorWidgetState extends State<CameraSelectorWidget> {
int _activeIndex = 0;
// class _CameraSelectorWidgetState extends State<CameraSelectorWidget> {
// int _activeIndex = 0;
@override
Widget build(BuildContext context) {
int cameraCount = widget.viewer.getCameraCount();
// @override
// Widget build(BuildContext context) {
// int cameraCount = widget.viewer.getCameraCount();
return Container(
height:32,
margin: const EdgeInsets.all(8),
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 4,
offset: const Offset(0, 2),
),
],
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
_buildCameraButton("Main", 0),
if (cameraCount > 1) const VerticalDivider(width: 16, thickness: 1),
...List.generate(cameraCount - 1, (index) {
return _buildCameraButton("${index + 1}", index + 1);
}),
],
),
);
}
// return Container(
// height:32,
// margin: const EdgeInsets.all(8),
// padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12),
// decoration: BoxDecoration(
// color: Colors.white,
// borderRadius: BorderRadius.circular(8),
// boxShadow: [
// BoxShadow(
// color: Colors.black.withOpacity(0.1),
// blurRadius: 4,
// offset: const Offset(0, 2),
// ),
// ],
// ),
// child: Row(
// crossAxisAlignment: CrossAxisAlignment.center,
// mainAxisSize: MainAxisSize.min,
// children: [
// _buildCameraButton("Main", 0),
// if (cameraCount > 1) const VerticalDivider(width: 16, thickness: 1),
// ...List.generate(cameraCount - 1, (index) {
// return _buildCameraButton("${index + 1}", index + 1);
// }),
// ],
// ),
// );
// }
Widget _buildCameraButton(String label, int index) {
bool isActive = _activeIndex == index;
return Flexible(child:TextButton(
onPressed: () async {
if (index == 0) {
await widget.viewer.setMainCamera();
} else {
Camera camera = widget.viewer.getCameraAt(index);
await widget.viewer.setActiveCamera(camera);
}
setState(() {
_activeIndex = index;
});
},
style: TextButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
minimumSize: Size.zero,
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
backgroundColor: isActive ? Colors.blue.withOpacity(0.1) : null,
),
child: Text(
label,
style: TextStyle(
fontSize: 10,
fontWeight: isActive ? FontWeight.bold : FontWeight.normal,
color: isActive ? Colors.blue : Colors.black87,
),
),
));
}
}
// Widget _buildCameraButton(String label, int index) {
// bool isActive = _activeIndex == index;
// return Flexible(child:TextButton(
// onPressed: () async {
// if (index == 0) {
// await widget.viewer.setMainCamera();
// } else {
// Camera camera = widget.viewer.getCameraAt(index);
// await widget.viewer.setActiveCamera(camera);
// }
// setState(() {
// _activeIndex = index;
// });
// },
// style: TextButton.styleFrom(
// padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
// minimumSize: Size.zero,
// tapTargetSize: MaterialTapTargetSize.shrinkWrap,
// backgroundColor: isActive ? Colors.blue.withOpacity(0.1) : null,
// ),
// child: Text(
// label,
// style: TextStyle(
// fontSize: 10,
// fontWeight: isActive ? FontWeight.bold : FontWeight.normal,
// color: isActive ? Colors.blue : Colors.black87,
// ),
// ),
// ));
// }
// }

View File

@@ -1,110 +1,110 @@
import 'package:animation_tools_dart/animation_tools_dart.dart';
import 'package:thermion_dart/thermion_dart.dart';
// import 'package:animation_tools_dart/animation_tools_dart.dart';
// import 'package:thermion_dart/thermion_dart.dart';
import 'package:flutter/material.dart';
import 'dart:math';
// import 'package:flutter/material.dart';
// import 'dart:math';
class ChildRenderableWidget extends StatelessWidget {
final ThermionViewer controller;
final ThermionEntity entity;
// class ChildRenderableWidget extends StatelessWidget {
// final ThermionViewer controller;
// final ThermionEntity entity;
const ChildRenderableWidget(
{super.key, required this.controller, required this.entity});
// const ChildRenderableWidget(
// {super.key, required this.controller, required this.entity});
Widget _childRenderable(ThermionEntity childEntity) {
var name = controller.getNameForEntity(childEntity) ?? "<none>";
var names = controller.getMorphTargetNames(entity, childEntity);
// Widget _childRenderable(ThermionEntity childEntity) {
// var name = controller.getNameForEntity(childEntity) ?? "<none>";
// var names = controller.getMorphTargetNames(entity, childEntity);
return FutureBuilder(
future: names,
builder: (_, morphTargetsSnapshot) {
if (!morphTargetsSnapshot.hasData) {
return Container();
}
var morphTargets = morphTargetsSnapshot.data!;
// return FutureBuilder(
// future: names,
// builder: (_, morphTargetsSnapshot) {
// if (!morphTargetsSnapshot.hasData) {
// return Container();
// }
// var morphTargets = morphTargetsSnapshot.data!;
final menuChildren = <Widget>[];
if (morphTargets.isEmpty) {
menuChildren.add(Text("None"));
} else {
for (int i = 0; i < 2; i++) {
var newWeights = List.filled(morphTargets.length, i.toDouble());
menuChildren.add(MenuItemButton(
child: Text("Set to $i"),
onPressed: () async {
try {
await controller!
.setMorphTargetWeights(childEntity, newWeights);
} catch (err, st) {
print("Error setting morph target weights");
print(err);
print(st);
}
}));
}
menuChildren.add(MenuItemButton(
child: Text("Animate all morph target from 0 to 1"),
onPressed: () async {
var morphData = MorphAnimationData(
List<List<double>>.generate(
120,
(i) => List<double>.filled(
morphTargets.length, i / 120)),
morphTargets);
await controller!.setMorphAnimationData(entity, morphData,
targetMeshNames: [name]);
}));
menuChildren.addAll(morphTargets.map((t) => Text(t)));
}
return SubmenuButton(child: Text(name), menuChildren: menuChildren);
});
}
// final menuChildren = <Widget>[];
// if (morphTargets.isEmpty) {
// menuChildren.add(Text("None"));
// } else {
// for (int i = 0; i < 2; i++) {
// var newWeights = List.filled(morphTargets.length, i.toDouble());
// menuChildren.add(MenuItemButton(
// child: Text("Set to $i"),
// onPressed: () async {
// try {
// await controller!
// .setMorphTargetWeights(childEntity, newWeights);
// } catch (err, st) {
// print("Error setting morph target weights");
// print(err);
// print(st);
// }
// }));
// }
// menuChildren.add(MenuItemButton(
// child: Text("Animate all morph target from 0 to 1"),
// onPressed: () async {
// var morphData = MorphAnimationData(
// List<List<double>>.generate(
// 120,
// (i) => List<double>.filled(
// morphTargets.length, i / 120)),
// morphTargets);
// await controller!.setMorphAnimationData(entity, morphData,
// targetMeshNames: [name]);
// }));
// menuChildren.addAll(morphTargets.map((t) => Text(t)));
// }
// return SubmenuButton(child: Text(name), menuChildren: menuChildren);
// });
// }
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: controller!.getChildEntities(entity, true),
builder: (ctx, snapshot) {
if (!snapshot.hasData) {
return Container();
}
// @override
// Widget build(BuildContext context) {
// return FutureBuilder(
// future: controller!.getChildEntities(entity, true),
// builder: (ctx, snapshot) {
// if (!snapshot.hasData) {
// return Container();
// }
var children = snapshot.data!;
return SubmenuButton(
child: Text("Renderable entities"),
menuChildren: <Widget>[
MenuItemButton(
child: Text("Set children transforms to identity"),
onPressed: () async {
var childEntities =
await controller.getChildEntities(entity, true);
for (final child in childEntities) {
await controller.setTransform(
child, Matrix4.identity());
}
}),
MenuItemButton(
child: Text("Set children transforms to 90/X"),
onPressed: () async {
var childEntities =
await controller.getChildEntities(entity, true);
for (final child in childEntities) {
await controller.setTransform(
child, Matrix4.rotationX(pi / 2));
}
}),
MenuItemButton(
child: Text("Set children transforms to 90/Y"),
onPressed: () async {
var childEntities =
await controller.getChildEntities(entity, true);
for (final child in childEntities) {
await controller.setTransform(
child, Matrix4.rotationY(pi / 2));
}
}),
] +
children.map(_childRenderable).toList());
});
}
}
// var children = snapshot.data!;
// return SubmenuButton(
// child: Text("Renderable entities"),
// menuChildren: <Widget>[
// MenuItemButton(
// child: Text("Set children transforms to identity"),
// onPressed: () async {
// var childEntities =
// await controller.getChildEntities(entity, true);
// for (final child in childEntities) {
// await controller.setTransform(
// child, Matrix4.identity());
// }
// }),
// MenuItemButton(
// child: Text("Set children transforms to 90/X"),
// onPressed: () async {
// var childEntities =
// await controller.getChildEntities(entity, true);
// for (final child in childEntities) {
// await controller.setTransform(
// child, Matrix4.rotationX(pi / 2));
// }
// }),
// MenuItemButton(
// child: Text("Set children transforms to 90/Y"),
// onPressed: () async {
// var childEntities =
// await controller.getChildEntities(entity, true);
// for (final child in childEntities) {
// await controller.setTransform(
// child, Matrix4.rotationY(pi / 2));
// }
// }),
// ] +
// children.map(_childRenderable).toList());
// });
// }
// }

View File

@@ -1,421 +1,421 @@
import 'dart:math';
// import 'dart:math';
import 'package:thermion_dart/thermion_dart.dart';
import 'package:animation_tools_dart/animation_tools_dart.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:vector_math/vector_math_64.dart';
// import 'package:thermion_dart/thermion_dart.dart';
// import 'package:animation_tools_dart/animation_tools_dart.dart';
// import 'package:flutter/material.dart';
// import 'package:flutter/widgets.dart';
// import 'package:vector_math/vector_math_64.dart';
class SkeletonMenuItemWidget extends StatelessWidget {
final ThermionViewer controller;
final ThermionEntity entity;
// class SkeletonMenuItemWidget extends StatelessWidget {
// final ThermionViewer controller;
// final ThermionEntity entity;
const SkeletonMenuItemWidget(
{super.key, required this.controller, required this.entity});
// const SkeletonMenuItemWidget(
// {super.key, required this.controller, required this.entity});
void _addBoneAnimation(String bone) async {
await controller.addAnimationComponent(entity);
var numFrames = 120;
var animationData = List<List<BoneAnimationFrame>>.generate(
numFrames,
(frameNum) => [
(
rotation: Quaternion.axisAngle(
Vector3(1, 0, 0), (frameNum / 90) * 2 * pi),
translation: Vector3.zero()
)
]);
var animation =
BoneAnimationData([bone], animationData, space: Space.ParentWorldRotation);
await controller.addAnimationComponent(entity);
await controller.addBoneAnimation(entity, animation);
}
// void _addBoneAnimation(String bone) async {
// await controller.addAnimationComponent(entity);
// var numFrames = 120;
// var animationData = List<List<BoneAnimationFrame>>.generate(
// numFrames,
// (frameNum) => [
// (
// rotation: Quaternion.axisAngle(
// Vector3(1, 0, 0), (frameNum / 90) * 2 * pi),
// translation: Vector3.zero()
// )
// ]);
// var animation =
// BoneAnimationData([bone], animationData, space: Space.ParentWorldRotation);
// await controller.addAnimationComponent(entity);
// await controller.addBoneAnimation(entity, animation);
// }
@override
Widget build(BuildContext context) {
var boneNames = controller.getBoneNames(entity);
// @override
// Widget build(BuildContext context) {
// var boneNames = controller.getBoneNames(entity);
return FutureBuilder(
future: boneNames,
builder: (_, boneNamesSnapshot) {
if (!boneNamesSnapshot.hasData) {
return Container();
}
var boneNames = boneNamesSnapshot.data!;
if (boneNames.isEmpty) {
return Text("No bones");
}
// return FutureBuilder(
// future: boneNames,
// builder: (_, boneNamesSnapshot) {
// if (!boneNamesSnapshot.hasData) {
// return Container();
// }
// var boneNames = boneNamesSnapshot.data!;
// if (boneNames.isEmpty) {
// return Text("No bones");
// }
return SubmenuButton(
menuChildren: <Widget>[
MenuItemButton(
onPressed: () async {
await controller.resetBones(entity);
},
child: Text("Reset")),
MenuItemButton(
onPressed: () async {
await controller.resetBones(entity);
// return SubmenuButton(
// menuChildren: <Widget>[
// MenuItemButton(
// onPressed: () async {
// await controller.resetBones(entity);
// },
// child: Text("Reset")),
// MenuItemButton(
// onPressed: () async {
// await controller.resetBones(entity);
var bone = await controller.getBone(entity, 1);
var frames = <List<BoneAnimationFrame>>[];
for (int i = 0; i < 60; i++) {
var frame = <BoneAnimationFrame>[];
frame.add((
rotation:
Quaternion.axisAngle(
Vector3(1, 0, 0), i/60 * pi/4) *
(Quaternion.axisAngle(
Vector3(0, 0, 1), i/60*-pi/4)
*
Quaternion.axisAngle(
Vector3(0, 1, 0), i/60 * pi/4) ),
translation: Vector3.zero()
));
frames.add(frame);
}
// var bone = await controller.getBone(entity, 1);
// var frames = <List<BoneAnimationFrame>>[];
// for (int i = 0; i < 60; i++) {
// var frame = <BoneAnimationFrame>[];
// frame.add((
// rotation:
// Quaternion.axisAngle(
// Vector3(1, 0, 0), i/60 * pi/4) *
// (Quaternion.axisAngle(
// Vector3(0, 0, 1), i/60*-pi/4)
// *
// Quaternion.axisAngle(
// Vector3(0, 1, 0), i/60 * pi/4) ),
// translation: Vector3.zero()
// ));
// frames.add(frame);
// }
var animation = BoneAnimationData(["Bone.002"], frames,
space: Space.ParentWorldRotation);
await controller.addAnimationComponent(entity);
await controller.addBoneAnimation(entity, animation);
},
child: Text("Test animation (parent space)")),
MenuItemButton(
onPressed: () async {
await controller.resetBones(entity);
// var animation = BoneAnimationData(["Bone.002"], frames,
// space: Space.ParentWorldRotation);
// await controller.addAnimationComponent(entity);
// await controller.addBoneAnimation(entity, animation);
// },
// child: Text("Test animation (parent space)")),
// MenuItemButton(
// onPressed: () async {
// await controller.resetBones(entity);
var bone = await controller.getBone(entity, 1);
// var bone = await controller.getBone(entity, 1);
var frames = <List<BoneAnimationFrame>>[];
for (int i = 0; i < 60; i++) {
var frame = <BoneAnimationFrame>[];
frame.add((
rotation: Quaternion.axisAngle(
Vector3(0, 0, 1), (i / 60) * pi / 2),
translation: Vector3.zero()
));
frames.add(frame);
}
var animation = BoneAnimationData(
["Bone.001"], frames,
space: Space.Bone);
await controller.addAnimationComponent(entity);
await controller.addBoneAnimation(entity, animation);
},
child: Text("Test animation (bone space)")),
MenuItemButton(
onPressed: () async {
var frames = <List<BoneAnimationFrame>>[];
for (int i = 0; i < 60; i++) {
var frame = <BoneAnimationFrame>[];
frame.add((
rotation: Quaternion.axisAngle(
Vector3(0, 0, 1), (i / 60) * pi / 2),
translation: Vector3.zero()
));
frames.add(frame);
}
var animation = BoneAnimationData(
["Bone.001"], frames,
space: Space.ParentWorldRotation);
await controller.addAnimationComponent(entity);
await controller.addBoneAnimation(entity, animation);
},
child: Text("Test animation 2")),
MenuItemButton(
onPressed: () async {
var frames = <List<BoneAnimationFrame>>[];
for (int i = 0; i < 60; i++) {
var frame = <BoneAnimationFrame>[];
frame.add((
rotation: Quaternion.axisAngle(
Vector3(0, 0, 1), (i / 60) * pi / 2),
translation: Vector3.zero()
));
frames.add(frame);
}
var animation = BoneAnimationData(
["Bone.002"], frames,
space: Space.ParentWorldRotation);
await controller.addAnimationComponent(entity);
await controller.addBoneAnimation(entity, animation);
},
child: Text("Test animation 3"))
] +
boneNames
.map((name) {
var boneIndex = boneNames.indexOf(name);
return SubmenuButton(child: Text(name), menuChildren: [
MenuItemButton(
child: Text("Print bone transforms "),
onPressed: () async {
var boneEntity =
await controller.getBone(entity, boneIndex);
var localTransform = await controller
.getLocalTransform(boneEntity);
var worldTransform = await controller
.getWorldTransform(boneEntity);
var inverseWorldTransform = Matrix4.identity()
..copyInverse(worldTransform);
print("Local $localTransform");
print("World $worldTransform");
print("World inverse $inverseWorldTransform");
}),
MenuItemButton(
child: Text("Set bone transform to identity"),
onPressed: () async {
var boneEntity =
await controller.getBone(entity, boneIndex);
var localTransform = Matrix4.identity();
await controller.setTransform(
boneEntity, localTransform);
await controller.updateBoneMatrices(entity);
}),
MenuItemButton(
child: Text(
"Set bone transform to 90/X (parent space)"),
onPressed: () async {
var boneEntity =
await controller.getBone(entity, boneIndex);
var localTransform = Matrix4.rotationX(pi / 2);
await controller.setTransform(
boneEntity, localTransform);
await controller.updateBoneMatrices(entity);
}),
MenuItemButton(
child: Text(
"Set bone transform to 90/X (pose space)"),
onPressed: () async {
var boneEntity =
await controller.getBone(entity, boneIndex);
var localTransform = await controller
.getLocalTransform(boneEntity);
localTransform =
localTransform * Matrix4.rotationX(pi / 2);
await controller.setTransform(
boneEntity, localTransform);
await controller.updateBoneMatrices(entity);
}),
MenuItemButton(
child: Text("Set bone transform to 90/X"),
onPressed: () async {
var boneEntity =
await controller.getBone(entity, boneIndex);
var localTransform = Matrix4.rotationX(pi / 2);
await controller.setTransform(
boneEntity, localTransform);
await controller.updateBoneMatrices(entity);
}),
MenuItemButton(
child: Text("Set bone transform to 0,-1,0"),
onPressed: () async {
var boneEntity =
await controller.getBone(entity, boneIndex);
var localTransform =
Matrix4.translation(Vector3(0, -1, 0));
await controller.setTransform(
boneEntity, localTransform);
await controller.updateBoneMatrices(entity);
}),
MenuItemButton(
child: Text(
"Set bone matrices/transform to identity"),
onPressed: () async {
var boneEntity = await controller.getBone(
entity, boneNames.indexOf(name));
await controller.setTransform(
boneEntity, Matrix4.identity());
var childEntities = await controller
.getChildEntities(entity, true);
for (final child in childEntities) {
await controller.setBoneTransform(
child,
boneNames.indexOf(name),
Matrix4.identity());
}
}),
SubmenuButton(
child: Text("Set bone matrices to"),
menuChildren: [
MenuItemButton(
child: Text("Identity"),
onPressed: () async {
await controller
.removeAnimationComponent(entity);
for (var child in await controller
.getChildEntities(entity, true)) {
print(
"Setting transform for ${await controller.getNameForEntity(child)}");
await controller.setBoneTransform(
child,
boneNames.indexOf(name),
Matrix4.identity());
}
}),
SubmenuButton(
child: Text("Global"),
menuChildren: ["90/X", "90/Y"]
.map((rot) => MenuItemButton(
onPressed: () async {
var transform = rot == "90/X"
? Matrix4.rotationX(pi / 2)
: Matrix4.rotationY(pi / 2);
await controller
.removeAnimationComponent(
entity);
// var frames = <List<BoneAnimationFrame>>[];
// for (int i = 0; i < 60; i++) {
// var frame = <BoneAnimationFrame>[];
// frame.add((
// rotation: Quaternion.axisAngle(
// Vector3(0, 0, 1), (i / 60) * pi / 2),
// translation: Vector3.zero()
// ));
// frames.add(frame);
// }
// var animation = BoneAnimationData(
// ["Bone.001"], frames,
// space: Space.Bone);
// await controller.addAnimationComponent(entity);
// await controller.addBoneAnimation(entity, animation);
// },
// child: Text("Test animation (bone space)")),
// MenuItemButton(
// onPressed: () async {
// var frames = <List<BoneAnimationFrame>>[];
// for (int i = 0; i < 60; i++) {
// var frame = <BoneAnimationFrame>[];
// frame.add((
// rotation: Quaternion.axisAngle(
// Vector3(0, 0, 1), (i / 60) * pi / 2),
// translation: Vector3.zero()
// ));
// frames.add(frame);
// }
// var animation = BoneAnimationData(
// ["Bone.001"], frames,
// space: Space.ParentWorldRotation);
// await controller.addAnimationComponent(entity);
// await controller.addBoneAnimation(entity, animation);
// },
// child: Text("Test animation 2")),
// MenuItemButton(
// onPressed: () async {
// var frames = <List<BoneAnimationFrame>>[];
// for (int i = 0; i < 60; i++) {
// var frame = <BoneAnimationFrame>[];
// frame.add((
// rotation: Quaternion.axisAngle(
// Vector3(0, 0, 1), (i / 60) * pi / 2),
// translation: Vector3.zero()
// ));
// frames.add(frame);
// }
// var animation = BoneAnimationData(
// ["Bone.002"], frames,
// space: Space.ParentWorldRotation);
// await controller.addAnimationComponent(entity);
// await controller.addBoneAnimation(entity, animation);
// },
// child: Text("Test animation 3"))
// ] +
// boneNames
// .map((name) {
// var boneIndex = boneNames.indexOf(name);
// return SubmenuButton(child: Text(name), menuChildren: [
// MenuItemButton(
// child: Text("Print bone transforms "),
// onPressed: () async {
// var boneEntity =
// await controller.getBone(entity, boneIndex);
// var localTransform = await controller
// .getLocalTransform(boneEntity);
// var worldTransform = await controller
// .getWorldTransform(boneEntity);
// var inverseWorldTransform = Matrix4.identity()
// ..copyInverse(worldTransform);
// print("Local $localTransform");
// print("World $worldTransform");
// print("World inverse $inverseWorldTransform");
// }),
// MenuItemButton(
// child: Text("Set bone transform to identity"),
// onPressed: () async {
// var boneEntity =
// await controller.getBone(entity, boneIndex);
// var localTransform = Matrix4.identity();
// await controller.setTransform(
// boneEntity, localTransform);
// await controller.updateBoneMatrices(entity);
// }),
// MenuItemButton(
// child: Text(
// "Set bone transform to 90/X (parent space)"),
// onPressed: () async {
// var boneEntity =
// await controller.getBone(entity, boneIndex);
// var localTransform = Matrix4.rotationX(pi / 2);
// await controller.setTransform(
// boneEntity, localTransform);
// await controller.updateBoneMatrices(entity);
// }),
// MenuItemButton(
// child: Text(
// "Set bone transform to 90/X (pose space)"),
// onPressed: () async {
// var boneEntity =
// await controller.getBone(entity, boneIndex);
// var localTransform = await controller
// .getLocalTransform(boneEntity);
// localTransform =
// localTransform * Matrix4.rotationX(pi / 2);
// await controller.setTransform(
// boneEntity, localTransform);
// await controller.updateBoneMatrices(entity);
// }),
// MenuItemButton(
// child: Text("Set bone transform to 90/X"),
// onPressed: () async {
// var boneEntity =
// await controller.getBone(entity, boneIndex);
// var localTransform = Matrix4.rotationX(pi / 2);
// await controller.setTransform(
// boneEntity, localTransform);
// await controller.updateBoneMatrices(entity);
// }),
// MenuItemButton(
// child: Text("Set bone transform to 0,-1,0"),
// onPressed: () async {
// var boneEntity =
// await controller.getBone(entity, boneIndex);
// var localTransform =
// Matrix4.translation(Vector3(0, -1, 0));
// await controller.setTransform(
// boneEntity, localTransform);
// await controller.updateBoneMatrices(entity);
// }),
// MenuItemButton(
// child: Text(
// "Set bone matrices/transform to identity"),
// onPressed: () async {
// var boneEntity = await controller.getBone(
// entity, boneNames.indexOf(name));
// await controller.setTransform(
// boneEntity, Matrix4.identity());
// var childEntities = await controller
// .getChildEntities(entity, true);
// for (final child in childEntities) {
// await controller.setBoneTransform(
// child,
// boneNames.indexOf(name),
// Matrix4.identity());
// }
// }),
// SubmenuButton(
// child: Text("Set bone matrices to"),
// menuChildren: [
// MenuItemButton(
// child: Text("Identity"),
// onPressed: () async {
// await controller
// .removeAnimationComponent(entity);
// for (var child in await controller
// .getChildEntities(entity, true)) {
// print(
// "Setting transform for ${await controller.getNameForEntity(child)}");
// await controller.setBoneTransform(
// child,
// boneNames.indexOf(name),
// Matrix4.identity());
// }
// }),
// SubmenuButton(
// child: Text("Global"),
// menuChildren: ["90/X", "90/Y"]
// .map((rot) => MenuItemButton(
// onPressed: () async {
// var transform = rot == "90/X"
// ? Matrix4.rotationX(pi / 2)
// : Matrix4.rotationY(pi / 2);
// await controller
// .removeAnimationComponent(
// entity);
var index =
boneNames.indexOf(name);
var childEntities =
await controller
.getChildEntities(
entity, true);
// var index =
// boneNames.indexOf(name);
// var childEntities =
// await controller
// .getChildEntities(
// entity, true);
for (var child in childEntities) {
print(
"Setting transform for ${await controller.getNameForEntity(child)} / bone $name (index $index)");
await controller
.setBoneTransform(child,
index, transform);
}
},
child: Text(rot)))
.toList()),
SubmenuButton(
child: Text("Bone"),
menuChildren: ["90/X", "90/Y", "90/Z"]
.map((rot) => MenuItemButton(
onPressed: () async {
await controller
.removeAnimationComponent(
entity);
var index =
boneNames.indexOf(name);
var boneEntity = await controller
.getBone(entity, index);
var rotation = rot == "90/X"
? Matrix4.rotationX(pi / 2)
: rot == "90/Y"
? Matrix4.rotationY(
pi / 2)
: Matrix4.rotationZ(
pi / 2);
// for (var child in childEntities) {
// print(
// "Setting transform for ${await controller.getNameForEntity(child)} / bone $name (index $index)");
// await controller
// .setBoneTransform(child,
// index, transform);
// }
// },
// child: Text(rot)))
// .toList()),
// SubmenuButton(
// child: Text("Bone"),
// menuChildren: ["90/X", "90/Y", "90/Z"]
// .map((rot) => MenuItemButton(
// onPressed: () async {
// await controller
// .removeAnimationComponent(
// entity);
// var index =
// boneNames.indexOf(name);
// var boneEntity = await controller
// .getBone(entity, index);
// var rotation = rot == "90/X"
// ? Matrix4.rotationX(pi / 2)
// : rot == "90/Y"
// ? Matrix4.rotationY(
// pi / 2)
// : Matrix4.rotationZ(
// pi / 2);
var inverseBindMatrix =
await controller
.getInverseBindMatrix(
entity, index);
var bindMatrix =
Matrix4.identity();
bindMatrix.copyInverse(
inverseBindMatrix);
var childEntities =
await controller
.getChildEntities(
entity, true);
// var inverseBindMatrix =
// await controller
// .getInverseBindMatrix(
// entity, index);
// var bindMatrix =
// Matrix4.identity();
// bindMatrix.copyInverse(
// inverseBindMatrix);
// var childEntities =
// await controller
// .getChildEntities(
// entity, true);
for (var child in childEntities) {
var childGlobalTransform =
await controller
.getWorldTransform(
child);
var inverseGlobalTransform =
Matrix4.identity();
inverseGlobalTransform
.copyInverse(
childGlobalTransform);
var globalBoneTransform =
childGlobalTransform *
bindMatrix;
// for (var child in childEntities) {
// var childGlobalTransform =
// await controller
// .getWorldTransform(
// child);
// var inverseGlobalTransform =
// Matrix4.identity();
// inverseGlobalTransform
// .copyInverse(
// childGlobalTransform);
// var globalBoneTransform =
// childGlobalTransform *
// bindMatrix;
var transform =
(inverseGlobalTransform *
(globalBoneTransform *
rotation)) *
inverseBindMatrix;
await controller
.setBoneTransform(child,
index, transform);
}
},
child: Text(rot)))
.toList()),
]),
MenuItemButton(
onPressed: () => _addBoneAnimation(name),
child: Text(
"Test animation (90 degreees around pose Y)")),
]);
})
.cast<Widget>()
.toList(),
child: Text("Skeleton"));
});
}
}
// var transform =
// (inverseGlobalTransform *
// (globalBoneTransform *
// rotation)) *
// inverseBindMatrix;
// await controller
// .setBoneTransform(child,
// index, transform);
// }
// },
// child: Text(rot)))
// .toList()),
// ]),
// MenuItemButton(
// onPressed: () => _addBoneAnimation(name),
// child: Text(
// "Test animation (90 degreees around pose Y)")),
// ]);
// })
// .cast<Widget>()
// .toList(),
// child: Text("Skeleton"));
// });
// }
// }
// MenuItemButton(
// onPressed: () async {
// var frames = <List<BoneAnimationFrame>>[];
// for (int i = 0; i < 60; i++) {
// var frame = <BoneAnimationFrame>[];
// frame.add((
// rotation: Quaternion.axisAngle(
// Vector3(0, 0, 1), (i / 60) * pi / 2),
// translation: Vector3.zero()
// ));
// frame.add((
// rotation: Quaternion.identity(),
// translation: Vector3.zero()
// ));
// frame.add((
// rotation: Quaternion.identity(),
// translation: Vector3.zero()
// ));
// frames.add(frame);
// }
// for (int i = 0; i < 60; i++) {
// var frame = <BoneAnimationFrame>[];
// frame.add((
// rotation: Quaternion.axisAngle(
// Vector3(0, 0, 1), pi / 2),
// translation: Vector3.zero()
// ));
// frame.add((
// rotation: Quaternion.axisAngle(
// Vector3(1, 0, 0), i / 60 * (-pi / 2)),
// translation: Vector3.zero()
// ));
// frame.add((
// rotation: Quaternion.identity(),
// translation: Vector3.zero()
// ));
// frames.add(frame);
// }
// for (int i = 0; i < 60; i++) {
// var frame = <BoneAnimationFrame>[];
// frame.add((
// rotation: Quaternion.axisAngle(
// Vector3(0, 0, 1), pi / 2),
// translation: Vector3.zero()
// ));
// frame.add((
// rotation: Quaternion.axisAngle(
// Vector3(1, 0, 0), (-pi / 2)),
// translation: Vector3.zero()
// ));
// frame.add((
// rotation: Quaternion.axisAngle(
// Vector3(1, 0, 0), i / 60 * (pi / 2)),
// translation: Vector3.zero()
// ));
// frames.add(frame);
// }
// // MenuItemButton(
// // onPressed: () async {
// // var frames = <List<BoneAnimationFrame>>[];
// // for (int i = 0; i < 60; i++) {
// // var frame = <BoneAnimationFrame>[];
// // frame.add((
// // rotation: Quaternion.axisAngle(
// // Vector3(0, 0, 1), (i / 60) * pi / 2),
// // translation: Vector3.zero()
// // ));
// // frame.add((
// // rotation: Quaternion.identity(),
// // translation: Vector3.zero()
// // ));
// // frame.add((
// // rotation: Quaternion.identity(),
// // translation: Vector3.zero()
// // ));
// // frames.add(frame);
// // }
// // for (int i = 0; i < 60; i++) {
// // var frame = <BoneAnimationFrame>[];
// // frame.add((
// // rotation: Quaternion.axisAngle(
// // Vector3(0, 0, 1), pi / 2),
// // translation: Vector3.zero()
// // ));
// // frame.add((
// // rotation: Quaternion.axisAngle(
// // Vector3(1, 0, 0), i / 60 * (-pi / 2)),
// // translation: Vector3.zero()
// // ));
// // frame.add((
// // rotation: Quaternion.identity(),
// // translation: Vector3.zero()
// // ));
// // frames.add(frame);
// // }
// // for (int i = 0; i < 60; i++) {
// // var frame = <BoneAnimationFrame>[];
// // frame.add((
// // rotation: Quaternion.axisAngle(
// // Vector3(0, 0, 1), pi / 2),
// // translation: Vector3.zero()
// // ));
// // frame.add((
// // rotation: Quaternion.axisAngle(
// // Vector3(1, 0, 0), (-pi / 2)),
// // translation: Vector3.zero()
// // ));
// // frame.add((
// // rotation: Quaternion.axisAngle(
// // Vector3(1, 0, 0), i / 60 * (pi / 2)),
// // translation: Vector3.zero()
// // ));
// // frames.add(frame);
// // }
// var animation = BoneAnimationData(
// ["Bone", "Bone.001", "Bone.002"], frames);
// await controller.addAnimationComponent(entity);
// await controller.addBoneAnimation(entity, animation);
// },
// child: Text("Test animation (pose space)")),
// // var animation = BoneAnimationData(
// // ["Bone", "Bone.001", "Bone.002"], frames);
// // await controller.addAnimationComponent(entity);
// // await controller.addBoneAnimation(entity, animation);
// // },
// // child: Text("Test animation (pose space)")),

View File

@@ -174,6 +174,7 @@ class _ThermionTextureWidgetState extends State<ThermionTextureWidget> {
}
WidgetsBinding.instance.scheduleFrameCallback((d) async {
if (!mounted) {
return;
}
@@ -241,7 +242,7 @@ class _ThermionTextureWidgetState extends State<ThermionTextureWidget> {
_logger.info(
"Resized texture to dimensions ${_texture!.width}x${_texture!.height} (pixel ratio : $dpr)");
await widget.viewer.view.setViewport(_texture!.width, _texture!.height);
await widget.viewer.setViewport(_texture!.width, _texture!.height);
await widget.onResize?.call(
Size(_texture!.width.toDouble(), _texture!.height.toDouble()),