Flutter 3D文本渲染插件three_js_text的使用

发布于 1周前 作者 gougou168 来自 Flutter

Flutter 3D 文本渲染插件 three_js_text 的使用

three_js_text

Pub 版本 分析 许可证: MIT

这是一个允许用户在其项目中添加视觉文本的 three_js API。

文字图片

这是由 @mrdoob 创建的 three.js 和 three_dart 的 Dart 转换版本,并且有一个由 @wasabia 维护的 Dart 分支。

使用

此 API 允许用户向其 three_js 项目中添加文本。

贡献

欢迎贡献。 如果遇到任何问题,请查看 现有问题,如果没有找到与您的问题相关的,请打开一个新问题。 在进行非简单修复之前,请先创建一个问题。 对于简单的修复,可以直接提交拉取请求。


示例代码

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_text/three_js_text.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 WebglGeometryText(),
    );
  }
}

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

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

class _MyAppState extends State<WebglGeometryText> {
  late three.ThreeJS threeJs;

  [@override](/user/override)
  void initState() {
    threeJs = three.ThreeJS(
      onSetupComplete: () { setState(() {}); },
      setup: setup,
      settings: three.Settings(
        renderOptions: {
          "minFilter": tmath.LinearFilter,
          "magFilter": tmath.LinearFilter,
          "format": tmath.RGBAFormat,
          "samples": 4
        }
      ),
    );
    super.initState();
  }

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

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

  late three.Group group;
  late three.GroupMaterial materials;

  Future<void> setup() async {
    // 摄像机

    threeJs.camera = three.PerspectiveCamera(30, threeJs.width / threeJs.height, 1, 1500);
    threeJs.camera.position.setValues(0, 400, 700);

    final cameraTarget = tmath.Vector3(0, 50, 0);
    threeJs.camera.lookAt(cameraTarget);

    // 场景

    threeJs.scene = three.Scene();
    threeJs.scene.background = tmath.Color.fromHex32(0x000000);
    threeJs.scene.fog = three.Fog(0x000000, 250, 1400);

    // 灯光

    final dirLight = three.DirectionalLight(0xffffff, 0.125);
    dirLight.position.setValues(0, 0, 1).normalize();
    threeJs.scene.add(dirLight);

    final pointLight = three.PointLight(0xffffff, 1.5);
    pointLight.position.setValues(0, 100, 90);
    threeJs.scene.add(pointLight);

    // 加载字体

    final font = await loadFont();

    createText(font);

    // 添加平面

    final plane = three.Mesh(
      three.PlaneGeometry(10000, 10000),
      three.MeshBasicMaterial.fromMap({"color": 0xffffff, "opacity": 0.5, "transparent": true})
    );

    plane.position.y = -100;
    plane.rotation.x = -math.pi / 2;
    threeJs.scene.add(plane);
  }

  Future<TYPRFont> loadFont() async {
    final loader = TYPRLoader();
    final font = await loader.fromAsset("assets/pingfang.ttf");
    loader.dispose();

    return font!;
  }

  void createText(font) {
    String text = "Three_JS";
    
    double fontHeight = 20,
      size = 70,
      hover = 30,
      bevelThickness = 2,
      bevelSize = 1.5;

    int curveSegments = 4;
    bool bevelEnabled = true;
    bool mirror = true;

    final textGeo = TextGeometry(text, TextGeometryOptions(
      font: font,
      size: size,
      depth: fontHeight,
      curveSegments: curveSegments,
      bevelThickness: bevelThickness,
      bevelSize: bevelSize,
      bevelEnabled: bevelEnabled
    ));

    textGeo.computeBoundingBox();

    final centerOffset =
        -0.5 * (textGeo.boundingBox!.max.x - textGeo.boundingBox!.min.x);

    final textMesh1 = three.Mesh(textGeo, materials);

    textMesh1.position.x = centerOffset;
    textMesh1.position.y = hover;
    textMesh1.position.z = 0;

    textMesh1.rotation.x = 0;
    textMesh1.rotation.y = math.pi * 2;

    group.add(textMesh1);

    if (mirror) {
      final textMesh2 = three.Mesh(textGeo, materials);

      textMesh2.position.x = centerOffset;
      textMesh2.position.y = -hover;
      textMesh2.position.z = threeJs.height;

      textMesh2.rotation.x = math.pi;
      textMesh2.rotation.y = math.pi * 2;

      group.add(textMesh2);
    }
  }
}

