这段时间一直在学习three,vue3 和TS 一直有了解但做项目都没有使用,趁着有时间,想着自己做个小demo检测所学成果。
安装three,@types/three,我使用vue创建项目,TS版本和three 不兼容,然后又下载的最新版本。
然后封装一个类,初始化场景,相机,控制器,渲染器,后期处理,以及加载模型和hdr资源的方法,需要注意是加载GLTFLoader文件,如果需要DRACOLoader解码,需要将node_modules/three/examples/js/libs/draco 文件拷贝到public目录下。
import * as THREE from "three"; import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"; import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader"; import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader"; import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; // 导入后期效果合成器 import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer"; import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass"; import { DotScreenPass } from "three/examples/jsm/postprocessing/DotScreenPass"; import { SMAAPass } from "three/examples/jsm/postprocessing/SMAAPass"; import { UnrealBloomPass } from "three/examples/jsm/postprocessing/UnrealBloomPass"; import gsap from "gsap"; export default class World{ public scene: THREE.Scene; public camera: THREE.PerspectiveCamera; public renderer: THREE.WebGLRenderer; public domElement: HTMLElement; public width: number; public height: number; public control: OrbitControls; public effectComposer: EffectComposer; constructor(id:string) { this.domElement = document.getElementById(id)!; this.width = this.domElement.clientWidth; this.height = this.domElement.clientHeight; this.init(); } public initScene():void { this.scene = new THREE.Scene(); this.scene.background = new THREE.Color("rgba(0,25,20,0)"); } public initCamera(): void{ this.camera = new THREE.PerspectiveCamera(45, this.width / this.height, 1, 1000); this.camera.position.set(20, 10, 20); this.scene.add(this.camera); this.camera.aspect = this.width / this.height; // 更新摄像机的投影矩阵 this.camera.updateProjectionMatrix(); } public initRenderer():void { this.renderer = new THREE.WebGLRenderer( { logarithmicDepthBuffer: true, antialias: true, } ) this.renderer.setSize(this.width, this.height); this.renderer.shadowMap.enabled = true; this.renderer.outputEncoding = THREE.sRGBEncoding; this.renderer.physicallyCorrectLights = true; this.renderer.toneMapping = THREE.ACESFilmicToneMapping; this.renderer.toneMappingExposure = 0.75; this.renderer.sortObjects = true; this.domElement.appendChild(this.renderer.domElement) } public addAxis(): void { let axis = new THREE.AxesHelper(5); this.scene.add(axis); } public initControl() { this.control = new OrbitControls( this.camera, this.renderer.domElement ); } public init():void { this.initScene(); this.initCamera(); this.initRenderer(); this.addAxis(); this.initControl(); //this.initEffect(); this.update() } public initEffect():void{ // 合成效果 this.effectComposer = new EffectComposer(this.renderer); this.effectComposer.setSize(window.innerWidth, window.innerHeight); // 添加渲染通道 const renderPass = new RenderPass(this.scene, this.camera); this.effectComposer.addPass(renderPass); // 点效果 // const dotScreenPass = new DotScreenPass(); // dotScreenPass.enabled = false; // effectComposer.addPass(dotScreenPass); // 抗锯齿 // const smaaPass = new SMAAPass(); // this.effectComposer.addPass(smaaPass); // // 发光效果 // this.unrealBloomPass = new UnrealBloomPass(); // this.effectComposer.addPass(this.unrealBloomPass); } public update(): void { this.control && this.control.update(); this.renderer.render(this.scene, this.camera); // this.effectComposer.render(); // 每一帧去执行这个渲染方法 requestAnimationFrame(this.update.bind(this)); } public hdrLoader(url:string):any { const hdrLoader = new RGBELoader(); return new Promise((resolve, reject) => { hdrLoader.load(url, (hdr) => { resolve(hdr); }); }); } public setBg(url:string):void { this.hdrLoader(url).then((texture : THREE.Texture):void => { texture.mapping = THREE.EquirectangularReflectionMapping; texture.anisotropy = 16; texture.format = THREE.RGBAFormat; this.scene.background = texture; this.scene.environment = texture; }); } public gltfLoader(url:string):any { const gltfLoader = new GLTFLoader(); const dracoLoader = new DRACOLoader(); dracoLoader.setDecoderPath("./draco/gltf/"); dracoLoader.setDecoderConfig({ type: "js" }); dracoLoader.preload(); gltfLoader.setDRACOLoader(dracoLoader); return new Promise((resolve, reject) => { gltfLoader.load(url, (gltf) => { resolve(gltf); }); }); } }
在vue页面引入,调用就可以了
<template> <div id="contain"></div> </template> <script lang="ts" setup> import * as THREE from "three"; import { onMounted } from "vue"; import World from "../three/index"; onMounted(() => { let world = new World("contain"); world.setBg("./textures/1.hdr"); world.gltfLoader("./model/RobotExpressive.glb").then((gltf: THREE.Group) => { world.scene.add(gltf.scene); }); }); </script> <style scoped > #contain { width: 1920px; height: 1080px; overflow: hidden; } </style>
页面渲染出来,three 初始化基本就搭建好了