引言
在 UniApp 的开发过程中,我们可能需要使用 Three.js 进行 3D 场景渲染。然而,由于 UniApp 的逻辑层和视图层是分离的,直接在逻辑层操作 DOM 并运行复杂的 WebGL 渲染代码可能会导致性能下降。因此,RenderJS 提供了一种在视图层运行 JavaScript 的方式,使得我们可以在 UniApp 的 App 端高效运行 Three.js,提高交互性能。
本篇文章将介绍 RenderJS 的作用,并结合 Three.js 进行 3D 建模,实现从 2D 线条数据生成 3D 墙体的效果。
RenderJS 简介
RenderJS 是 UniApp 提供的一个运行在视图层的 JavaScript 运行环境,主要用于以下两点:
- 让 App 端引入 Web 端的 JS 库,比如 Three.js、Chart.js 等,利用 Web 端的强大功能。
- 降低逻辑层和视图层的通讯损耗,提高渲染和交互的性能,适用于高频交互的场景。
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 墙体,提高了渲染性能并增强了交互体验。