This commit is contained in:
Nick Fisher
2024-03-01 22:48:39 +08:00
parent 9295059885
commit 6c6bcfe7a4
30 changed files with 1432 additions and 1052 deletions

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ab0cada556723be0d138d7b1cadb5e315a273524db0468e0c4255d8d2b0c1c2d
size 1222992
oid sha256:983af4eb524f24b17bf081ae40a7217b60415122ab02cbf02c0186fbf069d52a
size 1251408

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b728c8fe0ce9eb06290dc37034404a952df8ea360b014b76c82fe8b9d695e85a
size 113124
oid sha256:715793a3cf36ccf5608c347b961d0f2549e54edb4ba5227a5a008dc1d3445e83
size 116948

View File

@@ -73,8 +73,6 @@ class ExampleWidgetState extends State<ExampleWidget> {
static FilamentEntity? flightHelmet;
static FilamentEntity? buster;
static List<String>? animations;
static FilamentEntity? directionalLight;
static bool loop = false;
@@ -90,8 +88,6 @@ class ExampleWidgetState extends State<ExampleWidget> {
setState(() {
_filamentController = FilamentControllerFFI();
});
await Future.delayed(const Duration(milliseconds: 100));
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
await _filamentController!.createViewer();
_createEntityLoadListener();
@@ -101,8 +97,7 @@ class ExampleWidgetState extends State<ExampleWidget> {
await _filamentController!.setRendering(true);
assets.add(
await _filamentController!.loadGlb("assets/shapes/shapes.glb"));
ExampleWidgetState.animations =
await _filamentController!.getAnimationNames(assets.first);
await _filamentController!
.setCameraManipulatorOptions(zoomSpeed: 1.0);
@@ -123,7 +118,6 @@ class ExampleWidgetState extends State<ExampleWidget> {
_listener =
_filamentController!.onLoad.listen((FilamentEntity entity) async {
assets.add(entity);
animations = await _filamentController!.getAnimationNames(entity);
if (mounted) {
setState(() {});
}
@@ -136,37 +130,65 @@ class ExampleWidgetState extends State<ExampleWidget> {
final _sharedFocusNode = FocusNode();
Widget _assetEntry(FilamentEntity entity) {
return Row(children: [
Text("Asset ${entity}"),
IconButton(
tooltip: "Transform to unit cube",
onPressed: () async {
await _filamentController!.transformToUnitCube(entity);
},
icon: const Icon(Icons.settings_overscan_outlined)),
IconButton(
onPressed: () async {
_transformController?.dispose();
if (_controlled == entity) {
_controlled = null;
} else {
_controlled = entity;
_transformController?.dispose();
_transformController =
EntityTransformController(_filamentController!, entity);
}
setState(() {});
},
icon: Icon(Icons.control_camera,
color: _controlled == entity ? Colors.green : Colors.black)),
IconButton(
onPressed: () async {
await _filamentController!.removeEntity(entity);
assets.remove(entity);
setState(() {});
},
icon: const Icon(Icons.cancel_sharp)),
]);
return FutureBuilder(
future: _filamentController!.getAnimationNames(entity),
builder: (_, animations) {
if (animations.data == null) {
return Container();
}
return Row(children: [
Text("Asset ${entity}"),
IconButton(
iconSize: 14,
tooltip: "Transform to unit cube",
onPressed: () async {
await _filamentController!.transformToUnitCube(entity);
},
icon: const Icon(Icons.settings_overscan_outlined)),
IconButton(
iconSize: 14,
tooltip: "Attach mouse control",
onPressed: () async {
_transformController?.dispose();
if (_controlled == entity) {
_controlled = null;
} else {
_controlled = entity;
_transformController?.dispose();
_transformController =
EntityTransformController(_filamentController!, entity);
}
setState(() {});
},
icon: Icon(Icons.control_camera,
color:
_controlled == entity ? Colors.green : Colors.black)),
IconButton(
iconSize: 14,
tooltip: "Remove",
onPressed: () async {
await _filamentController!.removeEntity(entity);
assets.remove(entity);
setState(() {});
},
icon: const Icon(Icons.cancel_sharp)),
if (animations.data!.isNotEmpty)
PopupMenuButton(
tooltip: "Animations",
itemBuilder: (_) => animations.data!
.map((a) => PopupMenuItem<String>(
value: a,
child: Text(a),
))
.toList(),
onSelected: (value) async {
print("Playing animation $value");
await _filamentController!
.playAnimation(entity, animations.data!.indexOf(value!));
},
)
]);
});
}
@override
@@ -222,8 +244,9 @@ class ExampleWidgetState extends State<ExampleWidget> {
),
GestureDetector(
onTap: () async {
await _filamentController!
.loadGlb('assets/shapes/shapes.glb');
await _filamentController!.loadGlb(
'assets/shapes/shapes.glb',
numInstances: 10);
},
child: Container(
color: Colors.transparent,

View File

@@ -43,16 +43,25 @@ class _AssetSubmenuState extends State<AssetSubmenu> {
child: const Text('Find Cylinder entity by name')),
MenuItemButton(
onPressed: () async {
Timer.periodic(const Duration(milliseconds: 50), (_) async {
await widget.controller.setBoneTransform(
ExampleWidgetState.assets.last,
"Cylinder",
"Bone",
Matrix4.rotationX(pi / 2));
});
await widget.controller.addBoneAnimation(
ExampleWidgetState.assets.last,
BoneAnimationData([
"Bone"
], [
"Cylinder"
], [
[v.Quaternion.axisAngle(v.Vector3(1, 1, 1), pi / 2)]
], [
[v.Vector3.zero()]
], 16));
},
child:
const Text('Set bone transform for Cylinder (pi/2 rotation X)')),
MenuItemButton(
onPressed: () async {
await widget.controller.resetBones(ExampleWidgetState.assets.last);
},
child: const Text('Reset bones for Cylinder')),
MenuItemButton(
onPressed: () async {
await widget.controller.addBoneAnimation(
@@ -72,9 +81,11 @@ class _AssetSubmenuState extends State<AssetSubmenu> {
},
child: const Text('Set bone transform animation for Cylinder')),
MenuItemButton(
closeOnActivate: false,
onPressed: () async {
var names = await widget.controller.getMorphTargetNames(
ExampleWidgetState.assets.last, "Cylinder");
print("NAMES : $names");
await showDialog(
context: context,
builder: (ctx) {
@@ -134,26 +145,6 @@ class _AssetSubmenuState extends State<AssetSubmenu> {
child: Text(
"Toggle animation looping ${ExampleWidgetState.loop ? "OFF" : "ON"}"))
];
if (ExampleWidgetState.animations != null) {
children.addAll(ExampleWidgetState.animations!.map((a) => MenuItemButton(
onPressed: () {
widget.controller.playAnimation(ExampleWidgetState.assets.last,
ExampleWidgetState.animations!.indexOf(a),
replaceActive: true,
crossfade: 0.5,
loop: ExampleWidgetState.loop);
},
child: Text(
"play animation ${ExampleWidgetState.animations!.indexOf(a)} (replace/fade)"))));
children.addAll(ExampleWidgetState.animations!.map((a) => MenuItemButton(
onPressed: () {
widget.controller.playAnimation(ExampleWidgetState.assets.last,
ExampleWidgetState.animations!.indexOf(a),
replaceActive: false, loop: ExampleWidgetState.loop);
},
child: Text(
"Play animation ${ExampleWidgetState.animations!.indexOf(a)} (noreplace)"))));
}
return SubmenuButton(menuChildren: children, child: const Text("Shapes"));
}
@@ -213,8 +204,6 @@ class _AssetSubmenuState extends State<AssetSubmenu> {
force: true);
await widget.controller
.playAnimation(ExampleWidgetState.buster!, 0, loop: true);
ExampleWidgetState.animations = await widget.controller
.getAnimationNames(ExampleWidgetState.assets.last);
} else {
await widget.controller
.removeEntity(ExampleWidgetState.buster!);
@@ -242,7 +231,7 @@ class _AssetSubmenuState extends State<AssetSubmenu> {
: 'Remove flight helmet')),
MenuItemButton(
onPressed: () {
widget.controller.setBackgroundColor(const Color(0xFF73C9FA));
widget.controller.setBackgroundColor(const Color(0xAA73C9FA));
},
child: const Text("Set background color")),
MenuItemButton(

View File

@@ -2,7 +2,7 @@ import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:vector_math/vector_math_64.dart' as v;
import 'package:flutter_filament/filament_controller.dart';
import 'package:flutter_filament_example/main.dart';
@@ -99,7 +99,8 @@ class _CameraSubmenuState extends State<CameraSubmenu> {
MenuItemButton(
onPressed: () async {
widget.controller.setCameraPosition(0.0, 0.0, 0.0);
widget.controller.setCameraRotation(0, 0.0, 1.0, 0.0);
widget.controller.setCameraRotation(
v.Quaternion.axisAngle(v.Vector3(0, 0.0, 1.0), 0.0));
},
child: const Text('Move to 0,0,0, facing towards 0,0,-1'),
),
@@ -119,7 +120,8 @@ class _CameraSubmenuState extends State<CameraSubmenu> {
),
MenuItemButton(
onPressed: () {
widget.controller.setCameraRotation(pi / 4, 0.0, 1.0, 0.0);
widget.controller.setCameraRotation(
v.Quaternion.axisAngle(v.Vector3(0, 1, 0), pi / 4));
},
child: const Text("Rotate camera 45 degrees around y axis"),
),

View File

@@ -9,11 +9,8 @@ class PickerResultWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StreamBuilder(
stream: controller.pickResult.map((FilamentEntity? entityId) {
if (entityId == null) {
return null;
}
return controller.getNameForEntity(entityId);
stream: controller.pickResult.map((result) {
return controller.getNameForEntity(result.entity);
}),
builder: (ctx, snapshot) => snapshot.data == null
? Container()