嗨,我是小路。今天主要和大家分享的主题是“vue+ThreeJs 创造自动选择的甜甜圈”。
一个漂浮在页面中央的 3D 圆环,多个图标/文本/图片均匀分布在圆周上。它会自动缓慢旋转,形成动态视觉焦点。这就是今天要搭建的项目,并对其梳理。
项目效果示意图
1.圆环
定义:创建圆环主要用到TorusGeometry类;其中用到用到四个参数,如下:
属性列表 | 列表说明 |
径长 | radius |
管径 | tube |
径向分段 | radialSegments |
管状分段 | tubularSegments |
圆环边锯齿状 | arc |
二、实例代码
<!--创建一个圆环球体-->
<template>
<div class="pageBox">
<div class="leftBox" ref="leftRef"></div>
</div>
</template>
<script setup>
import { onMounted, onUnmounted, reactive, ref } from 'vue';
import * as THREE from 'three';
// 引入轨道控制器扩展库OrbitControls.js
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { getRandomColor, createLight } from '../utils/commonThree';
const leftRef = ref();
// 定义相机输出画布的尺寸(单位:像素px)
let width = window.innerWidth; //宽度
let height = window.innerHeight; //高度
// 创建3D场景对象Scene
const scene = new THREE.Scene();
//设置背景色
scene.background = getRandomColor(0.5, 0.4);
const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000);
//三角形缩放过大时,会形成多种三角形形成的背景图
camera.position.z = 10;
// 创建渲染器对象
const renderer = new THREE.WebGLRenderer();
let toruses = [];
const createTorus = () => {
// 参数说明: 半径, 管径, 径向分段, 管状分段
const geometry = new THREE.TorusGeometry(3, 1, 16, 100);
const material = new THREE.MeshStandardMaterial({
color: 0x00ff88,
metalness: 0.3,//金属性程度
roughness: 0.2,//粗糙程度
})
const torus = new THREE.Mesh(geometry, material);
return torus;
}
onMounted(() => {
initData()
//添加相机空间
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true; // 开启阻尼
controls.dampingFactor = 0.02; // 设置阻尼系数
controls.autoRotate = true; // 开启自动旋转
// 如果OrbitControls改变了相机参数,重新调用渲染器渲染三维场景
controls.addEventListener('change', function () {
renderer.render(scene, camera); //执行渲染操作
});//监听鼠标、键盘事件
renderer.setSize(width, height); //设置three.js渲染区域的尺寸(像素px)
//将innerHTML置空,避免append重复添加渲染
leftRef.value.innerHTML = ''
leftRef.value.append(renderer.domElement);
})
const initData = () => {
createLight(scene);
// AxesHelper:辅助观察的坐标系
const axesHelper = new THREE.AxesHelper(150);
scene.add(axesHelper);
for (let i = 1; i >= 0; i--) {
const outSphere = createTorus(500);
toruses.push(outSphere);
scene.add(outSphere);
}
render();
}
function render() {
requestAnimationFrame(render);
//旋转球体
toruses.forEach(torus => {
torus.rotation.x += 0.01;
torus.rotation.y += 0.01;
});
renderer.render(scene, camera);
}
onUnmounted(() => {
//释放内存
renderer.dispose();
})
</script>
<style scoped lang="less">
.pageBox {
width: 100%;
height: 100vh;
padding: 0;
margin: 0;
display: flex;
justify-content: space-between;
align-items: center;
.rightBox {
width: 100%;
height: 100%;
}
}
</style>
三、总结
当你做的越多,用的越多,发现学起来越来越简单!
都看到这里了,记得【点赞】+【关注】哟。