threejs 晶格实现
简介: threejs 晶格实现,核心思路是用 gridHelper 的顶点数据,生成线段,然后通过样条曲线的 getSpacedPoints
获取等距点,然后在这些等距点上绘制球体。
项目主要依赖:(先安装,步骤略)
{
"three": "^0.165.0",
"vue": "^3.4.29"
}
1.组件
lattice.vue
<template>
<div ref="container"></div>
</template>
<script lang="ts" setup>
import { ref, onMounted } from 'vue'
import {
GridHelper,
Group,
Scene,
PerspectiveCamera,
WebGLRenderer,
SphereGeometry,
MeshBasicMaterial,
Mesh,
Vector3,
LineBasicMaterial,
Color,
CatmullRomCurve3,
BufferGeometry,
Line
} from 'three'
import { OrbitControls } from 'three/addons/Addons.js'
const container = ref()
const getColor = () =>
`rgb(${Math.floor(Math.random() * 255)},${Math.floor(
Math.random() * 255
)},${Math.floor(Math.random() * 255)})`
onMounted(async () => {
// 场景
const scene = new Scene()
// 相机
const camera = new PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
)
camera.lookAt(scene.position)
camera.position.set(0, 100, 100)
// 渲染器
const renderer = new WebGLRenderer({
antialias: true
})
renderer.setPixelRatio(window.devicePixelRatio)
renderer.setSize(window.innerWidth, window.innerHeight)
container.value.appendChild(renderer.domElement)
// 控制器
const controls = new OrbitControls(camera, renderer.domElement)
controls.target.set(scene.position.x, scene.position.y, scene.position.z)
const group = new Group()
group.name = 'baseGroup'
scene.add(group)
const gridHelper = new GridHelper(100, 20, 0xffffff, 0xffffff)
const getBall = () => {
const geometry = new SphereGeometry(0.4, 32, 16)
const material = new MeshBasicMaterial({ color: 0xffffff })
const sphere = new Mesh(geometry, material)
return sphere
}
const pos = gridHelper.geometry.attributes.position
const count = pos.count
// 获取线段顶点数据
const list: Vector3[][] = []
for (let i = 0; i < count / 2; i++) {
const index = i * 2
const position = new Vector3(
pos.getX(index),
pos.getY(index),
pos.getZ(index)
)
const position1 = new Vector3(
pos.getX(index + 1),
pos.getY(index + 1),
pos.getZ(index + 1)
)
list.push([position, position1])
}
const map = new Map()
list.forEach(item => {
const material = new LineBasicMaterial({
color: new Color(getColor())
})
const curve = new CatmullRomCurve3(item)
// 获取等距点
const points = curve.getSpacedPoints(20)
points.forEach(i => {
const key = i.toArray().toString()
// 去重
if (!map.get(key)) {
const ball1 = getBall()
ball1.position.set(i.x, i.y, i.z)
group.add(ball1)
number++
map.set(key, i.toArray())
}
})
const geometry = new BufferGeometry().setFromPoints(points)
const line = new Line(geometry, material)
group.add(line)
})
animate()
function animate() {
renderer.render(scene, camera)
requestAnimationFrame(animate)
}
})
</script>
2.使用效果