THREE.JS使用TransformControls对模型拖拽的代码实例

 更新时间:2024年03月26日 14:31:50   作者:莫,imma  
拖拽是前端实现中比较常用的一种效果,下面这篇文章主要给大家介绍了关于THREE.JS使用TransformControls对模型拖拽的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

一、原理:

      TransformControls 是由 THREE.JS 提供的一类控制器。

      该类可提供一种类似于在数字内容创建工具(例如Blender)中对模型进行交互的方式,来在3D空间中变换物体。 和其他控制器不同的是,变换控制器不倾向于对场景摄像机的变换进行改变。

       详见官网。

二、步骤:

  • 初始化场景
  • 引入TransformControls控制器,并对其进行监听
  • 添加模型和连线
  • 根据控制器的改变对连线进行修改

三、代码:

<template>
  <div class="fa_container">
    <div class="container" ref="container"></div>
  </div>
</template>

<script>
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { TransformControls } from 'three/examples/jsm/controls/TransformControls.js'

const scene = new THREE.Scene()
let renderer = new THREE.WebGLRenderer({
  antialias: true,
  alpha: true,
  logarithmicDepthBuffer: true
})
let camera, controls, transformControl

const pointer = new THREE.Vector2()
const point = new THREE.Vector3()
const raycaster = new THREE.Raycaster()
let splineHelperObjects = []
const ARC_SEGMENTS = 200
let splines = []

export default {
  name: 'model',
  data () {
    return {
      positionList: [
        [10, 0, 0],
        [-10, 0, 0]
      ]
    }
  },
  mounted () {
    this.init()
    this.addMarkModel()
    this.render()
  },

  methods: {
    init () {
      this.dom = this.$refs['container']

      this.initHelper()
      this.initLight()
      this.initCamera()
      this.initRender()
      this.initControls()

      this.dom.addEventListener('pointermove', e => {
        this.onPointerMove(e)
      })
    },
    initHelper () {
      scene.background = new THREE.Color(0xf0f0f0)

      // const axes = new THREE.AxesHelper(50)
      // scene.add(axes)

      const planeGeometry = new THREE.PlaneGeometry(2000, 2000)
      planeGeometry.rotateX(-Math.PI / 2)
      const planeMaterial = new THREE.ShadowMaterial({ color: 0x000000, opacity: 0.2 })
      const plane = new THREE.Mesh(planeGeometry, planeMaterial)
      plane.position.y = -200
      plane.receiveShadow = true
      scene.add(plane)

      const helper = new THREE.GridHelper(2000, 100)
      helper.position.y = -199
      helper.material.opacity = 0.25
      helper.material.transparent = true
      scene.add(helper)
    },
    initCamera () {
      camera = new THREE.PerspectiveCamera(
        45,
        this.dom.offsetWidth / this.dom.offsetHeight,
        0.001,
        10000
      )
      camera.position.set(35, 35, 35)
    },
    initLight () {
      const directLight = new THREE.DirectionalLight('#ffffff', 0.5)
      const directLight1 = new THREE.DirectionalLight('#ffffff', 0.5)
      const directLight2 = new THREE.PointLight('#ffffff', 0.5)
      const ambientLight = new THREE.AmbientLight('#ffffff', 0.3)

      directLight.castShadow = true
      directLight.position.set(15, 15, 15)
      directLight1.position.set(-15, -15, 15)
      ambientLight.position.set(0, 0, -5)
      directLight2.position.set(-15, 15, -15)
      directLight2.castShadow = true

      scene.add(directLight, directLight1, ambientLight, directLight2)
    },
    initRender () {
      renderer.setSize(1902, 935)
      renderer.outputEncoding = THREE.sRGBEncoding
      this.dom.appendChild(renderer.domElement)
    },
    initControls () {
      controls = new OrbitControls(camera, renderer.domElement)

      transformControl = new TransformControls(camera, renderer.domElement)
      transformControl.addEventListener('change', () => {
        console.log('模型拖动')
      })
      transformControl.addEventListener('dragging-changed', function (event) {
        controls.enabled = !event.value
      })

      transformControl.addEventListener('objectChange', param => {
        this.updateSplineOutline()
      })
      scene.add(transformControl)
    },

    // 鼠标移动
    onPointerMove (event) {
      pointer.x = (event.clientX / window.innerWidth) * 2 - 1
      pointer.y = -(event.clientY / window.innerHeight) * 2 + 1

      raycaster.setFromCamera(pointer, camera)

      const intersects = raycaster.intersectObjects(splineHelperObjects, false)

      if (intersects.length > 0) {
        const object = intersects[0].object

        if (object !== transformControl.object) {
          transformControl.attach(object)
          controls.enabled = false
        }
      }
    },
    // 更新连线
    updateSplineOutline () {
      for (let k = 0; k < splines.length; k++) {
        const spline = splines[k]
        const splineMesh = spline.mesh
        const position = splineMesh.geometry.attributes.position
        for (let i = 0; i < ARC_SEGMENTS; i++) {
          const t = i / (ARC_SEGMENTS - 1)
          spline.getPoint(t, point)
          position.setXYZ(i, point.x, point.y, point.z)
        }
        position.needsUpdate = true
      }
    },
    render () {
      requestAnimationFrame(this.render.bind(this))
      controls.update()
      renderer.render(scene, camera)
    },

    addMarkModel () {
      for (let i = 0; i < this.positionList.length; i++) {
        let position = []

        let obj1 = this.creatSpot(this.positionList[i], i)
        let obj2 = this.creatHtml(i)

        setTimeout(() => {
          position.push(obj1.position)
          position.push(obj2.position)
          this.creatLine(position)
        }, 2000)
      }
    },
    creatSpot (positionArr, index) {
      const spherGeometry = new THREE.SphereGeometry(3, 32, 16)
      const spherMaterial = new THREE.MeshLambertMaterial({ color: 'red' })
      const sphere = new THREE.Mesh(spherGeometry, spherMaterial)
      sphere.position.set(positionArr[0], positionArr[1], positionArr[2])
      sphere.scale.set(0.2, 0.2, 0.2)
      splineHelperObjects.push(sphere)
      scene.add(sphere)
      return sphere
    },
    creatHtml (index, spot) {
      const spherGeometry = new THREE.BoxBufferGeometry(15, 15, 15)
      const spherMaterial = new THREE.MeshPhongMaterial({
        transparent: true,
        opacity: 1,
        color: 'green'
      })
      const sphere = new THREE.Mesh(spherGeometry, spherMaterial)

      sphere.position.x = Math.random() * 10
      sphere.position.y = Math.random() * 20
      sphere.position.z = Math.random() * 15
      sphere.scale.set(0.2, 0.2, 0.2)
      splineHelperObjects.push(sphere)
      scene.add(sphere)

      return sphere
    },
    creatLine (position) {
      var curve = new THREE.CatmullRomCurve3(position)
      var points = curve.getPoints(ARC_SEGMENTS)
      var geometry = new THREE.BufferGeometry().setFromPoints(points)
      var material = new THREE.LineBasicMaterial({ color: 0xff0000 })

      curve.mesh = new THREE.LineSegments(geometry, material)
      scene.add(curve.mesh)
      splines.push(curve)
    }
  }
}
</script>

