update example project
This commit is contained in:
@@ -14,7 +14,7 @@ const loadDefaultScene = bool.hasEnvironment('--load-default-scene');
|
||||
|
||||
void main() async {
|
||||
print(loadDefaultScene);
|
||||
runApp(MyApp());
|
||||
runApp(const MyApp());
|
||||
}
|
||||
|
||||
class MyApp extends StatefulWidget {
|
||||
@@ -63,12 +63,10 @@ class ExampleWidgetState extends State<ExampleWidget> {
|
||||
static double orbitSpeedX = 0.01;
|
||||
static double orbitSpeedY = 0.01;
|
||||
|
||||
static FilamentEntity? last;
|
||||
|
||||
static bool hasSkybox = false;
|
||||
static bool coneHidden = false;
|
||||
|
||||
static FilamentEntity? shapes;
|
||||
static final assets = <FilamentEntity>[];
|
||||
static FilamentEntity? flightHelmet;
|
||||
static FilamentEntity? buster;
|
||||
|
||||
@@ -90,16 +88,17 @@ class ExampleWidgetState extends State<ExampleWidget> {
|
||||
_filamentController = FilamentControllerFFI();
|
||||
});
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
|
||||
await _filamentController!.createViewer();
|
||||
await _filamentController!
|
||||
.loadSkybox("assets/default_env/default_env_skybox.ktx");
|
||||
|
||||
await _filamentController!.setRendering(true);
|
||||
shapes =
|
||||
await _filamentController!.loadGlb("assets/shapes/shapes.glb");
|
||||
ExampleWidgetState.animations = await _filamentController!
|
||||
.getAnimationNames(ExampleWidgetState.shapes!);
|
||||
assets.add(
|
||||
await _filamentController!.loadGlb("assets/shapes/shapes.glb"));
|
||||
ExampleWidgetState.animations =
|
||||
await _filamentController!.getAnimationNames(assets.first);
|
||||
hasSkybox = true;
|
||||
rendering = true;
|
||||
});
|
||||
@@ -113,6 +112,26 @@ class ExampleWidgetState extends State<ExampleWidget> {
|
||||
_listener.cancel();
|
||||
}
|
||||
|
||||
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 {
|
||||
await _filamentController!.removeAsset(entity);
|
||||
assets.remove(entity);
|
||||
setState(() {});
|
||||
},
|
||||
icon: const Icon(Icons.cancel_sharp))
|
||||
]);
|
||||
;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(children: [
|
||||
@@ -122,13 +141,33 @@ class ExampleWidgetState extends State<ExampleWidget> {
|
||||
padding: _viewportMargin,
|
||||
),
|
||||
),
|
||||
Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
Positioned(
|
||||
bottom: 80,
|
||||
left: 10,
|
||||
height: 200,
|
||||
width: 300,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.only(bottom: 30),
|
||||
padding: EdgeInsets.symmetric(horizontal: 30, vertical: 10),
|
||||
height: 100,
|
||||
color: Colors.white,
|
||||
child: Row(crossAxisAlignment: CrossAxisAlignment.end, children: [
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
color: Colors.white.withOpacity(0.25),
|
||||
),
|
||||
child: ListView(children: assets.map(_assetEntry).toList()))),
|
||||
Positioned(
|
||||
bottom: 10,
|
||||
left: 10,
|
||||
right: 10,
|
||||
height: 60,
|
||||
child: Container(
|
||||
height: 60,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
color: Colors.white.withOpacity(0.25),
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||
child:
|
||||
Row(crossAxisAlignment: CrossAxisAlignment.center, children: [
|
||||
ControllerMenu(
|
||||
controller: _filamentController,
|
||||
onControllerDestroyed: () {},
|
||||
@@ -136,9 +175,10 @@ class ExampleWidgetState extends State<ExampleWidget> {
|
||||
setState(() {
|
||||
_filamentController = controller;
|
||||
_listener = _filamentController!.onLoad
|
||||
.listen((FilamentEntity entity) {
|
||||
print("Set last to $entity");
|
||||
last = entity;
|
||||
.listen((FilamentEntity entity) async {
|
||||
assets.add(entity);
|
||||
animations = await _filamentController!
|
||||
.getAnimationNames(entity);
|
||||
if (mounted) {
|
||||
setState(() {});
|
||||
}
|
||||
@@ -150,6 +190,35 @@ class ExampleWidgetState extends State<ExampleWidget> {
|
||||
SceneMenu(
|
||||
controller: _filamentController,
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
await _filamentController!
|
||||
.loadGlb('assets/shapes/shapes.glb');
|
||||
},
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: const Text("shapes.glb"))),
|
||||
SizedBox(width: 5),
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
await _filamentController!.loadGlb('assets/1.glb');
|
||||
},
|
||||
child: Container(
|
||||
color: Colors.transparent, child: const Text("1.glb"))),
|
||||
SizedBox(width: 5),
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
await _filamentController!.loadGlb('assets/2.glb');
|
||||
},
|
||||
child: Container(
|
||||
color: Colors.transparent, child: const Text("2.glb"))),
|
||||
SizedBox(width: 5),
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
await _filamentController!.loadGlb('assets/3.glb');
|
||||
},
|
||||
child: Container(
|
||||
color: Colors.transparent, child: const Text("3.glb"))),
|
||||
Expanded(child: Container()),
|
||||
TextButton(
|
||||
child: const Text("Toggle viewport size"),
|
||||
|
||||
@@ -28,72 +28,35 @@ class _AssetSubmenuState extends State<AssetSubmenu> {
|
||||
var children = [
|
||||
MenuItemButton(
|
||||
onPressed: () async {
|
||||
if (ExampleWidgetState.shapes == null) {
|
||||
ExampleWidgetState.shapes =
|
||||
await widget.controller.loadGlb('assets/shapes/shapes.glb');
|
||||
ExampleWidgetState.animations = await widget.controller
|
||||
.getAnimationNames(ExampleWidgetState.shapes!);
|
||||
} else {
|
||||
await widget.controller.removeAsset(ExampleWidgetState.shapes!);
|
||||
ExampleWidgetState.shapes = null;
|
||||
ExampleWidgetState.animations = null;
|
||||
}
|
||||
Timer.periodic(Duration(milliseconds: 50), (_) async {
|
||||
await widget.controller.setBoneTransform(
|
||||
ExampleWidgetState.assets.last,
|
||||
"Cylinder",
|
||||
"Bone",
|
||||
Matrix4.rotationX(pi / 2));
|
||||
});
|
||||
},
|
||||
child: const Text('Load GLB')),
|
||||
MenuItemButton(
|
||||
onPressed: ExampleWidgetState.shapes != null
|
||||
? null
|
||||
: () async {
|
||||
if (ExampleWidgetState.shapes != null) {
|
||||
widget.controller.removeAsset(ExampleWidgetState.shapes!);
|
||||
}
|
||||
ExampleWidgetState.shapes = await widget.controller
|
||||
.loadGltf('assets/shapes/shapes.gltf', 'assets/shapes');
|
||||
},
|
||||
child: const Text('Load GLTF')),
|
||||
MenuItemButton(
|
||||
onPressed: ExampleWidgetState.shapes == null
|
||||
? null
|
||||
: () async {
|
||||
await widget.controller
|
||||
.transformToUnitCube(ExampleWidgetState.shapes!);
|
||||
},
|
||||
child: const Text('Transform to unit cube')),
|
||||
MenuItemButton(
|
||||
onPressed: ExampleWidgetState.shapes == null
|
||||
? null
|
||||
: () async {
|
||||
Timer.periodic(Duration(milliseconds: 50), (_) async {
|
||||
await widget.controller.setBoneTransform(
|
||||
ExampleWidgetState.shapes!,
|
||||
"Cylinder",
|
||||
"Bone",
|
||||
Matrix4.rotationX(pi / 2));
|
||||
});
|
||||
},
|
||||
child:
|
||||
const Text('Set bone transform for Cylinder (pi/2 rotation X)')),
|
||||
MenuItemButton(
|
||||
onPressed: ExampleWidgetState.shapes == null
|
||||
? null
|
||||
: () async {
|
||||
await widget.controller.addBoneAnimation(
|
||||
ExampleWidgetState.shapes!,
|
||||
BoneAnimationData(
|
||||
"Bone",
|
||||
["Cylinder"],
|
||||
List.generate(
|
||||
60,
|
||||
(idx) => v.Quaternion.axisAngle(
|
||||
v.Vector3(0, 0, 1), pi * 8 * (idx / 60))
|
||||
.normalized()),
|
||||
1000.0 / 60.0));
|
||||
},
|
||||
onPressed: () async {
|
||||
await widget.controller.addBoneAnimation(
|
||||
ExampleWidgetState.assets.last,
|
||||
BoneAnimationData(
|
||||
"Bone",
|
||||
["Cylinder"],
|
||||
List.generate(
|
||||
60,
|
||||
(idx) => v.Quaternion.axisAngle(
|
||||
v.Vector3(0, 0, 1), pi * 8 * (idx / 60))
|
||||
.normalized()),
|
||||
1000.0 / 60.0));
|
||||
},
|
||||
child: const Text('Set bone transform animation for Cylinder')),
|
||||
MenuItemButton(
|
||||
onPressed: () async {
|
||||
var names = await widget.controller
|
||||
.getMorphTargetNames(ExampleWidgetState.shapes!, "Cylinder");
|
||||
var names = await widget.controller.getMorphTargetNames(
|
||||
ExampleWidgetState.assets.last, "Cylinder");
|
||||
await showDialog(
|
||||
context: context,
|
||||
builder: (ctx) {
|
||||
@@ -108,28 +71,32 @@ class _AssetSubmenuState extends State<AssetSubmenu> {
|
||||
MenuItemButton(
|
||||
onPressed: () async {
|
||||
widget.controller.setMorphTargetWeights(
|
||||
ExampleWidgetState.shapes!, "Cylinder", List.filled(4, 1.0));
|
||||
ExampleWidgetState.assets.last,
|
||||
"Cylinder",
|
||||
List.filled(4, 1.0));
|
||||
},
|
||||
child: const Text("set Cylinder morph weights to 1")),
|
||||
MenuItemButton(
|
||||
onPressed: () async {
|
||||
widget.controller.setMorphTargetWeights(
|
||||
ExampleWidgetState.shapes!, "Cylinder", List.filled(4, 0.0));
|
||||
ExampleWidgetState.assets.last,
|
||||
"Cylinder",
|
||||
List.filled(4, 0.0));
|
||||
},
|
||||
child: const Text("Set Cylinder morph weights to 0")),
|
||||
MenuItemButton(
|
||||
onPressed: () async {
|
||||
widget.controller
|
||||
.setPosition(ExampleWidgetState.shapes!, 1.0, 1.0, -1.0);
|
||||
.setPosition(ExampleWidgetState.assets.last, 1.0, 1.0, -1.0);
|
||||
},
|
||||
child: const Text('Set position to 1, 1, -1'),
|
||||
),
|
||||
MenuItemButton(
|
||||
onPressed: () async {
|
||||
if (ExampleWidgetState.coneHidden) {
|
||||
widget.controller.reveal(ExampleWidgetState.shapes!, "Cone");
|
||||
widget.controller.reveal(ExampleWidgetState.assets.last, "Cone");
|
||||
} else {
|
||||
widget.controller.hide(ExampleWidgetState.shapes!, "Cone");
|
||||
widget.controller.hide(ExampleWidgetState.assets.last, "Cone");
|
||||
}
|
||||
|
||||
ExampleWidgetState.coneHidden = !ExampleWidgetState.coneHidden;
|
||||
@@ -137,12 +104,10 @@ class _AssetSubmenuState extends State<AssetSubmenu> {
|
||||
child:
|
||||
Text(ExampleWidgetState.coneHidden ? 'show cone' : 'hide cone')),
|
||||
MenuItemButton(
|
||||
onPressed: ExampleWidgetState.shapes == null
|
||||
? null
|
||||
: () async {
|
||||
widget.controller.setMaterialColor(
|
||||
ExampleWidgetState.shapes!, "Cone", 0, Colors.purple);
|
||||
},
|
||||
onPressed: () async {
|
||||
widget.controller.setMaterialColor(
|
||||
ExampleWidgetState.assets.last, "Cone", 0, Colors.purple);
|
||||
},
|
||||
child: const Text("Set cone material color to purple")),
|
||||
MenuItemButton(
|
||||
onPressed: () async {
|
||||
@@ -154,7 +119,7 @@ class _AssetSubmenuState extends State<AssetSubmenu> {
|
||||
if (ExampleWidgetState.animations != null) {
|
||||
children.addAll(ExampleWidgetState.animations!.map((a) => MenuItemButton(
|
||||
onPressed: () {
|
||||
widget.controller.playAnimation(ExampleWidgetState.shapes!,
|
||||
widget.controller.playAnimation(ExampleWidgetState.assets.last,
|
||||
ExampleWidgetState.animations!.indexOf(a),
|
||||
replaceActive: true,
|
||||
crossfade: 0.5,
|
||||
@@ -164,7 +129,7 @@ class _AssetSubmenuState extends State<AssetSubmenu> {
|
||||
"play animation ${ExampleWidgetState.animations!.indexOf(a)} (replace/fade)"))));
|
||||
children.addAll(ExampleWidgetState.animations!.map((a) => MenuItemButton(
|
||||
onPressed: () {
|
||||
widget.controller.playAnimation(ExampleWidgetState.shapes!,
|
||||
widget.controller.playAnimation(ExampleWidgetState.assets.last,
|
||||
ExampleWidgetState.animations!.indexOf(a),
|
||||
replaceActive: false, loop: ExampleWidgetState.loop);
|
||||
},
|
||||
@@ -202,7 +167,7 @@ class _AssetSubmenuState extends State<AssetSubmenu> {
|
||||
await widget.controller
|
||||
.playAnimation(ExampleWidgetState.buster!, 0, loop: true);
|
||||
ExampleWidgetState.animations = await widget.controller
|
||||
.getAnimationNames(ExampleWidgetState.shapes!);
|
||||
.getAnimationNames(ExampleWidgetState.assets.last);
|
||||
} else {
|
||||
await widget.controller.removeAsset(ExampleWidgetState.buster!);
|
||||
ExampleWidgetState.buster = null;
|
||||
@@ -272,7 +237,7 @@ class _AssetSubmenuState extends State<AssetSubmenu> {
|
||||
await widget.controller.clearAssets();
|
||||
ExampleWidgetState.flightHelmet = null;
|
||||
ExampleWidgetState.buster = null;
|
||||
ExampleWidgetState.shapes = null;
|
||||
ExampleWidgetState.assets.clear();
|
||||
},
|
||||
child: const Text('Clear assets')),
|
||||
],
|
||||
|
||||
@@ -82,21 +82,17 @@ class _CameraSubmenuState extends State<CameraSubmenu> {
|
||||
child: const Text('Move to 1, 1, -1'),
|
||||
),
|
||||
MenuItemButton(
|
||||
onPressed: ExampleWidgetState.last == null
|
||||
? null
|
||||
: () async {
|
||||
await widget.controller
|
||||
.setCamera(ExampleWidgetState.last!, null);
|
||||
},
|
||||
onPressed: () async {
|
||||
await widget.controller
|
||||
.setCamera(ExampleWidgetState.assets.last!, null);
|
||||
},
|
||||
child: const Text('Set to first camera in last added asset'),
|
||||
),
|
||||
MenuItemButton(
|
||||
onPressed: ExampleWidgetState.last == null
|
||||
? null
|
||||
: () async {
|
||||
await widget.controller
|
||||
.moveCameraToAsset(ExampleWidgetState.last!);
|
||||
},
|
||||
onPressed: () async {
|
||||
await widget.controller
|
||||
.moveCameraToAsset(ExampleWidgetState.assets.last!);
|
||||
},
|
||||
child: const Text("Move to last added asset"),
|
||||
),
|
||||
MenuItemButton(
|
||||
|
||||
@@ -100,18 +100,16 @@ class _ControllerMenuState extends State<ControllerMenu> {
|
||||
menuChildren: items,
|
||||
builder:
|
||||
(BuildContext context, MenuController controller, Widget? child) {
|
||||
return Align(
|
||||
alignment: Alignment.bottomLeft,
|
||||
child: TextButton(
|
||||
onPressed: () {
|
||||
if (controller.isOpen) {
|
||||
controller.close();
|
||||
} else {
|
||||
controller.open();
|
||||
}
|
||||
},
|
||||
child: const Text("Controller / Viewer"),
|
||||
));
|
||||
return TextButton(
|
||||
onPressed: () {
|
||||
if (controller.isOpen) {
|
||||
controller.close();
|
||||
} else {
|
||||
controller.open();
|
||||
}
|
||||
},
|
||||
child: const Text("Controller / Viewer"),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ class _SceneMenuState extends State<SceneMenu> {
|
||||
void didUpdateWidget(SceneMenu oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (widget.controller != null &&
|
||||
widget.controller != oldWidget.controller ||
|
||||
widget.controller!.hasViewer != oldWidget.controller!.hasViewer) {
|
||||
(widget.controller != oldWidget.controller ||
|
||||
widget.controller!.hasViewer != oldWidget.controller!.hasViewer)) {
|
||||
setState(() {});
|
||||
}
|
||||
}
|
||||
@@ -47,20 +47,18 @@ class _SceneMenuState extends State<SceneMenu> {
|
||||
],
|
||||
builder: (BuildContext context, MenuController controller,
|
||||
Widget? child) {
|
||||
return Align(
|
||||
alignment: Alignment.bottomLeft,
|
||||
child: TextButton(
|
||||
onPressed: !hasViewer
|
||||
? null
|
||||
: () {
|
||||
if (controller.isOpen) {
|
||||
controller.close();
|
||||
} else {
|
||||
controller.open();
|
||||
}
|
||||
},
|
||||
child: const Text("Scene"),
|
||||
));
|
||||
return TextButton(
|
||||
onPressed: !hasViewer
|
||||
? null
|
||||
: () {
|
||||
if (controller.isOpen) {
|
||||
controller.close();
|
||||
} else {
|
||||
controller.open();
|
||||
}
|
||||
},
|
||||
child: const Text("Scene"),
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user