WebGL_0020:threejs 加载glb模型,加载图片贴图,加载canvas贴图,创建精灵模型并贴图,设置正交相机射线方法
1,threejs 加载glb模型
import * as THREE from 'three'; import type { MapViewer } from '@/utils/map3d/mapViewer'; import { STATIC_URL } from '@/config'; import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; const getSpriteMaterial = (color: THREE.Color, text: string) => { const canvas = document.createElement('canvas'); canvas.width = 64; canvas.height = 64; const context: any = canvas.getContext('2d'); context.beginPath(); context.arc(32, 32, 16, 0, 2 * Math.PI); context.closePath(); context.fillStyle = color.getStyle(); context.fill(); if (text) { context.font = '24px Arial'; context.textAlign = 'center'; context.fillStyle = '#FFFFFF'; context.fillText(text, 32, 41); } const texture = new THREE.CanvasTexture(canvas); return new THREE.SpriteMaterial({ map: texture }); }; //WG ADD 增加获取canvas贴图方法 const getCanvasTexture = (color: THREE.Color, text: string) => { const canvas = document.createElement('canvas'); canvas.width = 64; canvas.height = 64; const context: any = canvas.getContext('2d'); context.fillStyle = 'blue'; context.fillRect(0, 0, 100, 100); if (text) { context.font = '30px Arial'; context.textAlign = 'center'; context.fillStyle = '#ffffff'; context.fillText(text, 32, 41); } const texture = new THREE.CanvasTexture(canvas); texture.flipY = false; return texture; }; const useViewHelper = (mapViewer: MapViewer) => { const viewer = mapViewer.viewer; const helperGroup = new THREE.Group(); const interactiveObjects: Array<THREE.Object3D> = []; const color1 = new THREE.Color('#ff4000'); const color2 = new THREE.Color('#0032ff'); const color3 = new THREE.Color('#46ff00'); const color4 = new THREE.Color('#888888'); const width = 150; const offsetX = 300; const viewport = new THREE.Vector4(); const domElement = viewer.renderer.domElement; // const orthoCamera = new THREE.OrthographicCamera(-2, 2, 2, -2, -10, 10); const orthoCamera = new THREE.OrthographicCamera(-2, 2, 2, -2, -2, 2); // const orthoCamera = new THREE.PerspectiveCamera(75,window.innerWidth / window.innerHeight,0.1,1000); orthoCamera.position.set(0, 0, 0); //WG orthoCamera.rotation.order = 'ZXY'; // orthoCamera.rotation.order = 'ZXY'; // orthoCamera.rotation.x = Math.PI / 2; orthoCamera.lookAt(new THREE.Vector3(0, 0, -1)); orthoCamera.updateMatrixWorld(); const cameraChange = (e: any) => { // console.log(e.camera); orthoCamera.rotation.copy(e.camera.rotation); orthoCamera.updateMatrixWorld(); }; let handleMouseDown = (event: any) => { let mouse = new THREE.Vector2(); const rect = domElement.getBoundingClientRect(); const x = rect.left + domElement.clientWidth - width - offsetX; mouse.x = event.clientX - x; mouse.y = event.clientY - rect.top; if (mouse.x < 0 || mouse.y > width) return; mouse.x = (mouse.x / width) * 2 - 1; mouse.y = -(mouse.y / width) * 2 + 1; let raycaster = new THREE.Raycaster(); raycaster.setFromCamera(mouse, orthoCamera); raycaster.ray.origin.sub(orthoCamera.getWorldDirection(new THREE.Vector3())); let intersects = raycaster.intersectObjects(interactiveObjects); console.log(intersects); if (intersects.length > 0) { mapViewer.setViews(intersects[0].object.name); } }; const renderHelper = () => { const x = domElement.offsetWidth - width - offsetX; const y = domElement.offsetHeight - width; viewer.renderer.getViewport(viewport); viewer.renderer.setViewport(x, y, width, width); viewer.renderer.render(helperGroup, orthoCamera); viewer.renderer.setViewport(viewport.x, viewport.y, viewport.z, viewport.w); }; //WG ADD 增加加载模型的方法 // function loadMod() { // let terminalGeo: THREE.BufferGeometry | null = null; // let gltfLoader = new GLTFLoader(); // let terminalMeh: THREE.Mesh | null = null; // return new Promise(resovle => { // gltfLoader.load(`${STATIC_URL}/model/terminal.glb`, (gltf) => { // const model = gltf.scene.getObjectByName('平面') as THREE.Mesh; // terminalGeo = model.geometry as THREE.BufferGeometry; // const material = new THREE.MeshBasicMaterial({ color: '#e5380a' }); // terminalMeh = new THREE.Mesh(terminalGeo.clone(), material); // helperGroup.add(terminalMeh); // resovle(terminalMeh); // }); // }); // }; // await loadMod(); function create() { // const geometry = new THREE.BoxGeometry(0.8, 0.02, 0.02); // geometry.translate(0.4, 0, 0); // // X轴 // const xAxis = new THREE.Mesh( // geometry, // new THREE.MeshBasicMaterial({ // color: color1, // side: 2, // depthWrite: false // }) // ); // const posXAxisHelper = new THREE.Sprite(getSpriteMaterial(color1, 'X')); // posXAxisHelper.name = 'R'; // posXAxisHelper.position.x = 0.8; // posXAxisHelper.scale.setScalar(0.4); // posXAxisHelper.updateMatrixWorld(); // const negXAxisHelper = new THREE.Sprite(getSpriteMaterial(color4, '-X')); // negXAxisHelper.name = 'L'; // negXAxisHelper.position.x = -0.8; // negXAxisHelper.scale.setScalar(0.4); // negXAxisHelper.updateMatrixWorld(); // // Y轴 // const yAxis = new THREE.Mesh( // geometry, // new THREE.MeshBasicMaterial({ // color: color2, // side: 2, // depthWrite: false // }) // ); // yAxis.rotation.y = -Math.PI / 2; // yAxis.updateMatrixWorld(); // const posYAxisHelper = new THREE.Sprite(getSpriteMaterial(color2, 'Y')); // posYAxisHelper.name = 'U'; // posYAxisHelper.position.z = 0.8; // posYAxisHelper.scale.setScalar(0.4); // posYAxisHelper.updateMatrixWorld(); // const negYAxisHelper = new THREE.Sprite(getSpriteMaterial(color4, '-Y')); // negYAxisHelper.name = 'F'; // negYAxisHelper.position.z = -0.8; // negYAxisHelper.scale.setScalar(0.4); // negYAxisHelper.updateMatrixWorld(); // // Z轴 // const zAxis = new THREE.Mesh( // geometry, // new THREE.MeshBasicMaterial({ // color: color3, // side: 2, // depthWrite: false // }) // ); // zAxis.rotation.z = Math.PI / 2; // zAxis.updateMatrixWorld(); // const posZAxisHelper = new THREE.Sprite(getSpriteMaterial(color3, 'Z')); // posZAxisHelper.name = 'B'; // posZAxisHelper.position.y = 0.8; // posZAxisHelper.scale.setScalar(0.4); // posZAxisHelper.updateMatrixWorld(); // const negZAxisHelper = new THREE.Sprite(getSpriteMaterial(color4, '-Z')); // negZAxisHelper.name = 'D'; // negZAxisHelper.position.y = -0.8; // negZAxisHelper.scale.setScalar(0.4); // negZAxisHelper.updateMatrixWorld(); // let terminalGeo: THREE.BufferGeometry | null = null; // let gltfLoader = new GLTFLoader(); // gltfLoader.load(`${STATIC_URL}/model/terminal.glb`, (gltf) => { // const model = gltf.scene.getObjectByName('平面') as THREE.Mesh; // terminalGeo = model.geometry as THREE.BufferGeometry; // }); // if (terminalGeo) { // const material = new THREE.MeshBasicMaterial({ color: '#e5380a' }); // const terminalMeh = new THREE.Mesh(terminalGeo.clone(), material); // terminalMeh.addEventListener('drag', handleDrag); // terminalMeh.addEventListener('mouseup', handleMouseup); // terminals.push(terminalMeh); // return terminalMeh; // } //WG ADD 调用加载模型方法 // let terminalGeo: THREE.BufferGeometry | null = null; let gltfLoader = new GLTFLoader(); // let terminalMeh: THREE.Mesh | null = null; gltfLoader.load(`${STATIC_URL}/model/navbox.glb`, (gltf) => { const model = gltf.scene; model.traverse((child) => { if (child instanceof THREE.Mesh) { // // 创建新的材质 // const newMaterial = new THREE.MeshBasicMaterial({ // color: 0xffffff, // 设置你想要的颜色 // // map: new THREE.TextureLoader().load(`${STATIC_URL}/model/front.png`) // 设置纹理贴图 // map: getCanvasTexture(color4, '前') // }); // // 赋予新的材质 // child.material = newMaterial; let newMat: THREE.MeshBasicMaterial | null = null; let lmap: THREE.CanvasTexture | null = null; switch (child.name) { case 'Front_1': newMat = new THREE.MeshBasicMaterial({ color: 0xffffff, map: getCanvasTexture(color4, '上') }); child.material = newMat; child.name = '上'; interactiveObjects.push(child); break; case 'After_1': lmap = getCanvasTexture(color4, '下'); lmap.rotation = THREE.MathUtils.degToRad(180); lmap.center.set(0.5, 0.5); newMat = new THREE.MeshBasicMaterial({ color: 0xffffff, map: lmap }); child.material = newMat; child.name = '下'; interactiveObjects.push(child); break; case 'Left_1': lmap = getCanvasTexture(color4, '左'); lmap.rotation = THREE.MathUtils.degToRad(90); lmap.center.set(0.5, 0.5); newMat = new THREE.MeshBasicMaterial({ color: 0xffffff, map: lmap }); child.material = newMat; child.name = '左'; interactiveObjects.push(child); break; case 'Right_1': lmap = getCanvasTexture(color4, '右'); lmap.rotation = THREE.MathUtils.degToRad(-90); lmap.center.set(0.5, 0.5); newMat = new THREE.MeshBasicMaterial({ color: 0xffffff, map: lmap }); child.material = newMat; child.name = '右'; interactiveObjects.push(child); break; case 'Up_1': lmap = getCanvasTexture(color4, '前'); lmap.rotation = THREE.MathUtils.degToRad(180); lmap.center.set(0.5, 0.5); newMat = new THREE.MeshBasicMaterial({ color: 0xffffff, map: lmap }); child.material = newMat; child.name = '前'; interactiveObjects.push(child); break; case 'Lower_1': newMat = new THREE.MeshBasicMaterial({ color: 0xffffff, map: getCanvasTexture(color4, '后') }); child.material = newMat; child.name = '后'; interactiveObjects.push(child); break; case 'Horn_1_1': newMat = new THREE.MeshBasicMaterial({ color: 0xFFFFFF, side: THREE.DoubleSide }); child.material = newMat; child.name = '上角4'; interactiveObjects.push(child); break; case 'Horn_2_1': newMat = new THREE.MeshBasicMaterial({ color: 0xFFFFFF, side: THREE.DoubleSide }); child.material = newMat; child.name = '上角3'; interactiveObjects.push(child); break; case 'Horn_3_1': newMat = new THREE.MeshBasicMaterial({ color: 0xFFFFFF, side: THREE.DoubleSide }); child.material = newMat; child.name = '下角3'; interactiveObjects.push(child); break; case 'Horn_4_1': newMat = new THREE.MeshBasicMaterial({ color: 0xFFFFFF, side: THREE.DoubleSide }); child.material = newMat; child.name = '下角4'; interactiveObjects.push(child); break; case 'Horn_5_1': newMat = new THREE.MeshBasicMaterial({ color: 0xFFFFFF, side: THREE.DoubleSide }); child.material = newMat; child.name = '上角1'; interactiveObjects.push(child); break; case 'Horn_6_1': newMat = new THREE.MeshBasicMaterial({ color: 0xFFFFFF, side: THREE.DoubleSide }); child.material = newMat; child.name = '上角2'; interactiveObjects.push(child); break; case 'Horn_7_1': newMat = new THREE.MeshBasicMaterial({ color: 0xFFFFFF, side: THREE.DoubleSide }); child.material = newMat; child.name = '下角2'; interactiveObjects.push(child); break; case 'Horn_8_1': newMat = new THREE.MeshBasicMaterial({ color: 0xFFFFFF, side: THREE.DoubleSide }); child.material = newMat; child.name = '下角1'; interactiveObjects.push(child); break; case 'Up_front_1': newMat = new THREE.MeshBasicMaterial({ color: 0x5A5858 }); child.material = newMat; child.name = '上边3'; interactiveObjects.push(child); break; case 'Right_up_1': newMat = new THREE.MeshBasicMaterial({ color: 0x5A5858 }); child.material = newMat; child.name = '中边3'; interactiveObjects.push(child); break; case 'Up_after_1': newMat = new THREE.MeshBasicMaterial({ color: 0x5A5858 }); child.material = newMat; child.name = '下边3'; interactiveObjects.push(child); break; case 'Left_up_1': newMat = new THREE.MeshBasicMaterial({ color: 0x5A5858 }); child.material = newMat; child.name = '中边4'; interactiveObjects.push(child); break; case 'Left_front_1': newMat = new THREE.MeshBasicMaterial({ color: 0x5A5858 }); child.material = newMat; child.name = '上边4'; interactiveObjects.push(child); break; case 'Right_front_1': newMat = new THREE.MeshBasicMaterial({ color: 0x5A5858 }); child.material = newMat; child.name = '上边2'; interactiveObjects.push(child); break; case 'Right_after_1': newMat = new THREE.MeshBasicMaterial({ color: 0x5A5858 }); child.material = newMat; child.name = '下边2'; interactiveObjects.push(child); break; case 'Left_after_1': newMat = new THREE.MeshBasicMaterial({ color: 0x5A5858 }); child.material = newMat; child.name = '下边4'; interactiveObjects.push(child); break; case 'Lower_front_1': newMat = new THREE.MeshBasicMaterial({ color: 0x5A5858 }); child.material = newMat; child.name = '上边1'; interactiveObjects.push(child); break; case 'Right_lower_1': newMat = new THREE.MeshBasicMaterial({ color: 0x5A5858 }); child.material = newMat; child.name = '中边2'; interactiveObjects.push(child); break; case 'Lower_after_1': newMat = new THREE.MeshBasicMaterial({ color: 0x5A5858 }); child.material = newMat; child.name = '下边1'; interactiveObjects.push(child); break; case 'Left_lower_1': newMat = new THREE.MeshBasicMaterial({ color: 0x5A5858 }); child.material = newMat; child.name = '中边1'; interactiveObjects.push(child); break; default: break; } } }); helperGroup.add(model); }); viewer.addEventListener('camera_changed', cameraChange); viewer.addEventListener('render.pass.perspective_overlay', renderHelper); domElement.addEventListener('mousedown', handleMouseDown, false); } function dispose() { if (interactiveObjects.length > 0) { helperGroup.traverse((item: any) => { if (item.geometry) { item.geometry.dispose(); item.material.map?.dispose(); item.material.dispose(); } }); helperGroup.children.length = 0; interactiveObjects.length = 0; viewer.removeEventListener('camera_changed', cameraChange); viewer.removeEventListener('render.pass.perspective_overlay', renderHelper); domElement.removeEventListener('mousedown', handleMouseDown); } } return { create, dispose }; }; export { useViewHelper };
2,设置正交相机射线方法
let handleMouseDown = (event: any) => { let mouse = new THREE.Vector2(); const rect = domElement.getBoundingClientRect(); const x = rect.left + domElement.clientWidth - width - offsetX; mouse.x = event.clientX - x; mouse.y = event.clientY - rect.top; if (mouse.x < 0 || mouse.y > width) return; mouse.x = (mouse.x / width) * 2 - 1; mouse.y = -(mouse.y / width) * 2 + 1; let raycaster = new THREE.Raycaster(); raycaster.setFromCamera(mouse, orthoCamera); //WG raycaster.ray.origin.sub(orthoCamera.getWorldDirection(new THREE.Vector3())); // 计算射线的起点和方向 // const rayOrigin = raycaster.ray.origin; // const rayDirection = raycaster.ray.direction; // // 获取相机的世界方向 // const cameraDirection = new THREE.Vector3(); // orthoCamera.getWorldDirection(cameraDirection); // // 将射线起点设置为相机位置加上相机的反向向量 // rayOrigin.copy(orthoCamera.position); // rayDirection.copy(cameraDirection).negate(); // 设置射线的起点为摄像机的位置 // raycaster.ray.origin.copy(orthoCamera.position); // // 设置射线的方向为摄像机的查看方向 // raycaster.ray.direction.set(0, 0, -1); // 假设摄像机沿着 Z 轴负方向查看 // raycaster.ray.direction.applyMatrix4(orthoCamera.matrixWorldInverse); raycaster.ray.origin.sub(orthoCamera.getWorldDirection(new THREE.Vector3())).sub(orthoCamera.getWorldDirection(new THREE.Vector3())); let intersects = raycaster.intersectObjects(interactiveObjects); console.log(intersects); if (intersects.length > 0) { mapViewer.setViews(intersects[0].object.name); } };
琥珀君的博客