;(function($){ //vrbk jQuery.fn.vrGameBase=function(optUser){ //options const optDef={ enableGyro : true, camera : { fov : 45, near : 1, far : 20000 } }; 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._ctrl =myCanvas.closest(".canvas_box").find(".canvas_ctrl"); this._w =this._box.width(); this._h =this._box.height(); } myCanvas.attr({ 'width' : cv._w, 'height' : cv._h }); //ジャイロセンサー確認 var isGyro=false; if((opt.enableGyro)&&(window.DeviceOrientationEvent)&&('ontouchstart' in window)){ isGyro=true; } //three.js var renderer; var scene; var camera; var controls; var mixer; var clock; var camera_height=200; //DeviceOrientationControls用カメラ var camera_doc; var camera_defx; var camera_defy; var camera_defz; //group var grpWorld; var grpBase; var grpHorse; //loader var loader={}; //timer var timerLoading; /////////////////////////////////////////////////////////////////////////////////////////// // Canvas /////////////////////////////////////////////////////////////////////////////////////////// setCanvas(); 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(); grpHorse=new THREE.Group(); clock=new THREE.Clock(); //スマホなどジャイロセンサーが有効なときはカメラを2台使う if(isGyro){ //通常カメラ camera=new THREE.PerspectiveCamera(opt.camera.fov,cv._w/cv._h,opt.camera.near,opt.camera.far); camera.position.set(0,0,0.01); camera.lookAt(new THREE.Vector3(0,0,0)); //ジャイロセンサーによる角度を取得する目的だけのカメラ camera_doc=new THREE.PerspectiveCamera(opt.camera.fov,cv._w/cv._h,opt.camera.near,opt.camera.far); camera_doc.position.set(0,0,0.01); camera_doc.lookAt(new THREE.Vector3(0,0,0)); controls=new THREE.DeviceOrientationControls(camera_doc); controls.connect(); controls.update(); camera_defx=camera_doc.rotation.x; camera_defy=camera_doc.rotation.y; camera_defz=camera_doc.rotation.z; //PCなどジャイロセンサーがない場合はOrbitControlsのみ }else{ camera=new THREE.PerspectiveCamera(opt.camera.fov,cv._w/cv._h,opt.camera.near,opt.camera.far); 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オブジェクト配置 /////////////////////////////////////////////////////////////////////// //world const srcWorld="./src/texture/world.jpg"; var gmWorld=new THREE.SphereBufferGeometry(10000,60,40); gmWorld.scale(-1,1,1); var mtrWorld; loader[srcWorld]=false; var textureWorld=new THREE.TextureLoader().load(srcWorld,function(){ loader[srcWorld]=true; }); mtrWorld=new THREE.MeshBasicMaterial({ map : textureWorld }); textureWorld.minFilter=textureWorld.magFilter=THREE.LinearFilter; textureWorld.mapping=THREE.UVMapping; var world=new THREE.Mesh(gmWorld,mtrWorld); world.rotation.y=(180*Math.PI/180)*-1; grpWorld.add(world); //light var light=new THREE.AmbientLight(0xffffff); light.castShadow=true; grpWorld.add(light); var pointLight=new THREE.PointLight(0xFFFFFF,1.5,1000); pointLight.position.set(0,400,0); pointLight.castShadow=true; grpWorld.add(pointLight); //horse const srcHorse="./src/dae/uma.dae"; loader[srcHorse]=false; var loaderHorse=new THREE.ColladaLoader(); loaderHorse.options.convertUpAxis=true; loaderHorse.load(srcHorse,function(collada){ var horse=collada.scene; horse.traverse(function(node){ if(node.isSkinnedMesh){ node.frustumCulled=false; } }); mixer=new THREE.AnimationMixer(horse); var action=mixer.clipAction(collada.animations[0]).play(); horse.scale.x=horse.scale.y=horse.scale.z=100; horse.rotation.z=(180*Math.PI/180); horse.position.set(0,0,0); horse.updateMatrix(); grpHorse.add(horse); grpHorse.rotation.y=0; grpHorse.position.set(0,0,-800); grpBase.add(grpHorse); loader[srcHorse]=true; }); var wky=camera_height*-1; grpBase.position.set(0,wky,0); grpWorld.add(grpBase); scene.add(grpWorld); /////////////////////////////////////////////////////////////////////// //checkLoading var check_sec=500; var check_cnt=0; var check_limit=30000; checkLoading(); function checkLoading(){ var flag_loading=false; Object.keys(loader).forEach(function(key){ if(!loader[key]){ flag_loading=true; } },loader); //読み込み中 if(flag_loading){ timerLoading=setTimeout(function(){ check_cnt+=check_sec; if(check_cnt<check_limit){ checkLoading(); }else{ //エラー処理など alert("読み込みに失敗しました。"); } },check_sec); //読み込み完了 }else{ clearTimeout(timerLoading); runAnimate(); gameReset(); } } //runAnimate function runAnimate(){ var delta=clock.getDelta(); if(mixer!==undefined){ mixer.update(delta); } controls.update(); if(isGyro){ var camera_nowx=camera_doc.rotation.x; var camera_nowy=camera_doc.rotation.y; var camera_nowz=camera_doc.rotation.z; //Y方向のみ制御する場合 camera.rotation.x=camera_nowx; camera.rotation.y=(camera_defy-camera_nowy)*-1; camera.rotation.z=camera_nowz; //全方向参照する場合 //camera.rotation.x=(camera_defx-camera_nowx)*-1; //camera.rotation.y=(camera_defy-camera_nowy)*-1; //camera.rotation.z=(camera_defz-camera_nowz)*-1; } grpHorse.rotation.y+=0.05; 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_reset").on("click",function(){ gameReset(); }); cv._start.on("click",function(){ cv._start.hide(); cv._ctrl.show(); //START画面を挟みユーザのアクションを得る //スマホなどでaudioの読み込みなど、アクションが必要な処理はここで行う }); /////////////////////////////////////////////////////////////////////////////////////////// // リセット処理 /////////////////////////////////////////////////////////////////////////////////////////// function gameReset(){ clearTimeout(timerLoading); grpHorse.rotation.y=0; cv._start.show(); cv._loader.hide(); cv._ctrl.hide(); if(isGyro){ controls.update(); camera_defx=camera_doc.rotation.x; camera_defy=camera_doc.rotation.y; camera_defz=camera_doc.rotation.z; } camera.position.set(0,0,0.01); camera.lookAt(new THREE.Vector3(0,0,0)); } }; })(jQuery);