【自己写全景】TreeJs实现全景图

news/2024/7/19 13:48:00 标签: 全景图, treejs, js

image

image

先附上两张成果图,我们的主要功能就是以上两个,实现全景图的浏览,将全景标记放在图上并实现属性查询。

注:并不是所有的图片都能当作全景图,可以到专门的网站下载全景图使用,有些拍摄的不好的全景图也会出现衔接的问题。

一.基本原理

我们可以把我们我们观察到的对象想象成一个球体,而全景图就是附在球体上的一张图片,我们通过鼠标移动来改变我们的视角,从而到达全景图的其他地方。

我估计将球体做的很小(如上面两张图)就是为了直观的看出这是一个球体。而通过特定的相机视角和 透视投影我们可以全景图尽可能少的发生变形。

当我们把视角,或者说相机的焦距稍稍变化一些,或者把球体的半径变大一些,我们就发现不了球体的存在,从而有身临其境的感觉。

还有一个功能是将我们特定的poi点标记在全景上,如下图,这也不是一个简单的问题,因为我们要在数据库中记录poi点的位置,然后跟随者我们全景图的变化位置要发生变化,这就涉及到了坐标转换的问题,我们在下面探讨。

image

一.参数初始化

在上一篇博客提到过要生成一个js>treejs场景的几个要素,在全景图中也无外乎这么几个(相机,渲染器,场景)。

1.1 初始化相机

我们要想让全景有更好的视觉效果所使用的相机最好是透视投影:这种投影模式旨在模仿人眼所看到的方式。它是用于渲染3D场景的最常用的投影模式。fov参数是视场角 人的视场角大致是30度到100度,这里设置75度左右。

js avrasm">        camera = new THREEjs-preprocessor">.PerspectiveCamera( fov, windowjs-preprocessor">.innerWidth / windowjs-preprocessor">.innerHeight, js-number">1, js-number">1100 )js-comment">;
        camerajs-preprocessor">.target = new THREEjs-preprocessor">.Vector3( js-number">0, js-number">0, js-number">0 )js-comment">;

我们的标记不是三维元素,他的大小不需要随着我们的视角改变,所以我们使用正投影:在这种投影模式下,渲染图像中物体的大小与摄像机的距离无关,保持不变。这可以用于渲染2D场景和UI元素等等。

js avrasm">        cameraOrtho = new THREEjs-preprocessor">.OrthographicCamera( - windowjs-preprocessor">.innerWidth / js-number">2, windowjs-preprocessor">.innerWidth / js-number">2, windowjs-preprocessor">.innerHeight / js-number">2, - windowjs-preprocessor">.innerHeight / js-number">2, js-number">1, js-number">10 )js-comment">;
        cameraOrthojs-preprocessor">.positionjs-preprocessor">.z = js-number">10js-comment">;

1.2 初始化场景

场景也要初始化两个:

js cs">        scene = js-keyword">new THREE.Scene();
        sceneOrtho = js-keyword">new THREE.Scene();

1.3 全景初始化

创建容纳全景的球形集合体:

js lasso">        mesh js-subst">= js-literal">new THREEjs-built_in">.Mesh( js-literal">new THREEjs-built_in">.SphereGeometry( js-number">2, js-number">60, js-number">40 ),
            js-literal">new THREEjs-built_in">.MeshBasicMaterial(
                { js-built_in">map: THREEjs-built_in">.ImageUtilsjs-built_in">.loadTexture( js-string">'textures/pano-1.jpg' ) }
            ) );
        meshjs-built_in">.scalejs-built_in">.x js-subst">= js-subst">-js-number">1;
        scenejs-built_in">.add( mesh );

第一个参数是半径,必须大于1小于某个数,第二三个参数为经纬度切片数,值太小全景图会变形,值越大越精细,但是会影响性能

1.4 创建渲染器

js avrasm">        renderer = new THREEjs-preprocessor">.WebGLRenderer()js-comment">;
        rendererjs-preprocessor">.setSize(windowjs-preprocessor">.innerWidth, windowjs-preprocessor">.innerHeight)js-comment">;
        rendererjs-preprocessor">.autoClear = falsejs-comment">;
        containerjs-preprocessor">.appendChild( rendererjs-preprocessor">.domElement )js-comment">;

1.5 初始化动画

js mel">    function animate() {
        requestAnimationFrame( animate );
        js-keyword">renderer.js-keyword">clear();
        js-keyword">renderer.js-keyword">render( scene, js-keyword">camera );
    }

