Coder Social home page Coder Social logo

Comments (11)

muyao1987 avatar muyao1987 commented on June 1, 2024

在事件内的event中可能没有相关值,是ceisum本身的回调,可以取 map.camera内值或调用map相关方法 即可获取相关参数

from mars3d.

FirokOtaku avatar FirokOtaku commented on June 1, 2024

另外在这些事件的监听器内尝试调用 map.camera.setView 等 API 均效果不佳, 会产生闪屏 / 视角错位等错误

当前视角参数的获取没有问题, 但是在监听器方法内直接操作 API 会导致视角错位.

function onCameraChanged(event)
{
    const { lat, lng, alt, heading, pitch } = Map.getCameraView()
    const paramView = {
        destination: Cesium.Cartesian3.fromDegrees(lng, lat, alt),
        orientation: { heading, pitch }
    }
    Map.camera.setView(paramView) // 把当前的经纬度等参数原样写回都会错位
}
map.on(mars3d.EventType.cameraChanged, onCameraChanged, this)

from mars3d.

muyao1987 avatar muyao1987 commented on June 1, 2024

有具体需求不,我分析下如果写合适

from mars3d.

FirokOtaku avatar FirokOtaku commented on June 1, 2024

现有需求限制摄像机视角锁定在固定经纬度 / 固定朝向范围 / 固定高度范围

这就是具体需求.

这边的应用场景是用来显示雕像 / 告示牌这样的模型,
相机视角会始终以模型为中心 (朝向这个模型),
另外不论如何用户拖动, 都只允许从正面 180 度 (或者其它自定义的) 范围查看模型.

from mars3d.

muyao1987 avatar muyao1987 commented on June 1, 2024

可能需要从鼠标交互事件入手,而不是相机变动事件

下面代码是片段性的关键逻辑,可以参考下

 setPitchRange(max, min = -90) { 
    map.scene.screenSpaceCameraController.inertiaSpin = 0
    map.scene.screenSpaceCameraController.inertiaTranslate = 0
 
    map.on(mars3d.EventType.mouseDown, this._setPitchRange_rightDownHandler, this)
    map.on(mars3d.EventType.mouseUp, this._setPitchRange_rightUpHandler, this)
  }

  _setPitchRange_rightDownHandler(evnet) { 
    map.on(mars3d.EventType.mouseMove, this._setPitchRange_mouseMoveHandler, this)
    map.on(mars3d.EventType.cameraChanged, this._setPitchRange_cameraChangedHandler, this)
  }

  _setPitchRange_rightUpHandler(evnet) {
    map.scene.screenSpaceCameraController.enableTilt = true
    map.off(mars3d.EventType.mouseMove, this._setPitchRange_mouseMoveHandler, this)
    map.off(mars3d.EventType.cameraChanged, this._setPitchRange_cameraChangedHandler, this)
  }

  _setPitchRange_mouseMoveHandler(evnet) {
    let enableTilt = true
    // const isUp = evnet.endPosition.y < evnet.startPosition.y
    // if (isUp && map.camera.pitch > this._pitch_max) {
    //   enableTilt = false
    // } else if (!isUp && map.camera.pitch < this._pitch_min) {
    //   enableTilt = false
    // } else {
    //   enableTilt = true
    // }
    map.scene.screenSpaceCameraController.enableTilt = enableTilt
  }

  _setPitchRange_cameraChangedHandler(evnet) {
    // if (map.scene.mode !== Cesium.SceneMode.SCENE3D) {
    //   return
    // }
    // if (map.camera.positionCartographic.height > map.scene.screenSpaceCameraController.minimumCollisionTerrainHeight) {
    //   return
    // }

    // let pitch = map.camera.pitch
    if (pitch > this._pitch_max || pitch < this._pitch_min) {
      // map.scene.screenSpaceCameraController.enableTilt = false

      // // clamp the pitch
      // if (pitch > this._pitch_max) {
      //   pitch = this._pitch_max
      // } else if (pitch < this._pitch_min) {
      //   pitch = this._pitch_min
      // }

      // const destination = Cesium.Cartesian3.fromRadians(
      //   map.camera.positionCartographic.longitude,
      //   map.camera.positionCartographic.latitude,
      //   Math.max(map.camera.positionCartographic.height, this._pitch_minHeight)
      // )

      map.camera.cancelFlight()
      map.camera.setView({
        destination: destination,
        orientation: {
          pitch: pitch
        }
      })
      map.scene.screenSpaceCameraController.enableTilt = true
    }
  }

from mars3d.

FirokOtaku avatar FirokOtaku commented on June 1, 2024

稍微加了点逻辑, 传给 map.camera.setView 的参数里已经对 pitch 等值限制了范围, 但是看起来不是很好用.
测试的时候视角还是会超出预定范围.
好的时候只超出范围一点点, 坏的时候视角整个就飞到不知道什么角度了.
有时候 pitch 会变成正数, 变成从地底朝上看;
另外相机视角离地高度也没法没法限制最小离地距离.
有点奇怪. 是我哪里理解有误吗?

