首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >三盒"projectToWorld“返回超出画布的值,如何修复这个问题?(带有示例代码)

三盒"projectToWorld“返回超出画布的值,如何修复这个问题?(带有示例代码)
EN

Stack Overflow用户
提问于 2021-06-07 00:34:03
回答 1查看 218关注 0票数 0

最近,我发现在三个框中有一个非常方便的方法,用于在地图上放置three.js对象,即"projectToworld“。

在尝试使用该方法放置three.js对象时,我意识到方法返回的Vector3非常大,而不是在地图上。

根据三盒的文档,上面写着

projectToWorld

tb.projectToWorld(lnglat):THREE.Vector3

为给定的lnglat计算相应的THREE.Vector3。它的逆方法是tb.unprojectFromWorld。

因此,我决定使用这种方法在三个js画布中定位我的动画对象。但是这些方法的回报是非常巨大的。

因此,正如我所预期的,这些值并没有将这三个物体放置在地图上,所有的物体都消失了,因为它们可能被放置在非常遥远的位置。

我该如何解决这个问题?

我做了一个最低限度的代码来演示这个问题,如下所示。

  1. 实例化映射

代码语言:javascript
复制
var viewOrigin = [-73.8, 40.7];

var map = new mapboxgl.Map({
    container: 'map',
    style: 'mapbox://styles/jotnajoa/ckpj6g4ho3nvf18pg0r98pjes/draft',
    zoom: 12,
    center: viewOrigin,
    pitch: 60,
    antialias: true // create the gl context with MSAA antialiasing, so custom layers are antialiased
});

var modelAltitude = 0;

  1. Set mapboxgl

代码语言:javascript
复制
function translateCoords(lon, lat) {

    let destination = [lon, lat];
    let finalCoord = mapboxgl.MercatorCoordinate.fromLngLat(destination, 0);

    return finalCoord
}
var modelAsMercatorCoordinate = translateCoords(viewOrigin[0], viewOrigin[1]);

var modelTransform = {
    translateX: modelAsMercatorCoordinate.x,
    translateY: modelAsMercatorCoordinate.y,
    translateZ: modelAsMercatorCoordinate.z,
    scale: modelAsMercatorCoordinate.meterInMercatorCoordinateUnits()
};

  1. set变量用于mapboxgl之外的three.js呈现,因为我需要在mapboxgl生命周期钩子之外访问它.

代码语言:javascript
复制
const camera = new THREE.Camera();
const scene = new THREE.Scene();

// Setting map, canvas, renderer variable from the outside to access that from outside later

var map;
var canvas;
var renderer;
let particleGroup;
var frameCount = 0;  

  1. 实例化mapboxgl自定义层

代码语言:javascript
复制
function generateMap() {

    var customLayer = {
        id: '3d-model',
        type: 'custom',
        renderingMode: '3d',
        onAdd: function(map, gl) {
            map = map;
            canvas = map.getCanvas()
            renderer = new THREE.WebGLRenderer({
                canvas: map.getCanvas(),
                context: gl,
                antialias: true,
                preserveDrawingBuffer: true
            });
            renderer.autoClear = false;
        },
        render: function(gl, matrix) {
            frameCount += 0.1;
            rotate(frameCount)
            var m = new THREE.Matrix4().fromArray(matrix);

            var l = new THREE.Matrix4()
                .makeTranslation(
                    modelTransform.translateX,
                    modelTransform.translateY,
                    modelTransform.translateZ
                )
                .scale(
                    new THREE.Vector3(
                        modelTransform.scale, -modelTransform.scale,
                        modelTransform.scale
                    )
                )

            camera.projectionMatrix = m.multiply(l);
            renderer.resetState();
            renderer.render(scene, camera);
            map.triggerRepaint();

        }
    };

    map.on('style.load', function() {
        map.addLayer(customLayer, 'waterway-label');
    });

}

  1. 不断绘制旋转球体

代码语言:javascript
复制
function fillingSpheres(group) {
    const meshGroup = new THREE.Group();

    const { count } = group.geometry.attributes.position
    const { array } = group.geometry.attributes.position

    for (let i = 0; i < count; i++) {

        let i3 = i * 3;
        const x = array[i3]
        const y = array[i3 + 1]
        const z = array[i3 + 2];
        const posVec = new THREE.Vector3(x, y, z);

        const circleGeo = new THREE.SphereGeometry(10, 10, 10);
        const circleMtl = new THREE.MeshBasicMaterial({ color: 'green' });
        const circleMesh = new THREE.Mesh(circleGeo, circleMtl);
        circleMesh.userData.destination = posExample[i % 10];
        circleMesh.position.set(posVec.x, posVec.y, posVec.z)
        meshGroup.add(circleMesh)
    };
    console.log(meshGroup)
    return meshGroup;

}

  1. 将球移动到地图上相应的位置(这是问题发生的地方)

首先,基于当前映射设置实例化tb对象。

代码语言:javascript
复制
function setThreeBox() {

    window.tb = new Threebox(
        map,
        map.getCanvas().getContext('webgl'), {
            realSunlight: true,
            enableSelectingObjects: true, //change this to false to disable 3D objects selection
            enableTooltips: true, // change this to false to disable default tooltips on fill-extrusion and 3D models
        }
    );
    tb.altitudeStep = 1;
}

第二,通过projectToWorld获取坐标并定位它们。

代码语言:javascript
复制
function moveSphere() {

    // instantiate threebox object based on map

    setThreeBox()

    const { children } = particleGroup
    children.forEach((d) => {
        const { destination } = d.userData;
        const coordVec = tb.projectToWorld([destination.lng, destination.lat])
        console.log(coordVec)
        d.position.set(coordVec)
    })
}

然后,所有的坐标都是x:200000,不再显示场景中的三个物体。

我做错什么了?

我不只是基于三盒,而是基于three.js,因为我不能说明three.js坐标空间中三盒的旋转圆。

正在运行的代码位于下面的链接中。

https://codepen.io/jotnajoa/pen/poeKoOW (由于某种原因,示例在刷新代码之后运行,打开后不会立即启动)

如果能有一个对三盒了如指掌的人能帮我做这件事,我将不胜感激。如果我可以直接访问只在三盒环境中的场景()对象,那么解决这个问题就更容易了。如果它是可访问的,我可以很容易地使基于帧的动画在三个框。(也许我错了)

单击按钮时会触发放置。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-06-12 22:39:09

奇怪的是,没有人能回答这个问题。所以我终于想出了自己的办法。

解决方案在下面的链接中。

主要原因是mapbox绘制的东西不是基于它的矢量配置。它通过矩阵来呈现事物,如下所示。

变量m=新的THREE.Matrix4().makeTranslation(modelTransform.translateX,().fromArray(矩阵);var l=新的modelTransform.translateY,modelTransform.translateZ) .scale( THREE.Vector3(modelTransform.scale,-modelTransform.scale,modelTransform.scale))

代码语言:javascript
复制
            sphere.position.y = 0.2;

            camera.projectionMatrix.elements = matrix;
            camera.projectionMatrix = m.multiply(l);
            renderer.state.reset();
            renderer.render(scene, camera);

https://codepen.io/jotnajoa/pen/BaWGBoL?editors=1010

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67864751

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档