二.实现移动视角

2.1 事件监听

对dom和window进行事件监听

js coffeescript">        js-built_in">document.addEventListener( js-string">'mousedown', onDocumentMouseDown, js-literal">false );
        js-built_in">document.addEventListener( js-string">'mousemove', onDocumentMouseMove, js-literal">false );
        js-built_in">document.addEventListener( js-string">'mouseup', onDocumentMouseUp, js-literal">false );
        js-built_in">window.addEventListener( js-string">'resize', onWindowResize, js-literal">false );

2.2 鼠标按下事件

js cs">    function onDocumentMouseDown( js-keyword">event ) {
        js-keyword">event.preventDefault();
        isUserInteracting = js-keyword">true;
        onPointerDownPointerX = js-keyword">event.clientX;
        onPointerDownPointerY = js-keyword">event.clientY;
        onPointerDownLon = lon;
        onPointerDownLat = lat;
    }

isUserInteracting 用于标识用户是否按下鼠标,记录下此时鼠标的屏幕坐标和初始经纬度。

注意这个经纬度不是传统意义上的经纬度,是我们模仿地球经纬度虚拟出的一个坐标,用于标记球体上的任意位置,方便计算。

2.3 鼠标移动,弹起事件

由鼠标移动的距离来计算屏幕中心移动的经纬度。

js nginx">    js-title">function js-built_in">onDocumentMouseMove( event ) {

        js-title">if ( isUserInteracting ) {
            js-title">lon = ( js-built_in">onPointerDownPointerX - event.clientX ) * js-number">0.js-number">1 + js-built_in">onPointerDownLjs-built_in">on;
            js-title">lat = ( event.clientY - js-built_in">onPointerDownPointerY ) * js-number">0.js-number">1 + js-built_in">onPointerDownLat;
        }
    }
js javascript">    js-function">js-keyword">function js-title">onDocumentMouseUpjs-params">( event ) {
        isUserInteracting = js-literal">false;
    }

2.4 动画渲染

这时我们只是改变了全局变量的数值,并没有产生实际效果,我们还需要再动画中添加如下代码以实现实时渲染:

将经纬度转换成世界坐标:

js avrasm">        lat = Mathjs-preprocessor">.max( - js-number">85, Mathjs-preprocessor">.min( js-number">85, lat ) )js-comment">;//纬度限制在-85---85度之间
        phi = THREEjs-preprocessor">.Mathjs-preprocessor">.degToRad( js-number">90 - lat )js-comment">;
        theta = THREEjs-preprocessor">.Mathjs-preprocessor">.degToRad( lon )js-comment">;

        camerajs-preprocessor">.targetjs-preprocessor">.x = pRadius * Mathjs-preprocessor">.sin( phi ) * Mathjs-preprocessor">.cos( theta )js-comment">;
        camerajs-preprocessor">.targetjs-preprocessor">.y = pRadius * Mathjs-preprocessor">.cos( phi )js-comment">;
        camerajs-preprocessor">.targetjs-preprocessor">.z = pRadius * Mathjs-preprocessor">.sin( phi ) * Mathjs-preprocessor">.sin( theta )js-comment">;
        camerajs-preprocessor">.lookAt( camerajs-preprocessor">.target )js-comment">;

2.5 适配窗体

当我们的窗口大小改变时适配全景的大小

js coffeescript">js-built_in">window.addEventListener( js-string">'resize', onWindowResize, js-literal">false );
js avrasm">    function onWindowResize() {
        camerajs-preprocessor">.aspect = windowjs-preprocessor">.innerWidth / windowjs-preprocessor">.innerHeightjs-comment">;
        camerajs-preprocessor">.projectionMatrixjs-preprocessor">.makePerspective( fov, camerajs-preprocessor">.aspect, js-number">1, js-number">1100 )js-comment">;
        camerajs-preprocessor">.updateProjectionMatrix()js-comment">;
        cameraOrthojs-preprocessor">.left = - windowjs-preprocessor">.innerWidth  / js-number">2js-comment">;
        cameraOrthojs-preprocessor">.right =  windowjs-preprocessor">.innerWidth / js-number">2js-comment">;
        cameraOrthojs-preprocessor">.top = windowjs-preprocessor">.innerHeight / js-number">2js-comment">;
        cameraOrthojs-preprocessor">.bottom = - windowjs-preprocessor">.innerHeight / js-number">2js-comment">;
        cameraOrthojs-preprocessor">.updateProjectionMatrix()js-comment">;
        rendererjs-preprocessor">.setSize( windowjs-preprocessor">.innerWidth, windowjs-preprocessor">.innerHeight )js-comment">;
    }

现在我们就可以看到全景并可以移动视角了,接下来就是将标记添加在全景上。

三.添加标记

3.1 添加标记

虚拟几个标记并将它添加到数组中:

js cs">        js-keyword">var p1={lon:js-number">158,lat:js-number">7};
        js-keyword">var p2={lon:js-number">120,lat:js-number">13};
        js-keyword">var p3={lon:-js-number">120,lat:js-number">10};

        sprites.push(createSprite(p1,js-string">"textures/school.png",js-string">"化学实验室"));
        sprites.push(createSprite(p2,js-string">"textures/school.png",js-string">"物理实验室"));
        sprites.push(createSprite(p3,js-string">"textures/food.png",js-string">"餐厅"));

创建标记函数

js actionscript">    js-function">js-keyword">function js-title">createSpritejs-params">(position,url,name){
        js-keyword">var textureLoader = js-keyword">new THREE.TextureLoader();
        js-keyword">var ballMaterial = js-keyword">new THREE.SpriteMaterial({
            map: textureLoader.load( url )js-comment">//( 'textures/sprite1.png' )
        });
        js-keyword">var sp1={
            pos:position,
            name:name,
            sprite:js-keyword">new THREE.Sprite(ballMaterial)
        };
        sp1.sprite.scale.js-keyword">set(js-number">32, js-number">32, js-number">1.0);
        sp1.sprite.position.js-keyword">set(js-number">0, js-number">0, js-number">0);
        sp1.sprite.name=name;
        sceneOrtho.add(sp1.sprite);
        clickableObjects.push(sp1.sprite);
        js-keyword">return sp1;
    }

