本文實(shí)例為大家分享了three.js 全景重力感應(yīng)的具體代碼,供大家參考,具體內(nèi)容如下
建網(wǎng)站原本是網(wǎng)站策劃師、網(wǎng)絡(luò)程序員、網(wǎng)頁(yè)設(shè)計(jì)師等,應(yīng)用各種網(wǎng)絡(luò)程序開發(fā)技術(shù)和網(wǎng)頁(yè)設(shè)計(jì)技術(shù)配合操作的協(xié)同工作。成都創(chuàng)新互聯(lián)公司專業(yè)提供成都網(wǎng)站制作、做網(wǎng)站,網(wǎng)頁(yè)設(shè)計(jì),網(wǎng)站制作(企業(yè)站、響應(yīng)式網(wǎng)站設(shè)計(jì)、電商門戶網(wǎng)站)等服務(wù),從網(wǎng)站深度策劃、搜索引擎友好度優(yōu)化到用戶體驗(yàn)的提升,我們力求做到極致!
實(shí)現(xiàn)three.js 全景圖demo
使用three.js 寫了球體和圓柱體版本的3D重力感應(yīng)全景圖,支持手指觸摸和陀螺儀感應(yīng),也支持PC端的鼠標(biāo)。給大家介紹一下基于移動(dòng)端H5球體的實(shí)現(xiàn)方法,圓柱體類似。
設(shè)置容器和展示的樣式
設(shè)置容器的寬高為全屏展示,清除body的margin,引用three.min.js(3D渲染框架) 和orienter.js (陀螺儀經(jīng)緯度計(jì)算)
<div id="CanvasBody"></div> <script src="js/three.min.js"></script> <!--重力感應(yīng)--> <script src="js/orienter.js"></script> <!--動(dòng)畫效果--> <script src="js/tween.js"></script> <!-- 代碼 -->
body {margin: 0;} html, body, #CanvasBody {width: 100vw;height: 100vh;overflow: hidden;} #CanvasBody {position: relative;}
設(shè)置html的data-dpr 屬性,設(shè)置html 的fontSize
設(shè)置html的fontSize,重新計(jì)算body的實(shí)際可展示尺寸,這樣可以使渲染出來(lái)的畫面更清晰,分辨率最完美。
(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);
定義相關(guān)變量
var camera,//攝像機(jī) scene,//舞臺(tái) renderer,//渲染器 isUserInteracting = false,//用戶是否正在操作 onMouseDownMouseX = 0, onMouseDownMouseY = 0,//鼠標(biāo)點(diǎn)擊的x和Y坐標(biāo) lon = 0, onMouseDownLon = 0, onPointerDownLon= 0.0,onPointerDownPointerX = 0,//經(jīng)度 lat = 0, onMouseDownLat = 0, onPointerDownLat= 0.0,onPointerDownPointerY = 0,//緯度 phi = 0, theta = 0,//計(jì)算相機(jī)位置的重要參數(shù) o = new Orienter(),//陀螺儀方法對(duì)象 new_longitude=0,last_longitude=0,move_longitude=0,//改變的經(jīng)度的計(jì)算 new_latitude=0,last_latitude=0,move_latitude=0,//改變的緯度的計(jì)算 is_touch=false,is_start=false,isPlay=true,isMusicPlay=true,tsa=100.1,ppl=''; var raycaster = new THREE.Raycaster();//拾取場(chǎng)景里面的物體,可判斷點(diǎn)擊或交互事件對(duì)應(yīng)的元素 var mouse = new THREE.Vector2();//二維向量的對(duì)象,鼠標(biāo)計(jì)算
初始化舞臺(tái)的元素和內(nèi)容
圖片的長(zhǎng)寬控制在4096px以內(nèi),部分機(jī)型性能不夠,渲染不了超大的圖片
function init() {/**初始化**/ var container, mesh;//容器和素材 container = document.getElementById( 'CanvasBody' );//容器 camera = new THREE.PerspectiveCamera( 72, window.innerWidth / window.innerHeight, 0.01, 1100 );//相機(jī) camera.target = new THREE.Vector3( 0, 0, 0 );//相機(jī)位置 scene = new THREE.Scene();//舞臺(tái) scene.updateMatrixWorld(true); var geometry = new THREE.SphereGeometry(1, 32, 16);//球體 geometry.scale( 1, 1, -1 ); //設(shè)置球體的背景貼圖 var textureBg = new THREE.TextureLoader().load("img/bg.jpg"); textureBg.generateMipmaps = true; textureBg.magFilter = THREE.LinearFilter;//設(shè)置貼紙素材的質(zhì)量 textureBg.minFilter = THREE.LinearFilter; var material = new THREE.MeshBasicMaterial( { map: textureBg,//圓柱體貼圖,全景圖 //color:0xFF0000, //transparent: true } ); mesh = new THREE.Mesh( geometry, material ); //這里可以設(shè)置對(duì)應(yīng)的動(dòng)畫效果 // new TWEEN.Tween( mesh).to( {transform:"rotate(90deg)"}, 800 ).repeat( false ).delay( 300 ).yoyo( true ).easing( TWEEN.Easing.Cubic.InOut ).start(); scene.add( mesh ); // 旋轉(zhuǎn)預(yù)設(shè) 攝影機(jī)看到的角度 Start// scene.rotation.set(0,0,0); //首頁(yè) //初始化渲染器,追加到容器 renderer = new THREE.WebGLRenderer({precision: 'highp' ,mipmap: 'highp',antialias:false});//加上precision 和 mipmap參數(shù),調(diào)整畫面清晰度 renderer.setPixelRatio( window.devicePixelRatio );//設(shè)置像素比 renderer.setSize( window.innerWidth, window.innerHeight );//設(shè)置渲染窗口的大小 container.appendChild( renderer.domElement );//追加到容器中去 //鼠標(biāo)、手機(jī)touch的各個(gè)事件 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 ); }
監(jiān)聽的各事件和方法
//監(jiān)聽橫豎屏重新設(shè)置尺寸 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 );//第一個(gè)是最上面一層的元素 console.log("點(diǎn)擊的元素",intersects); if ( intersects.length > 0 ) {//如果點(diǎn)到小圓點(diǎn) 就執(zhí)行回調(diào)函數(shù)回調(diào)函數(shù)為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(); }
動(dòng)畫播放和陀螺儀
function animate() {//播放動(dòng)畫 if(isPlay){ TWEEN.update(); update(); requestAnimationFrame( animate ); } } o.onOrient = function (obj) {//重力感應(yīng)計(jì)算角度 if(is_start){ //最新經(jīng)度 new_longitude = obj.lon; move_longitude=new_longitude-last_longitude; //最新緯度 new_latitude = obj.lat; move_latitude = new_latitude-last_latitude; //判斷經(jīng)緯度 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; } //計(jì)算得出重力感應(yīng)的經(jīng)緯度 lon=lon-move_longitude; last_longitude = obj.lon; lat = lat-move_latitude; last_latitude = obj.lat; } }; function update() {//更新攝像機(jī)位置,旋轉(zhuǎn)平移 //lat = Math.max( -6, Math.min( 6, lat ) );//設(shè)置lat緯度的范圍,只在一個(gè)范圍內(nèi)旋轉(zhuǎn) phi = THREE.Math.degToRad( 90 - lat ); theta = THREE.Math.degToRad( lon ); camera.target.x = 500 * Math.sin( phi ) * Math.cos( theta );//X軸的坐標(biāo) camera.target.y = 500 * Math.cos( phi );//y軸的坐標(biāo) camera.target.z = 500 * Math.sin( phi ) * Math.sin( theta ) ;//z軸的坐標(biāo) camera.lookAt( camera.target ); renderer.render( scene, camera );//重新渲染 }
執(zhí)行所有
//執(zhí)行所有 is_start=true; init(); o.init(); animate();
綜上,炫酷的3D重力感應(yīng)H5就出來(lái)啦!
源碼 GitHub
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持創(chuàng)新互聯(lián)。
分享標(biāo)題:three.js實(shí)現(xiàn)炫酷的全景3D重力感應(yīng)
文章來(lái)源:http://vcdvsql.cn/article34/gjigse.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站制作、網(wǎng)站排名、響應(yīng)式網(wǎng)站、網(wǎng)站改版、電子商務(wù)、服務(wù)器托管
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)