function range(value = NaN, min = NaN, max = NaN)
{
    value = +value
    if(isNaN(value)) return NaN
    min = +min
    max = +max
    if(!isNaN(min) && value <= min) return min
    if(!isNaN(max) && value >= max) return max
    return value
}

let cameraRange = {
    pitchMin: -90,
    pitchMax: -10,
    headingMin: 90,
    headingMax: 180,
    altMin: 300,
    altMax: 500,
}
function setCameraRange({ pitchMin, pitchMax, headingMin, headingMax, altMin, altMax, })
{
    map.scene.screenSpaceCameraController.inertiaSpin = 0
    map.scene.screenSpaceCameraController.inertiaTranslate = 0
    if(pitchMin != null) cameraRange.pitchMin = pitchMin
    if(pitchMax != null) cameraRange.pitchMax = pitchMax
    if(headingMin != null) cameraRange.headingMin = headingMin
    if(headingMax != null) cameraRange.headingMax = headingMax
    if(altMin != null) cameraRange.altMin = altMin
    if(altMax != null) cameraRange.altMax = altMax
}

function onMouseDown()
{
    map.on(mars3d.EventType.mouseMove, onMouseMove, this)
    map.on(mars3d.EventType.cameraChanged, onCameraChange, this)
}
function onMouseUp()
{
    map.scene.screenSpaceCameraController.enableTilt = true
    map.off(mars3d.EventType.mouseMove, onMouseMove, this)
    map.off(mars3d.EventType.cameraChanged, onCameraChange, this)
}

// 用来在 UI 显示当前值的测试变量
const LNG = ref(0), LAT = ref(0), HEADING = ref(0), PITCH = ref(0), ALT = ref(0)

function onMouseMove(event)
{
    const { heading, pitch } = map.getCameraView()
    const mcp = map.camera.positionCartographic
    const lng = mcp.longitude, lat = mcp.latitude, alt = mcp.height
    LNG.value = lng
    LAT.value = lat
    ALT.value = alt
    HEADING.value = heading
    PITCH.value = pitch

    const { pitchMin, pitchMax, headingMin, headingMax, altMin, altMax } = cameraRange

    let enableUpDown
    if (event.endPosition.y < event.startPosition.y)
        enableUpDown = !(
            (!isNaN(pitchMax) && pitch > pitchMax) ||
            (!isNaN(altMax) && alt > altMax)
        )
    else if (event.endPosition.y > event.startPosition.y)
        enableUpDown = !(
            (!isNaN(pitchMin) && pitch < pitchMin) ||
            (!isNaN(altMin) && alt < altMin)
        )
    else
        enableUpDown = true

    let enableLeftRight
    if(event.endPosition.x > event.startPosition.x)
        enableLeftRight = !(
            (!isNaN(headingMax) && heading > headingMax)
        )
    else if(event.endPosition.x < event.startPosition.x)
        enableLeftRight = !(
            (!isNaN(headingMin) && heading < headingMin)
        )
    else
        enableLeftRight = true

    map.scene.screenSpaceCameraController.enableTilt = enableUpDown && enableLeftRight
}

function onCameraChange(event)
{
    const { pitchMax, pitchMin, headingMax, headingMin, altMin, altMax } = cameraRange
    let { pitch, heading } = map.camera
    if (!map.scene.screenSpaceCameraController.enableTilt)
    {
        pitch = range(pitch, pitchMin, pitchMax)

        map.camera.cancelFlight()
        map.camera.setView({
            destination: Cesium.Cartesian3.fromRadians(
                map.camera.positionCartographic.longitude,
                map.camera.positionCartographic.latitude,
                range(map.camera.positionCartographic.height, altMin, altMax)
            ),
            orientation: {
                pitch: range(pitch, pitchMin, pitchMax),
                heading: range(heading, headingMin, headingMax),
            }
        })
        map.scene.screenSpaceCameraController.enableTilt = true
    }
}

onMounted(async () => {
    map.scene.screenSpaceCameraController.inertiaSpin = 0
    map.scene.screenSpaceCameraController.inertiaTranslate = 0
    map.on(mars3d.EventType.mouseDown, onMouseDown, this)
    map.on(mars3d.EventType.mouseUp, onMouseUp, this)
})

