最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

基于vue3+threejs實(shí)現(xiàn)可視化大屏效果

 更新時(shí)間:2023年06月08日 09:52:08   作者:蝴蝶刀砍手大師  
本文主要主要講述對(duì)threejs的一些api進(jìn)行基本的封裝,在vue3項(xiàng)目中來實(shí)現(xiàn)一個(gè)可視化的3d項(xiàng)目,包含了一些常用的功能,場景、燈光、攝像機(jī)初始化,模型、天空盒的加載,以及鼠標(biāo)點(diǎn)擊和懸浮的事件交互,感興趣的朋友可以參考下

前言

Three.js是一款基于原生WebGL封裝通用Web 3D引擎,在小游戲、產(chǎn)品展示、物聯(lián)網(wǎng)、數(shù)字孿生、智慧城市園區(qū)、機(jī)械、建筑、全景看房、GIS等各個(gè)領(lǐng)域基本上都有three.js的身影。

本文需要對(duì) threejs 的一些基本概念和 api 有一定了解。

本文主要主要講述對(duì) threejs 的一些 api 進(jìn)行基本的封裝,在 vue3 項(xiàng)目中來實(shí)現(xiàn)一個(gè)可視化的3d項(xiàng)目。包含了一些常用的功能,場景、燈光、攝像機(jī)初始化,模型、天空盒的加載,以及鼠標(biāo)點(diǎn)擊和懸浮的事件交互。

項(xiàng)目截圖:

Github 地址:GitHub - fh332393900/threejs-demo

項(xiàng)目預(yù)覽地址:Three Demo (stevenfeng.cn)

基礎(chǔ)功能

1.場景 Viewer 類

首先我們第一步需要初始化場景、攝像機(jī)、渲染器、燈光等。這些功能只需要加載一次,我們都放到 Viewer 類中可以分離關(guān)注點(diǎn),在業(yè)務(wù)代碼中就不需要關(guān)注這一部分邏輯。業(yè)務(wù)代碼中我們只需要關(guān)注數(shù)據(jù)與交互即可。

1.1 初始化場景和攝像機(jī)

private initScene() {
  this.scene = new Scene();
}
private initCamera() {
  // 渲染相機(jī)
  this.camera = new PerspectiveCamera(25, window.innerWidth / window.innerHeight, 1, 2000);
  //設(shè)置相機(jī)位置
  this.camera.position.set(4, 2, -3);
  //設(shè)置相機(jī)方向
  this.camera.lookAt(0, 0, 0);
}

1.2 初始化攝像機(jī)控制器

private initControl() {
  this.controls = new OrbitControls(
    this.camera as Camera,
    this.renderer?.domElement
  );
  this.controls.enableDamping = false;
  this.controls.screenSpacePanning = false; // 定義平移時(shí)如何平移相機(jī)的位置 控制不上下移動(dòng)
  this.controls.minDistance = 2;
  this.controls.maxDistance = 1000;
  this.controls.addEventListener('change', ()=>{
    this.renderer.render(this.scene, this.camera);
  });
}

1.3 初始化燈光

這里放了一個(gè)環(huán)境燈光和平行燈光,這里是寫在 Viewer 類里面的,如果想靈活一點(diǎn),也可以抽出去。

private initLight() {
  const ambient = new AmbientLight(0xffffff, 0.6);
  this.scene.add(ambient);
  const light = new THREE.DirectionalLight( 0xffffff );
  light.position.set( 0, 200, 100 );
  light.castShadow = true;
  light.shadow.camera.top = 180;
  light.shadow.camera.bottom = -100;
  light.shadow.camera.left = -120;
  light.shadow.camera.right = 400;
  light.shadow.camera.near = 0.1;
  light.shadow.camera.far = 400;
  // 設(shè)置mapSize屬性可以使陰影更清晰,不那么模糊
  light.shadow.mapSize.set(1024, 1024);
  this.scene.add(light);
}

1.4 初始化渲染器

private initRenderer() {
  // 獲取畫布dom
  this.viewerDom = document.getElementById(this.id) as HTMLElement;
  // 初始化渲染器
  this.renderer = new WebGLRenderer({
    logarithmicDepthBuffer: true,
    antialias: true, // true/false表示是否開啟反鋸齒
    alpha: true, // true/false 表示是否可以設(shè)置背景色透明
    precision: 'mediump', // highp/mediump/lowp 表示著色精度選擇
    premultipliedAlpha: true, // true/false 表示是否可以設(shè)置像素深度(用來度量圖像的分辨率)
    // preserveDrawingBuffer: false, // true/false 表示是否保存繪圖緩沖
    // physicallyCorrectLights: true, // true/false 表示是否開啟物理光照
  });
  this.renderer.clearDepth();
  this.renderer.shadowMap.enabled = true;
  this.renderer.outputColorSpace = SRGBColorSpace; // 可以看到更亮的材質(zhì),同時(shí)這也影響到環(huán)境貼圖。
  this.viewerDom.appendChild(this.renderer.domElement);
}

