文章目录

  • 前言
  • 一、flutter_cube
    • 1.依赖
    • 2.使用
  • 二、model_viewer_plus
    • 1.依赖
    • 2.配置
    • 2.使用
  • 三、结合three.js
    • 1. 配置three.js
      • 下载资源
      • 编写index.html
    • 2. 导入Flutter项目
      • 引入资源
      • 声明资源
    • 3. Flutter中使用
      • 依赖
      • 配置
      • 使用
  • 总结

前言

本文主要是对pub上的3D库使用总结及Flutter中结合three.js总结


一、flutter_cube

Flutter 3D 小部件,加载OBJ模型文件
支持Android,IOS,Window,Mac平台

1.依赖

  flutter_cube: ^0.1.1

2.使用

import 'package:flutter/material.dart';
import 'package:flutter_cube/flutter_cube.dart';class Model3DViewer extends StatefulWidget {final String name;const Model3DViewer({Key? key, required this.name}) : super(key: key);@overrideState<Model3DViewer> createState() {return _Model3DViewerState();}
}class _Model3DViewerState extends State<Model3DViewer> {@overrideWidget build(BuildContext context) {return Cube(onSceneCreated: _onSceneCreated);}void _onSceneCreated(Scene scene) {scene.camera.position.z = 10;scene.camera.target.y = 2;final parent = widget.name.substring(0, widget.name.lastIndexOf('.'));scene.world.add(Object(scale: Vector3(10.0, 10.0, 10.0), fileName: 'assets/models/$parent/${widget.name}'));}
}

二、model_viewer_plus

Flutter 3D小部件,用于以 glTF 和 GLB 格式渲染交互式 3D 模型,继承自model viewer
支持Android,IOS,Web平台

1.依赖

  model_viewer_plus: ^1.2.0

2.配置

Android清单文件中添加

   <applicationandroid:label="flutter3d"android:name="${applicationName}"android:icon="@mipmap/ic_launcher"android:usesCleartextTraffic="true">

Android将 minSdkVersion 更改为 19以上

    defaultConfig {applicationId "com.example.viewer.flutter3d"minSdkVersion 19targetSdkVersion 30versionCode flutterVersionCode.toInteger()versionName flutterVersionName}

Ios中ios/Runner/Info.plist中添加

    <key>io.flutter.embedded_views_preview</key><string>YES</string>

web中index.html中添加

<head><script type="module" src="./assets/packages/model_viewer_plus/assets/model-viewer.min.js" defer></script>
</head>

2.使用

import 'package:flutter/material.dart';
import 'package:model_viewer_plus/model_viewer_plus.dart';class Model3DViewer extends StatefulWidget {final String name;const Model3DViewer({Key? key, required this.name}) : super(key: key);@overrideState<Model3DViewer> createState() {return _Model3DViewerState();}
}class _Model3DViewerState extends State<Model3DViewer> {@overrideWidget build(BuildContext context) {return ModelViewer(src: 'assets/models/${widget.name}',alt: "A 3D model of an astronaut",ar: true,autoRotate: true,cameraControls: true,);}
}

三、结合three.js

JavaScript编写的WebGL第三方库
实现在Android,IOS,Web平台使用

1. 配置three.js

下载资源

在官网下载所需文件

编写index.html

