在 UniApp 中使用 RenderJS 与 Three.js 进行 3D 渲染

引言

在 UniApp 的开发过程中,我们可能需要使用 Three.js 进行 3D 场景渲染。然而,由于 UniApp 的逻辑层和视图层是分离的,直接在逻辑层操作 DOM 并运行复杂的 WebGL 渲染代码可能会导致性能下降。因此,RenderJS 提供了一种在视图层运行 JavaScript 的方式,使得我们可以在 UniApp 的 App 端高效运行 Three.js,提高交互性能。

本篇文章将介绍 RenderJS 的作用,并结合 Three.js 进行 3D 建模,实现从 2D 线条数据生成 3D 墙体的效果。


RenderJS 简介

RenderJS 是 UniApp 提供的一个运行在视图层的 JavaScript 运行环境,主要用于以下两点:

  1. 让 App 端引入 Web 端的 JS 库,比如 Three.js、Chart.js 等,利用 Web 端的强大功能。
  2. 降低逻辑层和视图层的通讯损耗,提高渲染和交互的性能,适用于高频交互的场景。

RenderJS 的特点

  • 无法直接访问逻辑层的任何数据 ,只能访问通过 option 显式传递的数据。
  • 不能直接在模板上绑定字符串,必须绑定逻辑层的数据,否则无法监听。
  • 模板传递的数据只能在视图层的 mounted 钩子之后访问
  • scriptmodule 名称可以随意,但 change: 参数名称必须与 module 保持一致,否则会报错。

RenderJS 只支持 App-VueWeb 端,不支持小程序端。在 RenderJS 中,可以通过 this.option 访问逻辑层传递的数据。


使用 RenderJS 进行 3D 渲染

1. 页面结构

xml 复制代码
<template>
	<view class="">
		<view id="threeView"></view>
		<view id="threeArea" :option="option" :change:option="threeArea.receiveInfo"></view>
	</view>
</template>

2. 逻辑层(Vue 逻辑部分)

xml 复制代码
<script>
export default {
	data() {
		return {
			option: null,
		};
	},
	mounted() {
		const storedLines = uni.getStorageSync('lines');
		this.option = {
			storedLines: storedLines || [],
		};
	},
	methods: {},
};
</script>

3. 视图层(RenderJS 部分)

ini 复制代码
<script module="threeArea" lang="renderjs">
const THREE = require('static/three/build/three.min.js');
import { OrbitControls } from 'static/three/examples/jsm/controls/OrbitControls.js';

var renderer, scene, camera, controls;

export default {
	data() {
		return {};
	},
	mounted() {},
	methods: {
		receiveInfo(newValue, oldValue) {
			if (newValue) {
				this.initThree();
				this.createGridHelper();
				this.createControls();
				this.loadLinesFromStorage(newValue.storedLines);
			}
		},
		initThree() {
			scene = new THREE.Scene();
			camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 10000);
			camera.position.set(0, 20, 20);
			camera.lookAt(new THREE.Vector3(0, 0, 0));

			renderer = new THREE.WebGLRenderer({ antialias: true });
			renderer.setSize(window.innerWidth, window.innerHeight);
			renderer.setClearColor(0xECF1F3, 1);

			document.getElementById('threeView').appendChild(renderer.domElement);
			this.render();
		},
		createGridHelper() {
			const gridHelper = new THREE.GridHelper(50, 10);
			scene.add(gridHelper);
		},
		createControls() {
			controls = new OrbitControls(camera, renderer.domElement);
		},
		loadLinesFromStorage(storedLines) {
			if (storedLines.length > 0) {
				this.createWalls(storedLines);
			}
		},
		createWalls(lines) {
			let points = lines.map(line => new THREE.Vector3(line.x1 / 50, 0, -line.y1 / 50));
			const curve = new THREE.CatmullRomCurve3(points);
			const shape = new THREE.Shape([
				new THREE.Vector2(0, -0.05),
				new THREE.Vector2(-2, -0.05),
				new THREE.Vector2(-2, 0.05),
				new THREE.Vector2(0, 0.05)
			]);

			const extrudeSettings = { extrudePath: curve };
			const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);
			const material = new THREE.MeshStandardMaterial({ color: 0x888888 });
			const wall = new THREE.Mesh(geometry, material);
			scene.add(wall);
		},
		render() {
			requestAnimationFrame(() => this.render());
			renderer.render(scene, camera);
		},
	}
};
</script>

结语

通过 UniApp 的 RenderJS,我们可以在 App 端高效运行 Web 端的 JavaScript 库,如 Three.js。利用 RenderJS 访问逻辑层数据,我们成功地将 2D 线条数据转换为 3D 墙体,提高了渲染性能并增强了交互体验。

相关推荐
幸福小宝1 天前
uniapp 抽屉实现左滑
前端
戳气球的爱玛镇皇后1 天前
BroadcastChannel 使用总结
前端
戳气球的爱玛镇皇后1 天前
wps加载项不同窗口间通信
前端
心在飞扬1 天前
LangGraph 基础知识
前端·后端
Lee川1 天前
深入浅出JavaScript事件机制:从捕获冒泡到事件委托
前端·javascript
光影少年1 天前
async/await和Promise的区别?
前端·javascript·掘金·金石计划
恋猫de小郭1 天前
Flutter 发布官方 Skills ,Flutter 在 AI 领域再添一助力
android·前端·flutter
心在飞扬1 天前
工具调用出错捕获提升程序健壮性
前端·后端
HelloReader1 天前
Tauri 命令作用域(Command Scopes)精细化控制你的应用权限
前端
心在飞扬1 天前
基于工具调用的智能体设计与实现(*)
前端·后端