简体   繁体   English

三框“projectToWorld”返回的值超过 canvas,我该如何解决? (附示例代码)

[英]threebox “projectToWorld” returns values exceeding canvas, how do I fix this? (with sample code)

I recently found out there is a very handy method in three-box for placing three.js objects on the map which is "projectToworld".我最近发现在三盒中有一个非常方便的方法,可以将 three.js 对象放在 map 上,即“projectToworld”。

While trying to place my three.js objects using the method, I realized that the Vector3 the method returns are really huge and not on the map.在尝试使用该方法放置我的 three.js 对象时,我意识到该方法返回的 Vector3 非常大,而不是在 map 上。

According to the documentation of threebox, it says根据threebox的文档,它说

projectToWorld项目到世界

tb.projectToWorld(lnglat): THREE.Vector3 tb.projectToWorld(lnglat): THREE.Vector3

Calculate the corresponding THREE.Vector3 for a given lnglat.计算给定 lnglat 对应的 THREE.Vector3。 It's inverse method is tb.unprojectFromWorld.它的逆方法是 tb.unprojectFromWorld。

So I decided to use this method to locate my animated object in three js canvas.所以我决定用这个方法在三个js canvas中定位我的动画object。 But what the methods returns are really huge.但是这些方法返回的东西真的很大。

在此处输入图像描述

So as I expected, these values don't place the three objects on the map and all the objects disappeared because they presumably are placed at very distant locations.因此,正如我所料,这些值不会将三个对象放在 map 上,并且所有对象都消失了,因为它们可能被放置在非常遥远的位置。

How do I fix this issue?我该如何解决这个问题?

I made a minimal code to demonstrate this issue as below.我做了一个最小的代码来演示这个问题,如下所示。

  1. instantiating map实例化 map
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设置 mapboxgl
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 variables for three.js render outside of mapboxgl because I need to access it outside of mapboxgl lifecycle hook.为 three.js 设置变量在 mapboxgl 之外渲染,因为我需要在 mapboxgl 生命周期挂钩之外访问它。
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. Instantiate mapboxgl customlayer实例化 mapboxgl 自定义层
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. Draw constantly revolving sphere绘制不断旋转的球体
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. Move the spheres to the corresponding location on the map (This is where the issue occurs)将球体移动到 map 上的相应位置(这是出现问题的地方)

First, I instantiated tb object based on the current map setting首先,我根据当前的 map 设置实例化了 tb object

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;
}

Second, get the coordinates by projectToWorld and locate them二、通过projectToWorld获取坐标并定位

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

Then, all the coordinates are like x:200000 and it no longer shows the three objects on the scene.然后,所有的坐标都像 x:200000 并且不再显示场景中的三个对象。

What did I do wrong?我做错了什么?

The reason why I based on three.js not solely on three-box is that I can't illustrate the revolving circle on the three.js coordinates space in three-box.我之所以基于three.js不单单在三箱上,是因为我无法说明在three.js坐标空间上的旋转圆在三箱上。

The running code is in the following link.运行代码在以下链接中。

https://codepen.io/jotnajoa/pen/poeKoOW (for some reason the sample is running after refreshing the code, doesn't start immediately once it is opened) https://codepen.io/jotnajoa/pen/poeKoOW (由于某种原因,示例在刷新代码后正在运行,打开后不会立即启动)

It would be grateful if someone who knows well about three-box could help me on this.如果有熟悉三盒的人可以帮助我,将不胜感激。 I assume it could be easier to solve this if I could directly access to scene() object in three-box only environment.我认为如果我可以在仅限三盒的环境中直接访问 scene() object,解决这个问题会更容易。 If it's accessible, I could easily make the frame-based animation in three-box.如果可以访问,我可以轻松地将基于框架的 animation 制作成三盒。 (Maybe I'm wrong) (也许我错了)

Placing is triggered when the button is clicked.单击按钮时触发放置。

It's strange that no one could answer this question.奇怪的是没有人能回答这个问题。 So I finally figured out how to make it by myself.所以我终于想出了如何自己制作它。

The solution is in the following link.解决方案在以下链接中。

The primary reason was that mapbox plots things not based on its vector configuration.主要原因是 mapbox 绘制的东西不是基于其矢量配置。 It renders things through its matrix as follows.它通过其矩阵呈现事物,如下所示。

var m = new THREE.Matrix4().fromArray(matrix); 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)) var l = new THREE.Matrix4().makeTranslation(modelTransform.translateX, modelTransform.translateY, modelTransform.translateZ).scale(new THREE.Vector3(modelTransform.scale, -modelTransform.scale, modelTransform.scale))

            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 https://codepen.io/jotnajoa/pen/BaWGBoL?editors=1010

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM