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 选择器 xpath 语法应用
May 13 Javascript
ASP.NET jQuery 实例6 (实现CheckBoxList成员全选或全取消)
Jan 13 Javascript
js综合应用实例简单的表格统计
Sep 03 Javascript
常用的jquery模板插件——jQuery Boilerplate介绍
Sep 23 Javascript
node.js中的console.log方法使用说明
Dec 09 Javascript
javascript获取wx.config内部字段解决微信分享
Mar 09 Javascript
简单实现的JQuery文本框水印插件
Jun 14 Javascript
BootStrap tab选项卡使用小结
Aug 09 Javascript
微信小程序之仿微信漂流瓶实例
Dec 09 Javascript
jQuery使用Layer弹出层插件闪退问题
Dec 22 Javascript
node.js处理前端提交的GET请求
Aug 30 Javascript
vue实现匀速轮播效果
Jun 29 Javascript
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
php的access操作类
2008/04/09 PHP
url decode problem 解决方法
2011/12/26 PHP
php实现文件下载实例分享
2014/06/02 PHP
Zend Framework动作助手(Zend_Controller_Action_Helper)用法详解
2016/03/05 PHP
php页面跳转session cookie丢失导致不能登录等问题的解决方法
2016/12/12 PHP
PHP ADODB实现事务处理功能示例
2018/05/25 PHP
脚本吧 - 幻宇工作室用到js,超强推荐base.js
2006/12/23 Javascript
javascript 定义初始化数组函数
2009/09/07 Javascript
用Jquery实现可编辑表格并用AJAX提交到服务器修改数据
2009/12/27 Javascript
JQUBAR1.1 jQuery 柱状图插件发布
2010/11/28 Javascript
javascript 事件处理程序介绍
2012/06/27 Javascript
js实现精确到毫秒的倒计时效果
2016/08/05 Javascript
vue的props实现子组件随父组件一起变化
2016/10/27 Javascript
详解基于vue的服务端渲染框架NUXT
2018/06/20 Javascript
Vue子组件向父组件通信与父组件调用子组件中的方法
2018/06/22 Javascript
vue中进入详情页记住滚动位置的方法(keep-alive)
2018/09/21 Javascript
vue自定义指令directive的使用方法
2019/04/07 Javascript
解决vue语法会有延迟加载显现{{xxx}}的问题
2019/11/14 Javascript
js与jquery获取input输入框中的值实例讲解
2020/02/27 jQuery
原生JS实现九宫格抽奖
2020/09/13 Javascript
python使用calendar输出指定年份全年日历的方法
2015/04/04 Python
python 显示数组全部元素的方法
2018/04/19 Python
python微信公众号之关注公众号自动回复
2018/10/25 Python
Python闭包思想与用法浅析
2018/12/27 Python
详解Python的循环结构知识点
2019/05/20 Python
Python跳出多重循环的方法示例
2019/07/03 Python
Opencv求取连通区域重心实例
2020/06/04 Python
CSS3实现3D翻书效果
2016/06/20 HTML / CSS
预订从美国飞往印度的机票:MyTicketsToIndia
2017/05/19 全球购物
Woods官网:加拿大最古老、最受尊敬的户外品牌之一
2020/09/12 全球购物
中国梦的演讲稿
2014/01/08 职场文书
茶叶店创业计划书范文
2014/01/19 职场文书
一份没有按时交货失信于客户的检讨书
2014/09/19 职场文书
社区文明倡议书
2015/04/28 职场文书
win10下go mod配置方式
2021/04/25 Golang
python中requests库+xpath+lxml简单使用
2021/04/29 Python