Flutter 3D渲染插件simple_3d_renderer的使用
Flutter 3D渲染插件simple_3d_renderer的使用
概述
simple_3d_renderer
是一个用于渲染 Sp3dObj
的Flutter插件。Sp3dObj
是一种为科学用途创建的简单3D格式,主要用于科学家使用。请参考以下需要一起使用的包:
如果你希望在直接编辑 Sp3dObj
的应用程序中实现撤销/重做功能,你可以使用以下包:
此外,虽然这是一个非常实验性的项目,但也有将其他3D格式转换为 Sp3dObj
的包。不过由于 Sp3dObj
主要用于科学目的,在功能上有显著差异,因此只支持最小兼容性。
使用方法
示例代码
import 'package:flutter/material.dart';
import 'package:simple_3d/simple_3d.dart';
import 'package:util_simple_3d/util_simple_3d.dart';
import 'package:simple_3d_renderer/simple_3d_renderer.dart';
void main() async {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
State<StatefulWidget> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late List<Sp3dObj> objs = [];
late Sp3dWorld world;
bool isLoaded = false;
@override
void initState() {
super.initState();
// 创建 Sp3dObj.
Sp3dObj obj = UtilSp3dGeometry.cube(200, 200, 200, 4, 4, 4);
obj.materials.add(FSp3dMaterial.green.deepCopy());
obj.fragments[0].faces[0].materialIndex = 1;
obj.materials[0] = FSp3dMaterial.grey.deepCopy()
..strokeColor = const Color.fromARGB(255, 0, 0, 255);
obj.rotate(Sp3dV3D(1, 1, 0).nor(), 30 * 3.14 / 180);
objs.add(obj);
loadImage();
}
void loadImage() async {
world = Sp3dWorld(objs);
world.initImages().then((List<Sp3dObj> errorObjs) {
setState(() {
isLoaded = true;
});
});
}
@override
Widget build(BuildContext context) {
if (!isLoaded) {
return MaterialApp(
title: 'Sp3dRenderer',
home: Scaffold(
appBar: AppBar(
backgroundColor: const Color.fromARGB(255, 0, 255, 0),
),
backgroundColor: const Color.fromARGB(255, 33, 33, 33),
body: Container(),
),
);
} else {
return MaterialApp(
title: 'Sp3dRenderer',
home: Scaffold(
appBar: AppBar(
backgroundColor: const Color.fromARGB(255, 0, 255, 0),
),
backgroundColor: const Color.fromARGB(255, 33, 33, 33),
body: Column(
children: [
Sp3dRenderer(
const Size(800, 800),
const Sp3dV2D(400, 400),
world,
// 如果你想减少失真,可以远距离高倍率拍摄。
Sp3dCamera(Sp3dV3D(0, 0, 3000), 6000),
Sp3dLight(Sp3dV3D(0, 0, -1), syncCam: true),
),
],
),
),
);
}
}
}
使用图片文件
例如,修改示例代码如下(*注意,为了简化起见保留了一些不必要的参数):
sample_image.png
// 修改initState中的立方体。
Sp3dObj obj = UtilSp3dGeometry.cube(200,200,200,1,1,1);
--------------------------------------------------------------------
// 修改函数
void loadImage() async {
this.objs[0].fragments[0].faces[0].materialIndex=1;
this.objs[0].fragments[0].faces[1].materialIndex=1;
this.objs[0].fragments[0].faces[2].materialIndex=1;
this.objs[0].fragments[0].faces[3].materialIndex=1;
this.objs[0].materials[1].imageIndex = 0;
// 你可以在项目的assets/images文件夹下添加图片,并在pubspec.yaml中添加资源路径来使用图片。
// 对于Flutter Web,还需要将其复制到你的web文件夹中。
this.objs[0].images.add(await _readFileBytes("./assets/images/sample_image.png"));
this.world = Sp3dWorld(objs);
this.world.initImages().then(
(List<Sp3dObj> errorObjs){
setState(() {
this.isLoaded = true;
});
}
);
}
// 添加函数
Future<Uint8List> _readFileBytes(String filePath) async {
ByteData bd = await rootBundle.load(filePath);
return bd.buffer.asUint8List(bd.offsetInBytes,bd.lengthInBytes);
}
处理用户触摸事件
例如,修改示例代码如下:
// 在_MyAppState中添加变量。
ValueNotifier<int> vn = ValueNotifier<int>(0);
--------------------------------------------------------------------
// 重写Sp3dRenderer。
Sp3dRenderer(
const Size(800, 800),
const Sp3dV2D(400, 400),
world,
// 如果你想减少失真,可以远距离高倍率拍摄。
Sp3dCamera(Sp3dV3D(0, 0, 30000), 60000),
Sp3dLight(Sp3dV3D(0, 0, -1), syncCam: true),
allowUserWorldRotation: true,
checkTouchObj: true,
vn: vn,
onPanDown: (Sp3dGestureDetails d, Sp3dFaceObj? info){
print("onPanDown");
if(info!=null) {
info.obj.move(Sp3dV3D(50, 0, 0));
vn.value++;
}
},
onPanCancel: (){
print("onPanCancel");
},
onPanStart: (Sp3dGestureDetails d){
print("onPanStart");
print(d.toOffset());
},
onPanUpdate: (Sp3dGestureDetails d){
print("onPanUpdate");
print(d.toOffset());
},
onPanEnd: (Sp3dGestureDetails d){
print("onPanEnd");
},
onPinchStart: (Sp3dGestureDetails d){
print("onPinchStart");
print(d.diffV);
},
onPinchUpdate: (Sp3dGestureDetails d){
print("onPinchUpdate");
print(d.diffV);
},
onPinchEnd: (Sp3dGestureDetails d){
print("onPinchEnd");
print(d.diffV);
},
onMouseScroll: (Sp3dGestureDetails d){
print("onMouseScroll");
print(d.diffV);
},
)
保存或恢复 Sp3dWorld
如果你想保存或恢复多个 Sp3dObj
及其位置,Sp3dWorld
也提供了 toDict
和 fromDict
方法。保存时建议使用 .s3dw
扩展名以避免混淆。
性能
在使用 CPU Ryzen5 5600 进行测试时,考虑了在调试模式和Web浏览器上绘制所需的时间。存在一些速度问题,如在CPU上运行且是单线程的。对于实时渲染,大约1000个立方体(8000个顶点)是一个极限,超过这个数量会变得沉重。
- 100个立方体:338.6 fps(800个顶点)
- 1000个立方体:34.1 fps
- 2500个立方体:13.6 fps
请注意,不是所有对象都能表现得同样好,因为加速逻辑的存在。对于顶点较多的模型(如球体),能够舒适操作的数量要小得多。
版本控制
C部分将在版本升级时更改。
- 添加变量、结构变化导致读取以前文件出现问题等重大变更:C.X.X
- 添加方法等:X.C.X
- 小的变更和错误修复:X.X.C
许可证
此软件根据MIT许可证发布,请参阅LICENSE文件。
版权声明
“Dart”名称和“Flutter”名称是Google LLC的商标。 *该包的开发者不是Google LLC。
更多关于Flutter 3D渲染插件simple_3d_renderer的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter 3D渲染插件simple_3d_renderer的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是如何在Flutter项目中使用simple_3d_renderer
插件进行3D渲染的示例代码。这个插件允许你在Flutter应用中进行基本的3D图形渲染。
1. 添加依赖
首先,在你的pubspec.yaml
文件中添加simple_3d_renderer
依赖:
dependencies:
flutter:
sdk: flutter
simple_3d_renderer: ^最新版本号 # 请替换为实际发布的最新版本号
然后运行flutter pub get
来安装依赖。
2. 导入插件
在你的Dart文件中导入simple_3d_renderer
:
import 'package:simple_3d_renderer/simple_3d_renderer.dart';
3. 初始化3D渲染器
在你的Flutter应用中,你需要一个Simple3DRendererWidget
来显示3D内容。下面是一个简单的例子,展示了如何初始化并显示一个3D立方体。
import 'package:flutter/material.dart';
import 'package:simple_3d_renderer/simple_3d_renderer.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Simple 3D Renderer Example'),
),
body: Center(
child: Simple3DRendererWidget(
width: 400,
height: 400,
renderer: My3DRenderer(),
),
),
),
);
}
}
class My3DRenderer extends Simple3DRenderer {
@override
void onDrawFrame(Canvas3D canvas) {
// 清除画布
canvas.clear(Colors.white);
// 设置视角矩阵
Matrix4 perspectiveMatrix = Matrix4.identity();
perspectiveMatrix.setPerspective(
fovy: 45.0 * (Math.PI / 180.0),
aspect: canvas.width / canvas.height,
zNear: 0.1,
zFar: 100.0,
);
// 设置视图矩阵
Matrix4 viewMatrix = Matrix4.identity();
viewMatrix.translate(Vector3(-0.0, 0.0, -5.0));
// 设置模型矩阵(立方体)
Matrix4 modelMatrix = Matrix4.identity();
modelMatrix.scale(Vector3(1.0, 1.0, 1.0));
// 组合矩阵
Matrix4 mvpMatrix = perspectiveMatrix * viewMatrix * modelMatrix;
// 绘制立方体
drawCube(canvas, mvpMatrix);
}
void drawCube(Canvas3D canvas, Matrix4 mvpMatrix) {
// 定义立方体的顶点位置和颜色
List<float> vertices = [
// 顶点位置(x, y, z)
-1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0,
-1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0,
// 顶点颜色(r, g, b, a)
1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0,
1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0,
];
// 定义立方体的索引(用于连接顶点形成面)
List<int> indices = [
0, 1, 2, 0, 2, 3, // 前面
4, 5, 6, 4, 6, 7, // 后面
0, 1, 5, 0, 5, 4, // 左面
2, 3, 7, 2, 7, 6, // 右面
0, 3, 7, 0, 7, 4, // 上面
1, 2, 6, 1, 6, 5, // 下面
];
// 绘制立方体
canvas.drawIndexedTriangles(
vertices: vertices,
indices: indices,
vertexStride: 6, // 每个顶点6个值(3个位置 + 3个颜色)
indexStride: 1,
modelViewProjectionMatrix: mvpMatrix,
);
}
}
4. 运行应用
现在你可以运行你的Flutter应用,应该会看到一个简单的3D立方体在屏幕上显示。
注意事项
simple_3d_renderer
是一个简化的3D渲染插件,适用于基本的3D图形渲染。如果需要更复杂的3D渲染功能,可能需要考虑使用更专业的3D引擎,比如Flutter的flutter_three
或原生平台的OpenGL/Vulkan等。- 确保你理解3D图形的基本概念,比如矩阵变换、顶点着色器和片段着色器等,以便更好地利用这个插件。
希望这个示例能帮助你在Flutter项目中成功使用simple_3d_renderer
插件进行3D渲染!