在 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 钩子之后访问。
  • script 的 module 名称可以随意,但 change: 参数名称必须与 module 保持一致,否则会报错。

RenderJS 只支持 App-Vue 和 Web 端,不支持小程序端。在 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 墙体,提高了渲染性能并增强了交互体验。

相关推荐
CappuccinoRose4 分钟前
拖拽交互体系
前端·javascript·css·html·交互·1024程序员节
开开心心就好5 分钟前
免安装PDF盖章工具,透明度和位置可调
运维·服务器·前端·javascript·pdf·ocr·1024程序员节
风骏时光牛马6 分钟前
AI服务线上推理异常故障
前端
king王一帅17 分钟前
做了三年 ProseMirror 后,我用四个月自研排版引擎实现 WPS / Google Docs 替代品,整套框架 MIT 开源
前端·vue.js·开源
এ慕ོ冬℘゜2 小时前
如何在 HTML 中嵌入音频和视频?
前端·html·音视频
变与不变80611 小时前
jQuery怎么使用
前端·javascript
神膘护体小月半11 小时前
flex 布局的 order 属性
前端·css
paopaokaka_luck11 小时前
流浪动物救助与收养系统(DeepSeek AI对话、 ECharts多维分析、救助流程衔接、领养与回访衔接、 捐赠确认与公示、志愿者协作)
java·前端·javascript·人工智能·mysql·echarts·推荐算法
仰望.11 小时前
vue 表格组件 vxe-table 树表格懒加载支持拖拽排序的详细用法
前端·javascript·vue.js·vxe-table
前端 贾公子11 小时前
vite-plugin-uni-manifest 升级指南
前端