Viewer 里面還加了一些 addAxis 添加坐標(biāo)軸、addStats 性能監(jiān)控等輔助的公用方法。具體可以看倉庫完整代碼。

1.5 鼠標(biāo)事件

里面主要使用了 mitt 這個(gè)庫,來發(fā)布訂閱事件。

threejs里面的鼠標(biāo)事件主要通過把屏幕坐標(biāo)轉(zhuǎn)換成 3D 坐標(biāo)。通過raycaster.intersectObjects方法轉(zhuǎn)換。

/**注冊鼠標(biāo)事件監(jiān)聽 */
public initRaycaster() {
  this.raycaster = new Raycaster();
  const initRaycasterEvent: Function = (eventName: keyof HTMLElementEventMap): void => {
    const funWrap = throttle(
      (event: any) => {
        this.mouseEvent = event;
        this.mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
        this.mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;
        // @ts-expect-error
        this.emitter.emit(Events[eventName].raycaster, this.getRaycasterIntersectObjects());
      },
      50
    );
    this.viewerDom.addEventListener(eventName, funWrap, false);
  };
  // 初始化常用的幾種鼠標(biāo)事件
  initRaycasterEvent('click');
  initRaycasterEvent('dblclick');
  initRaycasterEvent('mousemove');
}
/**自定義鼠標(biāo)事件觸發(fā)的范圍,給定一個(gè)模型組,對(duì)給定的模型組鼠標(biāo)事件才生效 */
public setRaycasterObjects (objList: THREE.Object3D[]): void {
  this.raycasterObjects = objList;
}
private getRaycasterIntersectObjects(): THREE.Intersection[] {
  if (!this.raycasterObjects.length) return [];
  this.raycaster.setFromCamera(this.mouse, this.camera);
  return this.raycaster.intersectObjects(this.raycasterObjects, true);
}

通過 setRaycasterObjects 方法,傳遞一個(gè)觸發(fā)鼠標(biāo)事件的模型范圍,可以避免在整個(gè)場景中都去觸發(fā)鼠標(biāo)事件。這里也可以用一個(gè) Map 去存不同模型的事件,在取消訂閱時(shí)再移除。

使用方式:

let viewer: Viewer;
viewer = new Viewer('three');
viewer.initRaycaster();
viewer.emitter.on(Event.dblclick.raycaster, (list: THREE.Intersection[]) => {
  onMouseClick(list);
});
viewer.emitter.on(Event.mousemove.raycaster, (list: THREE.Intersection[]) => {
  onMouseMove(list);
});

2.模型加載器 ModelLoder 類

模型的加載我們需要用的threejs里面的,GLTFLoader、DRACOLoader 這兩個(gè)類。

模型加載器 ModelLoder 初始化的時(shí)候需要把 Viewer 的實(shí)例傳進(jìn)去。

需要注意的是,需要把 draco 從 node_modules 拷貝到項(xiàng)目的 public 目錄中去。

實(shí)現(xiàn)代碼:

import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
import BaseModel from '../BaseModel';
import type Viewer from '../Viewer';
type LoadModelCallbackFn<T = any> = (arg: T) => any;
/**模型加載器 */
export default class ModelLoder {
  protected viewer: Viewer;
  private gltfLoader: GLTFLoader;
  private dracoLoader: DRACOLoader;
  constructor(viewer: Viewer, dracolPath: string = '/draco/') {
    this.viewer = viewer;
    this.gltfLoader = new GLTFLoader();
    this.dracoLoader = new DRACOLoader();
    // 提供一個(gè)DracLoader實(shí)例來解碼壓縮網(wǎng)格數(shù)據(jù)
    // 沒有這個(gè)會(huì)報(bào)錯(cuò) dracolPath 默認(rèn)放在public文件夾當(dāng)中
    this.dracoLoader.setDecoderPath(dracolPath);
    this.gltfLoader.setDRACOLoader(this.dracoLoader);
  }
  /**模型加載到場景 */
  public loadModelToScene(url: string, callback: LoadModelCallbackFn<BaseModel>) {
    this.loadModel(url, model => {
      this.viewer.scene.add(model.object);
      callback && callback(model);
    });
  }
  private loadModel(url: string, callback: LoadModelCallbackFn<BaseModel>) {
    this.gltfLoader.load(url, gltf => {
      const baseModel = new BaseModel(gltf, this.viewer);
      callback && callback(baseModel);
    });
  }
}

