以上是ThreeJS渲染物体的固定写法,不理解的话记住也行的???
球体全景所需的图片素材(下图):宽是高的两倍,数值是2的整数倍最好,建议图片宽高为2048px*1024px(后面实现全景会用到哈)
image.png
具体代码实现:
复制代码
浏览器页面效果(记得开启手机模拟调试):
image.png
2.2 基础知识点
2.2.1 经纬度
本文是使用经纬度来操作全景,需要科普一下经纬度的知识
经纬度是经度与纬度的合称组成一个坐标系统。称为地理坐标系统,它是一种利用三度空间的球面来定义地球上的空间的球面坐标系统,能够标示地球表面上的任何一个位置。
image.png
如图所示,经度:lon,取值范围:[0,360],纬度:lat,取值范围:[-90,90];
2.2.2 经纬度转换三维坐标
球面的点{lon,lat},其中R为球体的半径,求球面的点的在ThreeJS的坐标的位置为:
image.png
解:
X = R * cos(lat)* sin( lon )
Y = R * sin( lat )
Z = R * cos( lat )*cos( lon )
注:ThreeJS中默认的坐标系是右手坐标系,X轴为左右,Y轴为上下,Z轴为前后。
2.3 生成全景的步骤
在2.1的章节中,我们已经完成了绘制一个球体,绘制全景是在其基础上要做调整:
-
1、将相机移到球体的球心位置;
-
2、将全景图片贴到球体的内表面;
具体步骤如下:
-
第一步:创建一个场景(Scene)
-
第二步:创建一个球体,并将全景图片贴到球体的内表面,放入场景中
-
第四步:创建一个透视投影相机将camera拉到球体的中心,相机观看球体内表面
-
第五步:通过修改经纬度来,改变相机观察的点
具体代码实现:
复制代码
效果:
Jietu20210527-172203-HD.gif
至此,我们全景制作已经完成了,(只统计js代码:共_28行_代码,我才不是标题党呢????)。
三、全景交互原理
3.1 手势交互之旋转
手势交互之旋转指单指滑动操作,这与滑动地球仪的交互是一致的。
屏幕坐标系,左上角为原点,X轴:由左向右,Y轴:由上到下, 手指在屏幕滑动会依次触发三个事件:touchstart、touchmove和touchend;event对象中记录了手指屏幕的位置
TeamTalk_IMG_2021-05-27-173217.jpg
手指在屏幕滑动过程:
-
touchstart:记录滑动起始的位置(startX,startY)
-
touchmove:记录当前位置(curX,curY)相减上一次位置的值,计算出弧长除于半径乘以factor,计算出(lon,lat)
-
touchend:暂时没有用的
其中:弧长R值的是屏幕的滑动距离
那么单指在屏幕的滑动,由P1 (clientX1,clientY1)移动到P2 (clientX1,clientY1)长度为,对应经纬度变化:
distanceX = clientX1 - clientX2 // X轴方向
distanceY = clientY1 - clientY2 // Y轴方向
// 其中R为球体半径,根据弧长公式:
lon = distanX / R
lat = distanY / R
复制代码
代码实现:
// 增加touch事件监听
let lastX, lastY // 上次屏幕位置
let curX, curY // 当前屏幕位置
const factor = 1 / 10 // 灵敏系数
const $wrap = document.querySelector(‘#wrap’)
// 触摸开始
$wrap.addEventListener(‘touchstart’, function (evt) {
const obj = evt.targetTouches[0] // 选择第一个触摸点
startX = lastX = obj.clientX
startY = lastY = obj.clientY
})
// 触摸中
$wrap.addEventListener(‘touchmove’, function (evt) {
evt.preventDefault()
const obj = evt.targetTouches[0]
curX = obj.clientX
curY = obj.clientY
// 参考:弧长公式
lon -= ((curX - lastX) / radius) * factor // factor为了全景旋转平稳,乘以一个灵敏系数
lat += ((curY - lastY) / radius) * factor
lastX = curX
lastY = curY
})
单指操作效果:
上面的代码已经加上全景的单指交互,但是,缺少了旋转惯性。接下来,我们加一下惯性动画:
滑动惯性实现,手指在屏幕滑动过程:
-
touchstart:记录滑动起始的位置(startX,startY, startTime)
-
touchmove:记录当前位置(curX,curY)相减上一次位置的值,乘以factor,计算出(lon,lat),【触摸跟随】
-
touchend:记录endTime,计算本次滑动过程中的平均速度,然后,每帧减去减速度d,直至速度为0或者touchstart事件被触发 【触摸结束触发惯性动画】
代码实现:
let lastX, lastY // 上次屏幕位置
let curX, curY // 当前屏幕位置
let startX, startY // 开始触摸的位置,用于计算速度
let isMoving = false // 是否停止单指操作
let speedX, speedY // 速度
const factor = 1 / 10 // 灵敏系数,经验值
const deceleration = 0.1 // 减速度,惯性动画使用
const $wrap = document.querySelector(‘#wrap’)
// 触摸开始
$wrap.addEventListener(‘touchstart’, function (evt) {
const obj = evt.targetTouches[0] // 选择第一个触摸点
startX = lastX = obj.clientX
startY = lastY = obj.clientY
startTime = Date.now()
isMoving = true
})
// 触摸中
$wrap.addEventListener(‘touchmove’, function (evt) {
evt.preventDefault()
const obj = evt.targetTouches[0]
curX = obj.clientX
curY = obj.clientY
// 参考:弧长公式
lon -= ((curX - lastX) / radius) * factor // factor为了全景旋转平稳,乘以一个系数
lat += ((curY - lastY) / radius) * factor
lastX = curX
lastY = curY
})
// 触摸结束
$wrap.addEventListener(‘touchend’, function (evt) {
isMoving = false
var t = Date.now() - startTime
speedX = (curX - startX) / t // X轴方向的平均速度
speedY = (curY - startY) / t // Y轴方向的平均速度
subSpeedAnimate() // 惯性动画
})
let animateInt
// 减速度动画
function subSpeedAnimate() {
lon -= speedX * factor // X轴
lat += speedY * factor
// 减速度
speedX = subSpeed(speedX)
speedY = subSpeed(speedY)
// 速度为0或者有新的触摸事件,停止动画
if ((speedX === 0 && speedY === 0) || isMoving) {
if (animateInt) {
cancelAnimationFrame(animateInt)
animateInt = undefined
}
} else {
requestAnimationFrame(subSpeedAnimate)
}
}
// 减速度
function subSpeed(speed) {
if (speed !== 0) {
if (speed > 0) {
speed -= deceleration;
speed < 0 && (speed = 0);
} else {
speed += deceleration;
speed > 0 && (speed = 0);
}
}
return speed;
}
预览地址:azuoge.github.io/Opanorama/
3.2 手势交互之缩放
手势交互之缩放是双指操作,跟放大图片一样。
前面介绍ThreeJS,提到过相机,全景缩放也是依据相机拍照时,缩放拍摄照片内容的原理是一样的。
image.png
使用ThreeJS创建相机代码如下:
const camera = new THREE.PerspectiveCamera( fov , aspect , near , fear )
参数说明:
image.png
其中,
-
near:取默认值:0.1即可
-
fear:只要大于球体半径就可,取值为:球体半径R
-
aspect:在全景的场景已经确定了,照片的长宽比:屏幕宽度 / 屏幕高度
-
fov:视场,缩放是通过修改它的值来完成全景图片的缩放;
其实,很好理解,睁大眼睛,我们就看的视野就广,看到物体就显得小些【缩小】,反之,眯着眼,看到的视野就窄,看到物体就显得大【放大】,可以通过修改右图的 fov 的值来缩放全景图片
那么如何计算fov呢?这时候我们需要双指交互,同计算,开始触摸计算第一次双指的距离,在双指移动中不断计算双指距离,与上一次距离相除即为缩放倍数。
关键代码如下:
// 其中,(clientX1,clientY1)和(clientX2,clientY2)为双指在屏幕的当前位置
// 计算距离,简化运输不用平方计算
const distance = Math.abs(clientX1 - clientX2) + Math.abc(clientY1 - clientY)
// 计算缩放比
const scale = distance / lastDiance
// 计算新的视角
fov = camera.fov / scale
// 视角范围取值
camera.fov = Math.min(90, Math.max(fov,60)) // 90 > fov > 60 ,从参数说明中选取
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)
![](https://img-blog.csdnimg.cn/img_convert/b0deb3c4b8499134434d08702af5a833.jpeg)
最后
由于篇幅限制,pdf文档的详解资料太全面,细节内容实在太多啦,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!有需要的程序猿(媛)可以帮忙点赞+点击【学习资料】即可免费领取!
60 ,从参数说明中选取
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-7H2wCVyT-1712260421918)]
[外链图片转存中…(img-3lN0Rzvm-1712260421919)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!
[外链图片转存中…(img-SinqNdJA-1712260421919)]
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)
![](https://img-blog.csdnimg.cn/img_convert/b0deb3c4b8499134434d08702af5a833.jpeg)
最后
由于篇幅限制,pdf文档的详解资料太全面,细节内容实在太多啦,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!有需要的程序猿(媛)可以帮忙点赞+点击【学习资料】即可免费领取!
[外链图片转存中…(img-665swILs-1712260421919)]
[外链图片转存中…(img-oJsgtHLy-1712260421920)]