如何使用flutter_cube实现球体按特定角度持续旋转?
解决flutter_cube中使用updateTransform实现球体持续旋转的问题
问题分析
你当前的代码里直接在每帧给ball.rotation.x和y累加固定角度值,再调用updateTransform却无效,核心原因有两点:
- 未基于**时间增量(deltaTime)**计算角度增量,导致旋转速度不受控,还可能因帧速率波动出现异常
flutter_cube的updateTransform是通过rotation的绝对角度值生成变换矩阵,但你需要确保更新后的rotation能正确驱动矩阵更新,同时场景能感知到变换变化
修正方案
1. 基于时间增量计算旋转角度
把固定角度累加改成基于每帧的时间差计算增量,保证旋转速度稳定。同时明确rotation存储的是角度值(因为updateTransform内部会用radians()转成弧度)。
2. 确保场景刷新
调用updateTransform后,需要通知场景更新变换,或者通过setState触发组件重绘,让Cube组件感知到对象变换的变化。
修正后的完整代码
import 'package:flutter/material.dart'; import 'package:flutter_cube/flutter_cube.dart'; import 'package:flutter/scheduler.dart'; import 'dart:math'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar( title: const Text('Pool'), ), body: const Stack( children: [_Scene()], ), backgroundColor: Color.fromARGB(255, 13, 104, 250), ), ); } } class _Scene extends StatefulWidget { const _Scene(); @override _SceneState createState() => _SceneState(); } class _SceneState extends State<_Scene> with TickerProviderStateMixin { late Object ball; late Scene _scene; late Ticker _ticker; // 旋转速度(度/秒) final double rotationSpeed = 90.0; // 记录上次帧时间,用于计算时间增量 DateTime? _lastFrameTime; @override void initState() { super.initState(); _ticker = createTicker((elapsed) => _update(elapsed)); _ticker.start(); ball = Object(fileName: 'assets/ball.obj'); ball.scale.setValues(1, 1, 1); // 初始化rotation值 ball.rotation.setValues(0, 0, 0); } void _update(Duration elapsed) { final currentTime = DateTime.now(); if (_lastFrameTime == null) { _lastFrameTime = currentTime; return; } // 计算时间增量(秒) double delta = currentTime.difference(_lastFrameTime!).inMilliseconds / 1000.0; _lastFrameTime = currentTime; _updateBallPosition(delta); // 触发重绘,让Cube组件感知对象变换 setState(() {}); } void _updateBallPosition(double deltaTime) { // 基于时间增量计算角度增量 double angleDelta = rotationSpeed * deltaTime; // 更新对角线旋转角度(同时绕X和Y轴旋转) ball.rotation.x += angleDelta; ball.rotation.y += angleDelta; // 更新变换矩阵 ball.updateTransform(); // 直接通知场景更新,确保变换立即生效 _scene.update(); } @override void dispose() { _ticker.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Stack( children: [ Cube( onSceneCreated: (Scene scene) { _scene = scene; scene.world.add(ball); scene.camera.fov = 50; scene.world.scene!.camera.position.setValues(0, 0, 10); }, interactive: false, ), ], ); } }
关键修改点
- 新增
_lastFrameTime记录上一帧时间,计算时间增量(deltaTime),保证旋转速度在不同帧率下一致 - 将旋转角度累加改为基于
rotationSpeed * deltaTime的增量计算,避免角度疯涨和速度不稳定 - 调整
_update方法,使用实际时间差替代固定的16ms假设 - 在
_updateBallPosition中调用ball.updateTransform()后,同时调用_scene.update()确保场景立即刷新变换 - 初始化
ball.rotation的初始值,避免未定义的初始状态
自定义对角线旋转轴的补充
如果需要绕任意自定义对角线轴旋转,可以通过Quaternion直接构建旋转,再同步到对象的变换中:
// 示例:绕自定义对角线轴(1,1,0)旋转 void _updateBallPosition(double deltaTime) { double angleDelta = rotationSpeed * deltaTime; // 创建绕(1,1,0)轴旋转的四元数 Quaternion rotationQuat = Quaternion.axisAngle(Vector3(1,1,0), radians(angleDelta)); // 将当前旋转与新旋转叠加 ball.transform.rotateQuaternion(rotationQuat); // 同步rotation值到transform,保持两者状态一致 ball.rotation.setFromQuaternion(ball.transform.rotation); ball.updateTransform(); _scene.update(); }
内容的提问来源于stack exchange,提问作者Jhevi P.
相关产品推荐
相关产品推荐

