目录
0. 效果图
最近遇到一个新的需求,在threeJS的模型中加载我们的普通的H5页面,研究了下,发现threeJS中自带的CSS3DRenderer可以实现,先放一张展示图
可以看到,中间的面板就是加载的threeJS官网页面,并且可以操作互动
1. CSS3DRenderer介绍
CSS3DRenderer通过CSS3的transforms属性,将层级的3D变换应用到Dom元素上,将Dom元素和WebGL的内容相结合,操作Dom元素的positionh和rotation属性来创建动画。
代码结构:
/**
* CSS3DRenderer通过CSS3的transforms属性,将层级的3D变换应用到Dom元素上,将Dom元素和WebGL的内容相结合,Dom => Object3D
* 操作Dom元素的positionh和rotation属性来创建动画
* @type {CSS3DRenderer}
*/
this.labelRenderer = new CSS3DRenderer();
this.labelRenderer.setSize(this.container.clientWidth, this.container.clientHeight);
this.labelRenderer.domElement.style.position = "absolute";
this.labelRenderer.domElement.style.top = 0;
this.container.appendChild(this.labelRenderer.domElement);
console.log(this.labelRenderer);
//创建控件对象
this.controls = new OrbitControls(this.camera, this.labelRenderer.domElement);
同时创建控件对象,把CSS3DRenderer的场景加入控制器中
CSS3DRenderer跟场景下的Render一样,需要进行render()场景渲染处理
this.labelRenderer.render(this.scene, this.camera);
2. CSS3DObject介绍
配合CSS3DRenderer,将创建的Dom元素通过CSS3DObject包装成3D对象
DOM => Object3D
代码结构:
let domEle = document.createElement("div");
domEle.innerHTML = "<div class='domBox'><iframe src='https://threejs.org/docs/index.html#manual/en/introduction/Creating-a-scene'></iframe></div>"
/**
* 将创建的Dom元素用过CSS3DObject包装成3D对象
* @type {CSS3DObject}
*/
let domEleObj = new CSS3DObject(domEle);
domEleObj.position.set(-150, -50, -380);
this.scene.add(domEleObj);
将把转换后的3D对象直接加入场景中即可
3. 完整代码
<template>
<div class="wrap">
<div ref="container" id="container"></div>
</div>
</template>
<script>
import * as THREE from "three";
import {OrbitControls} from "three/examples/jsm/controls/OrbitControls.js";
import {CSS3DRenderer, CSS3DObject} from "three/examples/jsm/renderers/CSS3DRenderer.js";
export default {
name: "ThreeTest",
mounted() {
this.myReq = null
this.container
this.scene
this.camera
this.renderer
this.labelRenderer
this.controls
this.initRender();
this.initScene();
this.initModel();
this.animate();
window.onresize = this.onWindowResize;
},
methods: {
getTexturesFromAtlasFile(atlasImgUrl, tilesNum) {
const textures = [];
for (let i = 0; i < tilesNum; i++) {
textures[i] = new THREE.Texture();
}
new THREE.ImageLoader().load(atlasImgUrl, (image) => {
let canvas, context;
const tileWidth = image.height;
for (let i = 0; i < textures.length; i++) {
canvas = document.createElement('canvas');
context = canvas.getContext('2d');
canvas.height = tileWidth;
canvas.width = tileWidth;
context.drawImage(image, tileWidth * i, 0, tileWidth, tileWidth, 0, 0, tileWidth, tileWidth);
textures[i].image = canvas;
textures[i].needsUpdate = true;
}
});
return textures;
},
initRender: function () {
this.container = document.getElementById("container");
this.camera = new THREE.PerspectiveCamera(
70,
this.container.clientWidth / this.container.clientHeight,
1,
1000
);
this.camera.position.z = 1;
this.renderer = new THREE.WebGLRenderer({antialias: true});
this.renderer.setSize(this.container.clientWidth, this.container.clientHeight);
this.container.appendChild(this.renderer.domElement);
/**
* CSS3DRenderer通过CSS3的transforms属性,将层级的3D变换应用到Dom元素上,将Dom元素和WebGL的内容相结合,Dom => Object3D
* 操作Dom元素的positionh和rotation属性来创建动画
* @type {CSS3DRenderer}
*/
this.labelRenderer = new CSS3DRenderer();
this.labelRenderer.setSize(this.container.clientWidth, this.container.clientHeight);
this.labelRenderer.domElement.style.position = "absolute";
this.labelRenderer.domElement.style.top = 0;
this.container.appendChild(this.labelRenderer.domElement);
console.log(this.labelRenderer);
//创建控件对象
this.controls = new OrbitControls(this.camera, this.labelRenderer.domElement);
},
initScene() {
this.scene = new THREE.Scene();
},
initModel() {
const textures = this.getTexturesFromAtlasFile('source/sun_temple_stripe.jpg', 6);
const materialArr = [];
for (let i = 0; i < 6; i++) {
materialArr.push(new THREE.MeshBasicMaterial({map: textures[i]}));
}
var boxGeometry = new THREE.BoxGeometry(200, 200, 200, 100, 100, 100);
boxGeometry.scale(1, 1, -1);
let cube = new THREE.Mesh(boxGeometry, materialArr);
this.scene.add(cube);
let domEle = document.createElement("div");
domEle.innerHTML = "<div class='domBox'><iframe src='https://threejs.org/docs/index.html#manual/en/introduction/Creating-a-scene'></iframe></div>"
/**
* 将创建的Dom元素用过CSS3DObject包装成3D对象
* @type {CSS3DObject}
*/
let domEleObj = new CSS3DObject(domEle);
domEleObj.position.set(-150, -50, -380);
this.scene.add(domEleObj);
},
render() {
this.renderer.render(this.scene, this.camera);
this.labelRenderer.render(this.scene, this.camera);
},
onWindowResize() {
this.camera.aspect = window.innerWidth / window.innerHeight;
this.camera.updateProjectionMatrix();
this.render();
this.renderer.setSize(window.innerWidth, window.innerHeight);
},
animate() {
this.render();
this.myReq = requestAnimationFrame(this.animate);
}
},
beforeDestroy() {
cancelAnimationFrame(this.myReq)
this.scene = null
this.scene.dispose()
this.camera = null
this.renderer = null
this.labelRenderer = null
this.controls = null
}
};
</script>
<style>
.wrap {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: 100;
}
#container {
height: 100%;
}
.domBox {
width: auto;
}
</style>