threejs 晶格实现

发布于:2024-10-17 ⋅ 阅读:(12) ⋅ 点赞:(0)

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.使用效果

在这里插入图片描述