<style>
.container {
  width: 1902px;
  height: 935px;
  overflow: hidden;
  background: black;
  display: inline-block;
}

</style>

四、最终效果:

拖拽前:

鼠标拾取模型:

模型拖动:

总结 

到此这篇关于THREE.JS使用TransformControls对模型拖拽的文章就介绍到这了,更多相关THREE.JS对模型拖拽内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • JS中Json数据的处理和解析JSON数据的方法详解

    JS中Json数据的处理和解析JSON数据的方法详解

    JSON (JavaScript Object Notation)一种简单的数据格式,比xml更轻巧,这篇文章主要介绍了JS中Json数据的处理和解析JSON数据的方法详解的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2016-06-06
  • javascript贪吃蛇游戏设计与实现

    javascript贪吃蛇游戏设计与实现

    这篇文章主要为大家详细介绍了javascript贪吃蛇游戏设计与实现,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-09-09
  • Taro小程序自定义顶部导航栏功能的实现

    Taro小程序自定义顶部导航栏功能的实现

    这篇文章主要介绍了Taro小程序自定义顶部导航栏功能的实现,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-12-12
  • JS动态添加Table的TR,TD实现方法

    JS动态添加Table的TR,TD实现方法

    这篇文章主要介绍了JS动态添加Table的TR,TD实现方法,涉及js针对Table中TR、TD节点的操作技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-01-01
  • JavaScript实现页面一键全选或反选

    JavaScript实现页面一键全选或反选

    这篇文章主要为大家详细介绍了JavaScript实现页面一键全选或反选,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-07-07
  • 初步了解javascript面向对象

    初步了解javascript面向对象

    面向对象的语言有一个标志,即拥有类的概念,抽象实例对象的公共属性与方法,基于类可以创建任意多个实例对象,一般具有封装、继承、多态的特性!但JS中对象与纯面向对象语言中的对象是不同的,ECMA标准定义JS中对象:无序属性的集合,其属性可以包含基本值、对象或函数
    2015-11-11
  • JavaScript原生对象之Number对象的属性和方法详解

    JavaScript原生对象之Number对象的属性和方法详解

    这篇文章主要介绍了JavaScript原生对象之Number对象的属性和方法详解,本文讲解了创建 Number 对象的语法、MAX_VALUE、MIN_VALUE、NaN等属性或方法,需要的朋友可以参考下
    2015-03-03
  • javascript web页面刷新的方法收集

    javascript web页面刷新的方法收集

    javascript refresh page,页面刷新实现代码。
    2009-07-07
  • 关于JavaScript对象的动态选择及遍历对象

    关于JavaScript对象的动态选择及遍历对象

    本文为大家介绍下JavaScript对象的两点:动态选择方法及属性、遍历对象属性和方法,需要的朋友可以参考下
    2014-03-03
  • webpack css加载和图片加载的方法示例

    webpack css加载和图片加载的方法示例

    这篇文章主要介绍了webpack css加载和图片加载的方法示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-09-09

最新评论