Flutter三维变换控制插件three_js_transform_controls的使用

Flutter三维变换控制插件three_js_transform_controls的使用

Gif of Archball controls.

three_js_transform_controls 是一个用于在 Flutter 中添加三维变换控制的插件。它允许用户在项目中添加弧球控制器或变换控制器。

获取开始

要开始使用该插件,请将其添加到您的 pubspec.yaml 文件中,并确保同时引入 three_js_math, three_js_core 和其他必要的 three_js_(loader type) 库。

dependencies:
  three_js_transform_controls: ^版本号
  three_js_math: ^版本号
  three_js_core: ^版本号

初始化控制器

首先,我们需要初始化控制器并监听变化事件。

late ArcballControls controls;

void initControls() {
  controls = ArcballControls(camera, _globalKey, scene, 1);
  controls.addEventListener('change', (event) {
    render();
  });
}

void update() {
  controls.update();
}

使用示例

以下是一个完整的示例代码,展示了如何在 Flutter 项目中使用 three_js_transform_controls 插件。

import 'package:flutter/material.dart';
import 'package:three_js_transform_controls/three_js_transform_controls.dart';
import 'package:three_js_core/three_js_core.dart' as three;
import 'package:three_js_math/three_js_math.dart' as tmath;

import 'dart:math' as math;
import 'dart:async';
import 'package:flutter/services.dart';

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 MiscControlsArcball(),
    );
  }
}

class MiscControlsArcball extends StatefulWidget {
  const MiscControlsArcball({super.key});

  [@override](/user/override)
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MiscControlsArcball> {
  late three.ThreeJS threeJs;
  late TransformControls control;
  late ArcballControls orbit;
  late three.PerspectiveCamera cameraPersp;
  
  [@override](/user/override)
  void initState() {
    threeJs = three.ThreeJS(
      onSetupComplete: (){setState(() {});},
      setup: setup,
    );
    super.initState();
  }

  [@override](/user/override)
  void dispose() {
    threeJs.dispose();
    control.dispose();
    orbit.clearListeners();
    super.dispose();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return threeJs.build();
  }

  Future<void> setup() async {
    final aspect = threeJs.width / threeJs.height;
    cameraPersp = three.PerspectiveCamera(50, aspect, 0.1, 100);
    threeJs.camera = cameraPersp;

    threeJs.camera.position.setValues(5, 2.5, 5);

    threeJs.scene = three.Scene();

    final ambientLight = three.AmbientLight(0xffffff, 0.3);
    threeJs.scene.add(ambientLight);

    final light = three.DirectionalLight(0xffffff, 0.3);
    light.position = threeJs.camera.position;
    threeJs.scene.add(light);

    final geometry = three.BoxGeometry();
    final material = three.MeshLambertMaterial.fromMap();

    orbit = ArcballControls(threeJs.camera, threeJs.globalKey);
    orbit.update();
    orbit.addEventListener('change', (event) {
      threeJs.render();
    });

    control = TransformControls(threeJs.camera, threeJs.globalKey);
    control.addEventListener('change', (event) {
      threeJs.render();
    });

    control.addEventListener('dragging-changed', (event) {
      orbit.enabled = !event.value;
    });

    final mesh = three.Mesh(geometry, material);
    threeJs.scene.add(mesh);

    control.attach(mesh);
    threeJs.scene.add(control);

    threeJs.domElement.addEventListener(
      three.PeripheralType.resize,
      threeJs.onWindowResize
    );

    threeJs.domElement.addEventListener(three.PeripheralType.keydown, (event) {
      event as LogicalKeyboardKey;
      switch (event.keyLabel.toLowerCase()) {
        case 'q':
          control.setSpace(control.space == 'local' ? 'world' : 'local');
          break;
        case 'shift right':
        case 'shift left':
          control.setTranslationSnap(1);
          control.setRotationSnap(tmath.MathUtils.degToRad(15));
          control.setScaleSnap(0.25);
          break;
        case 'w':
          control.setMode(GizmoType.translate);
          break;
        case 'e':
          control.setMode(GizmoType.rotate);
          break;
        case 'r':
          control.setMode(GizmoType.scale);
          break;
        case 'c':
          final position = threeJs.camera.position.clone();

          threeJs.camera = cameraPersp;
          threeJs.camera.position.setFrom(position);

          control.camera = threeJs.camera;

          threeJs.camera.lookAt(orbit.target);
          threeJs.onWindowResize(context);
          break;
        case 'v':
          final randomFoV = math.Random().nextDouble() + 0.1;
          final randomZoom = math.Random().nextDouble() + 0.1;

          cameraPersp.fov = randomFoV * 160;

          cameraPersp.zoom = randomZoom * 5;
          threeJs.onWindowResize(context);
          break;
        case '+':
        case '=':
          control.setSize(control.size + 0.1);
          break;
        case '-':
        case '_':
          control.setSize(math.max(control.size - 0.1, 0.1));
          break;
        case 'x':
          control.showX = !control.showX;
          break;
        case 'y':
          control.showY = !control.showY;
          break;
        case 'z':
          control.showZ = !control.showZ;
          break;
        case ' ':
          control.enabled = !control.enabled;
          break;
        case 'escape':
          //control.reset();
          break;
      }
    });

    threeJs.domElement.addEventListener(three.PeripheralType.keyup, (event) {
      event as LogicalKeyboardKey;
      switch (event.keyLabel.toLowerCase()) {
        case 'shift right':
        case 'shift left':
          control.setTranslationSnap(null);
          control.setRotationSnap(null);
          control.setScaleSnap(null);
          break;
      }
    });
  }
}

更多关于Flutter三维变换控制插件three_js_transform_controls的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter三维变换控制插件three_js_transform_controls的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter中使用three_js_transform_controls插件来实现三维变换控制的示例代码。请注意,由于Flutter本身并不直接支持Three.js,通常我们会使用flutter_three或者类似的插件来在Flutter中集成Three.js。不过,直接用于Three.js的transform_controls插件在Flutter生态中并不常见,因此这里将提供一个较为通用的思路,并结合Three.js的transform_controls来展示如何在Web平台(通过Flutter的Web支持)实现这一功能。

首先,确保你的Flutter项目已经配置了Web支持。