3.模型 BaseModel 類

這里對(duì)模型外面包了一層,做了一些額外的功能,如模型克隆、播放動(dòng)畫、設(shè)置模型特性、顏色、材質(zhì)等方法。

/**
* 設(shè)置模型動(dòng)畫
* @param i 選擇模型動(dòng)畫進(jìn)行播放
*/
public startAnima(i = 0) {
  this.animaIndex = i;
  if (!this.mixer) this.mixer = new THREE.AnimationMixer(this.object);
  if (this.gltf.animations.length < 1) return;
  this.mixer.clipAction(this.gltf.animations[i]).play();
  // 傳入?yún)?shù)需要將函數(shù)與函數(shù)參數(shù)分開,在運(yùn)行時(shí)填入
  this.animaObject = {
    fun: this.updateAnima,
    content: this,
  };
  this.viewer.addAnimate(this.animaObject);
}
private updateAnima(e: any) {
  e.mixer.update(e.clock.getDelta());
}

還有一些其他方法的實(shí)現(xiàn),可以看倉庫代碼。

4.天空盒 SkyBoxs 類

import * as THREE from 'three';
import type Viewer from '../Viewer';
import { Sky } from '../type';
/** 場景天空盒*/
export default class SkyBoxs {
  protected viewer: Viewer;
  constructor (viewer: Viewer) {
    this.viewer = viewer;
  }
  /**
   * 添加霧效果
   * @param color 顏色
   */
  public addFog (color = 0xa0a0a0, near = 500, far = 2000) {
    this.viewer.scene.fog = new THREE.Fog(new THREE.Color(color), near, far);
  }
  /**
   * 移除霧效果
   */
  public removeFog () {
    this.viewer.scene.fog = null;
  }
  /**
   * 添加默認(rèn)天空盒
   * @param skyType
   */
  public addSkybox (skyType: keyof typeof Sky = Sky.daytime) {
    const path = `/skybox/${Sky[skyType]}/`; // 設(shè)置路徑
    const format = '.jpg'; // 設(shè)定格式
    this.setSkybox(path, format);
  }
  /**
   * 自定義添加天空盒
   * @param path 天空盒地址
   * @param format 圖片后綴名
   */
  private setSkybox (path: string, format = '.jpg') {
    const loaderbox = new THREE.CubeTextureLoader();
    const cubeTexture = loaderbox.load([
      path + 'posx' + format,
      path + 'negx' + format,
      path + 'posy' + format,
      path + 'negy' + format,
      path + 'posz' + format,
      path + 'negz' + format,
    ]);
    // 需要把色彩空間編碼改一下
    cubeTexture.encoding = THREE.sRGBEncoding;
    this.viewer.scene.background = cubeTexture;
  }
}

5.模型輪廓輔助線

通過 BoxHelper 可以實(shí)現(xiàn)簡單的鼠標(biāo)選中的特效。

也可以通過 OutlinePass 實(shí)現(xiàn)發(fā)光的特效。

import {
  BoxHelper,
  Color,
  Object3D
} from 'three';
import type Viewer from '../Viewer';
export default class BoxHelperWrap {
  protected viewer: Viewer;
  public boxHelper: BoxHelper;
  constructor (viewer: Viewer, color?: number) {
    this.viewer = viewer;
    const boxColor = color === undefined ? 0x00ffff : color;
    this.boxHelper = new BoxHelper(new Object3D(), new Color(boxColor));
    // // @ts-expect-error
    // this.boxHelper.material.depthTest = false;
    this.initBoxHelperWrap();
  }
  private initBoxHelperWrap () {
    this.viewer.scene.add(this.boxHelper);
  }
  public setVisible (visible: boolean): void {
    this.boxHelper.visible = visible;
  }
  public attach (obj: Object3D): void {
    this.boxHelper.setFromObject(obj);
    this.setVisible(true);
  }
  public dispose (): void {
    const parent = this.boxHelper.parent;
    if (parent !== null) {
      parent.remove(this.boxHelper);
    }
    Object.keys(this).forEach(key => {
      // @ts-expect-error
      this[key] = null;
    });
  }
}

使用方式:

let modelLoader = new ModelLoader(viewer);
boxHelperWrap = new BoxHelperWrap(viewer);
boxHelperWrap.setVisible(false);

