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

相关推荐
MiyueFE8 分钟前
bpmn-js 源码篇8:Featrues 体验优化与功能扩展(三)
前端·javascript
野猪佩奇00717 分钟前
Vue项目的 Sass 全局基础样式格式化方案,包含常见元素的样式重置
前端·css·vue.js·sass
独立开阀者_FwtCoder18 分钟前
penAI重磅发布GPT-4o文生图:免费、精准、媲美真实照片!
前端·后端·面试
IBELIEVE26 分钟前
前端打包文件本地简易部署
前端
逆袭的小黄鸭28 分钟前
仿 ElementPlus 组件库(九)—— Switch 组件实现
前端·vue.js·typescript
curdcv_po30 分钟前
Vue 项目线上更新无需强制刷新的方案
前端
dchen7741 分钟前
xhr和fetch的一些区别对比
前端·javascript·面试
进击的松鼠43 分钟前
AI 应用多的我眼花缭乱,不妨做个导航试试看
前端·全栈·next.js
徐小夕43 分钟前
耗资100小时,我开源了一款PPT在线编辑器
前端·javascript·github