update README

This commit is contained in:
Nick Fisher
2023-10-13 10:15:07 +08:00
parent d655672587
commit 05bc5b122e

129
README.md
View File

@@ -1,6 +1,6 @@
# Flutter Filament
Cross-platform, 3D PBR rendering and animation for Flutter.
Cross-platform, 3D PBR rendering and animation for [Flutter](https://github.com/google/filament).
Wraps the [the Filament rendering library](https://github.com/google/filament).
@@ -8,24 +8,20 @@ Powers the Polyvox and odd-io engines.
|Feature|Supported|
|---|---|
|glTF|Partial - see Known Issues|
|glb|✅|
|Camera movement (mouse/finger gesture)|✅|
|Skinning|✅|
|Morph targets|✅|
|Runtime material changes|Partial|
|Viewport entity selection|✅|
|Entity transform manipulation (mouse/finger gesture)|Partial|
|Entity/transform parenting|Planned|
|Entity material manipulation|Partial|
|Platforms|✅ iOS<br/>✅ MacOS<br/>✅ Android<br/>✅ Windows<br/>⚠️ Web (planned)|
|Formats|✅ glb <br/>⚠️ glTF (partial - see Known Issues)|
|Texture support|✅ PNG <br/>✅ JPEG <br/>✅ KTX <br/>⚠️ KTX2 (planned)|
|Camera movement|✅ Desktop (mouse)<br/>✅ Mobile (swipe/pinch)|
|Animation|✅ Embedded glTF skinning animations<br/>✅ Embedded glTF morph animations<br/> ✅ Runtime/dynamic morph animations<br/> ⚠️ Runtime/dynamic skinning animations <br/>
|Entity manipulation|✅ Viewport selection<br/>⚠️ Entity/transform parenting (planned)<br/> ⚠️ Transform manipulation (mouse/gesture to rotate/translate/scale object) (partial)<br/>⚠️ Runtime material changes (planned)|
Special thanks to odd-io for sponsoring work on supporting Windows, raycasting, testing and documentation.
PRs are welcome but please create a placeholder PR to discuss before writing any code. This will help avoid
PRs are welcome but please create a placeholder PR to discuss before writing any code. This will help with feature planning, avoid clashes with existing work and keep the project structure consistent.
## Getting Started
This package is currently only tested on Flutter `3.15.0-15.2.pre`, so you will need to first switch to the `beta` channel:
This package is currently only tested on Flutter >= `3.15.0-15.2.pre`, so you will need to first switch to the `beta` channel:
```
flutter channel beta
@@ -40,8 +36,8 @@ git clone <repo> && cd flutter_filament
git lfs pull
```
(these instructions will be updated after the plugin is published to pub.dev).
> [!NOTE]
(this step won't be needed after the plugin is published to pub.dev).
> You *do not need to build Filament yourself*. The repository is bundled with all necessary headers/static libraries (`windows/lib`, `ios/lib`, `macos/lib` and `linux/lib`) and the Flutter plugin has been configured to link at build time.
Run the example project to check:
@@ -65,13 +61,12 @@ dependencies:
## Basic Usage
See the `example` project for a complete sample of the below steps.
See the `example` project for a complete sample that incorporates many of the below steps, and more.
### Creating the viewport widget and controller
To embed a viewport in your app, create an instance of `FilamentControllerFFI` somewhere in your app:
Create an instance of `FilamentControllerFFI` somewhere in your app where it will not be garbage collected until you no longer need a rendering canvas:
e.g.
```
class MyApp extends StatelessWidget {
@@ -80,9 +75,8 @@ class MyApp extends StatelessWidget {
}
```
Constructing this object only load symbols from the native FFI library.
(Note this is not (yet) a singleton, so ensure it is placed somewhere in the widget hierachy where it will not be garbage-collected until you no longer need a rendering canvas).
This is a relatively lightweight object, however its constructor will load/bind symbols from the native library. This may momentarily block the UI, so you may wish to structure your app so that this is hidden behind a static widget until it is available.
Next, create an instance of `FilamentWidget` in the widget hierarchy where you want the rendering canvas to appear. This can be sized as large or as small as you want. Flutter widgets can be positioned above or below the `FilamentWidget`.
@@ -107,19 +101,49 @@ class MyApp extends StatelessWidget {
When a `FilamentWidget` is added to the widget hierarchy:
1) on the first frame, by default a Container will be rendered with solid red. If you want to change this, pass a widget as the `initial` paramer to the `FilamentWidget` constructor.
2) on the second frame, `FilamentWidget` will retrieve its actual size and request the `FilamentController` to create:
a) the backing textures needed to insert a `Texture` widget into
b) a rendering thread
c) a `FilamentViewer` and an `AssetManager`, which will allow you to load assets/cameras/lighting/etc via the `FilamentController`
* the backing textures needed to insert a `Texture` widget into
* a rendering thread
* a `FilamentViewer` and an `AssetManager`, which will allow you to load assets/cameras/lighting/etc via the `FilamentController`
3) after an indeterminate number of frames, `FilamentController` will notify `FilamentWidget` when a texture is available the viewport
4) `FilamentWidget` will replace the default `initial` Widget with the viewport (which will initially be solid black or white, depending on your platform).
If this was successful, the viewport should turn from red to black/white (depending on your platform).
It's important to note that there *will* be a delay between adding a `FilamentWidget` and the actual rendering viewport becoming available. This is why we fill `FilamentWidget` with red - to make it abundantly clear that you need to handle this asynchronous delay appropriately. You can call `await _filamentController.isReadyForScene` if you need to wait until the viewport is actually ready for rendering.
### Rendering
Congratulations! You now have a scene. It's completely empty, so you probably want to add.
### Load a background
You probably want to set a background for your scene. You can load a skybox:
```
await _filamentController.loadSkybox("assets/default_env/default_env_skybox.ktx)
```
or a static background image:
```
await _filamentController.setBackgroundImage("assets/background.ktx)
```
or a solid background color:
```
await _filamentController.setBackgroundColor(0.0, 1.0, 0.0, 1.0); // solid green
```
At this point, you might not see any change in the viewport. This is because the FilamentController will only actually render into the viewport once `render` has been called.
By default, the FilamentController will only render into the viewport by manually calling `render()` on the FilamentController. This is to avoid needlessly running a render loop when there is nothing to display.
To automatically render at 60fps, call `setRendering(true)` on `FilamentController`.
```
await _filamentController.render()
```
### Assets
You should now see your background displayed in the scene. To automatically render at 60fps, call `setRendering`:
```
await _filamentController.setRendering(true);
```
### Load an asset
To add a glTF asset to the scene, call `loadGlb()` on `FilamentController` with the Flutter asset path to your .glb file.
@@ -132,19 +156,37 @@ flutter:
Then you would call the following
```
var entity = _filamentController.loadGlb("assets/models/bob.glb");
var entity = await _filamentController.loadGlb("assets/models/bob.glb");
```
You can also pass a URI to indicate that the glTF file should be loaded from the filesystem:
```
var entity = _filamentController.loadGlb("file:///tmp/bob.glb");
var entity = await _filamentController.loadGlb("file:///tmp/bob.glb");
```
The return type `FilamentEntity` is simply an integer handle that be used to manipulate the entity in the scene. For example, to remove the asset:
```
_filamentController.removeAsset(entity);
entity = null; // see note* below
await _filamentController.removeAsset(entity);
entity = null;
```
* Removing an entity from the scene will invalidate the corresponding `FilamentEntity` handle, so ensure you don't retain any references to it after calling `removeAsset` or `clearAssets`. Removing one `FilamentEntity` does not invalidate/change any other `FilamentEntity` handles; you can continue to safely manipulate these via the `FilamentController`.
> Removing an entity from the scene will invalidate the corresponding `FilamentEntity` handle, so ensure you don't retain any references to it after calling `removeAsset` or `clearAssets`. Removing one `FilamentEntity` does not invalidate/change any other `FilamentEntity` handles; you can continue to safely manipulate these via the `FilamentController`.
### Lighting
You should now see your object in the viewport, but since we haven't added a light, this will be solid black.
Add an image-based light from a KTX file:
```
await _filamentController.loadIbl("assets/default_env/default_env_ibl.ktx");
```
You can also add dynamic lights:
```
var sun = await _filamentController.addLight(
```
### Manipulating entity transforms
To set the world space position of the asset:
```
@@ -153,7 +195,6 @@ _filamentController.setPositon(entity, 1.0, 1.0, 1.0);
On desktop, you can also click any renderable object in the viewport to retrieve its associated FilamentEntity (see below).
### Camera movement
To enable mouse/swipe navigation through the scene, wrap the `FilamentWidget` inside a `FilamentGestureDetector`:
@@ -189,6 +230,18 @@ On mobile:
2) double tap the viewport, then swipe with your finger to rotate the camera (double-tap again to return to pan)
3) pinch with two fingers in/out to zoom in/out.
### Changing the active camera
Every scene has a default camera. Whenever you rotate/pan/zoom the viewport, you are moving the default camera.
If you have added an entity to the scene that contains one or more camera nodes, you can change the active scene camera to one of those camera nodes.
```
var asset = await _filamentController.loadGlb("assets/some_asset_with_camera.glb");
await _filamentController.setCamera(asset, "Camera.002"); // pass the node name to load a specific camera under that entity node
await _filamentController.setCamera(asset, null); // pass null to load the first camera found under that entity
```
### Picking entities
On desktop, left-clicking an object in the viewport will retrieve the FilamentEntity for the top-most renderable instance at that cursor position (if any).
@@ -208,12 +261,10 @@ class _MyAppState extends State<MyApp> {
@override
void initState() {
_filamentController.pickResult.listen((FilamentEntity filamentEntity) async {
if(filamentEntity != FILAMENT_ASSET_ERROR) {
var entityName = _filamentController.getNameForEntity(filamentEntity);
await showDialog(builder:(ctx) {
return Container(child:Text("You clicked $entityName"));
});
}
var entityName = _filamentController.getNameForEntity(filamentEntity);
await showDialog(builder:(ctx) {
return Container(child:Text("You clicked $entityName"));
});
});
}