这里我们将标记存入了两个不同的数组,clickableObjects是为了搜索使用,sprites数组我们还存入了经纬度,这是为了在动画函数中的一些计算:

js avrasm">        if(typeof (sprites)!=js-string">"undefined") {
            for (var i = js-number">0js-comment">; i < sprites.length; i++) {
                var wp = geoPosition2World(sprites[i]js-preprocessor">.posjs-preprocessor">.lon,sprites[i]js-preprocessor">.posjs-preprocessor">.lat)js-comment">;
                var sp = worldPostion2Screen(wp, camera)js-comment">;
                var test=wpjs-preprocessor">.clone()js-comment">;
                testjs-preprocessor">.project(camera)js-comment">;
                //判断是否在视野范围内,在旋转球体的过程中有可能会转出我们的视野,把这些图标隐藏起来
                if (testjs-preprocessor">.x > -js-number">1 && testjs-preprocessor">.x < js-number">1 && testjs-preprocessor">.y > -js-number">1 && testjs-preprocessor">.y < js-number">1 && testjs-preprocessor">.z > -js-number">1 && testjs-preprocessor">.z < js-number">1) {
                    sprites[i]js-preprocessor">.spritejs-preprocessor">.scalejs-preprocessor">.set(js-number">32, js-number">32,js-number">32)js-comment">;
                    sprites[i]js-preprocessor">.spritejs-preprocessor">.positionjs-preprocessor">.set(spjs-preprocessor">.x, spjs-preprocessor">.y, js-number">1)js-comment">;
                }
                else {
                    sprites[i]js-preprocessor">.spritejs-preprocessor">.scalejs-preprocessor">.set(js-number">1.0,js-number">1.0,js-number">1.0)js-comment">;
                    sprites[i]js-preprocessor">.spritejs-preprocessor">.positionjs-preprocessor">.set(js-number">0,js-number">0,js-number">0)js-comment">;
                }
            }
        }

这是添加标记的核心函数所在,首先将标记的经纬度坐标转换成了世界坐标,我们再将他归一化,归一化的意义是判断它是否在我们的视野中(x,y坐标如果属于-1到1之间那么他就在我们的视野中)

因为我们不可能看到球体的所有部分,如果标记在我们的视野中我们才要添加他到屏幕上。

然后将经纬度坐标转换成屏幕坐标,并将添加到视野中。

3.2 实现标记属性查询

监听点击事件:

