vue3+3d-force-graph渲染glb模型
準備工作:
1.找好要渲染的glb/gltf模型
2.安裝three.js
3.安裝3d-force-graph
4.準備圖譜數據
開始操作
1、聲明一個div標簽 通過ref獲取此div元素
<div class="force_style" ref="graphRef"></div>
2、定義初始化圖譜方法(initGraph )
將準備好的glb加載進來
const loadGLBModel = async (url: string) => {
if (modelCache.has(url)) return modelCache.get(url).clone()
const loader = new GLTFLoader()
return new Promise<THREE.Object3D>((resolve, reject) => {
loader.load(
url,
gltf => {
const model = gltf.scene
model.traverse(child => {
if (child instanceof THREE.Mesh) {
child.castShadow = true
child.receiveShadow = true
}
})
modelCache.set(url, model.clone())
resolve(model)
},
undefined,
reject
)
})
}
定義力導向圖譜
graphInstance = ForceGraph3D()(graphRef.value)
加載圖譜數據
graphInstance .graphData({
nodes: nodes,
links: links
})
將默認節點替換為模型
graphInstance .nodeThreeObject(({ model }) => {
if (!model) return new THREE.Mesh() // 默認節點 // 克隆緩存的模型 const modelClone = modelCache.get('/models/MaiRealhot.glb').clone() modelClone.scale.set(10, 10, 10) // 調整模型大小 return modelClone })
效果圖

完整代碼:
<template> <div class="force_style" ref="graphRef"></div> </template> <script setup lang="ts">
import { onMounted, ref, onUnmounted } from 'vue' import ForceGraph3D from '3d-force-graph' import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader' import * as THREE from 'three' import {nodes, links} from '@/assets/graphData/miserables.json' import SpriteText from "three-spritetext"; const graphRef = ref<HTMLElement | null>(null) let graphInstance: any = null const modelCache = new Map() // 模型緩存 // 加載 GLB 模型 const loadGLBModel = async (url: string) => { if (modelCache.has(url)) return modelCache.get(url).clone() const loader = new GLTFLoader() return new Promise<THREE.Object3D>((resolve, reject) => { loader.load( url, gltf => { const model = gltf.scene model.traverse(child => { if (child instanceof THREE.Mesh) { child.castShadow = true child.receiveShadow = true } }) modelCache.set(url, model.clone()) resolve(model) }, undefined, reject ) }) } // 初始化圖表 const initGraph = async () => { if (!graphRef.value) return // 加載示例模型(替換為你的實際模型路徑) const model = await loadGLBModel('/models/MaiRealhot.glb') graphInstance = ForceGraph3D()(graphRef.value) .graphData({ nodes: nodes, links: links }) .nodeThreeObject(({ model }) => { if (!model) return new THREE.Mesh() // 默認節點 // 克隆緩存的模型 const modelClone = modelCache.get('/models/MaiRealhot.glb').clone() modelClone.scale.set(10, 10, 10) // 調整模型大小 return modelClone }) .nodeColor(() => '#ffffff') .nodeLabel((node) => { return node.id }) .nodeOpacity(0.8) .linkColor(() => 'rgba(255,255,255,0.2)') .linkWidth(0.5) .onNodeClick(node => { handleNodeClick(node) }) .cameraPosition({ z: 1000 }) // 添加環境光 const ambientLight = new THREE.AmbientLight(0xffffff, 0.8) graphInstance.scene().add(ambientLight) // 添加點光源 const pointLight = new THREE.PointLight(0xffffff, 1, 1000) pointLight.position.set(500, 500, 500) graphInstance.scene().add(pointLight) } // 節點點擊處理 const handleNodeClick = (node: any) => { const distance = 100 const distRatio = 1 + distance / Math.hypot(node.x, node.y, node.z) graphInstance.cameraPosition( { x: node.x * distRatio, y: node.y * distRatio, z: node.z * distRatio }, node, 3000 ) } onMounted(async () => { await initGraph() }) onUnmounted(() => { if (graphInstance) { graphInstance._destructor() modelCache.clear() } }) </script> <style scoped lang="scss">.force_style { width: 100%; height: 100vh; background: #1a1a1a; overflow: hidden; } </style>
浙公網安備 33010602011771號