three.js实现炫酷的全景3D重力感应

作者:Aimee芊 时间:2024-04-25 13:12:37 

本文实例为大家分享了three.js 全景重力感应的具体代码,供大家参考,具体内容如下

实现three.js 全景图 demo

使用three.js 写了球体和圆柱体版本的3D重力感应全景图,支持手指触摸和陀螺仪感应,也支持PC端的鼠标。给大家介绍一下基于移动端H5球体的实现方法,圆柱体类似。

设置容器和展示的样式
设置容器的宽高为全屏展示,清除body的margin,引用three.min.js(3D渲染框架) 和orienter.js (陀螺仪经纬度计算)

three.js实现炫酷的全景3D重力感应


<div id="CanvasBody"></div>

<script src="js/three.min.js"></script>
<!--重力感应-->
<script src="js/orienter.js"></script>
<!--动画效果-->
<script src="js/tween.js"></script>
<!-- 代码 -->

body {margin: 0;}
html, body, #CanvasBody {width: 100vw;height: 100vh;overflow: hidden;}
#CanvasBody {position: relative;}

设置html的data-dpr 属性,设置html 的fontSize

设置html的fontSize,重新计算body的实际可展示尺寸,这样可以使渲染出来的画面更清晰,分辨率最完美。


(function(_window) {
var navigatorUserAgent = navigator.userAgent;
var iPhone = navigatorUserAgent.indexOf("iPhone");
if (iPhone > -1) {
 var dpr = Number(window.devicePixelRatio),
   one_dpr = 1 / dpr
} else {
 var dpr = 1,
  one_dpr = 1
}
var writeText = "<meta name=\"viewport\" content=\"width=device-width,initial-scale=" + one_dpr + ",maximum-scale=" + one_dpr + ",minimum-scale=" + one_dpr + ",user-scalable=no\">\n  <meta name=\"'flexible\" content=\"initial-dpr=" + dpr + "\">";
document.write(writeText);
var html = document.getElementsByTagName("html");
var F0 = 75;
html[0].setAttribute("data-dpr", dpr);
var getFontSize = function getFontSize() {
 var windowWidth = window.innerWidth;
 html[0].style.fontSize = F0 * windowWidth / 750 + "px"
};
getFontSize();
_window.addEventListener("resize", getFontSize, false)
})(window);

定义相关变量


var camera,//摄像机
scene,//舞台
renderer,//渲染器
isUserInteracting = false,//用户是否正在操作
onMouseDownMouseX = 0, onMouseDownMouseY = 0,//鼠标点击的x和Y坐标
lon = 0, onMouseDownLon = 0, onPointerDownLon= 0.0,onPointerDownPointerX = 0,//经度
lat = 0, onMouseDownLat = 0, onPointerDownLat= 0.0,onPointerDownPointerY = 0,//纬度
phi = 0, theta = 0,//计算相机位置的重要参数
o = new Orienter(),//陀螺仪方法对象
new_longitude=0,last_longitude=0,move_longitude=0,//改变的经度的计算
new_latitude=0,last_latitude=0,move_latitude=0,//改变的纬度的计算
is_touch=false,is_start=false,isPlay=true,isMusicPlay=true,tsa=100.1,ppl='';
var raycaster = new THREE.Raycaster();//拾取场景里面的物体,可判断点击或交互事件对应的元素
var mouse = new THREE.Vector2();//二维向量的对象,鼠标计算

初始化舞台的元素和内容

图片的长宽控制在4096px以内,部分机型性能不够,渲染不了超大的图片


