Flutter三维图形与SVG渲染插件three_js_svg的使用
Flutter三维图形与SVG渲染插件three_js_svg的使用
这是一个允许用户向项目中添加或导出SVG文件的类型插件,基于three.js和three_dart。最初由@mrdoob创建,并由@wasabia进行了dart转换。
该插件是three.js和three_dart的一个dart版本,最初由@mrdoob创建,并由@wasabia进行了dart转换。
开始使用
在pubspec.yaml
文件中添加以下依赖项,同时还需要添加three_js_math
、three_js_core
和three_js_core_loaders
。
dependencies:
three_js_svg: ^x.x.x
three_js_math: ^x.x.x
three_js_core: ^x.x.x
three_js_core_loaders: ^x.x.x
然后初始化场景并加载SVG文件:
late Scene scene;
void init() {
scene = Scene();
scene.background = Color.fromHex32(0xf0f0f0);
final loader = SVGLoader();
final data = await loader.fromAsset('assets/${fileName}.svg');
List<ShapePath> paths = data!.paths;
Group group = Group();
group.scale.scale(0.25);
group.position.x = -25;
group.position.y = 25;
group.rotateZ(math.pi);
group.rotateY(math.pi);
//group.scale.y *= -1;
for (int i = 0; i < paths.length; i++) {
ShapePath path = paths[i];
final fillColor = path.userData?["style"]["fill"];
if (guiData["drawFillShapes"] == true && fillColor != null && fillColor != 'none') {
MeshBasicMaterial material = MeshBasicMaterial.fromMap({
"color":tmath.Color().setStyle(fillColor).convertSRGBToLinear(),
"opacity": path.userData?["style"]["fillOpacity"].toDouble(),
"transparent": true,
"side": tmath.DoubleSide,
"depthWrite": false,
"wireframe": guiData["fillShapesWireframe"]
});
final shapes = SVGLoader.createShapes(path);
for (int j = 0; j < shapes.length; j++) {
final shape = shapes[j];
ShapeGeometry geometry = ShapeGeometry([shape]);
Mesh mesh = Mesh(geometry, material);
group.add(mesh);
}
}
final strokeColor = path.userData?["style"]["stroke"];
if (guiData["drawStrokes"] == true &&
strokeColor != null &&
strokeColor != 'none') {
MeshBasicMaterial material = MeshBasicMaterial.fromMap({
"color":tmath.Color().setStyle(strokeColor).convertSRGBToLinear(),
"opacity": path.userData?["style"]["strokeOpacity"].toDouble(),
"transparent": true,
"side": tmath.DoubleSide,
"depthWrite": false,
"wireframe": guiData["strokesWireframe"]
});
for (int j = 0, jl = path.subPaths.length; j < jl; j++) {
Path subPath = path.subPaths[j];
final geometry = SVGLoader.pointsToStroke(subPath.getPoints(), path.userData?["style"]);
if (geometry != null) {
final mesh = Mesh(geometry, material);
group.add(mesh);
}
}
}
}
scene.add(group);
}
使用方法
这个项目是一个用于three.js的SVG模型加载器和导出器。
示例
可以在以下链接找到这个API的示例:这里。
示例代码
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:three_js_core/three_js_core.dart' as three;
import 'package:three_js_math/three_js_math.dart' as tmath;
import 'package:three_js_svg/three_js_svg.dart';
import 'package:three_js_helpers/three_js_helpers.dart';
import 'package:three_js_geometry/three_js_geometry.dart';
import 'package:three_js_curves/three_js_curves.dart';
import 'dart:math' as math;
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const WebglLoaderSvg(),
);
}
}
class WebglLoaderSvg extends StatefulWidget {
const WebglLoaderSvg({super.key});
[@override](/user/override)
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<WebglLoaderSvg> {
late three.ThreeJS threeJs;
[@override](/user/override)
void initState() {
threeJs = three.ThreeJS(
onSetupComplete: () { setState(() {}); },
setup: setup
);
super.initState();
}
[@override](/user/override)
void dispose() {
threeJs.dispose();
super.dispose();
}
[@override](/user/override)
Widget build(BuildContext context) {
return threeJs.build();
}
final guiData = {
"currentURL": 'assets/tiger.svg',
// "currentURL": 'assets/energy.svg',
// "currentURL": 'assets/hexagon.svg',
// "currentURL": 'assets/lineJoinsAndCaps.svg',
// "currentURL": 'assets/multiple-css-classes.svg',
// "currentURL": 'assets/threejs.svg',
// "currentURL": 'assets/zero-radius.svg',
"drawFillShapes": true,
"drawStrokes": true,
"fillShapesWireframe": false,
"strokesWireframe": false
};
Future<void> setup() async {
threeJs.camera = three.PerspectiveCamera(50, threeJs.width / threeJs.height, 1, 1000);
threeJs.camera.position.setValues(0, 0, 200);
loadSVG(guiData["currentURL"]);
}
void loadSVG(url) {
threeJs.scene = three.Scene();
threeJs.scene.background = tmath.Color.fromHex32(0xb0b0b0);
final helper = GridHelper(160, 10);
helper.rotation.x = math.pi / 2;
threeJs.scene.add(helper);
SVGLoader loader = SVGLoader();
loader.fromAsset(url).then((data) {
List<ShapePath> paths = data!.paths;
three.Group group = three.Group();
group.scale.scale(0.25);
group.position.x = -25;
group.position.y = 25;
group.rotateZ(math.pi);
group.rotateY(math.pi);
//group.scale.y *= -1;
for (int i = 0; i < paths.length; i++) {
ShapePath path = paths[i];
final fillColor = path.userData?["style"]["fill"];
if (guiData["drawFillShapes"] == true &&
fillColor != null &&
fillColor != 'none') {
three.MeshBasicMaterial material = three.MeshBasicMaterial.fromMap({
"color": tmath.Color().setStyle(fillColor).convertSRGBToLinear(),
"opacity": path.userData?["style"]["fillOpacity"],
"transparent": true,
"side": tmath.DoubleSide,
"depthWrite": false,
"wireframe": guiData["fillShapesWireframe"]
});
final shapes = SVGLoader.createShapes(path);
for (int j = 0; j < shapes.length; j++) {
final shape = shapes[j];
ShapeGeometry geometry = ShapeGeometry([shape]);
three.Mesh mesh = three.Mesh(geometry, material);
group.add(mesh);
}
}
final strokeColor = path.userData?["style"]["stroke"];
if (guiData["drawStrokes"] == true &&
strokeColor != null &&
strokeColor != 'none') {
three.MeshBasicMaterial material = three.MeshBasicMaterial.fromMap({
"color": tmath.Color().setStyle(strokeColor).convertSRGBToLinear(),
"opacity": path.userData?["style"]["strokeOpacity"],
"transparent": true,
"side": tmath.DoubleSide,
"depthWrite": false,
"wireframe": guiData["strokesWireframe"]
});
for (int j = 0, jl = path.subPaths.length; j < jl; j++) {
Path subPath = path.subPaths[j];
final geometry = SVGLoader.pointsToStroke(
subPath.getPoints(), path.userData?["style"]);
if (geometry != null) {
final mesh = three.Mesh(geometry, material);
group.add(mesh);
}
}
}
}
threeJs.scene.add(group);
});
}
}
更多关于Flutter三维图形与SVG渲染插件three_js_svg的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter三维图形与SVG渲染插件three_js_svg的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
在Flutter中,虽然three_js_svg
并不是一个广泛认知或官方支持的库,用于直接结合Three.js和SVG渲染,但我们可以通过一些方法实现三维图形和SVG的渲染。Flutter本身没有直接支持Three.js的插件,但可以通过平台通道(Platform Channels)与原生代码(如Android的Java/Kotlin或iOS的Swift/Objective-C)进行交互,从而使用Three.js进行渲染。
以下是一个大致的思路和代码示例,展示如何在Flutter中嵌入一个使用Three.js渲染的WebView,同时展示如何在Flutter中单独渲染SVG。请注意,这不会直接结合Three.js和SVG,但可以作为实现各自功能的基础。
1. 使用WebView加载Three.js渲染的内容
首先,确保你的Flutter项目中包含webview_flutter
插件:
dependencies:
flutter:
sdk: flutter
webview_flutter: ^3.0.4 # 请检查最新版本
然后,在你的Flutter应用中创建一个WebView来加载包含Three.js渲染的HTML页面:
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Three.js in WebView'),
),
body: WebViewExample(),
),
);
}
}
class WebViewExample extends StatefulWidget {
@override
_WebViewExampleState createState() => _WebViewExampleState();
}
class _WebViewExampleState extends State<WebViewExample> {
late WebViewController _controller;
@override
Widget build(BuildContext context) {
return WebView(
initialUrl: Uri.dataFromString(
'''
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Three.js Example</title>
<style>body { margin: 0; }</style>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script>
// Three.js rendering code here
let scene, camera, renderer, cube;
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
let geometry = new THREE.BoxGeometry();
let material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
cube = new THREE.Mesh(geometry, material);
scene.add(cube);
camera.position.z = 5;
animate();
}
function animate() {
requestAnimationFrame(animate);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
init();
</script>
</body>
</html>
''',
mimeType: 'text/html',
encoding: Encoding.getByName('utf-8')
).toString(),
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webViewController) {
_controller = webViewController;
},
);
}
}
2. 在Flutter中渲染SVG
对于SVG的渲染,可以使用flutter_svg
插件:
dependencies:
flutter:
sdk: flutter
flutter_svg: ^1.0.3 # 请检查最新版本
在你的Flutter应用中渲染一个SVG文件:
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('SVG Rendering'),
),
body: Center(
child: SvgPicture.asset(
'assets/sample.svg', // 确保在pubspec.yaml中声明了assets
width: 200,
height: 200,
),
),
),
);
}
}
在pubspec.yaml
中声明SVG资源:
flutter:
assets:
- assets/sample.svg
总结
虽然直接在Flutter中使用three_js_svg
这样的库来结合Three.js和SVG渲染并不现实,但通过上述方法,你可以在Flutter应用中分别实现Three.js的三维图形渲染和SVG的渲染。如果需要更复杂的交互或结合,可能需要更深入的自定义开发,比如通过平台通道在原生代码中实现更复杂的功能,并在Flutter中调用这些功能。