Three 之 three.js (webgl)Layers 图层的简单介绍和简单实用
Three 之 three.js (webgl)Layers 图层的简单介绍和简单实用
目录
一、简单介绍
Three js (官网: ) 开发的一些知识整理,方便后期遇到类似的问题,能够及时查阅使用。
本节介绍, three 开发网页 3D 场景,three.js Layers 图层的简单介绍和简单实用,如果有不足之处,欢迎指出,或者你有更好的方法,欢迎留言。
- 什么是 Layers
Layers 对象为 Object3D 分配 1个到 32 个图层。32个图层从 0 到 31 编号标记。 在内部实现上,每个图层对象被存储为一个 , 默认的,所有 Object3D 对象都存储在第 0 个图层上。
图层对象可以用于控制对象的显示。当 camera 的内容被渲染时与其共享图层相同的物体会被显示。每个对象都需要与一个 camera 共享图层。
每个继承自 Object3D 的对象都有一个 Object3D.layers 对象。
Layers() 创建一个新的图层对象,该对象默认与第 0 图层关联
属性 . : Integer
用 bit mask 表示当前图层对象与 0 - 31 中的哪些图层相对应。所属层所对应的比特位为 1,其他位位 0。
- 涉及的方法:
. ( layer : Integer ) : undefined
layer - 一个 0 - 31 的整数。
删除图层对象与参数指定图层的对应关系。
. ( layer : Integer ) : undefined
layer - 一个 0 - 31 的整数。
增加图层对象与参数指定图层的对应关系。
. ( layer : Integer ) : undefined
layer - 一个 0 - 31 的整数。
删除图层对象已有的所有对应关系,增加与参数指定的图层的对应关系。
. ( layers : Layers ) : Boolean
layers - 一个图层对象。
如果传入图层对象与当前对象属于相同的一组图层,则返回 true,否则返回 false。
. ( layer : Integer ) : Boolean
layer - an integer from 0 to 31.
Returns true if the given layer is enabled.
. ( layer : Integer ) : undefined
layer - 一个 0 - 31 的整数。
根据参数切换对象所属图层。
. () : undefined
Add membership to all layers.
. () : undefined
Remove membership from all layers.
二、实现原理
1、对应的 Object 进行对应的 layers 设置
object.layers.set(layer);
2、camera 开启使能对应的 layers 渲染
this.camera.layers.enable(0); // enabled by default
this.camera.layers.enable(1);
this.camera.layers.enable(2);
// 使能或者使不能 layer 1
this.camera.layers.toggle(1);
// 使能所有
this.camera.layers.enableAll();
// 使不能所有
this.camera.layers.disableAll();
三、注意事项
1、注意查看 layers 是 mask 的 二进制对用的值,例如 mask 为 8 ,二进制是 001000,layers 为 3
// 创建一个图层对象
let layer = new THREE.Layers();
// 设置图层为3
layer.set(3)
Mesh.layers = layer;
// 控制台可以查看mask值是8(二进制 ...001000),表示的就是图层3
console.log(layer.mask)
this.camera.layers.enable(0); // enabled by default
this.camera.layers.enable(1);
this.camera.layers.enable(2);
// 控制台可以查看mask值是7(二进制 ...000111),表示的使能图层 0 ,1,2
console.log(this.camera.layers)
2、如果发现 layers 的 Object light 渲染不对,可以使能 light d对用的 layers 试试
light.layers.enable(0);
light.layers.enable(1);
light.layers.enable(2);
3、注意 vue 中的 method 下定义的函数方法,里面在定义函数时,可能使用 lambda 的方式定义的函数(可以是作为委托事件),才能获取到 vue 中定义的全局变量参数
initGui() {
const layers = {
//注意: 使用 lambda 才能访问 this.camera , 使用 function() 访问不到 this.camera
'toggle red':() => {
this.camera.layers.toggle(0);
}
};
const gui = new GUI();
gui.add(layers, 'toggle red');
},
四、效果预览
五、实现步骤
创建 Vue 的 Three 开发环境,可参考博文:
1、在 src/App.vue 中添加代码,步骤基本 Three 环境,以及点击 按钮进行不同 layers 层级渲染显示
2、运行工程 (npm run serve ),在浏览器中查看,不同操作,即可显示不同layers 的 Object 渲染
六、关键代码
1、src/App.vue
<template>
<div id="container"></div>
</template>
<script>
import * as THREE from 'three';
import Stats from 'three/examples/jsm/libs/stats.module.js';
import { GUI } from 'three/examples/jsm/libs/lil-gui.module.min.js';
export default {
name: 'ThreeTest',
components: {},
data() {
return {}
},
mounted() {
this.container;
this.stats;
this.camera;
this.scene;
this.renderer;
this.theta = 0;
this.radius = 100;
this.init();
this.animate();
},
methods: {
init() {
this.container = document.createElement('div');
document.body.appendChild(this.container);
this.addSceneCameraAndLight();
this.addObjectsWithLayers();
this.initRenderer();
this.addStatus();
// Init gui
this.initGui();
// window.addEventListener
window.addEventListener('resize', this.onWindowResize);
},
addSceneCameraAndLight(){
this.camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 10000);
this.camera.layers.enable(0); // enabled by default
this.camera.layers.enable(1);
this.camera.layers.enable(2);
console.log(this.camera.layers)
this.scene = new THREE.Scene();
this.scene.background = new THREE.Color(0xf0f0f0);
const light = new THREE.PointLight(0xffffff, 1);
light.layers.enable(0);
light.layers.enable(1);
light.layers.enable(2);
this.scene.add(this.camera);
this.scene.add(light);
},
initRenderer(){
this.renderer = new THREE.WebGLRenderer();
this.renderer.setPixelRatio(window.devicePixelRatio);
this.renderer.setSize(window.innerWidth, window.innerHeight);
this.container.appendChild(this.renderer.domElement);
},
addStatus(){
this.stats = new Stats();
this.container.appendChild(this.stats.dom);
},
// 添加测试物体,并设置他们的层为 0 1 2
addObjectsWithLayers(){
const colors = [0xff0000, 0x00ff00, 0x0000ff];
const geometry = new THREE.BoxGeometry(20, 20, 20);
for (let i = 0; i < 100; i++) {
const layer = (i % 3);
const object = new THREE.Mesh(geometry, new THREE.MeshLambertMaterial({color: colors[layer]}));
object.position.x = Math.random() * 400 - 200;
object.position.y = Math.random() * 400 - 200;
object.position.z = Math.random() * 400 - 200;
object.rotation.x = Math.random() * 2 * Math.PI;
object.rotation.y = Math.random() * 2 * Math.PI;
object.rotation.z = Math.random() * 2 * Math.PI;
object.scale.x = Math.random() + 0.5;
object.scale.y = Math.random() + 0.5;
object.scale.z = Math.random() + 0.5;
object.layers.set(layer);
this.scene.add(object);
}
},
initGui() {
const layers = {
//注意: 使用 lambda 才能访问 this.camera , 使用 function() 访问不到 this.camera
'toggle red':() => {
this.camera.layers.toggle(0);
},
'toggle green': () =>{
this.camera.layers.toggle(1);
},
'toggle blue': () => {
this.camera.layers.toggle(2);
},
'enable all': () => {
this.camera.layers.enableAll();
},
'disable all': () => {
this.camera.layers.disableAll();
}
};
const gui = new GUI();
gui.add(layers, 'toggle red');
gui.add(layers, 'toggle green');
gui.add(layers, 'toggle blue');
gui.add(layers, 'enable all');
gui.add(layers, 'disable all');
},
onWindowResize() {
this.camera.aspect = window.innerWidth / window.innerHeight;
this.camera.updateProjectionMatrix();
this.renderer.setSize(window.innerWidth, window.innerHeight);
},
animate() {
requestAnimationFrame(this.animate);
this.render();
this.stats.update();
},
render() {
this.theta += 0.1;
this.camera.position.x = this.radius * Math.sin(THREE.MathUtils.degToRad(this.theta));
this.camera.position.y = this.radius * Math.sin(THREE.MathUtils.degToRad(this.theta));
this.camera.position.z = this.radius * Math.cos(THREE.MathUtils.degToRad(this.theta));
this.camera.lookAt(this.scene.position);
this.renderer.render(this.scene, this.camera);
},
},
// beforeDestroy 废弃,使用 beforeUnmount
beforeUnmount() {
this.container = null;
this.stats = null;
this.camera = null;
this.scene = null;
this.renderer = null;
this.theta = null;
this.radius = null;
console.log("beforeUnmount");
}
}
</script>
<style>
#app {
text-align: center;
height: 100%;
}
* {
/*初始化样式*/
margin: 0;
padding: 0;
}
html {
/*用于 获取 屏幕的可视宽高*/
width: 100%;
height: 100%;
overflow: hidden;
}
</style>