先附上两张成果图,我们的主要功能就是以上两个,实现全景图的浏览,将全景标记放在图上并实现属性查询。
注:并不是所有的图片都能当作全景图,可以到专门的网站下载全景图使用,有些拍摄的不好的全景图也会出现衔接的问题。
一.基本原理
我们可以把我们我们观察到的对象想象成一个球体,而全景图就是附在球体上的一张图片,我们通过鼠标移动来改变我们的视角,从而到达全景图的其他地方。
我估计将球体做的很小(如上面两张图)就是为了直观的看出这是一个球体。而通过特定的相机视角和 透视投影我们可以全景图尽可能少的发生变形。
当我们把视角,或者说相机的焦距稍稍变化一些,或者把球体的半径变大一些,我们就发现不了球体的存在,从而有身临其境的感觉。
还有一个功能是将我们特定的poi点标记在全景上,如下图,这也不是一个简单的问题,因为我们要在数据库中记录poi点的位置,然后跟随者我们全景图的变化位置要发生变化,这就涉及到了坐标转换的问题,我们在下面探讨。
一.参数初始化
在上一篇博客提到过要生成一个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">;
}
如果写的没有问题,以上代码就可以实现如下效果:
以下是所有源码:
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);
}