Flutter加载3D模型
思路
因为Flutter目前不支持3D图形API,所以考虑通过嵌入网页使用WebGL API来跨平台。 嵌入网页使用官方的webview_flutter插件,但是webview_flutter对加载本地网页没有提供便利的API, 通过Data URLs编码较大的3D模型在这种方案下也无法正常工作,最后依靠搭建本地http服务器来加载本地网页内容。
使用three.js加载3D模型
在项目根目录新建www文件夹,在pubspec.yaml里添加www文件夹:
flutter:
# ...
assets:
- www/
在www文件夹里添加3d模型文件(如test.glb)、three.js和相关的GLTFLoader.js(可用于加载.glb文件)。新建index.js:
var scene = new THREE.Scene()
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 100)
var renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true })
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.appendChild(renderer.domElement)
camera.position.z = 80
var light = new THREE.PointLight()
light.position.copy(camera.position)
scene.add(light)
var ambientLight = new THREE.AmbientLight(0x999999)
scene.add(ambientLight)
var loader = new THREE.GLTFLoader()
loader.load("./test.glb", function (gltf) {
scene.add(gltf.scene)
}, undefined, function (error) {
console.error(error)
})
setInterval(() => renderer.render(scene, camera), 1000 / 60)
新建index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>3D</title>
<style>
body {
margin: 0;
}
canvas {
display: block;
}
</style>
</head>
<body>
<script src="./three.js"></script>
<script src="./GLTFLoader.js"></script>
<script src="./index.js"></script>
</body>
</html>
添加webview_flutter和local_assets_server插件
local_assets_server插件用于搭建本地静态资源服务器,运行以下命令来添加插件:
flutter pub add local_assets_server
flutter pub add webview_flutter
嵌入网页
可以把lib/main.dart修改成如下内容:
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:local_assets_server/local_assets_server.dart';
import 'package:webview_flutter/webview_flutter.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool _isListening = false;
String? _address;
int? _port;
@override
initState() {
_initServer();
super.initState();
}
_initServer() async {
final server = LocalAssetsServer(
address: InternetAddress.loopbackIPv4,
assetsBasePath: 'www',
logger: DebugLogger(),
);
final address = await server.serve();
setState(() {
_address = address.address;
_port = server.boundPort!;
_isListening = true;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('3D'),
),
body: _isListening
? WebView(
debuggingEnabled: true,
initialUrl: 'http://$_address:$_port',
javascriptMode: JavascriptMode.unrestricted,
)
: Text('Loading...'),
);
}
}
安卓特别配置
打开android/app/src/main/AndroidManifest.xml,在application下添加android:usesCleartextTraffic="true"
来允许使用http明文网络流量。
打开android/app/build.gradle,修改minSdkVersion为19,以满足webview_flutter插件的最低版本要求。
转载自:https://juejin.cn/post/6970920584200847396