js coffeescript">js-built_in">document.addEventListener( js-string">'click', onDocumentMouseClick, js-literal">false);
js avrasm">    function onDocumentMouseClick(event){
        mousejs-preprocessor">.x = ( eventjs-preprocessor">.clientX/ windowjs-preprocessor">.innerWidth ) * js-number">2 - js-number">1js-comment">;
        mousejs-preprocessor">.y = - ( eventjs-preprocessor">.clientY / windowjs-preprocessor">.innerHeight ) * js-number">2 + js-number">1js-comment">;
        raycasterjs-preprocessor">.setFromCamera( mouse, cameraOrtho )js-comment">;
        var intersects = raycasterjs-preprocessor">.intersectObjects( clickableObjects )js-comment">;
        intersectsjs-preprocessor">.forEach(function(element){
            alert(js-string">"Intersection: " + elementjs-preprocessor">.objectjs-preprocessor">.name)js-comment">;
        })js-comment">;
    }

如果写的没有问题,以上代码就可以实现如下效果:

image

以下是所有源码:

js javascript">    js-comment">//三要素,相机,场景,渲染器
    js-keyword">var camera, scene, renderer;
    js-comment">//正投影的相机和场景
    js-keyword">var cameraOrtho, sceneOrtho;
    js-comment">//用于协助鼠标拾取
    js-keyword">var raycaster
    js-comment">//全景标记点数组
    js-keyword">var sprites = [];
    js-comment">//用于查询全景标记点的数组
    js-keyword">var clickableObjects = [];
    js-comment">//判断用户有没有操作的参数
    js-keyword">var isUserInteracting = js-literal">false;
    js-comment">//屏幕焦点的经纬度
    js-keyword">var lon =js-number">0,lat=js-number">0;
    js-comment">//临时经纬度
    js-keyword">var onPointerDownLon = js-number">0, onPointerDownLat =js-number">0;
    js-comment">//临时xy
    js-keyword">var onPointerDownPointerX = js-number">0, onPointerDownPointerY = js-number">0;
    js-comment">//鼠标2D坐标
    js-keyword">var mouse = js-keyword">new THREE.Vector2();
    js-comment">//焦距
    js-keyword">var fov = js-number">75;
    js-comment">//球半径
    js-keyword">var pRadius = js-number">1000;

    js-comment">//初始化各种参数
    init();
    js-comment">//初始化动画
    animate();

    js-function">js-keyword">function js-title">initjs-params">() {

        js-comment">//容器,用于融合集合体和
        js-keyword">var container, mesh;

        js-comment">//获取容器
        container = document.getElementById( js-string">'container' );

        js-comment">//初始化相机(透视投影)模仿人眼所看到的方式。它是用于渲染3D场景的最常用的投影模式。
        camera = js-keyword">new THREE.PerspectiveCamera( fov, window.innerWidth / window.innerHeight, js-number">1, js-number">1100 );
        camera.target = js-keyword">new THREE.Vector3( js-number">0, js-number">0, js-number">0 );

        js-comment">//初始化相机(正投影)渲染图像中物体的大小与摄像机的距离无关,保持不变。这可以用于渲染2D场景和UI元素等等。
        cameraOrtho = js-keyword">new THREE.OrthographicCamera( - window.innerWidth / js-number">2, window.innerWidth / js-number">2, window.innerHeight / js-number">2, - window.innerHeight / js-number">2, js-number">1, js-number">10 );
        cameraOrtho.position.z = js-number">10;

        js-comment">//初始化场景(普通和正投影)
        scene = js-keyword">new THREE.Scene();
        sceneOrtho = js-keyword">new THREE.Scene();

        js-comment">//协助鼠标拾取要素
        raycaster = js-keyword">new THREE.Raycaster();

        js-comment">//创建网格,融合几何体和材料,并添加到场景中
        js-comment">//创建圆形几何体(第一个参数是半径,必须大于1小于某个数,第二三个参数为经纬度切片数,值太小全景图会变形,值越大越精细,但是会影响性能)
        mesh = js-keyword">new THREE.Mesh( js-keyword">new THREE.SphereGeometry( js-number">2, js-number">60, js-number">40 ),
            js-keyword">new THREE.MeshBasicMaterial(
                { map: THREE.ImageUtils.loadTexture( js-string">'textures/pano-1.jpg' ) }
            ) );
        mesh.scale.x = -js-number">1;
        scene.add( mesh );

        js-comment">//创建渲染器并添加到场景中
        renderer = js-keyword">new THREE.WebGLRenderer();
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.autoClear = js-literal">false;
        container.appendChild( renderer.domElement );

        js-comment">//初始化全景标记
        initLable();


        document.addEventListener( js-string">'mousedown', onDocumentMouseDown, js-literal">false );
        document.addEventListener( js-string">'mousemove', onDocumentMouseMove, js-literal">false );
        document.addEventListener( js-string">'mouseup', onDocumentMouseUp, js-literal">false );
        document.addEventListener( js-string">'click', onDocumentMouseClick, js-literal">false);
        window.addEventListener( js-string">'resize', onWindowResize, js-literal">false );

    }

    js-comment">/*
     * 鼠标按下事件
     * */
    js-function">js-keyword">function js-title">onDocumentMouseDownjs-params">( event ) {

        event.preventDefault();

        isUserInteracting = js-literal">true;

        onPointerDownPointerX = event.clientX;
        onPointerDownPointerY = event.clientY;

        onPointerDownLon = lon;
        onPointerDownLat = lat;
    }

    js-comment">/*
     * 鼠标移动事件
     * */
    js-function">js-keyword">function js-title">onDocumentMouseMovejs-params">( event ) {
        js-keyword">if ( isUserInteracting ) {
            lon = ( onPointerDownPointerX - event.clientX ) * js-number">0.1 + onPointerDownLon;
            lat = ( event.clientY - onPointerDownPointerY ) * js-number">0.1 + onPointerDownLat;
        }
    }

    js-comment">/*
     * 鼠标弹起事件
     * */
    js-function">js-keyword">function js-title">onDocumentMouseUpjs-params">( event ) {
        isUserInteracting = js-literal">false;
    }

    js-comment">/*
     * 单机鼠标查询标记点
     * */
    js-function">js-keyword">function js-title">onDocumentMouseClickjs-params">(event){
        mouse.x = ( event.clientX/ window.innerWidth ) * js-number">2 - js-number">1;
        mouse.y = - ( event.clientY / window.innerHeight ) * js-number">2 + js-number">1;
        raycaster.setFromCamera( mouse, cameraOrtho );
        js-keyword">var intersects = raycaster.intersectObjects( clickableObjects );
        intersects.forEach(js-function">js-keyword">functionjs-params">(element){
            alert(js-string">"Intersection: " + element.object.name);
        });
    }

    js-comment">/*
     * 窗体变化事件
     * */
    js-function">js-keyword">function js-title">onWindowResizejs-params">() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.projectionMatrix.makePerspective( fov, camera.aspect, js-number">1, js-number">1100 );
        camera.updateProjectionMatrix();
        cameraOrtho.left = - window.innerWidth  / js-number">2;
        cameraOrtho.right =  window.innerWidth / js-number">2;
        cameraOrtho.top = window.innerHeight / js-number">2;
        cameraOrtho.bottom = - window.innerHeight / js-number">2;
        cameraOrtho.updateProjectionMatrix();
        renderer.setSize( window.innerWidth, window.innerHeight );
    }

    js-comment">//初始化全景标记函数
    js-function">js-keyword">function js-title">initLablejs-params">() {

        js-keyword">var p1={lon:js-number">158,lat:js-number">7};
        js-keyword">var p2={lon:js-number">120,lat:js-number">13};
        js-keyword">var p3={lon:-js-number">120,lat:js-number">10};
        js-keyword">var p4={lon:-js-number">180,lat:js-number">2};
        js-keyword">var p5={lon:-js-number">150,lat:js-number">5};
        js-keyword">var p6={lon:-js-number">20,lat:js-number">20};
        js-keyword">var p7={lon:js-number">50,lat:js-number">10};

        sprites.push(createSprite(p1,js-string">"textures/school.png",js-string">"化学实验室"));
        sprites.push(createSprite(p2,js-string">"textures/school.png",js-string">"物理实验室"));
        sprites.push(createSprite(p3,js-string">"textures/food.png",js-string">"餐厅"));
        sprites.push(createSprite(p4,js-string">"textures/home.png",js-string">"健身房"));
        sprites.push(createSprite(p5,js-string">"textures/home.png",js-string">"公寓"));
        sprites.push(createSprite(p6,js-string">"textures/shop.png",js-string">"图书馆"));
        sprites.push(createSprite(p7,js-string">"textures/hospital.png",js-string">"医务室"));

    }

    js-comment">/*
     * 创建标注
     * position:lable标签的位置(lon,lat)
     * **/
    js-function">js-keyword">function js-title">createSpritejs-params">(position,url,name){
        js-keyword">var textureLoader = js-keyword">new THREE.TextureLoader();
        js-keyword">var ballMaterial = js-keyword">new THREE.SpriteMaterial({
            map: textureLoader.load( url )js-comment">//( 'textures/sprite1.png' )
        });
        js-keyword">var sp1={
            pos:position,
            name:name,
            sprite:js-keyword">new THREE.Sprite(ballMaterial)
        };
        sp1.sprite.scale.set(js-number">32, js-number">32, js-number">1.0);
        sp1.sprite.position.set(js-number">0, js-number">0, js-number">0);
        sp1.sprite.name=name;
        sceneOrtho.add(sp1.sprite);
        clickableObjects.push(sp1.sprite);
        js-keyword">return sp1;
    }

    js-function">js-keyword">function js-title">animatejs-params">() {
        requestAnimationFrame( animate );
        render();
    }

    js-function">js-keyword">function js-title">renderjs-params">() {

        js-comment">/*
         * 1、POI点通过编辑工具进行定位(lon、lat)
         * 2、将全景视图按照经度分成四份各90度(0-90、90-180、180-270、270-360)
         * 3、在渲染线程中根据当前相机的经度范围查询当前需要绘制的POI:如何根据屏幕坐标计算经纬度
         *    设当前相机中心经度为lonn ,相机广度为num度,当前经度范围为lonn-num----------lonn+num
         * 4、将POI的经纬度位置转换为屏幕坐标进行POI绘制
         *
         * */
        lat = js-built_in">Math.max( - js-number">85, js-built_in">Math.min( js-number">85, lat ) );js-comment">//纬度限制在-85---85度之间
        phi = THREE.Math.degToRad( js-number">90 - lat );
        theta = THREE.Math.degToRad( lon );

        camera.target.x = pRadius * js-built_in">Math.sin( phi ) * js-built_in">Math.cos( theta );
        camera.target.y = pRadius * js-built_in">Math.cos( phi );
        camera.target.z = pRadius * js-built_in">Math.sin( phi ) * js-built_in">Math.sin( theta );
        camera.lookAt( camera.target );

        js-keyword">if(js-keyword">typeof (sprites)!=js-string">"undefined") {
            js-keyword">for (js-keyword">var i = js-number">0; i < sprites.length; i++) {
                js-keyword">var wp = geoPosition2World(sprites[i].pos.lon,sprites[i].pos.lat);
                js-keyword">var sp = worldPostion2Screen(wp, camera);
                js-keyword">var test=wp.clone();
                test.project(camera);
                js-comment">//判断是否在视野范围内,在旋转球体的过程中有可能会转出我们的视野,把这些图标隐藏起来
                js-keyword">if (test.x > -js-number">1 && test.x < js-number">1 && test.y > -js-number">1 && test.y < js-number">1 && test.z > -js-number">1 && test.z < js-number">1) {
                    sprites[i].sprite.scale.set(js-number">32, js-number">32,js-number">32);
                    sprites[i].sprite.position.set(sp.x, sp.y, js-number">1);
                }
                js-keyword">else {
                    sprites[i].sprite.scale.set(js-number">1.0,js-number">1.0,js-number">1.0);
                    sprites[i].sprite.position.set(js-number">0,js-number">0,js-number">0);
                }
            }
        }

        renderer.clear();
        renderer.render( scene, camera );
        renderer.clearDepth();
        renderer.render( sceneOrtho, cameraOrtho );
    }

    js-comment">/*
     * 经纬度坐标转换为世界坐标
     * lon:经度
     * lat:纬度
     * */
    js-function">js-keyword">function js-title">geoPosition2Worldjs-params">(lon,lat){
        lat = js-built_in">Math.max( - js-number">85, js-built_in">Math.min( js-number">85, lat ) );
        js-keyword">var phi = THREE.Math.degToRad( js-number">90 - lat);
        js-keyword">var theta = THREE.Math.degToRad( lon );

        js-keyword">var result={
            x:pRadius * js-built_in">Math.sin( phi ) * js-built_in">Math.cos( theta ),
            y:pRadius * js-built_in">Math.cos( phi ),
            z:pRadius * js-built_in">Math.sin( phi ) * js-built_in">Math.sin( theta )
        }
        js-keyword">return js-keyword">new THREE.Vector3(result.x,result.y,result.z);
    }

    js-comment">/*
     * 世界坐标转换为屏幕坐标
     * */
    js-function">js-keyword">function js-title">worldPostion2Screenjs-params">(world_vector,camera){
        js-keyword">var vector=world_vector.clone();
        vector.project(camera);
        js-keyword">var result = {
            js-comment">//SPriter以屏幕中心为原点
            x: js-built_in">Math.round((vector.x + js-number">1 ) * window.innerWidth  / js-number">2 -window.innerWidth  / js-number">2),
            y: js-built_in">Math.round(window.innerHeight  / js-number">2-(-vector.y + js-number">1 ) * window.innerHeight  / js-number">2 ),
            js-comment">//以屏幕左上角为原点
            js-comment">//x: Math.round((vector.x + 1 ) * window.innerWidth  / 2),
            js-comment">// y: Math.round(-(-vector.y + 1 ) * window.innerHeight  / 2 ),
            z:js-number">0
        };
        js-keyword">return js-keyword">new THREE.Vector3(result.x,result.y,result.z);
    }