更多关于Flutter 3D文本渲染插件three_js_text的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter 3D文本渲染插件three_js_text的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter中实现3D文本渲染可以通过结合使用three_js_text插件和Three.js库来完成。虽然Flutter本身不直接支持Three.js,但你可以通过平台通道(Platform Channels)或者通过Webview来嵌入Three.js的功能。不过,请注意,three_js_text并不是官方或广泛认可的Flutter插件名称,因此这里我将展示如何使用Three.js在Flutter的Web平台上渲染3D文本的一个基本示例。

首先,你需要确保你的Flutter项目支持Web平台。如果还没有设置,可以通过以下命令添加Web支持:

flutter config --enable-web

然后,在pubspec.yaml文件中确保添加了flutter_web_plugins依赖(尽管Flutter Web现在通常自动处理这些依赖,但检查一下总是好的):

dependencies:
  flutter:
    sdk: flutter
  flutter_web_plugins:
    sdk: flutter

接下来,我们将使用flutter_webview_plugin(或类似的Webview插件)来加载包含Three.js和3D文本渲染代码的HTML页面。以下是一个简化的步骤:

  1. 添加flutter_webview_plugin依赖

pubspec.yaml中添加:

dependencies:
  flutter_webview_plugin: ^0.4.0 # 请检查最新版本号
  1. 创建一个包含Three.js和3D文本渲染代码的HTML文件

创建一个名为assets/threejs_text.html的文件,内容如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Three.js Text Rendering</title>
    <style>
        body { margin: 0; }
        canvas { display: block; }
    </style>
</head>
<body>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
    <script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
    <script src="https://threejs.org/examples/js/loaders/FontLoader.js"></script>
    <script>
        let scene, camera, renderer, controls;
        let textMesh;

        function init() {
            scene = new THREE.Scene();
            camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
            camera.position.z = 5;

            renderer = new THREE.WebGLRenderer();
            renderer.setSize(window.innerWidth, window.innerHeight);
            document.body.appendChild(renderer.domElement);

            controls = new THREE.OrbitControls(camera, renderer.domElement);

            const loader = new THREE.FontLoader();
            loader.load('https://threejs.org/examples/fonts/helvetiker_regular.typeface.json', function (font) {
                const geometry = new THREE.TextGeometry('Hello, Three.js!', {
                    font: font,
                    size: 1,
                    height: 0.1,
                    curveSegments: 12,
                    bevelEnabled: true,
                    bevelThickness: 0.1,
                    bevelSize: 0.05,
                    bevelSegments: 5
                });
                const material = new THREE.MeshStandardMaterial({ color: 0x0077ff });
                textMesh = new THREE.Mesh(geometry, material);
                scene.add(textMesh);

                animate();
            });

            window.addEventListener('resize', onWindowResize, false);
        }

        function animate() {
            requestAnimationFrame(animate);
            controls.update();
            renderer.render(scene, camera);
        }

        function onWindowResize() {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        }

        init();
    </script>
</body>
</html>
  1. 在Flutter中加载这个HTML文件

修改你的main.dart文件,使用flutter_webview_plugin来加载HTML文件:

import 'package:flutter/material.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter Three.js Text Rendering'),
        ),
        body: WebViewExample(),
      ),
    );
  }
}

class WebViewExample extends StatefulWidget {
  @override
  _WebViewExampleState createState() => _WebViewExampleState();
}

class _WebViewExampleState extends State<WebViewExample> {
  final flutterWebviewPlugin = FlutterWebviewPlugin();

  @override
  Widget build(BuildContext context) {
    return WebviewScaffold(
      url: 'assets/threejs_text.html', // 这里加载你的HTML文件
      appBar: AppBar(
        title: Text('Three.js Text Example'),
      ),
      withJavascript: true,
    );
  }

  @override
  void initState() {
    super.initState();
    flutterWebviewPlugin.onUrlChanged.listen((String url) {
      print("URL changed: $url");
    });
  }

  @override
  void dispose() {
    flutterWebviewPlugin.dispose();
    super.dispose();
  }
}
  1. 确保HTML文件被包含在assets中

pubspec.yamlflutter部分添加assets:

flutter:
  assets:
    - assets/threejs_text.html
  1. 运行你的Flutter应用
flutter run -d chrome

这将启动你的Flutter应用,并在Chrome浏览器中打开,展示一个包含3D渲染文本的页面。

请注意,这只是一个基本的示例,实际项目中你可能需要处理更多的细节,比如错误处理、资源加载优化等。此外,如果你希望在不支持Webview的原生平台上使用Three.js,你可能需要探索更复杂的平台通道实现或者使用其他支持3D渲染的Flutter插件(如sceneformarkit_flutter_plugin,但这些通常针对特定的原生平台)。

回到顶部