Quick Start
If all you need is a quick and easy route to rendering a single 3D model in your Flutter application, start with ViewerWidget.
This is a simplified, Flutter-only wrapper around the underlying 3D rendering API with sane defaults for most people.
ViewerWidget handles all the setup and configuration of the underlying Thermion API, including:
- Loading 3D models (glTF assets)
- Configuring skyboxes and image-based lighting
- Setting up camera positions and manipulators
- Managing the rendering lifecycle
Follow the steps listed in Getting Started to configure your Flutter installation and project.
If you’re running Windows, delete the examples/flutter/quickstart/assets symlink and copy the assets folder from examples/assets to examples/flutter/quickstart/assets.
Basic Usage
Section titled “Basic Usage”import 'package:flutter/material.dart';import 'package:thermion_flutter/thermion_flutter.dart';import 'path_to_your_viewer_widget.dart';
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: ViewerWidget( assetPath: 'assets/my_model.glb', initialCameraPosition: Vector3(0, 0, 5), manipulatorType: ManipulatorType.ORBIT, ), ), ); }}Properties
Section titled “Properties”| Property | Type | Default | Description |
|---|---|---|---|
initial |
Widget |
Red decorated box | Widget to display while the viewer is loading |
initialCameraPosition |
Vector3 |
Vector3(0, 0, 5) |
The starting position for the camera (looking towards origin) |
showFpsCounter |
bool |
false |
Whether to show an FPS counter overlay |
assetPath |
String? |
null |
Path to the glTF asset to load |
skyboxPath |
String? |
null |
Path to a KTX skybox image |
iblPath |
String? |
null |
Path to a KTX image for image-based lighting |
directLightType |
LightType? |
null |
Type of direct light to add to the scene |
transformToUnitCube |
bool |
true |
If true, rescales the model to fit within a 1x1x1 cube |
postProcessing |
bool |
true |
Enables ACES tone mapping and basic anti-aliasing |
background |
Color? |
null |
Background color (not visible when skybox is provided) |
destroyEngineOnUnload |
bool |
false |
If true, disposes the engine when widget is disposed |
manipulatorType |
ManipulatorType |
ORBIT |
Type of camera control to use |
onViewerAvailable |
Future Function(ThermionViewer)? |
null |
Callback when viewer is ready |
Camera Manipulators
Section titled “Camera Manipulators”ViewerWidget supports three different camera manipulation modes:
ManipulatorType.NONE: No camera controls, static viewManipulatorType.ORBIT: Orbit controls (pinch to zoom, swipe to rotate)ManipulatorType.FREE_FLIGHT: Free flight controls for unrestricted movement
Example:
ViewerWidget( assetPath: 'assets/model.glb', manipulatorType: ManipulatorType.FREE_FLIGHT,)Lighting
Section titled “Lighting”You can set up lighting in multiple ways:
Image-Based Lighting
Section titled “Image-Based Lighting”ViewerWidget( assetPath: 'assets/model.glb', iblPath: 'assets/environment.ktx',)Direct Light
Section titled “Direct Light”ViewerWidget( assetPath: 'assets/model.glb', directLightType: LightType.SUN,)Advanced Usage
Section titled “Advanced Usage”Accessing the Viewer
Section titled “Accessing the Viewer”You can get access to the underlying ThermionViewer object for more advanced control:
ViewerWidget( assetPath: 'assets/model.glb', onViewerAvailable: (viewer) async { // Now you can use the viewer directly final camera = await viewer.getActiveCamera(); await camera.lookAt(Vector3(0, 1, 5));
// Add custom lights, manipulate materials, etc. },)Changing Manipulator at Runtime
Section titled “Changing Manipulator at Runtime”The manipulatorType is the only property that can be changed after the widget is created:
class _MyWidgetState extends State<MyWidget> { ManipulatorType _manipulatorType = ManipulatorType.ORBIT;
@override Widget build(BuildContext context) { return Column( children: [ Expanded( child: ViewerWidget( assetPath: 'assets/model.glb', manipulatorType: _manipulatorType, ), ), Row( children: [ ElevatedButton( onPressed: () { setState(() { _manipulatorType = ManipulatorType.ORBIT; }); }, child: Text('Orbit'), ), ElevatedButton( onPressed: () { setState(() { _manipulatorType = ManipulatorType.FREE_FLIGHT; }); }, child: Text('Free Flight'), ), ], ), ], ); }}Limitations
Section titled “Limitations”- Only the
manipulatorTypeproperty can be changed at runtime. For any other property changes, create a new widget. - The widget requires that you have the correct environment setup for Thermion (Flutter master channel with native assets enabled).
Example
Section titled “Example”Here’s a complete example showing how to use ViewerWidget with multiple configuration options:
import 'package:flutter/material.dart';import 'package:thermion_flutter/thermion_flutter.dart';import 'package:vector_math/vector_math_64.dart';
class ModelViewer extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('3D Model Viewer')), body: ViewerWidget( assetPath: 'assets/robot.glb', skyboxPath: 'assets/studio_skybox.ktx', iblPath: 'assets/studio_ibl.ktx', initialCameraPosition: Vector3(0, 1.5, 3), manipulatorType: ManipulatorType.ORBIT, showFpsCounter: true, background: Colors.grey, postProcessing: true, transformToUnitCube: true, onViewerAvailable: (viewer) async { // You can perform additional setup here print('Viewer is ready!'); }, ), ); }}