http://www.niftyadmin.cn/n/517800.html

相关文章

【javascript知识进阶】对象

一.对象简述 JavaScript 中所有变量都可以当作对象&#xff08;拥有属性和方法&#xff09;使用&#xff0c;除了两个例外 null 和 undefined。 数字的字面值也可以当作对象使用。 JavaScript 解析器的一个错误很容易弄混&#xff0c; 它试图将点操作符解析为浮点数字面值的…

GridControl相关设置

列头文字居中&#xff1a; gridView-》Appearance》HeaderPanel-》TextOptions-》HAlignment-》Center 使用Grid内置导航栏 gridControl1.UseEmbeddedNativgatorTrue 设定内置导航栏按钮其他属性 gridControl1.EmbeddedNavigator 单行点击 GridView->OptionBehavior->…

【javascript知识进阶】this和闭包

一.javascript中的this 在几种不同的情况下 &#xff0c;this 指向的各不相同。 全局范围内 console.log(this); 当在全部范围内使用 this&#xff0c;它将会指向全局window对象。 函数调用 function fun() {console.log(this);}fun(); 这里 this 也会指向全局对象。 方…

软件功能是不是越多越好

软件业流传有这么一句话&#xff1a; 有两种方式构建软件设计&#xff1a;一种是把软件做得很简单以至于明显找不到缺陷&#xff1b;另一种是把它做得很复杂以至于找不到明显的缺陷。 最近接手一个项目。软件是一个开发工具&#xff0c;类似VS那种的可视化开发。原来的软件使用…

