three_js_urdf_parser 0.1.0
three_js_urdf_parser: ^0.1.0 copied to clipboard
A urdf parser extension for three_dart that also includes a dae/stl loader.
import 'dart:async';
import 'dart:math';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:three_js/three_js.dart' as three;
import 'package:three_js_urdf_parser/three_js_urdf_parser.dart';
void main(List<String> args) {
runApp(
const MaterialApp(
debugShowCheckedModeBanner: false,
home: ExamplePage(),
),
);
}
class ExamplePage extends StatefulWidget {
const ExamplePage({Key? key}) : super(key: key);
@override
State<ExamplePage> createState() => _ExamplePageState();
}
class _ExamplePageState extends State<ExamplePage> with WidgetsBindingObserver {
bool loading = true;
late three.ThreeJS threeJs;
URDFRobot? robot;
@override
void initState() {
Future.delayed(const Duration(seconds: 1), () {
setState(() {
loading = false;
});
threeJs = three.ThreeJS(
onSetupComplete: () {
setState(() {});
},
setup: setup,
);
});
super.initState();
}
@override
void dispose() {
threeJs.dispose();
three.loading.clear();
super.dispose();
}
FutureOr<void> setup() async {
threeJs.scene = three.Scene();
threeJs.scene.autoUpdate = true;
threeJs.scene.background = three.Color(204, 204, 204);
threeJs.camera = three.PerspectiveCamera(60, threeJs.width / threeJs.height, 1, 2000);
threeJs.camera.position.setValues(200, 100, 0);
final ambientLight = three.AmbientLight(0xffffff, 0.3);
threeJs.scene.add(ambientLight);
final pointLight = three.PointLight(0xffffff, 0.1);
pointLight.position.setValues(0, 0, 0);
threeJs.camera.add(pointLight);
threeJs.scene.add(threeJs.camera);
threeJs.camera.lookAt(threeJs.scene.position);
// --- Controls ---
var controls = three.OrbitControls(threeJs.camera, threeJs.globalKey);
controls.enableDamping = true; // an animation loop is required when either damping or auto-rotation are enabled
controls.dampingFactor = 0.05;
controls.screenSpacePanning = false;
controls.minDistance = 10;
controls.maxDistance = 1000;
// --- World ---
// axis
three.Mesh xMesh = three.Mesh(
three.CylinderGeometry(0.5, 0.5, 100), three.MeshPhongMaterial({three.MaterialProperty.color: 0xff0000, three.MaterialProperty.flatShading: false}));
xMesh.position = three.Vector3(60, 0, 0);
xMesh.setRotationFromEuler(three.Euler(0, 0, pi / 2));
threeJs.scene.add(xMesh);
three.Mesh yMesh = three.Mesh(
three.CylinderGeometry(0.5, 0.5, 100), three.MeshPhongMaterial({three.MaterialProperty.color: 0x00ff00, three.MaterialProperty.flatShading: false}));
yMesh.position = three.Vector3(0, 60, 0);
threeJs.scene.add(yMesh);
three.Mesh zMesh = three.Mesh(
three.CylinderGeometry(0.5, 0.5, 100), three.MeshPhongMaterial({three.MaterialProperty.color: 0x0000ff, three.MaterialProperty.flatShading: false}));
zMesh.position = three.Vector3(0, 0, 60);
zMesh.setRotationFromEuler(three.Euler(pi / 2, 0, 0));
threeJs.scene.add(zMesh);
// URDF
robot = await URDFLoader.parse(
"assets/T12/urdf/T12.URDF",
"assets/T12",
URDFLoaderOptions(
materialCb: (linkName, visualNode, material) {
return three.MeshStandardMaterial({
three.MaterialProperty.color: material.color,
three.MaterialProperty.flatShading: material.flatShading,
three.MaterialProperty.roughness: 0.3,
three.MaterialProperty.metalness: 0.8,
});
},
),
);
robot!.transform.scale = three.Vector3(30, 30, 30);
// robot!.transform.printHierarchy();
threeJs.scene.add(robot!.getObject());
// --- Lights ---
var dirLight1 = three.DirectionalLight(0xffffff);
dirLight1.position.setValues(30, 30, 30);
threeJs.scene.add(dirLight1);
var dirLight2 = three.DirectionalLight(0x3C8488);
dirLight2.position.setValues(-30, -30, -30);
threeJs.scene.add(dirLight2);
threeJs.addAnimationEvent(
(dt) {
controls.update();
animate();
},
);
}
void animate() {
if (robot == null) {
return;
}
int t1 = DateTime.now().millisecondsSinceEpoch;
double time = t1 / 3e2;
// robot animation
for (int i = 1; i <= 6; i++) {
double offset = i * pi / 3;
double ratio = max(0, sin(time + offset));
robot!.trySetAngle("HP$i", lerpDouble(30, 0, ratio)! * three.MathUtils.deg2rad);
robot!.trySetAngle("KP$i", lerpDouble(90, 150, ratio)! * three.MathUtils.deg2rad);
robot!.trySetAngle("AP$i", lerpDouble(-30, -60, ratio)! * three.MathUtils.deg2rad);
robot!.trySetAngle("TC${i}A", lerpDouble(0, 0.065, ratio)!);
robot!.trySetAngle("TC${i}B", lerpDouble(0, 0.065, ratio)!);
robot!.trySetAngle("W$i", t1 * 0.000001);
}
threeJs.render();
}
@override
Widget build(BuildContext context) => loading ? const Center(child: CircularProgressIndicator()) : threeJs.build();
}