add skeleton menu widget for debugging
This commit is contained in:
@@ -0,0 +1,422 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:dart_filament/dart_filament.dart';
|
||||||
|
import 'package:dart_filament/dart_filament/abstract_filament_viewer.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 AbstractFilamentViewer controller;
|
||||||
|
final FilamentEntity 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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 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 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 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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)")),
|
||||||
Reference in New Issue
Block a user