<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
指定一條折線路徑,鏡頭沿著路徑向前移動,類似第一視角走在當前路徑上。
很簡單畫一條折線路徑,將鏡頭位置動態繫結在當前路徑上,同時設定鏡頭朝向路徑正前方。
畫一條折線路徑,通常將每一個轉折點標出來畫出的THREE.Line,會變成曲線。
難點解答:
對於controls繫結的camera,修改camera的lookAt和rotation並無反應。
難點解答:
相機觀察方向camera.lookAt設定無效需要設定controls.target
對於controls繫結的camera,動態修改camera的位置總存在一定錯位。
難點解答:
蒼天啊,這個問題糾結我好久,怎麼設定都不對,即便參考上一個問題控制controls.object.position也不對。
結果這是一個假的難點,鏡頭位置是受控的,感覺不受控是因為,設定了相機距離原點的最近距離!!! 導致轉彎時距離太近鏡頭會往回退著轉彎,碰到旁邊的東西啊,哭唧唧。
// 設定相機距離原點的最近距離 即可控制放大限值 // controls.minDistance = 4 // 設定相機距離原點的最遠距離 即可控制縮小限值 controls.maxDistance = 40
鏡頭抖動,懷疑是設定位置和朝向時座標被四捨五入時,導致一會上一會下一會左一會右的抖動。
難點解答:
開始以為是我整個場景太小了,放大場景,拉長折線,拉遠相機,並沒有什麼用。
最後發現是在animate()動畫中設定相機位置,y座標加了0.01:
controls.object.position.set(testList[testIndex].x, testList[testIndex].y + 0.01, testList[testIndex].z)
相機位置座標和相機朝向座標不在同一平面,導致的抖動,將+0.01去掉就正常了。
controls.object.position.set(testList[testIndex].x, testList[testIndex].y, testList[testIndex].z)
在此通過兩個相機,先觀察相機cameraTest的移動路徑和轉向,再切換成原始相機camera。
公共程式碼如下:
// 外層相機,原始相機 let camera = null // 內層相機和相機輔助線 let cameraTest = null let cameraHelper = null // 控制器 let controls = null // 折線點的集合和索引 let testList = [] let testIndex = 0 initCamera () { // 原始相機 camera = new THREE.PerspectiveCamera(45, div3D.clientWidth / div3D.clientHeight, 0.1, 1000) camera.position.set(16, 6, 10) // scene.add(camera) // camera.lookAt(new THREE.Vector3(0, 0, 0)) // 設定第二個相機 cameraTest = new THREE.PerspectiveCamera(45, div3D.clientWidth / div3D.clientHeight, 0.1, 1000) cameraTest.position.set(0, 0.6, 0) cameraTest.lookAt(new THREE.Vector3(0, 0, 0)) cameraTest.rotation.x = 0 // 照相機幫助線 cameraHelper = new THREE.CameraHelper(cameraTest) scene.add(cameraTest) scene.add(cameraHelper) } // 初始化控制器 initControls () { controls = new OrbitControls(camera, renderer.domElement) }
inspectCurveList () { let curve = new THREE.CatmullRomCurve3([ new THREE.Vector3(2.9, 0.6, 7), new THREE.Vector3(2.9, 0.6, 1.6), new THREE.Vector3(2.89, 0.6, 1.6), // 用於直角轉折 new THREE.Vector3(2.2, 0.6, 1.6), new THREE.Vector3(2.2, 0.6, 1.59), // 用於直角轉折 new THREE.Vector3(2.2, 0.6, -5), new THREE.Vector3(2.21, 0.6, -5), // 用於直角轉折 new THREE.Vector3(8, 0.6, -5), new THREE.Vector3(8, 0.6, -5.01), // 用於直角轉折 new THREE.Vector3(8, 0.6, -17), new THREE.Vector3(7.99, 0.6, -17), // 用於直角轉折 new THREE.Vector3(-1, 0.6, -17), // new THREE.Vector3(-2, 0.6, -17.01), // 用於直角轉折 new THREE.Vector3(-3, 0.6, -20.4), new THREE.Vector3(-2, 0.6, 5) ]) let geometry = new THREE.Geometry() let gap = 1000 for (let i = 0; i < gap; i++) { let index = i / gap let point = curve.getPointAt(index) let position = point.clone() curveList.push(position) geometry.vertices.push(position) } // geometry.vertices = curve.getPoints(500) // curveList = geometry.vertices // let material = new THREE.LineBasicMaterial({color: 0x3cf0fa}) // let line = new THREE.Line(geometry, material) // 連成線 // line.name = 'switchInspectLine' // scene.add(line) // 加入到場景中 } // 模仿管道的鏡頭推進 if (curveList.length !== 0) { if (curveIndex < curveList.length - 20) { // 推進裡層相機 /* cameraTest.position.set(curveList[curveIndex].x, curveList[curveIndex].y, curveList[curveIndex].z) controls = new OrbitControls(cameraTest, labelRenderer.domElement) */ // 推進外層相機 // camera.position.set(curveList[curveIndex].x, curveList[curveIndex].y + 1, curveList[curveIndex].z) controls.object.position.set(curveList[curveIndex].x, curveList[curveIndex].y, curveList[curveIndex].z) controls.target = curveList[curveIndex + 20] // controls.target = new THREE.Vector3(curveList[curveIndex + 2].x, curveList[curveIndex + 2].y, curveList[curveIndex + 2].z) curveIndex += 1 } else { curveList = [] curveIndex = 0 this.inspectSwitch = false this.addRoomLabel() this.removeLabel() // 移除場景中的線 // let removeLine = scene.getObjectByName('switchInspectLine') // if (removeLine !== undefined) { // scene.remove(removeLine) // } // 還原鏡頭位置 this.animateCamera({x: 16, y: 6, z: 10}, {x: 0, y: 0, z: 0}) } }
inspectTween () { let wayPoints = [ { point: {x: 2.9, y: 0.6, z: 1.6}, camera: {x: 2.9, y: 0.6, z: 7}, time: 3000 }, { point: {x: 2.2, y: 0.6, z: 1.6}, camera: {x: 2.9, y: 0.6, z: 1.6}, time: 5000 }, { point: {x: 2.2, y: 0.6, z: -5}, camera: {x: 2.2, y: 0.6, z: 1.6}, time: 2000 }, { point: {x: 8, y: 0.6, z: -5}, camera: {x: 2.2, y: 0.6, z: -5}, time: 6000 }, { point: {x: 8, y: 0.6, z: -17}, camera: {x: 8, y: 0.6, z: -5}, time: 3000 }, { point: {x: -2, y: 0.6, z: -17}, camera: {x: 8, y: 0.6, z: -17}, time: 3000 }, { point: {x: -2, y: 0.6, z: -20.4}, camera: {x: -2, y: 0.6, z: -17}, time: 3000 }, { point: {x: -2, y: 0.6, z: 5}, camera: {x: -3, y: 0.6, z: -17}, time: 3000 }, // { // point: {x: -2, y: 0.6, z: 5}, // camera: {x: -2, y: 0.6, z: -20.4} // }, { point: {x: 0, y: 0, z: 0}, camera: {x: -2, y: 0.6, z: 5}, time: 3000 } ] this.animateInspect(wayPoints, 0) } animateInspect (point, k) { let self = this let time = 3000 if (point[k].time) { time = point[k].time } let count = point.length let target = point[k].point let position = point[k].camera let tween = new TWEEN.Tween({ px: camera.position.x, // 起始相機位置x py: camera.position.y, // 起始相機位置y pz: camera.position.z, // 起始相機位置z tx: controls.target.x, // 控制點的中心點x 起始目標位置x ty: controls.target.y, // 控制點的中心點y 起始目標位置y tz: controls.target.z // 控制點的中心點z 起始目標位置z }) tween.to({ px: position.x, py: position.y, pz: position.z, tx: target.x, ty: target.y, tz: target.z }, time) tween.onUpdate(function () { camera.position.x = this.px camera.position.y = this.py camera.position.z = this.pz controls.target.x = this.tx controls.target.y = this.ty controls.target.z = this.tz // controls.update() }) tween.onComplete(function () { // controls.enabled = true if (self.inspectSwitch && k < count - 1) { self.animateInspect(point, k + 1) } else { self.inspectSwitch = false self.addRoomLabel() self.removeLabel() } // callBack && callBack() }) // tween.easing(TWEEN.Easing.Cubic.InOut) tween.start() },
個人喜歡方法二,只要找好了線路上的控制點,動畫效果更佳更容易控制每段動畫的時間。
過程中的使用過的其他方法,僅做記錄用。
// 獲取折線點陣列 testInspect () { // 描折線點,為了能使一條折線能直角轉彎,特新增「用於直角轉折」的輔助點,嘗試將所有標為「用於直角轉折」的點去掉,折線馬上變曲線。 let curve = new THREE.CatmullRomCurve3([ new THREE.Vector3(2.9, 0.6, 7), new THREE.Vector3(2.9, 0.6, 1.6), new THREE.Vector3(2.89, 0.6, 1.6), // 用於直角轉折 new THREE.Vector3(2.2, 0.6, 1.6), new THREE.Vector3(2.2, 0.6, 1.59), // 用於直角轉折 new THREE.Vector3(2.2, 0.6, -5), new THREE.Vector3(2.21, 0.6, -5), // 用於直角轉折 new THREE.Vector3(8, 0.6, -5), new THREE.Vector3(8, 0.6, -5.01), // 用於直角轉折 new THREE.Vector3(8, 0.6, -17), new THREE.Vector3(7.99, 0.6, -17), // 用於直角轉折 new THREE.Vector3(-2, 0.6, -17), new THREE.Vector3(-2, 0.6, -17.01), // 用於直角轉折 new THREE.Vector3(-2, 0.6, -20.4), new THREE.Vector3(-2, 0.6, 5), ]) let material = new THREE.LineBasicMaterial({color: 0x3cf0fa}) let geometry = new THREE.Geometry() geometry.vertices = curve.getPoints(1500) let line = new THREE.Line(geometry, material) // 連成線 scene.add(line) // 加入到場景中 testList = geometry.vertices } // 場景動畫-推進相機 animate () { // 模仿管道的鏡頭推進 if (testList.length !== 0) { if (testIndex < testList.length - 2) { // 推進裡層相機 // cameraTest.position.set(testList[testIndex].x, testList[testIndex].y, testList[testIndex].z) // controls = new OrbitControls(cameraTest, labelRenderer.domElement) // controls.target = new THREE.Vector3(testList[testIndex + 2].x, testList[testIndex + 2].y, testList[testIndex + 2].z) // testIndex += 1 // 推進外層相機 camera.position.set(testList[testIndex].x, testList[testIndex].y, testList[testIndex].z) controls.target = new THREE.Vector3(testList[testIndex + 2].x, testList[testIndex + 2].y, testList[testIndex + 2].z) testIndex += 1 } else { testList = [] testIndex = 0 } } }
說明:
推進裡層相機,相機移動和轉向正常,且在直角轉彎處,鏡頭轉動>90°再切回90°;
推進外層相機,鏡頭突然開始亂切(因為設定了最近距離),且在直角轉彎處,鏡頭轉動>90°再切回90°。
// 獲取折線點陣列 testInspect () { let points = [ [2.9, 7], [2.9, 1.6], [2.2, 1.6], [2.2, -5], [8, -5], [8, -17], [-2, -17], [-2, -20.4], [-2, 5] ] testList = this.linePointList(points, 0.6) } linePointList (xz, y) { let allPoint = [] for (let i = 0; i < xz.length - 1; i++) { if (xz[i][0] === xz[i + 1][0]) { let gap = (xz[i][1] - xz[i + 1][1]) / 100 for (let j = 0; j < 100; j++) { allPoint.push(new THREE.Vector3(xz[i][0], y, xz[i][1] - gap * j)) } } else { let gap = (xz[i][0] - xz[i + 1][0]) / 100 for (let j = 0; j < 100; j++) { allPoint.push(new THREE.Vector3(xz[i][0] - gap * j, y, xz[i][1])) } } } return allPoint } // 場景動畫-推進相機 animate () { // 模仿管道的鏡頭推進 if (testList.length !== 0) { if (testIndex < testList.length - 2) { // 推進裡層相機 // cameraTest.position.set(testList[testIndex].x, testList[testIndex].y, testList[testIndex].z) // controls = new OrbitControls(cameraTest, labelRenderer.domElement) // controls.target = new THREE.Vector3(testList[testIndex + 2].x, testList[testIndex + 2].y, testList[testIndex + 2].z) // testIndex += 1 // 推進外層相機 camera.position.set(testList[testIndex].x, testList[testIndex].y, testList[testIndex].z) controls.target = new THREE.Vector3(testList[testIndex + 2].x, testList[testIndex + 2].y, testList[testIndex + 2].z) testIndex += 1 } else { testList = [] testIndex = 0 } } }
說明:
推進裡層相機,相機移動和轉向正常,直角轉彎處突兀,因為是多個線段拼接出來的點;
推進外層相機,相機移動有些許錯位(因為設定了最近距離),相機轉向正常,但是直角轉彎處突兀,因為是多個線段拼接出來的點。
// 獲取折線點陣列 testInspect () { let points = [ [2.9, 7], [2.9, 1.6], [2.2, 1.6], [2.2, -5], [8, -5], [8, -17], [-2, -17], [-2, -20.4], [-2, 5] ] this.tweenCameraTest(points, 0) // tween動畫-控制裡層相機 // this.tweenCamera(points, 0) // tween動畫-控制外層相機 } // tween動畫-控制裡層相機 tweenCameraTest (point, k) { let self = this let count = point.length let derection = 0 if (cameraTest.position.x === point[k][0]) { // x相同 if (cameraTest.position.z - point[k][1] > 0) { derection = 0 } else { derection = Math.PI } } else { // z相同 if (cameraTest.position.x - point[k][0] > 0) { derection = Math.PI / 2 } else { derection = - Math.PI / 2 } } cameraTest.rotation.y = derection let tween = new TWEEN.Tween({ px: cameraTest.position.x, // 起始相機位置x py: cameraTest.position.y, // 起始相機位置y pz: cameraTest.position.z // 起始相機位置z }) tween.to({ px: point[k][0], py: 0.6, pz: point[k][1] }, 3000) tween.onUpdate(function () { cameraTest.position.x = this.px cameraTest.position.y = this.py cameraTest.position.z = this.pz }) tween.onComplete(function () { if (k < count - 1) { self.tweenCameraTest(point, k + 1) } else { console.log('結束了!!!!!!') } // callBack && callBack() }) // tween.easing(TWEEN.Easing.Cubic.InOut) tween.start() } // tween動畫-控制外層相機 tweenCamera (point, k) { let self = this let count = point.length let derection = 0 if (camera.position.x === point[k][0]) { // x相同 if (camera.position.z - point[k][1] > 0) { derection = 0 } else { derection = Math.PI } } else { // z相同 if (camera.position.x - point[k][0] > 0) { derection = Math.PI / 2 } else { derection = - Math.PI / 2 } } camera.rotation.y = derection let tween = new TWEEN.Tween({ px: camera.position.x, // 起始相機位置x py: camera.position.y, // 起始相機位置y pz: camera.position.z // 起始相機位置z }) tween.to({ px: point[k][0], py: 0.6, pz: point[k][1] }, 3000) tween.onUpdate(function () { camera.position.x = this.px camera.position.y = this.py camera.position.z = this.pz }) tween.onComplete(function () { if (k < count - 1) { self.tweenCamera(point, k + 1) } else { console.log('結束了!!!!!!') } // callBack && callBack() }) // tween.easing(TWEEN.Easing.Cubic.InOut) tween.start() }
說明:
控制裡層相機使用tweenCameraTest()方法,相機移動正常,通過rotation.y控制直接轉向,轉彎時略突兀因為沒有動畫控制rotation.y轉動;
控制外層相機使用tweenCamera()方法,相機移動有些許錯位(因為設定了最近距離),相機轉向完全不受控,似乎始終看向座標原點。
// 獲取折線點陣列 testInspect () { // 描折線點,為了能使一條折線能直角轉彎,特新增「用於直角轉折」的輔助點,嘗試將所有標為「用於直角轉折」的點去掉,折線馬上變曲線。 let curve = new THREE.CatmullRomCurve3([ new THREE.Vector3(2.9, 0.6, 7), new THREE.Vector3(2.9, 0.6, 1.6), new THREE.Vector3(2.89, 0.6, 1.6), // 用於直角轉折 new THREE.Vector3(2.2, 0.6, 1.6), new THREE.Vector3(2.2, 0.6, 1.59), // 用於直角轉折 new THREE.Vector3(2.2, 0.6, -5), new THREE.Vector3(2.21, 0.6, -5), // 用於直角轉折 new THREE.Vector3(8, 0.6, -5), new THREE.Vector3(8, 0.6, -5.01), // 用於直角轉折 new THREE.Vector3(8, 0.6, -17), new THREE.Vector3(7.99, 0.6, -17), // 用於直角轉折 new THREE.Vector3(-2, 0.6, -17), new THREE.Vector3(-2, 0.6, -17.01), // 用於直角轉折 new THREE.Vector3(-2, 0.6, -20.4), new THREE.Vector3(-2, 0.6, 5), ]) let material = new THREE.LineBasicMaterial({color: 0x3cf0fa}) let geometry = new THREE.Geometry() let gap = 500 for (let i = 0; i < gap; i++) { let index = i / gap let point = curve.getPointAt(index) let position = point.clone() testList.push(position) // 通過此方法獲取點比curve.getPoints(1500)更好,不信你試試,用getPoints獲取,鏡頭會有明顯的俯視效果不知為何。 geometry.vertices.push(position) } let line = new THREE.Line(geometry, material) // 連成線 scene.add(line) // 加入到場景中 } // 場景動畫-推進外層相機 animate () { // 模仿管道的鏡頭推進 if (testList.length !== 0) { if (testIndex < testList.length - 2) { // 推進裡層相機 // cameraTest.position.set(testList[testIndex].x, testList[testIndex].y, testList[testIndex].z) // controls = new OrbitControls(cameraTest, labelRenderer.domElement) // 推進外層相機 // camera.position.set(testList[testIndex].x, testList[testIndex].y + 0.01, testList[testIndex].z) controls.object.position.set(testList[testIndex].x, testList[testIndex].y + 0.01, testList[testIndex].z) // 稍微講相機位置上移,就不會出現似乎亂切鏡頭穿過旁邊物體的效果。 controls.target = testList[testIndex + 2] // controls.target = new THREE.Vector3(testList[testIndex + 2].x, testList[testIndex + 2].y, testList[testIndex + 2].z) testIndex += 1 } else { testList = [] testIndex = 0 } } }
說明:
解決了,直角轉彎處,鏡頭轉動>90°再切回90°的問題。
解決了,推進外層相機鏡頭亂切的問題。
但是,相機移動在轉彎時有明顯的往後閃(因為設定了最近距離),並不是嚴格跟隨折線前進。
以上就是three.js鏡頭追蹤的移動效果範例的詳細內容,更多關於three.js鏡頭追蹤移動的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45