function init() {/**初始化**/
   var container, mesh;//容器和素材
   container = document.getElementById( 'CanvasBody' );//容器
   camera = new THREE.PerspectiveCamera( 72, window.innerWidth / window.innerHeight, 0.01, 1100 );//相机
   camera.target = new THREE.Vector3( 0, 0, 0 );//相机位置

scene = new THREE.Scene();//舞台
   scene.updateMatrixWorld(true);
   var geometry = new THREE.SphereGeometry(1, 32, 16);//球体

geometry.scale( 1, 1, -1 );
   //设置球体的背景贴图
   var textureBg = new THREE.TextureLoader().load("img/bg.jpg");
   textureBg.generateMipmaps = true;
   textureBg.magFilter = THREE.LinearFilter;//设置贴纸素材的质量
   textureBg.minFilter = THREE.LinearFilter;
   var material = new THREE.MeshBasicMaterial( {
     map: textureBg,//圆柱体贴图,全景图
     //color:0xFF0000,
     //transparent: true
   } );
   mesh = new THREE.Mesh( geometry, material );
   //这里可以设置对应的动画效果
//    new TWEEN.Tween( mesh).to( {transform:"rotate(90deg)"}, 800 ).repeat( false ).delay( 300 ).yoyo( true ).easing( TWEEN.Easing.Cubic.InOut ).start();
   scene.add( mesh );

// 旋转预设 摄影机看到的角度 Start//
   scene.rotation.set(0,0,0); //首頁

//初始化渲染器,追加到容器
   renderer = new THREE.WebGLRenderer({precision: 'highp' ,mipmap: 'highp',antialias:false});//加上precision 和 mipmap参数,调整画面清晰度
   renderer.setPixelRatio( window.devicePixelRatio );//设置像素比
   renderer.setSize( window.innerWidth, window.innerHeight );//设置渲染窗口的大小
   container.appendChild( renderer.domElement );//追加到容器中去

//鼠标、手机touch的各个事件
   document.addEventListener( 'mousedown', onDocumentMouseDown, false );
   document.addEventListener( 'mousemove', onDocumentMouseMove, false );
   document.addEventListener( 'mouseup', onDocumentMouseUp, false );

document.addEventListener( 'touchstart', onDocumentTouchDown, false );
   document.addEventListener( 'touchmove', onDocumentTouchMove, false );
   document.addEventListener( 'touchend', onDocumentTouchUp, false );
   // document.addEventListener( 'wheel', onDocumentMouseWheel, false );
   //
   document.addEventListener( 'dragover', function ( event ) {
     event.preventDefault();
     event.dataTransfer.dropEffect = 'copy';
   }, false );
   document.addEventListener( 'dragenter', function ( event ) {
     document.body.style.opacity = 0.5;
   }, false );
   document.addEventListener( 'dragleave', function ( event ) {
     document.body.style.opacity = 1;
   }, false );
   document.addEventListener( 'drop', function ( event ) {
     event.preventDefault();
     var reader = new FileReader();
     reader.addEventListener( 'load', function ( event ) {
       material.map.image.src = event.target.result;
       material.map.needsUpdate = true;
     }, false );
     reader.readAsDataURL( event.dataTransfer.files[ 0 ] );
     document.body.style.opacity = 1;
   }, false );
 }

监听的各事件和方法


//监听横竖屏重新设置尺寸
 function onWindowResize() {
   camera.aspect = window.innerWidth / window.innerHeight;
   camera.updateProjectionMatrix();
   renderer.setSize( window.innerWidth, window.innerHeight );
 }
 function onDocumentMouseDown( event ) {
   event.preventDefault();
   isUserInteracting = true;
   onPointerDownPointerX = event.clientX;
   onPointerDownPointerY = event.clientY;
   onPointerDownLon = lon;
   onPointerDownLat = lat;

// Click action
   mouse.x = ( event.clientX / renderer.domElement.clientWidth ) * 2 - 1;
   mouse.y = - ( event.clientY / renderer.domElement.clientHeight ) * 2 + 1;
   raycaster.setFromCamera( mouse, camera );
   var intersects = raycaster.intersectObjects( scene.children );//第一个是最上面一层的元素
   console.log("点击的元素",intersects);
   if ( intersects.length > 0 ) {//如果点到小圆点 就执行回调函数回调函数为goto_p
     try {
       intersects[0].object.callback();
     }
     catch(err) {}
   }
 }
 function onDocumentMouseMove( event ) {
   if ( isUserInteracting === true ) {
     lon = ( onPointerDownPointerX - event.clientX ) * 0.1 + onPointerDownLon;
     lat = ( event.clientY - onPointerDownPointerY ) * 0.1 + onPointerDownLat;
   }
 }
 function onDocumentMouseUp( event ) {
   isUserInteracting = false;
 }

// touch event start
 function onDocumentTouchDown( event ) {
   is_touch=true;

event.preventDefault();
   isUserInteracting = true;
   onPointerDownPointerX = event.touches[ 0 ].clientX;
   onPointerDownPointerY = event.touches[ 0 ].clientY;
   if(is_start){
     onPointerDownLon = lon;
     onPointerDownLat = lat;
   }
   // For Click action

mouse.x = ( onPointerDownPointerX / renderer.domElement.clientWidth ) * 2 - 1;
   mouse.y = - ( onPointerDownPointerY / renderer.domElement.clientHeight ) * 2 + 1;

raycaster.setFromCamera( mouse, camera );
   var intersects = raycaster.intersectObjects( scene.children );
   console.log('touchDown',lon,lat);
   if ( intersects.length > 0 ) {
     try {
       intersects[0].object.callback();
     }
     catch(err) {}
   }
 }
 function onDocumentTouchMove( event ) {
   if(is_start){
     if ( isUserInteracting === true ) {

lon = ( onPointerDownPointerX - event.touches[ 0 ].clientX ) * 0.1 + onPointerDownLon;
       lat = ( event.touches[ 0 ].clientY - onPointerDownPointerY ) * 0.1 + onPointerDownLat;
     }
   }
 }
 function onDocumentTouchUp( event ) {
   is_touch=false;
 }
 // touch event end

