在 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 墙体,提高了渲染性能并增强了交互体验。

相关推荐
前端不太难13 分钟前
《Vue 项目路由 + Layout 的最佳实践》
前端·javascript·vue.js
LYFlied16 分钟前
【每日算法】 LeetCode 56. 合并区间
前端·算法·leetcode·面试·职场和发展
想学后端的前端工程师38 分钟前
【Vue3组合式API实战指南:告别Options API的烦恼】
前端·javascript·vue.js
否子戈1 小时前
WebCut前端视频编辑UI框架一周开源进度
前端·音视频开发·ui kit
昔人'1 小时前
`corepack` 安装pnpm
前端·pnpm·node·corepack
萌萌哒草头将军1 小时前
pnpm + monorepo 才是 AI 协同开发的最佳方案!🚀🚀🚀
前端·react.js·ai编程
hboot2 小时前
💪别再迷茫!一份让你彻底掌控 TypeScript 类型系统的终极指南
前端·typescript
GISer_Jing2 小时前
深入拆解Taro框架多端适配原理
前端·javascript·taro
毕设源码-邱学长2 小时前
【开题答辩全过程】以 基于VUE的藏品管理系统的设计与实现为例,包含答辩的问题和答案
前端·javascript·vue.js
用户28907942162714 小时前
Spec-Kit应用指南
前端