THREE.JS使用TransformControls對模型拖拽的代碼實例
一、原理:
TransformControls 是由 THREE.JS 提供的一類控制器。
該類可提供一種類似于在數(shù)字內(nèi)容創(chuàng)建工具(例如Blender)中對模型進行交互的方式,來在3D空間中變換物體。 和其他控制器不同的是,變換控制器不傾向于對場景攝像機的變換進行改變。
詳見官網(wǎng)。
二、步驟:
- 初始化場景
- 引入TransformControls控制器,并對其進行監(jiān)聽
- 添加模型和連線
- 根據(jù)控制器的改變對連線進行修改
三、代碼:
<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) }, // 鼠標(biāo)移動 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>
四、最終效果:
拖拽前:
鼠標(biāo)拾取模型:
模型拖動:
總結(jié)
到此這篇關(guān)于THREE.JS使用TransformControls對模型拖拽的文章就介紹到這了,更多相關(guān)THREE.JS對模型拖拽內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
js和html5實現(xiàn)手機端刮刮卡抽獎效果完美兼容android/IOS
手機完美支持html5,所以如果手機端想要做個抽獎模塊的話,用刮刮卡抽獎效果,相信這個互動體驗是非常棒的,本人親自完成,有錯誤請大家指出2013-11-11Bootstrap CSS組件之按鈕組(btn-group)
這篇文章主要為大家詳細(xì)介紹了Bootstrap CSS組件之按鈕組(btn-group),具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-12-12js中的異步獲取到的數(shù)據(jù)到底能不能賦值給一個全局變量問題
這篇文章主要介紹了js中的異步獲取到的數(shù)據(jù)到底能不能賦值給一個全局變量問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-04-04Javascript中call,apply,bind方法的詳解與總結(jié)
本文主要Javascript中call,apply,bind方法的進行全面分析,并在文章結(jié)尾對call,apply,bind方法的聯(lián)系和區(qū)別做了總結(jié),具有很好的參考價值,需要的朋友一起來看下吧2016-12-12js使用onmousemove和onmouseout獲取鼠標(biāo)坐標(biāo)的方法
這篇文章主要介紹了js使用onmousemove和onmouseout獲取鼠標(biāo)坐標(biāo)的方法,涉及javascript操作鼠標(biāo)事件的技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-03-03JavaScript實現(xiàn)淘寶京東6位數(shù)字支付密碼效果
這篇文章主要為大家詳細(xì)介紹了JavaScript實現(xiàn)淘寶京東6位數(shù)字支付密碼效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-08-08js中數(shù)組(Array)的排序(sort)注意事項說明
本篇文章主要是對js中數(shù)組(Array)的排序(sort)注意事項進行了說明介紹,需要的朋友可以過來參考下,希望對大家有所幫助2014-01-01