【javascript知识进阶】关于for循环中定义setTimeout

for(var i 0; i < 10; i) {setTimeout(function() {console.log(i); }, 1000); } 上面的代码不会输出数字 0 到 9&#xff0c;而是会输出数字 10 十次&#xff0c;而且是同时输出。 可见&#xff0c;外部循环完毕后才对settimeout进行了定义&#xff0c;即i值变成10以后…

【javascript知识进阶】变量声明和提升规则和自定义作用域

1.作用域 尽管 JavaScript 支持一对花括号创建的代码段&#xff0c;但是并不支持块级作用域&#xff1b; 而仅仅支持 函数作用域。 function test() { // 一个作用域for(var i 0; i < 10; i) { // 不是一个作用域// count}console.log(i); // 10 } 2.变量声明提升 Java…

智能表单(1) : 开源HtmlEditor介绍

在开发智能表单的时候&#xff0c;需要使用WebBrowser控件&#xff0c;.NET中有封装好的WebBrowser控件&#xff0c;但在这里&#xff0c;将介绍一个开源的类似与.NET中的WebBrowser的控件&#xff0c;HtmlEditor。这个开源控件实现了大部分的WebBrowser控件提供的功能。 主地址…

如何免费从网上获取全景图片

网上大部分获取全景图的路径都是收费的或者有下载限制的&#xff0c;我们可以用如下的方法免费获取一些全景图片。 打开谷歌浏览器&#xff08;其他浏览器也可以&#xff0c;使用方法类似&#xff09; 打开微博&#xff0c;在微博中搜索名字中包含全景的用户 找到里面想看的全…