onMounted(async () => {
    let mapOptions = {
        scene: {
            shadows: false, //是否启用日照阴影
            removeDblClick: true, //是否移除Cesium默认的双击事件

            //以下是Cesium.Viewer所支持的options【控件相关的写在另外的control属性中】
            sceneMode: 3, //3等价于Cesium.SceneMode.SCENE3D,

            //以下是Cesium.Scene对象相关参数
            showSun: false, //是否显示太阳
            showMoon: false, //是否显示月亮
            showSkyBox: true, //是否显示天空盒
            showSkyAtmosphere: false, //是否显示地球大气层外光圈
            fog: false, //是否启用雾化效果
            fxaa: true, //是否启用抗锯齿

            //以下是Cesium.Globe对象相关参数
            globe: {
                depthTestAgainstTerrain: false, //是否启用深度监测
                baseColor: '#546a53', //地球默认背景色
                showGroundAtmosphere: false, //是否在地球上绘制的地面大气
                enableLighting: false //是否显示昼夜区域
            },
            //以下是Cesium.ScreenSpaceCameraController对象相关参数
            cameraController: {
                zoomFactor: 5, //鼠标滚轮放大的步长参数
                minimumZoomDistance: 50, //地球放大的最小值(以米为单位)
                maximumZoomDistance: 100, //地球缩小的最大值(以米为单位)
                minimumCollisionTerrainHeight: 100,
                enableRotate: true , //2D和3D视图下,是否允许用户旋转相机
                enableTranslate: false, //2D和哥伦布视图下,是否允许用户平移地图
                enableTilt: true, // 3D和哥伦布视图下,是否允许用户倾斜相机
                enableZoom: true, // 是否允许 用户放大和缩小视图
                enableCollisionDetection: true //是否允许 地形相机的碰撞检测
            },
        },
        control: {
            baseLayerPicker: false, //basemaps底图切换按钮
            homeButton: true, //视角复位按钮
            sceneModePicker: false, //二三维切换按钮
            navigationHelpButton: false, //帮助按钮
            fullscreenButton: false, //全屏按钮
        },
        basemaps: []
    }

    map = new mars3d.Map(
        'mars3dContainer',
        mapOptions,
    )
    map.fixedLight = true
    map = markRaw(map)

    const tiles3dLayer = new mars3d.layer.TilesetLayer({
        name: "县城社区",
        url: "//data.mars3d.cn/3dtiles/qx-shequ/tileset.json",
        position: { alt: 11.5 },
        maximumScreenSpaceError: 1,
        maximumMemoryUsage: 1024,
        dynamicScreenSpaceError: true,
        cullWithChildrenBounds: false,
        skipLevelOfDetail: true,
        preferLeaves: true,
        center: { lat: 28.439577, lng: 119.476925, alt: 229, heading: 57, pitch: -29 },

        enableDebugWireframe: true, // 是否可以进行三角网的切换显示
        flyTo: true
    })
    map.addLayer(tiles3dLayer)
    tiles3dLayer.flyTo().finally(() => {})

    map.on(mars3d.EventType.mouseDown, onMouseDown, this)
    map.on(mars3d.EventType.mouseUp, onMouseUp, this)
    window.map = map
})

from mars3d.

FirokOtaku avatar FirokOtaku commented on June 1, 2024

好吧, 想了想, 完全换了一种写法,
禁用 mars3d 所有的视角移动选项,

cameraController: {
    enableRotate: false , //2D和3D视图下,是否允许用户旋转相机
    enableTranslate: false, //2D和哥伦布视图下,是否允许用户平移地图
    enableTilt: false, // 3D和哥伦布视图下,是否允许用户倾斜相机
    enableZoom: false, // 是否允许 用户放大和缩小视图
    enableCollisionDetection: false //是否允许 地形相机的碰撞检测
}

然后监听 mouseUp, mouseDown, mouseMove 事件,
手动根据鼠标移动的偏移角度用三角函数算相机的空间位置和朝向,
把算出来的东西 map.setCameraView 到 mars3d 里,
大致实现需要用的功能了.

新问题来了, 翻了半天 wheel 事件实例的字段,
没找到滚轮滚动值 (判断滚轮向上 / 向下滚动),
镜头视角缩放功能少一个常见的快捷键.

所以说传入监听器的事件实例能不能把原生 Web 事件实例加上啊,
哪怕不允许直接访问原生 MouseEvent 对象,
把里面字段复制一份让监听器方法能读到, 有些事能好办很多.

from mars3d.

FirokOtaku avatar FirokOtaku commented on June 1, 2024

另外请问有没有对 各类型事件触发的时候会传给监听器什么结构的事件实例参数 的描述文档?

现有文档 (Event, Global#EventType, BaseClass#fire) 里没找到相关信息.
现在只知道发生 xx 事件之后 xx 监听器方法就会被调用,
不知道调用的时候会传给监听器方法什么参数,
还得现翻 F12 控制台挨个字段瞅.

from mars3d.

muyao1987 avatar muyao1987 commented on June 1, 2024

cameraController

建议看看ScreenSpaceCameraController类代码,是cesium对鼠标交互控制相机的所有逻辑。

from mars3d.

muyao1987 avatar muyao1987 commented on June 1, 2024

另外请问有没有对 各类型事件触发的时候会传给监听器什么结构的事件实例参数 的描述文档?

现有文档 (Event, Global#EventType, BaseClass#fire) 里没找到相关信息. 现在只知道发生 xx 事件之后 xx 监听器方法就会被调用, 不知道调用的时候会传给监听器方法什么参数, 还得现翻 F12 控制台挨个字段瞅.

目前还没有,需要F12打印event后看下值。

from mars3d.

FirokOtaku avatar FirokOtaku commented on June 1, 2024

目前还没有,需要F12打印event后看下值。

好的

from mars3d.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.