示例效果
原理
通过threejs的插件CSS3DRenderer,实现dom元素的3d效果,本质是把原来三维场景场景中的视图矩阵、模型矩阵、投影矩阵的变换,通过css中的translateZ、matrix3d、perspective等属性模拟出来在,作用在dom上
CSS3DRenderer中暴露出的三个对象
1.CSS3DObject
类似threejs中的网格模型
2.CSS3DSprite
类似threejs中精灵模型
3.CSS3DRenderer
css3d的渲染器,主要不同是在渲染器层面,渲染器来处理原理中提到的变换过程,调整dom的style
使用
引入
import { CSS3DRenderer, CSS3DObject, CSS3DSprite } from 'three/examples/jsm/renderers/CSS3DRenderer.js'
初始化渲染器
初始化场景时把WebGLRenderer换成了CSS3DRenderer,其他的Scene,OrbitControls,camera等同threejs中用法
this.CSS3Renderer = new CSS3DRenderer()
this.CSS3Renderer.setSize(宽, 高) // 设置渲染区域尺寸
document.getElementById(被挂载的domId).appendChild(this.CSS3Renderer.domElement) // 挂载dom
生成页面元素
// 五只猫跟地板的dom
<div class="cat cat1">
</div>
<div class="cat cat2">
</div>
<div class="cat cat3">
</div>
<div class="cat cat4">
</div>
<div class="cat cat5">
</div>
<div class="plane">
</div>
// 样式
.cat {
width: 80px;
height: 80px;
position: absolute;
background-size: 100% 100%;
}
.cat1 {
background-image: url("~@/assets/img/buoumao-xiyouse.png");
}
.cat2 {
background-image: url("~@/assets/img/buoumao-zhongdianse.png");
}
.cat3 {
background-image: url("~@/assets/img/dajumao.png");
}
.cat4 {
background-image: url("~@/assets/img/lanbaimao.png");
}
.cat5 {
background-image: url("~@/assets/img/xianluomao.png");
}
.plane {
width: 200px;
height: 200px;
position: absolute;
background-image: url("~@/assets/img/plane.png");
background-size: 100% 100%;
}
包装元素
// 获取页面元素用相应方法包装
const domArr = document.getElementsByClassName('cat')
renderCsss3d(domArr)
const dom = document.getElementsByClassName('plane')
addCss3dPlane(dom)
渲染猫图标的函数 renderCsss3d
renderCsss3d(domArr) {
const r = 100
// 计算出半径为r的圆上等分的五个点的x,y坐标
const pointArry = this.computePosition(new THREE.Vector2(0, 0), new THREE.Vector2(r, 0), 5)
// 循环设置五个dom
for (let i = 0; i < domArr.length; i++) {
// 需要时刻面向镜头,所以采用精灵对象
const obj = new CSS3DSprite(domArr[i])
// 根据计算的坐标,设置每个猫图标的位置,高度为50(50设置给y因为相机up为y)
obj.position.set(pointArry[i].x, 50, pointArry[i].y)
// 加到组中,为了后续一起旋转
this.css3dGroup.add(obj)
}
}
工具函数 computePosition
/**
* 计算出半径为r的圆上等分的cnt个点的x,y坐标
* @param center 圆的中点 vec2
* @param first 第一个点的坐标 vec2
* @param cnt 等分个数
* @returns {[vec2]}
*/
computePosition(center, first, cnt) {
const pointList = [first]
for (let i = 1; i < cnt; i++) {
const p = first.clone()
p.rotateAround(center, Math.PI * 2 / cnt * i)
pointList.push(p)
}
return pointList
}
渲染地板的函数 addCss3dPlane
addCss3dPlane(dom) {
// 不需要时刻面向镜头所以采用常规模型对象
const obj = new CSS3DObject(dom[0])
// 平面默认是竖着的,需要放倒
obj.rotateX(Math.PI / 2)
// 添加到场景中
this.scene.add(obj)
}
渲染
// 渲染
_animate() {
requestAnimationFrame(this._animate.bind(this))
this.CSS3Renderer.render(this.scene, this.camera)
// 绕y轴旋转
this.css3dGroup.rotation.y += 0.005
}