Open In App

How to Use 3D Models in Flutter?

Last Updated : 06 Nov, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Flutter is a versatile UI toolkit developed by Google. It has empowered developers to create visually appealing and interactive applications. With its recent development into 3D graphics, Flutter is not just limited to 2D anymore. In this article, we will delve into the exciting world of creating 3D objects in Flutter using its flutter_cube library.

Step-By-Step Implementation

Step 1: Create Project

Create a project from the terminal of IDE using the following command:

Dart




flutter create threedobjects


Step 2: Add library

In the pubspec.yaml file, add flutter_cube dependency under the dependencies section. Run pub get to install this dependency or hit Ctrl + S in Windows do to so. The other method to add a library is from the terminal using the following command:-

Dart




flutter pub add flutter_cube


Step 3: Import package

Import the package in the file before using it.

Dart




import 'package:flutter_cube/flutter_cube.dart';


Step 4: Create 3D Objects

Let’s delve into code of creating 3D objects using flutter_cube.

Example 1: Create a Moon

Dart




class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, this.title}) : super(key: key);
  
  final String? title;
  
  @override
  _MyHomePageState createState() => _MyHomePageState();
}
  
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
  late Scene _scene;
  Object? _moon;
  Object? _moonObj;
  late AnimationController _controller;
  
  Future<Mesh> generateSphereMesh({num radius = 0.5, int latSegments = 32, int lonSegments = 64, required String texturePath}) async {
  int count = (latSegments + 1) * (lonSegments + 1);
  List<Vector3> vertices = List<Vector3>.filled(count, Vector3.zero());
  List<Offset> texcoords = List<Offset>.filled(count, Offset.zero);
  List<Polygon> indices = List<Polygon>.filled(latSegments * lonSegments * 2, Polygon(0, 0, 0));
  
  int i = 0;
  for (int y = 0; y <= latSegments; ++y) {
    final double v = y / latSegments;
    final double sv = math.sin(v * math.pi);
    final double cv = math.cos(v * math.pi);
    for (int x = 0; x <= lonSegments; ++x) {
      final double u = x / lonSegments;
      vertices[i] = Vector3(radius * math.cos(u * math.pi * 2.0) * sv, radius * cv, radius * math.sin(u * math.pi * 2.0) * sv);
      texcoords[i] = Offset(1.0 - u, 1.0 - v);
      i++;
    }
  }
  
  i = 0;
  for (int y = 0; y < latSegments; ++y) {
    final int base1 = (lonSegments + 1) * y;
    final int base2 = (lonSegments + 1) * (y + 1);
    for (int x = 0; x < lonSegments; ++x) {
      indices[i++] = Polygon(base1 + x, base1 + x + 1, base2 + x);
      indices[i++] = Polygon(base1 + x + 1, base2 + x + 1, base2 + x);
    }
  }
  
  ui.Image texture = await loadImageFromAsset(texturePath);
  final Mesh mesh = Mesh(vertices: vertices, texcoords: texcoords, indices: indices, texture: texture, texturePath: texturePath);
  return mesh;
}
  
  void generateSphereObject(Object parent, String name, double radius, bool backfaceCulling, String texturePath) async {
    final Mesh mesh = await generateSphereMesh(radius: radius, texturePath: texturePath);
    parent.add(Object(name: name, mesh: mesh, backfaceCulling: backfaceCulling));
    _scene.updateTexture();
  }
  
  
  void _onSceneCreated(Scene scene) {
    _scene = scene;
    scene.camera.position.z = 50;
    _moonObj = Object(scale: Vector3(2.0, 2.0, 2.0), backfaceCulling: true, fileName: 'assets/moon.jpg');
     
    _moon = Object(name: 'moon', scale: Vector3(10, 10, 10));
    generateSphereObject(_moon!, 'surface', 0.9, true, 'assets/moon.jpg');
    _moonObj!.add(_moon!);
    scene.world.add(_moonObj!);
  }
  
  @override
  void initState() {
    super.initState();
    _controller = AnimationController(duration: Duration(milliseconds: 30000), vsync: this)
      ..addListener(() {
        if (_moon != null) {
          _moon!.rotation.y = _controller.value * 360;
          _moon!.updateTransform();
          _scene.update();
        }
      })
      ..repeat();
  }
  
  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title!),
        centerTitle: true,
      ),
      body: Center(
        child: Cube(
          onSceneCreated: _onSceneCreated,
        ),
      ),
    );
  }
}


The generateSphereMesh function creates a 3D mesh representing a sphere (the moon) using latitude and longitude segments to approximate the sphere’s shape. It calculates vertices (points in 3D space), texture coordinates, and indices (defining how vertices are connected to form triangles) for the sphere.

It also loads a moon texture from an image file using the loadImageFromAsset function. The generateSphereObject function creates a 3D object representing the moon. It calls generateSphereMesh to get the mesh data for the moon.

The moon object is created with a specific scale (making it larger), backface culling enabled (for efficiency), and the moon texture applied. In the _onSceneCreated callback, the 3D scene is initialized. The moon object is created and added to the scene as a child of another object _moonObj. The moon is rotated around the Y-axis in a continuous animation using the _controller. The 3D scene is rendered inside a Cube widget provided by the flutter_cube package.

Output GIF:

threedshapesflutter-2023-10-23-15-50-26

Example 2: Create a Cube

We use the flutter_cube package to create a 3D space. When the Scene widget is created, it’s like opening up a blank canvas. Inside a function _onSceneCreated, we build 3D world. In this world, we add a cube and another object that sits inside the cube. These objects are loaded from special files. In this example code, we have used file.obj, which contains blueprint of cube. It’s a special file that defines the cube’s shape, size, and how it looks in 3D space.

Dart




class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
  late Scene _scene;
  Object? _cube;
  late AnimationController _controller;
  
  Object? _c;
  void _onSceneCreated(Scene scene) async{
    _scene = scene;
    scene.camera.position.z = 50;
    _cube = Object(scale: Vector3(5.0, 5.0, 5.0), backfaceCulling: true, fileName: 'assets/file.obj');
    _c = Object(scale: Vector3(5.0, 5.0, 5.0), backfaceCulling: true, fileName: 'assets/file.obj');
    _cube!.add(_c!);
      
    scene.world.add(_cube!);
  }
  
  @override
  void initState() {
    super.initState();
    _controller = AnimationController(duration: Duration(milliseconds: 30000), vsync: this)
      ..addListener(() {
        if (_cube != null) {
          _cube!.rotation.y = _controller.value * 360;
          _cube!.updateTransform();
          _scene.update();
        }
      })
      ..repeat();
  }
  
  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        centerTitle: true,
        title: Text(widget.title!),
      ),
      body: Center(
        child: Cube(
          onSceneCreated: _onSceneCreated,
        ),
      ),
    );
  }
}


Output GIF:

threedshapesflutter-2023-10-23-15-41-49

Conclusion

With Flutter’s ongoing advancements, app development is reaching new creative heights. It is opening doors to incredibly immersive experiences for users everywhere. So, jump into the exciting world of 3D and let the imagination run wild.



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads