效果图
注意:
鼠标滚动 标题卡片大小不变
1. 引入 CSS2DRenderer.js
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { TWEEN } from "three/examples/jsm/libs/tween.module.min";
import {CSS2DObject,CSS2DRenderer} from "three/examples/jsm/renderers/CSS2DRenderer.js";
2. 在 初始渲染 three.js 中添加
let labelRenderer = new THREE.CSS2DRenderer();
labelRenderer.setSize(window.innerWidth, window.innerHeight);
labelRenderer.domElement.style.position = 'absolute';
labelRenderer.domElement.style.top = 0;
document.body.appendChild(labelRenderer.domElement);
controls = new OrbitControls(camera, labelRenderer.domElement);
2.1 屏幕发生变化可以添加
window.addEventListener('resize', function() {
labelRenderer.setSize(window.innerWidth, window.innerHeight);
})
3. 在刷新three.js 函数中 (requestAnimationFrame
)添加
labelRenderer.render(scene, camera);
4. 创建 标题 卡片 函数
methods: {
//初始渲染
initial() {
......
let data = {
name: "这是一个标题",
scale: { x: 0, y: 0, z: 0 },
};
let img = require("@/assets/logo.png");
let title = this.titleCard(data, img);
scene.add(title);
this.animate();
},
// 生成 标题 卡片
titleCard(text, imgs) {
laberDiv = document.createElement("div"); //创建div容器
laberDiv.className = "laber_name";
laberDiv.innerHTML = `<div class='title_text'>${text.name}</div>
<div class= 'laber_imgs'><img src="${imgs}" alt=""></div>`;
let pointLabel = new CSS2DObject(laberDiv);
pointLabel.position.set(text.scale.x, text.scale.y, text.scale.z);
return pointLabel;
},
}
5. css样式
.laber_name{
width: 100px;
height: 120px;
color: #05D2FF;
}
.laber_name .title_text{
height: 20px;
width: 100%;
line-height: 20px;
font-size: 12px;
font-weight: 700;
text-align: center;
}
.laber_name .laber_imgs{
width: 100px;
height: 100px;
}
.laber_name .laber_imgs img{
width: 100%;
height: 100%;
}
6. 完整示例代码
<!-- 使用 three 中 CSS2DRenderer 生成标题卡片 鼠标滚动 标题卡片不变 -->
<template>
<div class="title_TEXT">
<div class="title_state">
<div
class="title_state_li"
@click="clickState(index)"
:class="stateIndex == index ? 'title_state_li_te' : 'state_li'"
v-for="(item, index) in stateData"
:key="index"
>
{{ item.name }}
</div>
</div>
<div id="title_CSS2DRenderer"></div>
</div>
</template>
<script>
//---------------------- 引用 three 的属性 --------------------------------
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { TWEEN } from "three/examples/jsm/libs/tween.module.min";
import {
CSS2DObject,
CSS2DRenderer,
} from "three/examples/jsm/renderers/CSS2DRenderer.js";
//---------------------- 引用 three 的属性 --------------------------------
// ----------------------------------- 自定义属性 -----------------------
// 创建场景对象Scene
let scene = new THREE.Scene();
//点光源
let point = new THREE.PointLight(0xffffff);
//环境光
let ambient = new THREE.AmbientLight(0x444444);
//创建相机对象 属性
let camera = null;
// 创建渲染器对象
let renderer = new THREE.WebGLRenderer({
//增加下面两个属性,可以抗锯齿
antialias: true,
alpha: true,
});
let controls = null;
let labelRenderer = new CSS2DRenderer(); // 使用 CSS2DRenderer
let laberDiv = null; // DoM属性
// ----------------------------------- 自定义属性 -----------------------
export default {
name: "titleCSS2DRenderer",
data() {
return {
stateData: [
{
name: "开",
},
{
name: "关",
},
],
stateIndex: 0,
};
},
mounted() {
this.initial();
},
methods: {
// 初始 加载
initial() {
let CSS2D = document.querySelector("#title_CSS2DRenderer");
let gridHelper = new THREE.GridHelper(400, 10, 0x2c2c2c, 0x666666);
scene.add(gridHelper); // 网格辅助线
/**
* 光源设置
*/
point.position.set(400, 200, 300); //点光源位置
scene.add(point); //点光源添加到场景中
scene.add(ambient); //环境光添加到场景中
/**
* 相机设置
*/
let width = window.innerWidth; //窗口宽度
let height = window.innerHeight; //窗口高度
let k = width / height; //窗口宽高比
let s = 200; //三维场景显示范围控制系数,系数越大,显示的范围越大
//创建相机对象
camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);
camera.position.set(200, 300, 200); //设置相机位置
camera.lookAt(scene.position); //设置相机方向(指向的场景对象)
/**
* 创建渲染器对象
*/
renderer.setSize(width, height); //设置渲染区域尺寸
renderer.setClearColor(0xb9d3ff, 1); //设置背景颜色
CSS2D.appendChild(renderer.domElement); //body元素中插入canvas对象
labelRenderer.setSize(window.innerWidth, window.innerHeight);
labelRenderer.domElement.style.position = "absolute";
labelRenderer.domElement.style.top = 0;
CSS2D.appendChild(labelRenderer.domElement);
//执行渲染操作 指定场景、相机作为参数
renderer.render(scene, camera);
controls = new OrbitControls(camera, labelRenderer.domElement);
// 如果使用animate方法时,将此函数删除
//controls.addEventListener( 'change', render );
// 使动画循环使用时阻尼或自转 意思是否有惯性
controls.enableDamping = true;
//动态阻尼系数 就是鼠标拖拽旋转灵敏度
controls.dampingFactor = 0.25;
//是否可以缩放
controls.enableZoom = true;
//是否自动旋转
controls.autoRotate = true;
controls.autoRotateSpeed = 0.3;
//设置相机距离原点的最近距离
controls.minDistance = 1;
//设置相机距离原点的最远距离
controls.maxDistance = 300;
//是否开启右键拖拽
controls.enablePan = true;
//上下翻转的最大角度
controls.maxPolarAngle = 1.5;
//上下翻转的最小角度
controls.minPolarAngle = 0.3;
// 使用 CSS2DRenderer.js
let data = {
name: "这是一个标题",
scale: { x: 0, y: 0, z: 0 },
};
let img = require("@/assets/logo.png");
let title = this.titleCard(data, img);
scene.add(title);
this.animate();
},
// 生成 标题 卡片
titleCard(text, imgs) {
laberDiv = document.createElement("div"); //创建div容器
laberDiv.className = "laber_name";
laberDiv.innerHTML = `<div class='title_text'>${text.name}</div>
<div class= 'laber_imgs'><img src="${imgs}" alt=""></div>`;
let pointLabel = new CSS2DObject(laberDiv);
pointLabel.position.set(text.scale.x, text.scale.y, text.scale.z);
return pointLabel;
},
// 自动刷新
animate() {
TWEEN.update();
controls.update();
labelRenderer.render(scene, camera);
requestAnimationFrame(this.animate);
renderer.render(scene, camera);
},
// 切换状态
clickState(index) {
this.stateIndex = index;
if (index === 0) {
laberDiv.className = "laber_name";
} else {
laberDiv.className = "laber_name_te";
}
},
},
};
</script>
<style lang="scss">
#title_CSS2DRenderer {
.laber_name {
width: 100px;
height: 120px;
color: #05d2ff;
}
.laber_name_te {
display: none;
}
.laber_name .title_text {
height: 20px;
width: 100%;
line-height: 20px;
font-size: 12px;
font-weight: 700;
text-align: center;
}
.laber_name .laber_imgs {
width: 100px;
height: 100px;
}
.laber_name .laber_imgs img {
width: 100%;
height: 100%;
}
}
</style>
<style lang="scss" scoped>
.title_state {
position: fixed;
top: 20px;
left: 20px;
z-index: 100;
display: flex;
border-radius: 4px;
overflow: hidden;
.title_state_li {
width: 50px;
height: 30px;
background-color: #fff;
display: flex;
justify-content: center;
align-items: center;
font-size: 14px;
cursor: pointer;
}
.state_li:hover {
background-color: #f1f1f1;
}
.title_state_li_te {
font-weight: 700;
color: #fff;
background-color: #00a6ff;
}
}
#title_CSS2DRenderer {
width: 100%;
height: 100%;
}
</style>