前言
在我们生成全景预览的时候,用户观看的视角是固定的,因为在创建全景作品的时候对于视角的设置会给一个默认值,对于用户观看的方向和距离,我们想要有更多的设置,例如初始视角 、视角的范围大小 、水平/垂直的视角限制都可以自定义修改,这篇文章就来实现自定义每个场景的视角
效果预览
1.制作定义视角框
首先制作视频中的红白色的框框,用来定义初始的视角
但是发现使用html制作的框,在框内拖动不了全景,所以得使用krpano来制作,新建一个xml文件,命名为perspective.xml,并在主xml文件里引入,设置一个layer元素命名为view_bar,宽度为屏幕的60%,高度为屏幕的70%,并且设置bgborder属性为layer元素添加白色的虚线边框
在view_bar里再添加四个layer,代表四个角,最后在添加一个命名为view_bar_btn的layer元素,固定在定义视角框的底部,作为设置初始视角的交互按钮
html
<krpano>
<layer name="view_bar" type="container" keep="true" width="60%" height="70%" bgborder="2 0xffffff 1 dashed" align="top" y="10%" scalechildren="true" visible="false">
<layer name="view_bar_tl" type="container" keep="true" width="50" height="50" bgborder="4,0,0,4 0xD6000F 1" bgroundedge="5 0 0 0" align="lefttop"></layer>
<layer name="view_bar_tr" type="container" keep="true" width="50" height="50" bgborder="4,4,0,0 0xD6000F 1" bgroundedge="0 5 0 0" align="righttop"></layer>
<layer name="view_bar_bl" type="container" keep="true" width="50" height="50" bgborder="0,0,4,4 0xD6000F 1" bgroundedge="0 0 0 5" align="leftbottom"></layer>
<layer name="view_bar_br" type="container" keep="true" width="50" height="50" bgborder="0,4,4,0 0xD6000F 1" bgroundedge="0 0 5 0" align="rightbottom"></layer>
<layer name="view_bar_btn" type="container" keep="true" width="180" height="30" bgcolor="0xD6000F" bgalpha="1.0" bgroundedge="4" align="bottom" y="40">
<layer
name="view_bar_text"
type="text"
keep="true"
html="设置当前视角为初始视角"
css="font-size:14px;color:#ffffff;"
align="center"
bgalpha="0"
/>
</layer>
</layer>
</krpano>
2.设置初始视角
在全景中用户的观看方向是由view元素 决定的,它可用于设置启动视图设置,view元素可以说是一个全局标签,有且只能有一个,元素的更多说明可以查看文档
为了便于区分当前的视角和初始视角,在右边的操作栏里新增一个当前初始视角的场景
直接引入定义好的组件,传入当前场景的id(scene)和目标html元素id(target),以及krpano回调(onPanoReady),具体如何定义通用的Krpano组件可以参考这篇文章
html
import Krpano from '@/components/Krpano'
<Krpano
scene={scene.scene_id ? scene.scene_id + '_view' : ''}
target="krpano_view"
onPanoReady={onPanoReady}
/>
当回调触发就可以加载当前初始场景了,直接将手动生成的案例代码复制过来
根据当前场景的参数设置对应的属性
js
const onPanoReady = (e: any) => {
const content = `
<control bouncinglimits="calc:image.cube ? true : false" />
<view hlookat="${scene.view.hlookat}" vlookat="${scene.view.vlookat}" fovtype="MFOV" fov="${scene.view.fov}" maxpixelzoom="${scene.view.maxpixelzoom}" fovmin="${scene.view.fovmin}"
fovmax="${scene.view.fovmax}" hlookatmin="${scene.view.hlookatmin}" hlookatmax="${scene.view.hlookatmax}" vlookatmin="${scene.view.vlookatmin}" vlookatmax="${scene.view.vlookatmax}" limitview="lookat" />
<preview url="https://oss-krp.oss-cn-shenzhen.aliyuncs.com${scene.path}/preview.jpg" />
<image>
<cube url="https://oss-krp.oss-cn-shenzhen.aliyuncs.com${scene.path}/%s/l%l/%v/l%l_%s_%v_%h.jpg" multires="${scene.multires}" />
</image>
`
// 设置场景title属性
e.set(`scene[${scene.scene_id}_view].title`, scene.name)
// 设置场景缩略图
e.set(
`scene[${scene.scene_id}_view].thumburl`,
`https://oss-krp.oss-cn-shenzhen.aliyuncs.com${scene.thumbUrl}`
)
// 设置场景内容
e.set(`scene[${scene.scene_id}_view].content`, content)
// 固定视角禁止移动和缩放
e.set('control.usercontrol', false)
setViewKp(e)
}
然后为定义视角框里的按钮绑定点击事件,返回当前视角的垂直视角和水平视角,通过get
方法可以获取到
html
<krpano>
<layer name="view_bar" type="container" keep="true" width="60%" height="70%" bgborder="2 0xffffff 1 dashed" align="top" y="10%" scalechildren="true" visible="false">
// ....
<layer name="view_bar_btn" type="container" keep="true" width="180" height="30" bgcolor="0xD6000F" bgalpha="1.0" bgroundedge="4" align="bottom" y="40">
<layer
name="view_bar_text"
type="text"
keep="true"
html="设置当前视角为初始视角"
css="font-size:14px;color:#ffffff;"
align="center"
bgalpha="0"
onclick.addevent="js(handleViewSetting(get(view.hlookat),get(view.vlookat)))"
/>
</layer>
</layer>
</krpano>
当点击按钮的时候修改当前场景的hlookat和vlookat,并且监听这两个值,发生变化重新设置垂直视角和水平视角
js
useEffect(() => {
if (viewKp) {
viewKp.set(`view.hlookat`, scene.view.hlookat)
viewKp.set(`view.vlookat`, scene.view.vlookat)
}
}, [scene.view.hlookat, scene.view.vlookat])
window.handleViewSetting = (hlookat: number, vlookat: number) => {
const sceneList = [...workConfig.scene]
const index = sceneList.findIndex((item) => item.scene_id === selectSceneId)
sceneList[index].view.hlookat = Math.floor(hlookat)
sceneList[index].view.vlookat = Math.floor(vlookat)
setWorkConfig((prevConfig) => ({
...prevConfig,
scene: sceneList
}))
}
再给初始视角场景添加一个回到初始视角的功能
html
<Button
className="init-perspective-button"
type="primary"
size="small"
onClick={handleViewReset}
>
回到初始视角
</Button>
kp.call(`reset_view(${view.hlookat},${view.vlookat},${view.fov})`)
js
const handleViewReset = () => {
kp.call(`reset_view(${view.hlookat},${view.vlookat},${view.fov})`)
}
// xml中添加一个action
// 初始视角重置
<action name="reset_view" scope="local">
tween(view.hlookat | view.vlookat | view.fov, %1 | %2 | %3,1.5);
</action>
2.设置视角的范围
场景当前观看的范围和范围的大小都是通过view元素的fov,fovmin和fovmax设置的,我们通过antd的Slider
组件来绑定这三个属性
html
<Card bordered={false} className="pano-view-card" style={{ background: '#282828' }}>
<div className="f14 mb15">视角 (FOV) 范围</div>
<Slider
min={0.1}
max={180}
range
marks={{
0.1: '最近',
180: '最远'
}}
step={0.1}
defaultValue={[scene.view.fovmin, scene.view.fov, scene.view.fovmax]}
onChange={handleFovChange}
/>
</Card>
当Slider的值发生改变时,触发onChange事件,拿到改变后的值通过set
方法修改场景当前观看的范围和范围的大小
js
const handleFovChange = (value: number[]) => {
const sceneList = [...workConfig.scene]
const index = sceneList.findIndex((item) => item.scene_id === selectSceneId)
if(index === -1) return
if (sceneList[index].view.fov !== value[1]) {
kp.set(`view.fov`, value[1])
} else if (sceneList[index].view.fovmin !== value[0]) {
kp.set(`view.fovmin`, value[0])
kp.set(`view.fov`, value[0])
} else if (sceneList[index].view.fovmax !== value[2]) {
kp.set(`view.fovmax`, value[2])
kp.set(`view.fov`, value[2])
}
}
3.设置观看范围
限制观看的垂直视角通过vlookatmax,vlookatmin这两个属性来限制,代表最小垂直观察位置和垂直水平观察位置,可设置的值为-90到90之间
水平视角则是通过hlookatmax,hlookatmin这两个属性来限制,代表最小水平观察位置和最大水平观察位置,可设置的值为-180到180之间
也是通过Slider
组件来设置这些属性,和视角的范围的设置一样
html
<Card bordered={false} className="pano-view-card" style={{ background: '#282828' }}>
<div className="f16 mb15">视角限制</div>
<div className="f14 mb15">水平视角限制</div>
<Slider
min={-180}
max={180}
range
marks={{
'-180': '-180',
180: '180'
}}
defaultValue={[scene.view.hlookatmin, scene.view.hlookatmax]}
onChange={handleHlookChange}
/>
<div className="f14 mb15">垂直视角限制</div>
<Slider
min={-90}
max={90}
range
marks={{
'-90': '-90',
90: '90'
}}
defaultValue={[scene.view.vlookatmin, scene.view.vlookatmax]}
onChange={handleVlookChange}
/>
</Card>
js
const handleHlookChange = (value: number[]) => {
const sceneList = [...workConfig.scene]
const index = sceneList.findIndex((item) => item.scene_id === selectSceneId)
if (sceneList[index].view.hlookatmin !== value[0]) {
kp.set(`view.hlookatmin`, value[0])
kp.set(`view.hlookatmax`, value[1])
kp.set(`view.hlookat`, value[0])
} else if (sceneList[index].view.hlookatmax !== value[1]) {
kp.set(`view.hlookatmin`, value[0])
kp.set(`view.hlookatmax`, value[1])
kp.set(`view.hlookat`, value[1])
}
}
const handleVlookChange = (value: number[]) => {
const sceneList = [...workConfig.scene]
const index = sceneList.findIndex((item) => item.scene_id === selectSceneId)
if (sceneList[index].view.vlookatmin !== value[0]) {
kp.set(`view.vlookatmin`, value[0])
kp.set(`view.vlookatmax`, value[1])
kp.set(`view.vlookat`, value[0])
} else if (sceneList[index].view.vlookatmax !== value[1]) {
kp.set(`view.vlookatmin`, value[0])
kp.set(`view.vlookatmax`, value[1])
kp.set(`view.vlookat`, value[1])
}
}
结尾
以上就是我对场景视角设置的实现,如果还有更好的方式也欢迎大家一起分享交流,学习学习😊🤞💋😘