前言：threejs实现导入模型，点击模型，被点击模型出现呼吸灯描边效果，主要使用threejs后处理模块实现使用技术：vue3+threejs@0.165.0效果图：引入使用库import * as THREE from 'three'; // threejs import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'; // 控制器 import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; // gltf/glb模型加载器 import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader'; // hdr环境贴图加载器 import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer"; // 后期效果合成器 import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass"; // 后期通道效果 import { OutlinePass } from "three/examples/jsm/postprocessing/OutlinePass"; // 发光描边 import { ShaderPass } from "three/examples/jsm/postprocessing/ShaderPass"; // 着色器 import { FXAAShader } from "three/examples/jsm/shaders/FXAAShader"; // 抗锯齿后处理 import { SMAAPass } from "three/examples/jsm/postprocessing/SMAAPass"; // 抗锯齿后处理 import { GammaCorrectionShader } from "three/examples/jsm/shaders/GammaCorrectionShader"; // 后处理颜色 伽马校正定义全局变量let camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000), scene = new THREE.Scene(), renderer = new THREE.WebGLRenderer({ antialias: true }), controls, smaaPass, raycaster = new THREE.Raycaster(), mouse, composer, renderPass, outlinePass;点击事件// 点击事件 const onDocumentMouseDown = (event) => { // 将鼠标位置转换成归一化设备坐标(-1 到 +1) mouse = new THREE.Vector2(); mouse.x = (event.clientX / window.innerWidth) * 2 - 1; mouse.y = - (event.clientY / window.innerHeight) * 2 + 1; // 使用鼠标的位置和当前相机的矩阵来更新射线 raycaster.setFromCamera(mouse, camera); // 计算物体和射线的交点 let intersects = raycaster.intersectObjects(scene.children); if (intersects.length != 0 && intersects[0].object instanceof THREE.Mesh) { outlineObj([intersects[0].object]) // 判断点击到模型，触发高亮效果 animate() } } // 双击事件 const onDocumentDoubleClick = () => { // 取消高亮显示 composer = null }高亮效果实现// 高亮显示模型（呼吸灯） const outlineObj = (selectedObjects) => { // 创建一个EffectComposer（效果组合器）对象，然后在该对象上添加后期处理通道。 composer = new EffectComposer(renderer) // 新建一个场景通道 覆盖到原来的场景上 renderPass = new RenderPass(scene, camera) composer.addPass(renderPass); // 物体边缘发光通道 --应用的宽高-应用的场景-应用的相机-应用的模型==计算位置 outlinePass = new OutlinePass(new THREE.Vector2(window.innerWidth, window.innerHeight), scene, camera, selectedObjects) outlinePass.selectedObjects = selectedObjects outlinePass.edgeStrength = 10.0 // 边框的亮度 outlinePass.edgeGlow = 1 // 光晕[0,1] outlinePass.usePatternTexture = false // 是否使用父级的材质 outlinePass.edgeThickness = 1.0 // 边框宽度 outlinePass.downSampleRatio = 1 // 边框弯曲度 outlinePass.pulsePeriod = 2 // 呼吸闪烁的速度 outlinePass.visibleEdgeColor.set(parseInt(0x00CCFF)) // 呼吸显示的颜色 0x00CCFF 0x00ff00 outlinePass.hiddenEdgeColor = new THREE.Color(0, 0, 0) // 呼吸消失的颜色 outlinePass.clear = true composer.addPass(outlinePass) // 自定义的着色器通道 作为参数 let effectFXAA = new ShaderPass(FXAAShader) effectFXAA.uniforms.resolution.value.set(1 / window.innerWidth, 1 / window.innerHeight) effectFXAA.renderToScreen = true composer.addPass(effectFXAA) // 抗锯齿 smaaPass = new SMAAPass(); composer.addPass(smaaPass); // 创建伽马校正通道 const gammaPass = new ShaderPass(GammaCorrectionShader); composer.addPass(gammaPass); }
前言：threejs入门，场景贴图、模型引入技术：vue3+three@0.165.0依赖引入import * as THREE from 'three'; import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'; import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader';代码let camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000), scene = new THREE.Scene(), renderer = new THREE.WebGLRenderer({ antialias: true }), controls； // 初始化场景 const initScene = () => { setEnvMap(); loadGltf('three/01.glb', [0, -20, 0], [0, 0, 0], [0.1, 0.1, 0.1], 'three/01.jpg') loadGltf('three/02.glb', [-20, -19, 0], [0, 0, 0], [10, 10, 10], 'three/02.png') } // 场景设置 const setEnvMap = () => { new RGBELoader().load(`three/001.hdr`, (texture) => { texture.mapping = THREE.EquirectangularRefractionMapping; scene.background = texture; scene.environment = texture; }, // 加载失败的回调 (xhr) => { console.error(xhr); } ); } // 加载gltf/glb模型 const loadGltf = (url, position, rotation, scale, textureUrl) => { const gltfLoader = new GLTFLoader(); gltfLoader.load(url, (gltf) => { let model = gltf.scene; if (textureUrl) { const textureLoader = new THREE.TextureLoader(); const texture = textureLoader.load(textureUrl); model.traverse((child) => { if (child instanceof THREE.Mesh) { child.material.map = texture; } }); } model.position.set(position[0], position[1], position[2]); model.rotation.set(rotation[0], rotation[1], rotation[2]); model.scale.set(scale[0], scale[1], scale[2]); scene.add(model); }); } // 相机 const initCamera = () => { camera.position.set(0, 28, 10); camera.lookAt(0, 0, 1); } // 渲染器 const initRenderer = () => { renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); } // 控制器 const initControls = () => { controls = new OrbitControls(camera, renderer.domElement); controls.dampingFactor = 0.25; controls.minDistance = 10; controls.maxDistance = 50; controls.maxPolarAngle = Math.PI / 2; controls.minPolarAngle = Math.PI / 4; controls.target.set(0, 0, 0); controls.update(); } // 渲染 const render = () => { requestAnimationFrame(render); renderer.render(scene, camera); controls.update(); for (let key in renderFunc) { renderFunc[key](); } }