以上就是基于vue3+threejs實(shí)現(xiàn)可視化大屏效果的詳細(xì)內(nèi)容,更多關(guān)于vue3+threejs 可視化的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Vue+(SSE)EventSource實(shí)現(xiàn)流式輸出過程

    Vue+(SSE)EventSource實(shí)現(xiàn)流式輸出過程

    文章介紹了如何在Vue項(xiàng)目中使用EventSource和FetchEventSource實(shí)現(xiàn)服務(wù)器端事件驅(qū)動(dòng)推送,并分享了它們的特點(diǎn)、優(yōu)勢以及使用流程,通過設(shè)置請(qǐng)求頭和請(qǐng)求方式,解決了EventSource無法設(shè)置這些屬性的問題
    2025-12-12
  • vue+ts實(shí)現(xiàn)元素鼠標(biāo)拖動(dòng)效果

    vue+ts實(shí)現(xiàn)元素鼠標(biāo)拖動(dòng)效果

    這篇文章主要為大家詳細(xì)介紹了vue+ts實(shí)現(xiàn)元素鼠標(biāo)拖動(dòng)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • jenkins自動(dòng)構(gòu)建發(fā)布vue項(xiàng)目的方法步驟

    jenkins自動(dòng)構(gòu)建發(fā)布vue項(xiàng)目的方法步驟

    這篇文章主要介紹了jenkins自動(dòng)構(gòu)建發(fā)布vue項(xiàng)目的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • vue3動(dòng)態(tài)加載組件以及動(dòng)態(tài)引入組件詳解

    vue3動(dòng)態(tài)加載組件以及動(dòng)態(tài)引入組件詳解

    ?平常的vue項(xiàng)目開發(fā),已經(jīng)很難遇見一千行,甚至幾千行代碼的頁面了,畢竟大家都會(huì)去拆分組件,下面這篇文章主要給大家介紹了關(guān)于vue3動(dòng)態(tài)加載組件以及動(dòng)態(tài)引入組件的相關(guān)資料,需要的朋友可以參考下
    2023-03-03
  • 詳解Vue.js項(xiàng)目API、Router配置拆分實(shí)踐

    詳解Vue.js項(xiàng)目API、Router配置拆分實(shí)踐

    這篇文章主要介紹了詳解Vue.js項(xiàng)目API、Router配置拆分實(shí)踐,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-03-03
  • vue如何實(shí)現(xiàn)本項(xiàng)目頁面之間跳轉(zhuǎn)

    vue如何實(shí)現(xiàn)本項(xiàng)目頁面之間跳轉(zhuǎn)

    這篇文章主要介紹了vue如何實(shí)現(xiàn)本項(xiàng)目頁面之間跳轉(zhuǎn),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • vue中input的v-model清空操作

    vue中input的v-model清空操作

    這篇文章主要介紹了vue中input的v-model清空操作,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-09-09
  • Vue項(xiàng)目中使用v-show和v-if指令以及原理、區(qū)別和適用場景說明

    Vue項(xiàng)目中使用v-show和v-if指令以及原理、區(qū)別和適用場景說明

    Vue中v-show通過display屬性控制顯示隱藏,元素始終存在DOM,適合頻繁切換;v-if條件為false時(shí)移除元素,適合初始條件不成立的情況,性能上首次渲染可能更優(yōu),但切換頻繁時(shí)v-show更高效,其他方式包括綁定style/class、計(jì)算屬性及第三方動(dòng)畫庫
    2025-07-07
  • Vue3+Vite項(xiàng)目依賴更新的完整指南

    Vue3+Vite項(xiàng)目依賴更新的完整指南

    本文介紹了Vue3項(xiàng)目依賴更新的推薦方法,包括使用npm-check-updates或Yarn交互式升級(jí)工具,強(qiáng)調(diào)需謹(jǐn)慎處理版本兼容性及破壞性變更,建議分步更新并充分測試,確保項(xiàng)目穩(wěn)定性,需要的朋友可以參考下
    2025-09-09
  • vue-extend和vue-component注冊一個(gè)全局組件方式

    vue-extend和vue-component注冊一個(gè)全局組件方式

    這篇文章主要介紹了vue-extend和vue-component注冊一個(gè)全局組件方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11

最新評(píng)論

永胜县| 秦安县| 广汉市| 玉环县| 东平县| 汕尾市| 古丈县| 尼玛县| 望都县| 上栗县| 连云港市| 陆丰市| 湘潭县| 从化市| 泗水县| 礼泉县| 平邑县| 大丰市| 信丰县| 富宁县| 固安县| 江山市| 辽源市| 邵阳县| 成武县| 岑巩县| 江都市| 资阳市| 依安县| 年辖:市辖区| 天水市| 惠东县| 辉南县| 沾益县| 福清市| 张家界市| 老河口市| 五指山市| 兴义市| 佛山市| 德保县|