Krpano:打造全景漫游体验—全景开发(三)

前言

在我们生成全景预览的时候,用户观看的视角是固定的,因为在创建全景作品的时候对于视角的设置会给一个默认值,对于用户观看的方向和距离,我们想要有更多的设置,例如初始视角视角的范围大小水平/垂直的视角限制都可以自定义修改,这篇文章就来实现自定义每个场景的视角

效果预览

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])
    }
  }

结尾

以上就是我对场景视角设置的实现,如果还有更好的方式也欢迎大家一起分享交流,学习学习😊🤞💋😘

相关推荐
Cool----代购系统API12 分钟前
css设置盒子动画,CSS3 transition动画 animation动画
前端·css·css3
哟哟耶耶22 分钟前
css-设置元素的溢出行为为可见overflow: visible;
前端·css
sunly_24 分钟前
CSS:跑马灯
前端·css
2301_8187320632 分钟前
用layui表单,前端页面的样式正常显示,但是表格内无数据显示(数据库连接和获取数据无问题)——已经解决
java·前端·javascript·前端框架·layui·intellij idea
yqcoder33 分钟前
npm link 作用
前端·npm·node.js
林涧泣39 分钟前
【Uniapp-Vue3】页面和路由API-navigateTo及页面栈getCurrentPages
前端·vue.js·uni-app
Komorebi゛41 分钟前
【uniapp】获取上传视频的md5,适用于APP和H5
前端·javascript·uni-app
林涧泣1 小时前
【Uniapp-Vue3】动态设置页面导航条的样式
前端·javascript·uni-app
杰九1 小时前
【全栈】SprintBoot+vue3迷你商城(10)
开发语言·前端·javascript·vue.js·spring boot
Hopebearer_2 小时前
入门 Canvas:Web 绘图的强大工具
前端·javascript·es6·canva可画