;(function($){ //vrbk jQuery.fn.vrmvViewer=function(optUser){ //options const optDef={ src : "", rotationY : 0 }; const opt=$.extend(optDef,optUser); //canvas const myCanvas=$(this); var cv=new Canvas(); function Canvas(){ this._id =myCanvas.attr("id"); this._box =myCanvas.closest(".canvas_box"); this._loader =myCanvas.closest(".canvas_box").find(".canvas_loader"); this._start =myCanvas.closest(".canvas_box").find(".canvas_start"); this._w =this._box.width(); this._h =this._box.height(); } myCanvas.attr({ 'width' : cv._w, 'height' : cv._h }); //three.js var renderer; var scene; var camera; var controls; //group var grpWorld; var grpBase; //video var video; var flag_video=false; var flag_loader=false; var video_totaltime="--:--:--"; //ジャイロセンサー確認 var isGyro=false; if((window.DeviceOrientationEvent)&&('ontouchstart' in window)){ isGyro=true; } //PCなど非ジャイロ if(!isGyro){ setCanvas(); //一応ジャイロ持ちデバイス }else{ //ジャイロ動作確認 var resGyro=false; window.addEventListener("deviceorientation",doGyro,false); function doGyro(){ resGyro=true; window.removeEventListener("deviceorientation",doGyro,false); } //数秒後に判定 setTimeout(function(){ //ジャイロが動いた if(resGyro){ setCanvas(); //ジャイロ持ってるくせに動かなかった }else{ //iOS13+方式ならクリックイベントを要求 if(typeof DeviceOrientationEvent.requestPermission==="function"){ //ユーザアクションを得るための要素を表示 cv._start.show(); cv._start.on("click",function(){ cv._start.hide(); DeviceOrientationEvent.requestPermission().then(res => { //「動作と方向」が許可された if(res==="granted"){ setCanvas(); //「動作と方向」が許可されなかった }else{ isGyro=false; setCanvas(); } }); }); //iOS13+じゃない }else{ //早くアップデートしてもらうのを祈りながら諦める isGyro=false; setCanvas(); } } },300); } /////////////////////////////////////////////////////////////////////////////////////////// // Canvas /////////////////////////////////////////////////////////////////////////////////////////// function setCanvas(){ if(!Detector.webgl){Detector.addGetWebGLMessage();} renderer=new THREE.WebGLRenderer({ canvas : document.querySelector('#'+cv._id), antialias : true, alpha : true }); renderer.setPixelRatio(window.devicePixelRatio); renderer.setSize(cv._w,cv._h); scene=new THREE.Scene(); grpWorld=new THREE.Group(); grpBase=new THREE.Group(); //スマホなどジャイロセンサーが有効なときはDeviceOrientationControls if(isGyro){ camera=new THREE.PerspectiveCamera(60,cv._w/cv._h,1,20000); camera.position.set(0,0,0.01); camera.lookAt(new THREE.Vector3(0,0,0)); controls=new THREE.DeviceOrientationControls(camera); controls.connect(); controls.update(); //PCなどジャイロセンサーがない場合はOrbitControlsのみ }else{ camera=new THREE.PerspectiveCamera(60,cv._w/cv._h,1,20000); camera.position.set(0,0,0.01); camera.lookAt(new THREE.Vector3(0,0,0)); controls=new THREE.OrbitControls(camera,renderer.domElement); controls.autoRotate =false; controls.enableRotate =true; controls.rotateSpeed =-0.05; controls.enableDamping =true; controls.dampingFactor =0.1; controls.enableZoom =false; controls.enablePan =false; } /////////////////////////////////////////////////////////////////////// // 3Dオブジェクト配置 /////////////////////////////////////////////////////////////////////// //base var gmBase=new THREE.SphereBufferGeometry(1000,60,40); gmBase.scale(-1,1,1); var mtrBase; if(opt.src==""){ mtrBase=new THREE.MeshNormalMaterial(); }else{ flag_video=true; video=document.createElement("video"); if(Hls.isSupported()){ var hls=new Hls(); hls.loadSource(opt.src); hls.attachMedia(video); hls.on(Hls.Events.MANIFEST_PARSED,function(){ video.play(); }); }else if(video.canPlayType("application/vnd.apple.mpegurl")){ video.src=opt.src; video.addEventListener("canplay",function(){ video.play(); }); }else{ flag_video=false; mtrBase=new THREE.MeshNormalMaterial(); alert("Failed to play video."); } if(flag_video){ flag_loader=true; cv._loader.show(); video.loop=true; video.muted=true; video.setAttribute("webkit-playsinline","webkit-playsinline"); video.setAttribute("playsinline","playsinline"); video.setAttribute("muted","muted"); video.play(); texture=new THREE.Texture(video); texture.minFilter=texture.magFilter=THREE.LinearFilter; texture.format=THREE.RGBFormat; texture.mapping=THREE.UVMapping; mtrBase=new THREE.MeshBasicMaterial({ map : texture }); var tm_totaltime=setInterval(function(){ if(video.readyState>0){ $("#btn_start").show(); $("#btn_stop").show(); video_totaltime=sec2timestr(video.duration); clearInterval(tm_totaltime); } },300); } } var base=new THREE.Mesh(gmBase,mtrBase); base.rotation.y=(opt.rotationY*Math.PI/180); grpBase.add(base); grpWorld.add(grpBase); scene.add(grpWorld); //runAnimate runAnimate(); function runAnimate(){ controls.update(); if(flag_video){ if(video.readyState>=video.HAVE_CURRENT_DATA){ texture.needsUpdate=true; } //再生中 if(!video.paused){ if(flag_loader){ if(video.currentTime>0){ flag_loader=false; cv._loader.hide(); $("#btn_start").text("PAUSE"); } } set_playtime(); } } renderer.render(scene,camera); requestAnimationFrame(runAnimate); } } /////////////////////////////////////////////////////////////////////////////////////////// // Window Resize /////////////////////////////////////////////////////////////////////////////////////////// var timerResize=false; $(window).on("resize",function(){ if(timerResize!==false){ clearTimeout(timerResize); } timerResize=setTimeout(function(){ resizeCanvas(); },500); }); function resizeCanvas(){ cv._w=cv._box.width(); cv._h=cv._box.height(); myCanvas.attr({ 'width' : cv._w, 'height' : cv._h }); renderer.setPixelRatio(window.devicePixelRatio); renderer.setSize(cv._w,cv._h); camera.aspect=cv._w/cv._h; camera.updateProjectionMatrix(); } /////////////////////////////////////////////////////////////////////////////////////////// // 操作イベント /////////////////////////////////////////////////////////////////////////////////////////// $("#btn_start").on("click",function(){ if(flag_video){ if(video.paused){ video.play(); $(this).text("PAUSE"); }else{ video.pause(); $(this).text("PLAY"); } set_playtime(); } }); $("#btn_stop").on("click",function(){ if(flag_video){ video.pause(); video.currentTime=0; $("#btn_start").text("PLAY"); set_playtime(); } }); function set_playtime(){ if(flag_video){ var playtime=sec2timestr(video.currentTime); $("#time_ctrl").text(playtime+"/"+video_totaltime); } } }; function sec2timestr(sec){ var time=Math.floor(sec); var s=time; var m=Math.floor((time/(1000*60))%60); var h=Math.floor((time/(1000*60*60))%24); if(s<10){ s="0"+s; } if(m<10){ m="0"+m; } if(h<10){ h="0"+h; } return h+":"+m+":"+s; } })(jQuery);