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

相关推荐
前端工作日常3 小时前
我理解的`npm pack` 和 `npm install <local-path>`
前端
李剑一3 小时前
说个多年老前端都不知道的标签正确玩法——q标签
前端
嘉小华3 小时前
大白话讲解 Android屏幕适配相关概念(dp、px 和 dpi)
前端
姑苏洛言3 小时前
在开发跑腿小程序集成地图时,遇到的坑,MapContext.includePoints(Object object)接口无效在组件中使用无效?
前端
奇舞精选4 小时前
Prompt 工程实用技巧:掌握高效 AI 交互核心
前端·openai
Danny_FD4 小时前
React中可有可无的优化-对象类型的使用
前端·javascript
用户757582318554 小时前
混合应用开发:企业降本增效之道——面向2025年移动应用开发趋势的实践路径
前端
P1erce4 小时前
记一次微信小程序分包经历
前端
LeeAt4 小时前
从Promise到async/await的逻辑演进
前端·javascript
等一个晴天丶4 小时前
不一样的 TypeScript 入门手册
前端