欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2023-02-21 16:10:13
本文实例为大家分享了three.js 全景重力感应的具体代码,供大家参考,具体内容如下 实现three.js 全景图 demo 使用three.js 写了球体和圆柱体版...

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

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