  1. 创建Flutter项目并添加Web支持

    flutter create my_threejs_app
    cd my_threejs_app
    flutter config --enable-web
    
  2. 添加flutter_web_plugin依赖(如果需要的话,用于与Web平台交互,但这里我们主要依赖Three.js,所以可能不需要这个插件,仅作为参考):

    dependencies:
      flutter:
        sdk: flutter
      flutter_web_plugin: ^0.0.0+1  # 这是一个示例,具体依赖根据实际情况调整
    
  3. web目录下创建index.html并引入Three.js(如果你使用的是Flutter的Web插件,通常不需要手动修改这个文件,但这里为了直接引入Three.js,我们手动添加):

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>Flutter Three.js App</title>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
        <script src="https://threejs.org/examples/js/controls/TransformControls.js"></script>
    </head>
    <body>
        <script>
            // 这里将放置Three.js的初始化代码
        </script>
        <div id="flutter_web_container"></div>
        <script src="main.dart.js" defer></script>
    </body>
    </html>
    
  4. lib目录下创建并修改main.dart文件

    由于Flutter与Three.js的直接交互需要通过JavaScript接口,我们可以使用dart:html库来与Web内容进行交互。以下是一个简化的示例,展示如何在Flutter Web中集成Three.js,并使用TransformControls

    import 'dart:html' as html;
    import 'dart:js' as js;
    
    void main() {
      // 初始化Flutter应用
      html.window.onLoad.listen((_) {
        // 通过JavaScript调用Three.js
        js.context.callMethod('eval', ['''
          // Three.js 初始化代码
          var scene = new THREE.Scene();
          var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
          var renderer = new THREE.WebGLRenderer();
          renderer.setSize(window.innerWidth, window.innerHeight);
          document.body.appendChild(renderer.domElement);
    
          var geometry = new THREE.BoxGeometry();
          var material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
          var cube = new THREE.Mesh(geometry, material);
          scene.add(cube);
    
          camera.position.z = 5;
    
          var controls = new THREE.TransformControls(camera, renderer.domElement);
          controls.addEventListener('change', function () {
            renderer.render(scene, camera);
          });
          scene.add(controls);
    
          var animate = function () {
            requestAnimationFrame(animate);
            controls.update();
            renderer.render(scene, camera);
          };
    
          animate();
    
          // 暴露给Dart的函数,用于与Flutter交互
          window.dartThreeJSInit = function() {
            console.log("Three.js initialized from Dart!");
          };
        ''']);
    
        // 调用暴露的函数,验证集成
        js.context.callMethod('dartThreeJSInit', []);
      });
    
      // Flutter UI代码(这里可以添加你的Flutter Widget,但在这个示例中我们主要关注Three.js)
    }
    

请注意,这个示例代码主要是为了展示如何在Flutter Web项目中集成Three.js,并使用TransformControls进行三维变换控制。在实际应用中,你可能需要更复杂的逻辑来处理Flutter与Three.js之间的交互,包括事件处理、数据传递等。此外,由于Flutter本身是一个跨平台框架,而Three.js主要运行在Web上,因此在实际项目中,你可能需要考虑平台差异和性能优化。

回到顶部