原創(chuàng) 雪天前端 雪天前端 2024-05-22 23:50 陜西 最近看了看Three.js,做了個入門級的小案例--簡易版的全景看房(可上下左右拖動,可滾輪調(diào)整遠(yuǎn)近,可操作面板自動轉(zhuǎn)動),vue2項目,注釋詳細(xì),需要學(xué)習(xí)three.js的道友可以一鍵復(fù)制去學(xué)習(xí),代碼看著挺多,其實不復(fù)雜。 1. 創(chuàng)建一個vue2項目
2. 安裝threeJs--主包 3. 安裝lil-gui--用于控制面板 4. 安裝tweenJs--用于做動畫 npm i @tweenjs/tween.js@^18
安裝以上包之后,創(chuàng)建一個空的.vue文件,CV以下代碼運行即可 <template> <div> <div id="container" ref="container"></div> </div> </template>
<script> import * as THREE from 'three'; import TWEEN from '@tweenjs/tween.js' import { OrbitControls } from "three/examples/jsm/controls/OrbitControls" import GUI from 'lil-gui'; export default { data() { return { bigImg: require("../assets/2.webp"), // 全景圖片路徑 container: null, // 頁面容器 camera: null, // 相機 renderer: null, // 渲染器 scene: null, // 場景 material: null, // 添加材質(zhì) texture: null, // 創(chuàng)建紋理貼圖 skyBox: null, // 網(wǎng)格 controls: null, // 軌道控制 clock: null, // 軌道更新時間 // 鼠標(biāo)屬性 bMouseDown: false, x: -1, y: -1, isClickCamera: false, // 是否點運動相機 raycaster: null, mouse: null, // 面板操作 myObject: { isRotation: false, // 是否自動旋轉(zhuǎn) isEnablePan: false, // 是否開啟右鍵拖拽 } } }, mounted() { this.init(); this.animate(); this.initGui() }, created() {}, methods: { // 初始化軌道控制 initControls() { this.controls = new OrbitControls(this.camera, this.renderer.domElement); this.controls.target = new THREE.Vector3(0, 0, 0); this.controls.minDistance = 18; // 相機最近 this.controls.maxDistance = 90; // 相機最遠(yuǎn) 太遠(yuǎn)就會顯示出球體 this.controls.autoRotate = this.myObject.isRotation; // 圖片自動旋轉(zhuǎn) this.controls.enableDamping = true; // 使動畫循環(huán)使用時阻尼或自轉(zhuǎn) 意思是否有慣性 this.controls.enablePan = this.myObject.isEnablePan; // 是否開啟右鍵拖拽 this.controls.autoRotateSpeed = 0.5; // 阻尼系數(shù) }, init() { // 頁面容器 this.container = document.getElementById('container');
// 創(chuàng)建渲染器 this.renderer = new THREE.WebGLRenderer(); this.renderer.setPixelRatio(window.devicePixelRatio);
// 設(shè)置畫布的寬高 this.renderer.setSize(window.innerWidth, window.innerHeight);
// 判斷容器中子元素的長度 let childs = this.container.childNodes; if (this.container.childNodes.length > 0) { this.container.removeChild(childs[0]); this.container.appendChild(this.renderer.domElement); } else { this.container.appendChild(this.renderer.domElement); }
// 創(chuàng)建場景 this.scene = new THREE.Scene();
// 創(chuàng)建相機 this.camera = new THREE.PerspectiveCamera(80, window.innerWidth / window.innerHeight, 1, 10000); this.camera.position.set(5, 0, 0); this.camera.lookAt(new THREE.Vector3(0, 0, 0)); //讓相機指向原點
// 創(chuàng)建軌道控制器 this.initControls();
// 添加材質(zhì) this.material = new THREE.MeshBasicMaterial(); // 創(chuàng)建紋理貼圖 this.texture = new THREE.TextureLoader().load(this.bigImg); this.material.map = this.texture;
const sphereGeometry = new THREE.SphereGeometry(100, 100, 100);
this.skyBox = new THREE.Mesh(sphereGeometry, this.material);
this.skyBox.geometry.scale(1, 1, -1); // 添加到場景中去 this.scene.add(this.skyBox);
// 鼠標(biāo)事件監(jiān)聽 this.renderer.domElement.addEventListener('pointerdown', this.onMouseDown, false); this.renderer.domElement.addEventListener('pointerup', this.onMouseUp, false); this.renderer.domElement.addEventListener('pointermove', this.onMouseMove, false);
// 監(jiān)聽布局變化 window.addEventListener('resize', this.onWindowResize, false);
}, // 更新相機動畫 tweenCamera(position, target) { new TWEEN.Tween(this.camera.position).to({ x: position.x, y: position.y, z: position.z }, 600).easing(TWEEN.Easing.Sinusoidal.InOut).start();
new TWEEN.Tween(this.controls.target).to({ x: target.x, y: target.y, z: target.z }, 600).easing(TWEEN.Easing.Sinusoidal.InOut).start(); }, // 鼠標(biāo)按下 onMouseDown(event) { event.preventDefault(); // 取消默認(rèn)事件 console.log("---onMouseDown---"); this.isClickCamera = true; }, // 鼠標(biāo)放開 onMouseUp(event) { event.preventDefault(); // 取消默認(rèn)事件 console.log("---onMouseUp---"); if (this.isClickCamera) { console.log("---移動相機---", event); // 紅色代表X軸,綠色代表Y軸,藍(lán)色代表Z軸 this.mouse = new THREE.Vector3(); // 三維坐標(biāo)對象 // 屏幕坐標(biāo)到標(biāo)準(zhǔn)化設(shè)備坐標(biāo)(Normalized Device Coordinates, NDC)轉(zhuǎn)換 this.mouse.set((event.clientX / window.innerWidth) * 2 - 1, -(event.clientY / window.innerHeight) * 2 + 1, 0.5); this.mouse.unproject(this.camera);
this.raycaster = new THREE.Raycaster(this.camera.position, this.mouse.sub(this.camera.position) .normalize()); // 投手 var intersects = this.raycaster.intersectObjects(this.scene.children);
if (intersects.length > 0) { var selected = intersects[0]; // 取第一個物體 console.log("x坐標(biāo):" + selected.point.x); console.log("y坐標(biāo):" + selected.point.y); console.log("z坐標(biāo):" + selected.point.z); this.camera.position.set(selected.point.x, selected.point.y, selected.point.z); } } }, // 鼠標(biāo)移動 onMouseMove(event) { event.preventDefault(); // 取消默認(rèn)事件 console.log("---onMouseMove---"); this.isClickCamera = false; }, onWindowResize() { // 窗口縮放的時候,保證場景也跟著一起縮放 this.camera.aspect = window.innerWidth / window.innerHeight; this.camera.updateProjectionMatrix(); this.renderer.setSize(window.innerWidth, window.innerHeight); }, animate() { requestAnimationFrame(this.animate); this.controls.update(); // 更新軌道控制 TWEEN.update(); this.renderer.render(this.scene, this.camera); }, initGui() { // 初始化 const gui = new GUI(); // 點擊控制是否自動旋轉(zhuǎn) gui.add(this.myObject, 'isRotation').onChange(value => { console.log(value); this.myObject.isRotation = value console.log(this.myObject.isRotation, '當(dāng)前狀態(tài)'); // 需重新調(diào)用控制器才能生效 this.initControls(); }); }, } } </script>
<style scoped>
</style>
使用的圖片(來源網(wǎng)絡(luò)) ![]()
threeJS是一個強大的開源JavaScript庫,用于創(chuàng)建3D圖形的交互式網(wǎng)頁應(yīng)用程序。它具有許多優(yōu)點,使得它成為開發(fā)人員首選的3D圖形庫之一。 提供了豐富的功能和靈活性,使開發(fā)人員能夠輕松地創(chuàng)建復(fù)雜的3D場景和動畫效果。它包含了大量的內(nèi)置功能和效果,如陰影、紋理映射、光照、粒子效果等,同時還支持各種3D模型和幾何體的加載和渲染。 具有優(yōu)秀的跨平臺性能和兼容性,可以在各種設(shè)備和瀏覽器上運行,包括桌面電腦、筆記本電腦、平板電腦和手機。這意味著開發(fā)人員可以開發(fā)一次,然后在各種設(shè)備上進(jìn)行測試和部署,同時確保用戶有一致的用戶體驗。 擁有龐大的社區(qū)支持和資源庫,開發(fā)人員可以從中獲取各種教程、示例和插件,幫助他們解決問題和加快開發(fā)進(jìn)度。這使得學(xué)習(xí)和使用threeJS變得更加容易和高效。 threeJS的優(yōu)點包括豐富的功能和靈活性、跨平臺性能和兼容性以及龐大的社區(qū)支持和資源庫,這些優(yōu)勢使得它成為開發(fā)3D圖形應(yīng)用程序的理想選擇。
|