// set
 function onDocumentTouchDown2( event ) {
   tsa = event.touches[0].clientY;
   console.log( '@:'+event.touches[0].clientY );
   event.preventDefault();

}
 function onDocumentMouseWheel( event ) {
   camera.fov += event.deltaY * 0.05;
   camera.updateProjectionMatrix();
 }

动画播放和陀螺仪


function animate() {//播放动画
   if(isPlay){
     TWEEN.update();
     update();
     requestAnimationFrame( animate );
   }

}
 o.onOrient = function (obj) {//重力感应计算角度
   if(is_start){
     //最新经度
     new_longitude = obj.lon;
     move_longitude=new_longitude-last_longitude;

//最新纬度
     new_latitude = obj.lat;
     move_latitude = new_latitude-last_latitude;

//判断经纬度
     if(move_longitude>=300){
       move_longitude=move_longitude-361;
     }else if(move_longitude<=-300){
       move_longitude=move_longitude+359;
     }

if(move_latitude>=300){
       move_latitude=move_latitude-361;
     }else if(move_latitude<=-300){
       move_latitude=move_latitude+359;
     }

if( is_touch ){
       move_longitude=0;
       move_latitude=0;
     }else{
       move_longitude=move_longitude*0.6;
       move_latitude=move_latitude*0.6;
     }
     //计算得出重力感应的经纬度
     lon=lon-move_longitude;
     last_longitude = obj.lon;
     lat = lat-move_latitude;
     last_latitude = obj.lat;
   }

};

function update() {//更新摄像机位置,旋转平移
   //lat = Math.max( -6, Math.min( 6, lat ) );//设置lat纬度的范围,只在一个范围内旋转
   phi = THREE.Math.degToRad( 90 - lat );
   theta = THREE.Math.degToRad( lon );
   camera.target.x = 500 * Math.sin( phi ) * Math.cos( theta );//X轴的坐标
   camera.target.y = 500 * Math.cos( phi );//y轴的坐标
   camera.target.z = 500 * Math.sin( phi ) * Math.sin( theta ) ;//z轴的坐标
   camera.lookAt( camera.target );
   renderer.render( scene, camera );//重新渲染
 }

执行所有


//执行所有
 is_start=true;
 init();
 o.init();
 animate();

综上,炫酷的3D重力感应H5就出来啦!

源码 GitHub

来源:https://blog.csdn.net/Aimee1608/article/details/79403684

标签:three.js,全景,重力感应
0
投稿

猜你喜欢

  • Pandas.DataFrame时间序列数据处理的实现

    2022-09-20 08:43:41
  • JavaScript Alert通用美化类

    2024-04-27 15:20:50
  • 文字超长自动省略,以...代替,CSS实现

    2009-07-16 10:15:00
  • 浅谈vue项目,访问路径#号的问题

    2024-05-29 22:46:08
  • 在MySQL中删除表的操作教程

    2024-01-15 09:37:46
  • php注册系统和使用Xajax即时验证用户名是否被占用

    2023-09-12 05:27:55
  • Python实现消消乐小游戏

    2021-02-19 19:37:42
  • 基于canvas的二维码邀请函生成插件

    2024-04-17 10:40:53
  • MySQL获取所有分类的前N条记录

    2024-01-21 09:39:27
  • 未能加载文件或程序集“XXX”或它的某一个依赖项。试图加载格式不正确的程序。

    2023-07-01 00:38:21
  • python每天定时运行某程序代码

    2023-11-03 07:03:52
  • OpenCV-Python实现油画效果的实例

    2022-03-26 09:16:37
  • 如何将Python脚本打包成exe应用程序介绍

    2021-12-26 20:42:07
  • MySQL索引背后的之使用策略及优化(高性能索引策略)

    2024-01-23 04:21:19
  • Python 列表映射后的平均值

    2021-12-25 19:02:39
  • Python3 log10()函数简单用法

    2021-06-27 16:47:16
  • 浅谈MySQL中的自增主键用完了怎么办

    2024-01-24 07:51:50
  • javascript放大镜效果的简单实现

    2024-04-27 15:18:53
  • 在python中实现将一张图片剪切成四份的方法

    2023-10-04 02:20:04
  • VC基于ADO技术访问数据库的方法

    2024-01-28 22:25:08
  • asp之家 网络编程 m.aspxhome.com