<!DOCTYPE html>
<html><head><title>Flutter 3D To ThreeJS</title><meta charset="utf-8" /><meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"><style>body {margin: 0;padding: 0;width: 100%;height: 100%;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);}</style>
</head><body><script async src="https://ga.jspm.io/npm:es-module-shims@1.5.4/dist/es-module-shims.js"></script><script type="importmap">{"imports": {"three": "./three.module.js"}}</script><script type="module">import * as THREE from 'three';import { GLTFLoader } from './GLTFLoader.js';import { RGBELoader } from './RGBELoader.js';import { OrbitControls } from './OrbitControls.js';let camera, scene, renderer, controls, object;let windowHalfX = window.innerWidth / 2;let windowHalfY = window.innerHeight / 2;init();animate();function init() {const container = document.createElement('div');document.body.appendChild(container);// 透视镜头 PerspectiveCameracamera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 2000);// 设置视角离原点的位置(眼睛距离模型的距离)camera.position.z = 3;scene = new THREE.Scene();// 环境光会均匀的照亮场景中的所有物体,环境光不能用来投射阴影,因为它没有方向。const ambientLight = new THREE.AmbientLight(0xcccccc, 1.5);scene.add(ambientLight);// 从一个点向各个方向发射的光源。一个常见的例子是模拟一个灯泡发出的光,该光源可以投射阴影。const pointLight = new THREE.PointLight(0xffffff, 0.01);camera.add(pointLight);scene.add(camera);// 加载进度监听const onProgress = function (xhr) {if (xhr.lengthComputable) {const percentComplete = xhr.loaded / xhr.total * 100;let progress = Math.round(percentComplete, 2)console.log(progress + '% downloaded');}};const onError = function (error) {console.log(error);}const params = new URLSearchParams(location.search);const name = params.get('name');new GLTFLoader().setPath("../models/").load(name, function (obj) {object = obj.scene;// 模型缩放// object.scale.set(0.3, 0.3, 0.3);// 改变模型的加载位置object.position.set(0, -1, 0);scene.add(object);}, onProgress, onError);// 渲染器设置 alpha: true 否则背景图不显示renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });renderer.outputEncoding = THREE.sRGBEncoding;renderer.setPixelRatio(window.devicePixelRatio);renderer.setSize(window.innerWidth, window.innerHeight);container.appendChild(renderer.domElement);// 轨道控制器,用于模型手势处理controls = new OrbitControls(camera, renderer.domElement);controls.listenToKeyEvents(window);controls.enableDamping = true;// 相机向内和向外移动不超过远近截面controls.maxDistance = 2000;controls.minDistance = 1;controls.enablePan = false;controls.enableRotate = true;controls.screenSpacePanning = false;controls.enableZoom = true;// // 禁用垂直旋转// controls.minPolarAngle = Math.PI / 2;// controls.maxPolarAngle = Math.PI / 2;// 包含由控件所使用的鼠标操作的引用controls.mouseButtons = {LEFT: THREE.MOUSE.ROTATE,MIDDLE: THREE.MOUSE.DOLLY,RIGHT: THREE.MOUSE.PAN}// 包含由控件所使用的触摸操作的引用controls.touches = {ONE: THREE.TOUCH.ROTATE,TWO: THREE.TOUCH.DOLLY_PAN}window.addEventListener('resize', onWindowResize);}function onWindowResize() {windowHalfX = window.innerWidth / 2;windowHalfY = window.innerHeight / 2;camera.aspect = window.innerWidth / window.innerHeight;camera.updateProjectionMatrix();renderer.setSize(window.innerWidth, window.innerHeight);}function animate() {requestAnimationFrame(animate);controls.update();render();}function render() {renderer.render(scene, camera);}</script>
</body></html>

2. 导入Flutter项目

引入资源

声明资源

  assets:- assets/three3d/- assets/

3. Flutter中使用

依赖

  webview_flutter: ^3.0.4local_assets_server: ^2.0.2+12

配置

Android清单文件中添加

   <applicationandroid:label="flutter3d"android:name="${applicationName}"android:icon="@mipmap/ic_launcher"android:usesCleartextTraffic="true">

Android将 minSdkVersion 更改为 19以上

    defaultConfig {applicationId "com.example.viewer.flutter3d"minSdkVersion 19targetSdkVersion 30versionCode flutterVersionCode.toInteger()versionName flutterVersionName}

Ios中ios/Runner/Info.plist中添加

    <key>io.flutter.embedded_views_preview</key><string>YES</string>

使用

‘dart:ui’ 和dart:html 库是 web-only 的,没有把该方法允许外部调用,动态引入该方法。

// shim/dart_html_fake.dart
class IFrameElement {dynamic get style => null;dynamic src;
}
// shim/dart_ui_fake.dart
class platformViewRegistry {static void registerViewFactory(String viewTypeId, dynamic Function(int viewId) viewFactory,{bool isVisible = true}) {}
}

区分平台实现

import 'dart:io';import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:local_assets_server/local_assets_server.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'shim/dart_ui_fake.dart' if (dart.library.html) 'dart:ui' as ui;
import 'shim/dart_html_fake.dart' if (dart.library.html) 'dart:html';class Model3DViewer extends StatefulWidget {final String name;const Model3DViewer({Key? key, required this.name}) : super(key: key);@overrideState<Model3DViewer> createState() {return _Model3DViewerState();}
}class _Model3DViewerState extends State<Model3DViewer> {bool _isListening = false;String? _address;int? _port;final String _divID = DateTime.now().toIso8601String();@overridevoid initState() {if (kIsWeb) {ui.platformViewRegistry.registerViewFactory(_divID,(int viewId) => IFrameElement()..style.border = 'none'..src = 'assets/three3d/index.html?name=${widget.name}');} else {_startService();}super.initState();}///  启动静态服务器,解决跨域问题和加载本地html_startService() async {final server = LocalAssetsServer(address: InternetAddress.loopbackIPv4,assetsBasePath: 'assets',logger: const DebugLogger());final netAddress = await server.serve();setState(() {_address = netAddress.address;_port = server.boundPort!;_isListening = true;print('http://$_address:$_port');});}@overrideWidget build(BuildContext context) {return Scaffold(body: LayoutBuilder(builder: (context, constraints) {if (kIsWeb) {return HtmlElementView(viewType: _divID);} else {return _isListening? WebView(debuggingEnabled: true,initialUrl: 'http://$_address:$_port/three3d/index.html?name=${widget.name}',javascriptMode: JavascriptMode.unrestricted): const Center(child: Text("加载中..."));}}),);}
}

总结

1、cube在Android和IOS上表现不错,而且是基于Flutter实现的
2、model_viewer_plus内部也是基于WebView实现的,所以简单展示模型推荐cube。
3、结合three.js看业务需求,若业务复杂推荐使用。

Flutter 加载3D模型方案总结相关推荐

  1. threejs加载3D模型例子

    加载3D模型 首先要引入ColladaLoader加载器,Collada是一个3D模型交换方案,即不同的3D模型可以通过Collada进行相互转换,言外之意,threejs可以使用Collada将3D ...

  2. Labview加载3D模型(.wrl)出现内存不足的解决方法

    Labview加载3D模型(.wrl)出现内存不足的解决方法 最近,由于项目的要求,需要做一个上位机,用于实时采集装备的状态信息.最终方案采用Labview数据流的方式构建应用程序.在加载wrl3D模 ...

  3. threejs加载3D模型

    加载3D模型 首先要引入ColladaLoader加载器,Collada是一个3D模型交换方案,即不同的3D模型可以通过Collada进行相互转换,言外之意,threejs可以使用Collada将3D ...

  4. 如何加载3D模型(odj文件和mtl文件)

    模型的加载 因为,在最近的项目模块中需要加载部分"模型".在加载模型在方面我从来的没有接触过,是通过同事告诉,慢慢摸索才完成的,其中是我遇到的问题和总结的一些的方法. 使用VUE加 ...

  5. Unity动态加载3D模型

    Unity动态加载3D模型 在Unity中创建游戏对象的方法有 3 种: 第一种是将物体模型资源由 Project 视图直接拖曳到 Hierarchy 面板中: 第二种是在 Unity 3D 菜单 G ...

  6. qt opengl 加载3d模型(obj格式)

    和一般c++程序加载3d模型一样,解读出数据内容,再用一个常规的着色程序就可以了. 我实现的效果如下,采用的免费模型 实现思路和前面的略有不同,就是把自己生成顶点.纹理.法线的过程变成从文件读取了. ...

  7. Qt和OpenGL:使用Open Asset Import Library(ASSIMP)加载3D模型

    Qt和OpenGL:使用Open Asset Import Library(ASSIMP)加载3D模型 翻译自:https://www.ics.com/blog/qt-and-opengl-loadi ...

  8. Cesium.js 加载3D模型

    一.Cesuimjs介绍 Cesiunjs是一套GIS行业中进行地图渲染的js库,该库使用的WebGL进行地图渲染.并且结合HTML5进行相应,从而实现3D中渲染地图.本篇文章则介绍如何将后缀名为ma ...

  9. Qt Quick 3D系列(一):加载3d模型

    如果我们想在QML中使用3D且你之前没有三维程序开发的基础,使用Qt Quick 3D是个不错的选择,下面我介绍如何使用Qt Quick 3D加载3d模型.注意:Qt Quick 3D从Qt 5.15 ...

最新文章

  1. 美研究最新生物活性玻璃 可消灭致命的细菌
  2. NR 5G 移动性和状态变化
  3. python学习之- 内置函数
  4. 62.类文件结构(平台无关性、类文件结构)
  5. php zpo框架,Yii使用DeleteAll连表删除出现报错问题的解决方法
  6. Python 用hashlib求中文字符串的MD5值
  7. php析构函数使用,php析构函数__destruct()使用方法及实例讲解
  8. Python基础100题
  9. Linux命令格式及帮助命令详解
  10. 电子计算机说明文作文,关于电脑说明文作文(精选3篇)
  11. .NET框架怎样解决DLL Hell问题?
  12. matlab工作区显示的是什么,matlab工作区介绍
  13. 怎样在线分解gif图片?如何将gif拆分为静态图片?
  14. 如何完美清除被磁碟机感染的文件?
  15. ttl传输种过期_来自 202.112.36.253 的回复: TTL 传输中过期。解决思路
  16. 水溶性CdSe/ZnS量子点PL480nm--660nm(亲水配体包裹的核/壳型荧光纳米材料)
  17. Cannot copy param 0 weights from layer 'fc6'; shape mismatch.
  18. 腾讯云CentOS7 LAMP(linux的apache MariaDB php)yum方式部署
  19. ORB-SLAM2代码解析
  20. 基于ssm的万卷图书馆借阅管理平台#计算机毕业设计

热门文章

  1. vue仿卷皮折扣App
  2. 2020的一篇鸡鸣狗盗的远程桌面配置文档
  3. VBA学习笔记之随机数数组redim
  4. 车辆检测站管理系统如何选择?
  5. [转载] SQL导入导出大全
  6. 加密壳的一般脱壳步骤与实例演示
  7. 使用opencv调用IP摄像头APP
  8. ubuntu18 将/目录挂载到/home 目录下导致无法正常启动
  9. Java求一组数中最大值的方法
  10. 【原创 HadoopSpark 动手实践 11】Spark Streaming 应用与动手实践