運(yùn)用相關(guān):vue3、three.js
模型下載:https://github.com/mrdoob/three.js/??

<template>
? <div ref="sceneRef">
</template>
<script setup>
import {onMounted,ref }from 'vue'
import *as THREEfrom "three"
import { OrbitControls }from 'three/examples/jsm/controls/OrbitControls'
import { GLTFLoader }from 'three/examples/jsm/loaders/GLTFLoader.js'
import gsapfrom 'gsap'
let scene,camera,renderer,orbitControls
let sceneRef =ref()
let model =ref(null)//用于模型移動(dòng)
let mixer =ref(null)
let clock =new THREE.Clock()
let curve =null
//啟動(dòng)動(dòng)畫
function startAnimation(skinnedMesh, animations, animationName) {
// 申明動(dòng)畫場景
? const m_mixer =new THREE.AnimationMixer(skinnedMesh)
// 查找動(dòng)畫
? const clip = THREE.AnimationClip.findByName(animations, animationName)
if (clip) {
// 播放
? ? const action =m_mixer.clipAction(clip)
action.play()
}
return m_mixer
}
// 曲線/移動(dòng)
function makeCurve() {
// 創(chuàng)建曲線
? curve =new THREE.CatmullRomCurve3([
new THREE.Vector3(0,0,0),
new THREE.Vector3(5,0,0),
new THREE.Vector3(0,0,5)
])
// 曲線類型
? curve.curveType ="catmullrom"
? // 設(shè)置曲線閉環(huán)
? curve.closed =true
? // 設(shè)置曲線張力0-1
? curve.tension =0.5
? // 獲取點(diǎn)位
? const points =curve.getPoints(100)
// 存儲(chǔ)屬性
? const geometry =new THREE.BufferGeometry().setFromPoints(points)
// 更改線的顏色
? const material =new THREE.LineBasicMaterial({color:0x000000})
// 生成線
? const? curveObject =new THREE.Line(geometry,material)
// 加入場景
? scene.add(curveObject)
let obj ={num:0 }
gsap.to(obj, {
num:1,
// 時(shí)間
? ? duration:30,
// 循環(huán)
? ? repeat: -1,
// 緩動(dòng)效果
? ? ease:'none',
onUpdate() {
let point =curve.getPoint(obj.num)
model.value.scene.position.copy(point)
let pointNext =curve.getPoint(obj.num -0.001)
model.value.scene.lookAt(pointNext)
}
})
// console.log(points)
// console.log('gltf', model)
}
// 引入模型
function loadModel() {
const gltfLoader =new GLTFLoader()
gltfLoader.setPath('/modules/')
.load('Soldier.glb', (gltf) => {
console.log(gltf,'gltf')
// 旋轉(zhuǎn)模型
? ? gltf.scene.rotation.y =Math.PI
? ? // 模型縮放
? ? gltf.scene.scale.set(1,1,1)
// 遍歷模型對象(網(wǎng)格對象:改變屬性)
? ? gltf.scene.traverse((object) => {
if (object.isMesh) {
// 陰影
? ? ? ? object.castShadow =true
? ? ? ? // 接受投影
? ? ? ? object.receiveShadow =true
? ? ? }
})
// 獲取跑步動(dòng)畫
? ? mixer.value =startAnimation(
gltf.scene,
gltf.animations,
gltf.animations[3].name
? ? )
model.value = gltf
makeCurve()
scene.add(gltf.scene)
})
}
function init() {
// 場景
? scene =new THREE.Scene()
// 相機(jī) 透視相機(jī) fov視場角 aspect寬高比 near靠近攝像機(jī)的裁剪平面的距離 far遠(yuǎn)處的裁剪平面的距離
? camera =new THREE.PerspectiveCamera(75,window.innerWidth /window.innerHeight,0.1,1000)
// 渲染器
? renderer =new? THREE.WebGLRenderer()
// 相機(jī)位置
? camera.position.set(5,5,5)
// 相機(jī)看向那邊
? camera.lookAt(scene.position)
// 添加輔助坐標(biāo)x(紅色),y(綠色),z(藍(lán)色)
? const axes =new THREE.AxesHelper(20)
scene.add(axes)
// 場景背景
? scene.background =new THREE.Color(0xa0a0a0)
// 場景邊界霧化效果
? scene.fog =new THREE.Fog(0xa0a0a0,10,30)
// 半球形光源
? const hemiLight =new THREE.HemisphereLight(0xffffff,0x444444)
hemiLight.position.set(0,10,0)
scene.add(hemiLight)
// 創(chuàng)建一個(gè)虛擬的球形網(wǎng)格 Mesh 的輔助對象來模擬 半球形光源HemisphereLight
? const hemiLightHelper =new THREE.HemisphereLightHelper(hemiLight,5)
scene.add(hemiLightHelper)
// 地面 Mesh三位網(wǎng)格對象(集合體對象,材質(zhì)) PlaneGeometry創(chuàng)建平面幾何體 MeshPhongMaterial模擬光滑表面的高光效果
? const mesh =new THREE.Mesh(new THREE.PlaneGeometry(100,100),new THREE.MeshPhongMaterial({color:0x999999,depthWrite:false}))
mesh.rotation.x = -Math.PI /2
? mesh.receiveShadow =true
? scene.add(mesh)
// 平行光
? const directionalLight =new THREE.DirectionalLight(0xffffff)
// 燈光需要開啟“引起陰影”
? directionalLight.castShadow =true
? // 陰影樣式
? directionalLight.shadow.camera.near =0.5
? directionalLight.shadow.camera.far =50
? directionalLight.shadow.camera.left = -10
? directionalLight.shadow.camera.right =10
? directionalLight.shadow.camera.top =10
? directionalLight.shadow.camera.bottom = -10
? directionalLight.position.set(0,5,5)
// 陰影清晰度 默認(rèn)512
? directionalLight.shadow.mapSize.set(2048,2048)
scene.add(directionalLight)
// 用于模擬場景中平行光 DirectionalLight 的輔助對象. 其中包含了表示光位置的平面和表示光方向的線段
? const directionalLightHelper =new THREE.DirectionalLightHelper(directionalLight,5)
scene.add(directionalLightHelper)
// 渲染陰影
? renderer.shadowMap.enabled =true
? renderer.setSize(window.innerWidth,window.innerHeight)
sceneRef.value.appendChild(renderer.domElement)
}
function animate() {
requestAnimationFrame(animate)
if(mixer.value){
mixer.value.update(clock.getDelta())
}
renderer.render(scene,camera)
}
function initOrbitControls() {
orbitControls =new OrbitControls(camera,renderer.domElement)
// orbitControls.enableDamping = true
? //相機(jī)位置與觀察目標(biāo)點(diǎn)最大值
? // orbitControls.maxDistance = 1300
// orbitControls.maxPolarAngle = Math.PI / 2
? // // 上下旋轉(zhuǎn)范圍
? // orbitControls.minPolarAngle = -Math.PI / 2 //默認(rèn)值0
? // orbitControls.maxPolarAngle = Math.PI / 2 //默認(rèn)值Math.PI
? // // // 左右旋轉(zhuǎn)范圍
? // orbitControls.minAzimuthAngle = -Math.PI / 2
// orbitControls.maxAzimuthAngle = Math.PI / 2
}
// 監(jiān)聽窗口大小變化事件
window.addEventListener('resize',function() {
// 更新渲染器尺寸
? renderer.setSize(window.innerWidth,window.innerHeight);
// 更新相機(jī)寬高比
? camera.aspect =window.innerWidth /window.innerHeight;
camera.updateProjectionMatrix();
});
onMounted(() => {
init()
loadModel()
initOrbitControls()
animate()
})
<style scoped lang="scss">
</style>
