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


Posted in Javascript onDecember 30, 2018

本文实例为大家分享了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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
基于JQuery的浮动DIV显示提示信息并自动隐藏
Feb 11 Javascript
如何使用Javascript正则表达式来格式化XML内容
Jul 04 Javascript
js中arguments,caller,callee,apply的用法小结
Jan 28 Javascript
浅谈Jquery核心函数
Jun 18 Javascript
jquery zTree异步加载简单实例讲解
Feb 25 Javascript
javascript获取select标签选中的值
Jun 04 Javascript
js 弹出虚拟键盘修改密码的简单实例
Oct 10 Javascript
详解通过JSON数据使用VUE.JS
May 26 Javascript
详解Angular2响应式表单
Jun 14 Javascript
Element实现表格分页数据选择+全选所有完善批量操作
Jun 07 Javascript
jQuery实现放大镜案例
Oct 19 jQuery
解决vue自定义组件@click点击失效问题
Apr 30 Vue.js
Three.js实现3D机房效果
Dec 30 #Javascript
JavaScript对象的特性与实践应用深入详解
Dec 30 #Javascript
three.js搭建室内场景教程
Dec 30 #Javascript
Three.JS实现三维场景
Dec 30 #Javascript
Three.js实现简单3D房间布局
Dec 30 #Javascript
JavaScript数组特性与实践应用深入详解
Dec 30 #Javascript
微信小程序实现通过双向滑动缩放图片大小的方法
Dec 30 #Javascript
You might like
给WordPress中的留言加上楼层号的PHP代码实例
2015/12/14 PHP
PHP微信支付实例解析
2016/07/22 PHP
laravel5.4利用163邮箱发送邮件的步骤详解
2017/09/22 PHP
jquery入门—数据删除与隔行变色以及图片预览
2013/01/07 Javascript
JS保留小数点(四舍五入、四舍六入)实现思路及实例
2013/04/25 Javascript
浅谈JavaScript Date日期和时间对象
2014/12/29 Javascript
jQuery手机拨号界面特效代码分享
2015/08/27 Javascript
尝试动手制作javascript放大镜效果
2015/12/25 Javascript
JS DOM实现鼠标滑动图片效果
2020/09/17 Javascript
原生js实现图片放大缩小计时器效果
2017/01/20 Javascript
jQuery EasyUI 页面加载等待及页面等待层
2017/02/06 Javascript
js实现从左向右滑动式轮播图效果
2017/07/07 Javascript
Vue.directive 自定义指令的问题小结
2018/03/04 Javascript
关于Vue项目跨平台运行问题的解决方法
2018/09/18 Javascript
Next.js实现react服务器端渲染的方法示例
2019/01/06 Javascript
JS深入学习之数组对象排序操作示例
2020/05/01 Javascript
[00:16]热血竞技场
2019/03/06 DOTA
python 多进程通信模块的简单实现
2014/02/20 Python
python如何查看微信消息撤回
2018/11/27 Python
CentOS7安装Python3的教程详解
2019/04/10 Python
详解Python3网络爬虫(二):利用urllib.urlopen向有道翻译发送数据获得翻译结果
2019/05/07 Python
Python二进制文件读取并转换为浮点数详解
2019/06/25 Python
使用Python快乐学数学Github万星神器Manim简介
2019/08/07 Python
通过python实现windows桌面截图代码实例
2020/01/17 Python
Python3 ffmpeg视频转换工具使用方法解析
2020/08/10 Python
python 多线程爬取壁纸网站的示例
2021/02/20 Python
英国知名小木屋定制网站:Tiger Sheds
2020/03/06 全球购物
教师现实表现材料
2014/02/14 职场文书
食品安全标语
2014/06/07 职场文书
党员批评与自我批评范文
2014/09/23 职场文书
培养联系人考察意见
2015/06/01 职场文书
信仰纪录片观后感
2015/06/08 职场文书
2016大学生暑期社会实践心得体会
2016/01/14 职场文书
如何利用js在两个html窗口间通信
2021/04/27 Javascript
python中redis包操作数据库的教程
2022/04/19 Python
Java实现注册登录跳转
2022/06/16 Java/Android