edgeのアドレスバーへ、以下を入力することで、起動
edge://compat/enterprise
edgeのアドレスバーへ、以下を入力することで、起動
edge://compat/enterprise
hands-on three.js + cannon.js - end0tknr's kipple - web写経開発 の更に前段です。
目次
以下の実際の動作は、github pagesをご覧ください。 https://end0tknr.github.io/sandbox/threejs_cannonjs_misc/test_threejs.html
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/109/three.min.js"></script> <script src="https://cdn.jsdelivr.net/gh/mrdoob/three.js@r109/examples/js/controls/OrbitControls.js"></script> </head> <body> <div id="stage"></div> <script> (function() { 'use strict'; var width = 500; var height = 250; var scene = new THREE.Scene(); // mesh 物体 var head = new THREE.Mesh( new THREE.BoxGeometry(20, 20, 20), new THREE.MeshLambertMaterial({ color: 0xff0000 }) ); head.position.set(0, 40, 0); // scene.add(head); var body = new THREE.Mesh( new THREE.BoxGeometry(40, 60, 40), new THREE.MeshLambertMaterial({ color: 0xff0000 }) ); body.position.set(0, 0, 0); // scene.add(body); // 頭部と体をグループ化 var person = new THREE.Group(); person.add(head); person.add(body); scene.add(person); // light var light = new THREE.DirectionalLight(0xffffff, 1); light.position.set(0, 100, 30); scene.add(light); // 環境光源 var ambient = new THREE.AmbientLight(0x404040); scene.add(ambient); // camera var camera = new THREE.PerspectiveCamera(45, width / height, 1, 1000); camera.position.set(200, 100, 300); camera.lookAt(scene.position); // helper var gridHelper = new THREE.GridHelper(200, 50); scene.add(gridHelper); var axisHelper = new THREE.AxisHelper(1000); scene.add(axisHelper); var lightHelper = new THREE.DirectionalLightHelper(light, 20); scene.add(lightHelper); // controls - マウスによる操作 var controls = new THREE.OrbitControls(camera); // controls.autoRotate = true; // renderer var renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(width, height); renderer.setClearColor(0xefefef); renderer.setPixelRatio(window.devicePixelRatio); document.getElementById('stage').appendChild(renderer.domElement); function render() { requestAnimationFrame(render); person.rotation.y += 0.01; controls.update(); renderer.render(scene, camera); } render(); })(); </script> </body> </html>
https://ozateck.sakura.ne.jp/wordpress/category/three-js/
上記urlからの写経です。
https://end0tknr.github.io/sandbox/threejs_cannonjs_shimeji/index.html
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <!-- refer to https://ozateck.sakura.ne.jp/wordpress/ --> <title>Hello Three.js</title> <style> body{ margin: 0; overflow: hidden; } </style> </head> <body> <div id="stage"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/97/three.min.js"></script> <!-- 処理速度やフレームレートを確認する為 --> <script src="https://cdn.jsdelivr.net/npm/stats-js@1.0.1/build/stats.min.js"></script> <!-- マウスによるカメラ操作 --> <script src="https://cdn.jsdelivr.net/npm/three@0.105.2/examples/js/controls/TrackballControls.js"> </script> <script src="https://cdn.jsdelivr.net/npm/cannon@0.6.2/build/cannon.min.js"></script> <script src="js/app.js"></script> </body> </html>
// refer to http://ozateck.sakura.ne.jp/wordpress var width = 480; var height = 320; var fov = 60; var aspect = width / height; var near = 1; var far = 1000; //座標系 Z↑ /Y // │/ // 原点─→X // Scene - 各オブジェクト(円、四角等)を表示 var scene = new THREE.Scene(); // Axes - 空間のx, y, zを原点から表す var axes = new THREE.AxisHelper(20); scene.add(axes); // Camera - 空間の視点をを決める. // コンストラクタの引数はそれぞれ、 // 視野角(fov)、縦横幅比率(aspect)、描画領域(近い方)、描画領域(遠い方) var camera = new THREE.PerspectiveCamera(fov, aspect, near, far); camera.position.set(0, 100, 200); camera.lookAt(scene.position); // Controls - マウスによる操作. // google chromeで以下のerrorとなる場合、その更に下のurlが参考になります。 // [Intervention] Unable to preventDefault inside passive event listener // due to target being treated as passive. // https://note.com/cfbif/n/n92195df174bf var controls = new THREE.TrackballControls(camera); controls.rotateSpeed = 5.0; //回転速度 controls.zoomSpeed = 0.5;//ズーム速度 controls.panSpeed = 2.0;//パン速度 // Light - 空間への光の方向を決める var directionalLight = new THREE.DirectionalLight(0xffffff); directionalLight.position.set(0, 0.7, 0.7); scene.add(directionalLight); // Stats - 処理速度やフレームレートを確認する為 var stats = new Stats(); stats.setMode(0); stats.domElement.style.position = "absolute"; stats.domElement.style.left = "0px"; stats.domElement.style.top = "0px"; document.getElementById("stage").appendChild(stats.domElement); // Plane // Three.js のobjectには、Geometry, Material, Mesh を使う。 // Geometryはオブジェクトの形や大きさ. Materialにはオブジェクトの色や質感を表す。 // Meshオブジェクトに、これらの2つのオブジェクトを指定しインスタンス化 var geometry = new THREE.PlaneGeometry(200, 250); var material = new THREE.MeshBasicMaterial({color: 0x666666}); var plane = new THREE.Mesh(geometry, material); plane.position.set(0, 0, 0); plane.rotation.set(-90 * Math.PI / 180, 0, 0); scene.add(plane); // Particles var geometry = new THREE.Geometry(); var material = new THREE.PointsMaterial({color: 0xffffff, size: 4, vertexColors: true}); for(var x=0; x<10; x++){ for(var y=0; y<10; y++){ var particle = new THREE.Vector3(x*10, y*10, 0); geometry.vertices.push(particle); geometry.colors.push(new THREE.Color(Math.random() * 0x00ffff)); } } // 複数の点が、1コとobjectとして扱われます var points = new THREE.Points(geometry, material); scene.add(points); // Cubeを作成し、その後、順に削除 for(var i=0; i<20; i++){ var x = getRandom(-80, 80); var y = getRandom( 0, 80); var z = getRandom(-80, 80); var mesh = new THREE.Mesh( new THREE.BoxBufferGeometry(10,10,10), new THREE.MeshBasicMaterial({color: 0xccffcc, wireframe: true}) ); mesh.position.set(x, y, z); mesh.name = "tmpCube"; scene.add(mesh); } function getRandom(min, max){ return Math.floor(Math.random()*(max-min+1))+min; } function removeCube(){ var total = scene.children.length; for(var i=0; i<total; i++){ var obj = scene.children[i]; if(obj.name == "tmpCube"){ scene.remove(obj); return; } } } setInterval(removeCube, 2000); // Cube var geometry = new THREE.BoxGeometry(30, 30, 30); var material = new THREE.MeshNormalMaterial(); var cube = new THREE.Mesh(geometry, material); cube.position.set(0, 50, 0); scene.add(cube); // Earth var txLoader = new THREE.TextureLoader(); var earth = null; txLoader.load( "img/earth.jpg", function(texture){ var geometry = new THREE.SphereGeometry(30, 30, 30); var material = new THREE.MeshBasicMaterial({map:texture, overdraw:0.5}); earth = new THREE.Mesh(geometry, material); earth.position.set(-30, 50, 100); scene.add(earth); }); // Moon var moon = null; txLoader.load( "img/moon.jpg", function(texture){ var geometry = new THREE.SphereGeometry(10, 10, 10); var material = new THREE.MeshBasicMaterial({map:texture, overdraw:0.5}); moon = new THREE.Mesh(geometry, material); moon.position.set(50, 50, 50); // moon.position.set(100, 50, 0); scene.add(moon); }); // Renderer - 毎フレーム描画 var renderer = new THREE.WebGLRenderer({antialias: true}); renderer.setSize(width, height); renderer.setClearColor(0xcccccc); renderer.setPixelRatio(window.devicePixelRatio); document.getElementById("stage").appendChild(renderer.domElement); // Radian - 360 = 2 * PI , 180 = PI var radius = 50; var degree = 0; // Loop loop(); function loop(){ stats.update(); // Earth, Moon を回転 degree += 0.5; if(360 <= degree) degree = 0; var radian = degree * Math.PI / 180; var x = radius * Math.cos(radian); var y = radius * Math.sin(radian); if(earth != null){ earth.rotation.set(0, radian, 0); } if(moon != null){ moon.rotation.set(0, radian, 0); // 以下の x,y を入れ替えると、逆向きに回転します moon.position.set(y-30, 50, x+50); } // Cube を回転 cube.rotation.x += 0.05; cube.rotation.y += 0.05; controls.update(); renderer.render(scene, camera); window.requestAnimationFrame(loop ); //再帰呼び出し };
https://ozateck.sakura.ne.jp/wordpress/category/three-js/
先程と同様、上記urlからの写経です。
ブラウザ経由で、PCのマイクを使用しますので、 PCに向かって、手を叩くと、緑色の部分に波形として現れます。
ただし、navigator.getUserMedia() は、depricated のようですので、 そのうち、navigator.mediaDevices.getUserMedia() へ書き換える必要があります。
https://end0tknr.github.io/sandbox/threejs_cannonjs_shimeji/index_audio.html
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <!-- refer to https://ozateck.sakura.ne.jp/wordpress/ --> <title>Hello Three.js</title> <style> body{ margin: 0; overflow: hidden; } </style> </head> <body> <h1>マイクからの入力音声を波形として表示</h1> <div id="stage"></div> <audio muted></audio> <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/97/three.min.js"></script> <!-- 処理速度やフレームレートを確認する為 --> <script src="https://cdn.jsdelivr.net/npm/stats-js@1.0.1/build/stats.min.js"></script> <!-- マウスによるカメラ操作 --> <script src="https://cdn.jsdelivr.net/npm/three@0.105.2/examples/js/controls/TrackballControls.js"> </script> <script src="https://cdn.jsdelivr.net/npm/cannon@0.6.2/build/cannon.min.js"></script> <script src="js/app_audio.js"></script> </body> </html>
console.log("Hello Three.js!!"); var width = 480; var height = 320; var fov = 60; var aspect = width / height; var near = 1; var far = 1000; // Scene var scene = new THREE.Scene(); // Axes var axes = new THREE.AxisHelper(20); scene.add(axes); // Stats var stats = new Stats(); stats.setMode(0); stats.domElement.style.position = "absolute"; stats.domElement.style.left = "0px"; stats.domElement.style.top = "0px"; document.getElementById("stage").appendChild(stats.domElement); // Plane var geometry = new THREE.PlaneGeometry(100, 200); var material = new THREE.MeshBasicMaterial({color: 0x666666}); var plane = new THREE.Mesh(geometry, material); plane.position.set(0, 0, 0); plane.rotation.set(-90 * Math.PI / 180, 0, 0); scene.add(plane); // Camera var camera = new THREE.PerspectiveCamera(fov, aspect, near, far); camera.position.set(0, 100, 200); camera.lookAt(scene.position); // Light var directionalLight = new THREE.DirectionalLight(0xffffff); directionalLight.position.set(0, 0.7, 0.7); scene.add(directionalLight); // Renderer var renderer = new THREE.WebGLRenderer({antialias: true}); renderer.setSize(width, height); renderer.setClearColor(0x333333); renderer.setPixelRatio(window.devicePixelRatio); document.getElementById("stage").appendChild(renderer.domElement); //========== // Web Audio navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia; navigator.getUserMedia({audio : true}, onSuccess, onError); function onSuccess(stream){ console.log("onSuccess"); // document.querySelector("audio").src = URL.createObjectURL(stream); // ↑old. ↓new document.querySelector("audio").src = window.URL.createObjectURL(new Blob([stream], {type: "application/zip"})) var audioContext = new AudioContext(); var analyser = audioContext.createAnalyser(); var timeDomain = new Float32Array(analyser.frequencyBinCount); var frequency = new Uint8Array(analyser.frequencyBinCount); audioContext.createMediaStreamSource(stream).connect(analyser); console.log("frequency:" + frequency.length); loop(); function loop(){ analyser.getFloatTimeDomainData(timeDomain); analyser.getByteFrequencyData(frequency); // update updateThree(timeDomain, frequency); window.requestAnimationFrame(loop); } } function onError(e){ console.log("onError:" + e); } // Points var points; // Draw function updateThree(timeDomain, frequency){ // Stats stats.update(); // Remove Points if(points != null) scene.remove(points); // Particles var geom = new THREE.Geometry(); var material = new THREE.PointsMaterial({ color: 0xffffff, size: 2, vertexColors: true, transparent: true, opacity: 1.0 }); var paddingX = 2; // パーティクルの間隔 var offset = 4; // 1024を4分割 var total = Math.floor(frequency.length / offset); var minX = total * paddingX / -2; // 開始位置x var maxY = 100;// 最大の高さy console.log(total); for(var i=0; i<total; i++){ var particle = new THREE.Vector3( minX + i * paddingX, Math.max(0, frequency[i*offset] * maxY / 255), 0); geom.vertices.push(particle); var color = new THREE.Color(0x00ff00); color.setHSL(color.getHSL().h, color.getHSL().s, color.getHSL().l); geom.colors.push(color); } // Add Points points = new THREE.Points(geom, material); scene.add(points); // Render renderer.render(scene, camera); }
「音声の可視化 」の別バージョンです。
PCマイクに向かって、手をたたくと、cubeが追加されます。
反応が悪いようですが、src修正は実施していません。
https://end0tknr.github.io/sandbox/threejs_cannonjs_shimeji/index_audio_2.html
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <!-- refer to https://ozateck.sakura.ne.jp/wordpress/ --> <title>Hello Three.js</title> <style> body{ margin: 0; overflow: hidden; } </style> </head> <body> <h1>マイクからの(拍手)入力で、Cubeを追加</h1> 反応が悪いようですが、js srcは修正していません。 <div id="stage"></div> <audio muted></audio> <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/97/three.min.js"></script> <!-- 処理速度やフレームレートを確認する為 --> <script src="https://cdn.jsdelivr.net/npm/stats-js@1.0.1/build/stats.min.js"></script> <!-- マウスによるカメラ操作 --> <script src="https://cdn.jsdelivr.net/npm/three@0.105.2/examples/js/controls/TrackballControls.js"> </script> <script src="https://cdn.jsdelivr.net/npm/cannon@0.6.2/build/cannon.min.js"></script> <script src="js/app_audio_2.js"></script> </body> </html>
console.log("Hello Three.js!!"); var width = 480; var height = 320; var fov = 60; var aspect = width / height; var near = 1; var far = 1000; // Scene var scene = new THREE.Scene(); // Axes var axes = new THREE.AxisHelper(20); scene.add(axes); // Stats var stats = new Stats(); stats.setMode(0); stats.domElement.style.position = "absolute"; stats.domElement.style.left = "0px"; stats.domElement.style.top = "0px"; document.getElementById("stage").appendChild(stats.domElement); // Plane var geometry = new THREE.PlaneGeometry(100, 200); var material = new THREE.MeshBasicMaterial({color: 0x666666}); var plane = new THREE.Mesh(geometry, material); plane.position.set(0, 0, 0); plane.rotation.set(-90 * Math.PI / 180, 0, 0); scene.add(plane); // Camera var camera = new THREE.PerspectiveCamera(fov, aspect, near, far); camera.position.set(0, 100, 200); camera.lookAt(scene.position); // Light var directionalLight = new THREE.DirectionalLight(0xffffff); directionalLight.position.set(0, 0.7, 0.7); scene.add(directionalLight); // Renderer var renderer = new THREE.WebGLRenderer({antialias: true}); renderer.setSize(width, height); renderer.setClearColor(0x333333); renderer.setPixelRatio(window.devicePixelRatio); document.getElementById("stage").appendChild(renderer.domElement); //========== // Web Audio navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia; navigator.getUserMedia({audio : true}, onSuccess, onError); function onSuccess(stream){ console.log("onSuccess"); //document.querySelector("audio").src = URL.createObjectURL(stream); // ↑old. ↓new document.querySelector("audio").src = window.URL.createObjectURL(new Blob([stream], {type: "application/zip"})) var audioContext = new AudioContext(); var analyser = audioContext.createAnalyser(); var timeDomain = new Float32Array(analyser.frequencyBinCount); var frequency = new Uint8Array(analyser.frequencyBinCount); audioContext.createMediaStreamSource(stream).connect(analyser); //========== // 拍手を検出するクラス // 第一引数:次の拍手までの待機時間(ミリ秒) // 第二引数:反応する拍手音量の閾値 var cManager = new CrapManager(500, 2); loop(); function loop(){ // Analiser analyser.getFloatTimeDomainData(timeDomain); analyser.getByteFrequencyData(frequency); // Stats stats.update(); // 拍手の判定 if(cManager.trigger(timeDomain, frequency) == true){ console.log("start addCube()"); // Cubeを追加する addCube(); } // Render renderer.render(scene, camera); // Request window.requestAnimationFrame(loop); } } function onError(e){ console.log("onError:" + e); } //========== // Cubeをランダムで配置する関数 function addCube(){ var x = getRandom(-80, 80); var y = getRandom(0, 80); var z = getRandom(-80, 80); var cube = createCube(5, 0xffffff, x, y, z); scene.add(cube); } //========== // Cubeを指定のサイズ、色、座標で作り出す関数 function createCube(size, color, x, y, z){ var geometry = new THREE.BoxBufferGeometry(size, size, size); var material = new THREE.MeshBasicMaterial({color: 0xccffcc, wireframe: true}); var mesh = new THREE.Mesh(geometry, material); mesh.position.set(x, y, z); return mesh; } function getRandom(min, max){ return Math.floor(Math.random()*(max-min+1))+min; } //========== // CrapManager class CrapManager{ constructor(interTime, interThreshold){ this.interTime = interTime; this.interThreshold = interThreshold; this.interFlg = false; } trigger(timeDomain, frequency){ if(this.interFlg == true) return false; var offset = 30; var total = Math.floor(frequency.length / offset); var volume = 0; for(var i=0; i<total; i+=offset){ volume += frequency[i * offset]; } if(volume < this.interThreshold) return false; this.interFlg = true; setInterval(()=>{this.interFlg = false;}, this.interTime); return true; } }
本来、 hands-on three.js + cannon.js - 3D迷路 (like fps ?) - end0tknr's kipple - web写経開発 より前に、記載すべき入門的なものですが、今更、post。
目次
https://end0tknr.github.io/sandbox/threejs_cannonjs_misc/test_cannonjs_1.html
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <!-- refer to https://liginc.co.jp/378458 --> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/109/three.min.js"></script> <script src="https://cdn.jsdelivr.net/gh/mrdoob/three.js@r109/examples/js/controls/OrbitControls.js"></script> <script src="https://cdn.jsdelivr.net/npm/cannon@0.6.2/build/cannon.min.js"></script> </head> <body> <div id="stage"></div> <div class="kakudo"> 手玉を突く角度 <input type="range" class="range js-range" value="0" step="0.1" min="-4" max="4"> <button class="js-fire">発射</button> </div> <!-- #kakudo --> <script> (function() { var controls; var scene; var camera; var renderer; var phySphere; var phySphere2; var phySphere3; var viewSphere; var viewSphere2; var viewSphere3; var rand = Math.random()*20 - 10; // 的玉の位置 var world = setPhy(); setView(); animate(); function setPhy() { var world = new CANNON.World(); // 物理世界 world.gravity.set(0, -9.82, 0); // 重力 //「衝突可能性」の剛体同士を探索 world.broadphase = new CANNON.NaiveBroadphase(); world.solver.iterations = 5; // 反復計算回数 world.solver.tolerance = 0.1; // 許容値 //地面 var groundMat = new CANNON.Material('groundMat'); //質量定義 var phyPlane = new CANNON.Body({ mass: 0, material: groundMat }); phyPlane.addShape(new CANNON.Plane()); // X軸に90度回転 phyPlane.quaternion.setFromAxisAngle( new CANNON.Vec3(1, 0, 0), -Math.PI / 2 ); world.add(phyPlane); var sphereMat = new CANNON.Material('sphereMat'); //質量定義 phySphere = new CANNON.Body({ mass: 1, material: sphereMat }); phySphere.addShape(new CANNON.Sphere(1)); phySphere.position.set(20, 1, 0); //位置 phySphere.velocity.set(0, 0, 0); //角速度 phySphere.angularDamping = 0.1; //減衰率 world.add(phySphere); var sphereMat2 = new CANNON.Material('sphereMat2'); //質量定義 phySphere2 = new CANNON.Body({ mass: 1, material: sphereMat2 }); phySphere2.addShape(new CANNON.Sphere(1)); phySphere2.position.set(10, 1, 0); //位置 phySphere2.velocity.set(0, 0, 0); //角速度 phySphere2.angularDamping = 0.1; //減衰率 world.add(phySphere2); var sphereMat3 = new CANNON.Material('sphereMat3'); //質量定義 phySphere3 = new CANNON.Body({ mass: 2, material: sphereMat3 }); phySphere3.addShape(new CANNON.Sphere(2)); phySphere3.position.set(-10, 2, rand); //位置 phySphere3.velocity.set(0, 0, 0); //角速度 phySphere3.angularDamping = 0.1; //減衰率 world.add(phySphere3); //SphereとSphere2が接触した際のContactMaterial var sphereSphereCM = new CANNON.ContactMaterial( sphereMat, sphereMat2, {contactEquationRelaxation: 3, //接触式の緩和性 contactEquationStiffness: 10000000, //接触式の剛性 friction: 0.3, //摩擦係数 frictionEquationRelaxation: 3, //摩擦式の剛性 frictionEquationStiffness: 10000000, //摩擦式の緩和性 restitution: 0.3 //反発係数 } ); world.addContactMaterial(sphereSphereCM); //地面とSphereが接触した際のContactMaterial spherePlaneCM = new CANNON.ContactMaterial( groundMat, sphereMat, {friction: 0, //摩擦係数 restitution: 0 //反発係数 } ); world.addContactMaterial(spherePlaneCM); //地面とSphereが接触した際のContactMaterial spherePlaneCM2 = new CANNON.ContactMaterial( groundMat, sphereMat2, {friction: 0, //摩擦係数 restitution: 0 //反発係数 } ); world.addContactMaterial(spherePlaneCM2); world.bsc_dist = new CANNON.Vec3(); return world; } function setView() { scene = new THREE.Scene(); scene.fog = new THREE.Fog(0x000000, 1, 100); camera = new THREE.PerspectiveCamera(40, 650 / 400, 1, 10000); camera.position.set(50, 15, 0); camera.lookAt(new THREE.Vector3(0, 0, 0)); scene.add(camera); var light = new THREE.DirectionalLight(0xffffff, 2); light.position.set(5, 10, -10); light.castShadow = true; light.shadowMapWidth = 1024; light.shadowMapHeight = 1024; light.shadowCameraLeft = -10; light.shadowCameraRight = 10; light.shadowCameraTop = 10; light.shadowCameraBottom = -10; light.shadowCameraFar = 100; light.shadowCameraNear = 0; light.shadowDarkness = 0.5; scene.add(light); var amb = new THREE.AmbientLight(0x999999); scene.add(amb); var viewPlane = new THREE.Mesh( new THREE.PlaneGeometry(300, 300), new THREE.MeshPhongMaterial( {color: 0x333333} ) ); viewPlane.rotation.x = -Math.PI / 2; viewPlane.position.y = 1 / 30; viewPlane.receiveShadow = true; scene.add(viewPlane); viewSphere = new THREE.Mesh( new THREE.SphereGeometry(1, 50, 50), new THREE.MeshLambertMaterial( {color: 0xffffff} ) ); viewSphere.castShadow = true; viewSphere.receiveShadow = true; viewSphere.position = phySphere.position; scene.add(viewSphere); viewSphere2 = new THREE.Mesh( new THREE.SphereGeometry(1, 50, 50), new THREE.MeshLambertMaterial( {color: 0xffffff} ) ); viewSphere2.castShadow = true; viewSphere2.receiveShadow = true; viewSphere2.position = phySphere2.position; scene.add(viewSphere2); viewSphere3 = new THREE.Mesh( new THREE.SphereGeometry(2, 50, 50), new THREE.MeshLambertMaterial( {side: THREE.DoubleSide // 裏からも見える為 //map: textureHayachi, } ) ); viewSphere3.castShadow = true; viewSphere3.receiveShadow = true; viewSphere3.position = phySphere3.position; scene.add(viewSphere3); renderer = new THREE.WebGLRenderer({antialias: true}); renderer.setSize(650, 400); renderer.setClearColor(0x000000, 1); renderer.shadowMapEnabled = true; document.body.appendChild(renderer.domElement); renderer.render(scene, camera); // controls controls = new THREE.OrbitControls(camera, renderer.domElement); controls.minDistance = 0; //近づける距離の最小値 controls.maxDistance = 9800; //遠ざかる距離の最大値 } function animate() { requestAnimationFrame(animate); world.step(1 / 60); // 物理エンジンの時間を進める viewSphere.position.copy(phySphere.position); viewSphere.quaternion.copy(phySphere.quaternion); viewSphere2.position.copy(phySphere2.position); viewSphere2.quaternion.copy(phySphere2.quaternion); viewSphere3.position.copy(phySphere3.position); viewSphere3.quaternion.copy(phySphere3.quaternion); controls.update(); renderer.render(scene, camera); } var angle = 0; $('.js-range').on('change', function(e) { e.preventDefault(); angle = parseInt($(this).val(), 10); }); $('.js-fire').on('click', function(e) { e.preventDefault(); phySphere.velocity.set(-20, 0, -angle); }); })(); </script> </body> </html>
Cannon.jsで簡単なゲームを作ってみよう! | 株式会社LIG の写経 + 少々、リファクタリングです。
https://end0tknr.github.io/sandbox/threejs_cannonjs_misc/test_cannonjs_2.html
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <!-- refer to https://liginc.co.jp/378458 --> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/109/three.min.js"></script> <script src="https://cdn.jsdelivr.net/gh/mrdoob/three.js@r109/examples/js/controls/OrbitControls.js"></script> <script src="https://cdn.jsdelivr.net/npm/cannon@0.6.2/build/cannon.min.js"></script> </head> <body> <div id="stage"></div> <div class="kakudo"> 手玉を突く角度 <input type="range" class="range js-range" value="0" step="0.1" min="-4" max="4"> <button class="js-fire">発射</button> </div> <!-- #kakudo --> <script> (function() { var controls; var scene; var camera; var renderer; var phySphere; var phySphere2; var phySphere3; var viewSphere; var viewSphere2; var viewSphere3; var rand = Math.random()*20 - 10; // 的玉の位置 var world = setPhy(); setView(); animate(); function setPhy() { var world = new CANNON.World(); // 物理世界 world.gravity.set(0, -9.82, 0); // 重力 //「衝突可能性」の剛体同士を探索 world.broadphase = new CANNON.NaiveBroadphase(); world.solver.iterations = 5; // 反復計算回数 world.solver.tolerance = 0.1; // 許容値 //地面 var groundMat = new CANNON.Material('groundMat'); //質量定義 var phyPlane = new CANNON.Body({ mass: 0, material: groundMat }); phyPlane.addShape(new CANNON.Plane()); // X軸に90度回転 phyPlane.quaternion.setFromAxisAngle( new CANNON.Vec3(1, 0, 0), -Math.PI / 2 ); world.add(phyPlane); var sphereMat = new CANNON.Material('sphereMat'); //質量定義 phySphere = new CANNON.Body({ mass: 1, material: sphereMat }); phySphere.addShape(new CANNON.Sphere(1)); phySphere.position.set(20, 1, 0); //位置 phySphere.velocity.set(0, 0, 0); //角速度 phySphere.angularDamping = 0.1; //減衰率 world.add(phySphere); var sphereMat2 = new CANNON.Material('sphereMat2'); //質量定義 phySphere2 = new CANNON.Body({ mass: 1, material: sphereMat2 }); phySphere2.addShape(new CANNON.Sphere(1)); phySphere2.position.set(10, 1, 0); //位置 phySphere2.velocity.set(0, 0, 0); //角速度 phySphere2.angularDamping = 0.1; //減衰率 world.add(phySphere2); var sphereMat3 = new CANNON.Material('sphereMat3'); //質量定義 phySphere3 = new CANNON.Body({ mass: 2, material: sphereMat3 }); phySphere3.addShape(new CANNON.Sphere(2)); phySphere3.position.set(-10, 2, rand); //位置 phySphere3.velocity.set(0, 0, 0); //角速度 phySphere3.angularDamping = 0.1; //減衰率 world.add(phySphere3); //SphereとSphere2が接触した際のContactMaterial var sphereSphereCM = new CANNON.ContactMaterial( sphereMat, sphereMat2, {contactEquationRelaxation: 3, //接触式の緩和性 contactEquationStiffness: 10000000, //接触式の剛性 friction: 0.3, //摩擦係数 frictionEquationRelaxation: 3, //摩擦式の剛性 frictionEquationStiffness: 10000000, //摩擦式の緩和性 restitution: 0.3 //反発係数 } ); world.addContactMaterial(sphereSphereCM); //地面とSphereが接触した際のContactMaterial spherePlaneCM = new CANNON.ContactMaterial( groundMat, sphereMat, {friction: 0, //摩擦係数 restitution: 0 //反発係数 } ); world.addContactMaterial(spherePlaneCM); //地面とSphereが接触した際のContactMaterial spherePlaneCM2 = new CANNON.ContactMaterial( groundMat, sphereMat2, {friction: 0, //摩擦係数 restitution: 0 //反発係数 } ); world.addContactMaterial(spherePlaneCM2); world.bsc_dist = new CANNON.Vec3(); return world; } function setView() { scene = new THREE.Scene(); scene.fog = new THREE.Fog(0x000000, 1, 100); camera = new THREE.PerspectiveCamera(40, 650 / 400, 1, 10000); camera.position.set(50, 15, 0); camera.lookAt(new THREE.Vector3(0, 0, 0)); scene.add(camera); var light = new THREE.DirectionalLight(0xffffff, 2); light.position.set(5, 10, -10); light.castShadow = true; light.shadowMapWidth = 1024; light.shadowMapHeight = 1024; light.shadowCameraLeft = -10; light.shadowCameraRight = 10; light.shadowCameraTop = 10; light.shadowCameraBottom = -10; light.shadowCameraFar = 100; light.shadowCameraNear = 0; light.shadowDarkness = 0.5; scene.add(light); var amb = new THREE.AmbientLight(0x999999); scene.add(amb); var viewPlane = new THREE.Mesh( new THREE.PlaneGeometry(300, 300), new THREE.MeshPhongMaterial( {color: 0x333333} ) ); viewPlane.rotation.x = -Math.PI / 2; viewPlane.position.y = 1 / 30; viewPlane.receiveShadow = true; scene.add(viewPlane); viewSphere = new THREE.Mesh( new THREE.SphereGeometry(1, 50, 50), new THREE.MeshLambertMaterial( {color: 0xffffff} ) ); viewSphere.castShadow = true; viewSphere.receiveShadow = true; viewSphere.position = phySphere.position; scene.add(viewSphere); viewSphere2 = new THREE.Mesh( new THREE.SphereGeometry(1, 50, 50), new THREE.MeshLambertMaterial( {color: 0xffffff} ) ); viewSphere2.castShadow = true; viewSphere2.receiveShadow = true; viewSphere2.position = phySphere2.position; scene.add(viewSphere2); viewSphere3 = new THREE.Mesh( new THREE.SphereGeometry(2, 50, 50), new THREE.MeshLambertMaterial( {side: THREE.DoubleSide // 裏からも見える為 //map: textureHayachi, } ) ); viewSphere3.castShadow = true; viewSphere3.receiveShadow = true; viewSphere3.position = phySphere3.position; scene.add(viewSphere3); renderer = new THREE.WebGLRenderer({antialias: true}); renderer.setSize(650, 400); renderer.setClearColor(0x000000, 1); renderer.shadowMapEnabled = true; document.body.appendChild(renderer.domElement); renderer.render(scene, camera); // controls controls = new THREE.OrbitControls(camera, renderer.domElement); controls.minDistance = 0; //近づける距離の最小値 controls.maxDistance = 9800; //遠ざかる距離の最大値 } function animate() { requestAnimationFrame(animate); world.step(1 / 60); // 物理エンジンの時間を進める viewSphere.position.copy(phySphere.position); viewSphere.quaternion.copy(phySphere.quaternion); viewSphere2.position.copy(phySphere2.position); viewSphere2.quaternion.copy(phySphere2.quaternion); viewSphere3.position.copy(phySphere3.position); viewSphere3.quaternion.copy(phySphere3.quaternion); controls.update(); renderer.render(scene, camera); } var angle = 0; $('.js-range').on('change', function(e) { e.preventDefault(); angle = parseInt($(this).val(), 10); }); $('.js-fire').on('click', function(e) { e.preventDefault(); phySphere.velocity.set(-20, 0, -angle); }); })(); </script> </body> </html>
Javascript で動く軽量物理エンジン Cannon.js と3Dレンダラ Three.js で書いた短いサンプルコード - Qiita の写経 + 少々、リファクタリングです。
https://end0tknr.github.io/sandbox/threejs_cannonjs_misc/test_cannonjs_3.html
<html> <head> <!-- refer to https://qiita.com/yamazaki3104/items/fafb7879591caf137b52 --> <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/109/three.js"></script> <script src="https://cdn.jsdelivr.net/gh/mrdoob/three.js@r109/examples/js/controls/TrackballControls.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/cannon.js/0.6.2/cannon.js"></script> </head> <body> <script> class THREEJS { constructor(){ const w = document.body.clientWidth const h = document.body.clientHeight this.renderer = new THREE.WebGLRenderer() this.renderer.setClearColor( 0x8888dd ) this.renderer.setSize( w, h ) this.camera = new THREE.PerspectiveCamera( 40, w / h, 0.1, 1000 ) this.camera.position.x = 0 this.camera.position.y = 20 this.camera.position.z = 30 this.trackball = new THREE.TrackballControls( this.camera ) this.scene = new THREE.Scene() let directionalLight = new THREE.DirectionalLight( 0xffffff, 1 ) directionalLight.position.set( 0.2, 0.5, 0.3 ) this.scene.add( directionalLight ) // this.scene.add( new THREE.AmbientLight( 0x101020 ) ) document.body.appendChild( this.renderer.domElement ) } render(){ for ( let mesh of this.scene.children ) { if ( ! mesh.cannon_rigid_body ) continue mesh.position.copy( mesh.cannon_rigid_body.position ) mesh.quaternion.copy( mesh.cannon_rigid_body.quaternion ) } this.trackball.update() this.renderer.render( this.scene, this.camera ) } } class CANNON_PHYSICS { constructor( _threejs ) { this.cannon_world = new CANNON.World() this.cannon_world.gravity.set( 0, -9.80665, 0 ) this.cannon_world.broadphase = new CANNON.NaiveBroadphase() this.cannon_world.solver.iterations = 10 this.threejs = _threejs } add_box( _arg ) { const body = new CANNON.Body( { mass: _arg.mass, shape: new CANNON.Box( new CANNON.Vec3(_arg.w/2, _arg.h/2, _arg.d/2 )), position: new CANNON.Vec3( _arg.x, _arg.y, _arg.z ), // 摩擦係数 0.1 マテリアルを作成 material: new CANNON.Material( { friction: 0.1, } ), } ) this.add_body( body, _arg.color ) } add_body( _body, _color ){ this.cannon_world.addBody( _body ) var obj = new THREE.Object3D(); const color_mat = new THREE.MeshLambertMaterial( { color: _color } ) // ここのコードは connon.demo.js の 977 shape2mesh() から、まるっと借りてきた。 for (var l = 0; l < _body.shapes.length; l++) { var shape = _body.shapes[l]; var mesh; switch(shape.type){ case CANNON.Shape.types.SPHERE: var sphere_geometry = new THREE.SphereGeometry( shape.radius, 8, 8); mesh = new THREE.Mesh( sphere_geometry, color_mat ); break; case CANNON.Shape.types.PARTICLE: mesh = new THREE.Mesh( this.particleGeo, this.particleMaterial ); var s = this.settings; mesh.scale.set(s.particleSize,s.particleSize,s.particleSize); break; case CANNON.Shape.types.PLANE: var geometry = new THREE.PlaneGeometry(10, 10, 4, 4); mesh = new THREE.Object3D(); var submesh = new THREE.Object3D(); var ground = new THREE.Mesh( geometry, color_mat ); ground.scale.set(100, 100, 100); submesh.add(ground); ground.castShadow = true; ground.receiveShadow = true; mesh.add(submesh); break; case CANNON.Shape.types.BOX: var box_geometry = new THREE.BoxGeometry( shape.halfExtents.x*2, shape.halfExtents.y*2, shape.halfExtents.z*2 ); mesh = new THREE.Mesh( box_geometry, color_mat ); break; case CANNON.Shape.types.CONVEXPOLYHEDRON: var geo = new THREE.Geometry(); // Add vertices for (var i = 0; i < shape.vertices.length; i++) { var v = shape.vertices[i]; geo.vertices.push(new THREE.Vector3(v.x, v.y, v.z)); } for(var i=0; i < shape.faces.length; i++){ var face = shape.faces[i]; // add triangles var a = face[0]; for (var j = 1; j < face.length - 1; j++) { var b = face[j]; var c = face[j + 1]; geo.faces.push(new THREE.Face3(a, b, c)); } } geo.computeBoundingSphere(); geo.computeFaceNormals(); mesh = new THREE.Mesh( geo, color_mat ); break; case CANNON.Shape.types.HEIGHTFIELD: var geometry = new THREE.Geometry(); var v0 = new CANNON.Vec3(); var v1 = new CANNON.Vec3(); var v2 = new CANNON.Vec3(); for (var xi = 0; xi < shape.data.length - 1; xi++) { for (var yi = 0; yi < shape.data[xi].length - 1; yi++) { for (var k = 0; k < 2; k++) { shape.getConvexTrianglePillar(xi, yi, k===0); v0.copy(shape.pillarConvex.vertices[0]); v1.copy(shape.pillarConvex.vertices[1]); v2.copy(shape.pillarConvex.vertices[2]); v0.vadd(shape.pillarOffset, v0); v1.vadd(shape.pillarOffset, v1); v2.vadd(shape.pillarOffset, v2); geometry.vertices.push( new THREE.Vector3(v0.x, v0.y, v0.z), new THREE.Vector3(v1.x, v1.y, v1.z), new THREE.Vector3(v2.x, v2.y, v2.z) ); var i = geometry.vertices.length - 3; geometry.faces.push(new THREE.Face3(i, i+1, i+2)); } } } geometry.computeBoundingSphere(); geometry.computeFaceNormals(); mesh = new THREE.Mesh(geometry, color_mat); break; case CANNON.Shape.types.TRIMESH: var geometry = new THREE.Geometry(); var v0 = new CANNON.Vec3(); var v1 = new CANNON.Vec3(); var v2 = new CANNON.Vec3(); for (var i = 0; i < shape.indices.length / 3; i++) { shape.getTriangleVertices(i, v0, v1, v2); geometry.vertices.push( new THREE.Vector3(v0.x, v0.y, v0.z), new THREE.Vector3(v1.x, v1.y, v1.z), new THREE.Vector3(v2.x, v2.y, v2.z) ); var j = geometry.vertices.length - 3; geometry.faces.push(new THREE.Face3(j, j+1, j+2)); } geometry.computeBoundingSphere(); geometry.computeFaceNormals(); mesh = new THREE.Mesh(geometry, color_mat); break; default: throw "Visual type not recognized: "+shape.type; } var o = _body.shapeOffsets[l]; var q = _body.shapeOrientations[l]; mesh.position.set(o.x, o.y, o.z); mesh.quaternion.set(q.x, q.y, q.z, q.w); obj.add(mesh); } obj.cannon_rigid_body = _body this.threejs.scene.add( obj ) } render( _sec ) { this.cannon_world.step( _sec ) this.threejs.render() } } let cannon_phy = new CANNON_PHYSICS( new THREEJS() ) //床面 cannon_phy.add_box( { mass: 0, x: 0, y: -0.2, z: 0, w: 150, h: 0.4, d: 150, color: 0x333333, } ) //ドミノ const box_size = 1.5 for ( let y=0 ; y<16; y++ ) { for ( let x=0 ; x<16; x++ ) { cannon_phy.add_box( { mass: 1, x: (x-7) * box_size * 0.95, y: box_size * 0.5, z: (y-7) * box_size * 1.2, w: box_size*0.1, h: box_size*1, d: box_size*1, color:0xDCAA6B }) } } var w_mat = new CANNON.Material() // CANNON.Cylinder()の引数は // radiusTop, radiusBottom, height, numSegments. var ws = new CANNON.Cylinder( 1.9, 1.2, 1, 8 ) var leftFrontWheel = new CANNON.Body({ mass: 1, material: w_mat, shape: ws, position: { x: 5, y: 5+20, z: 0 }, //以下で向きを決めていますが、結局、HingeConstraintの axisB で補正. quaternion: new CANNON.Quaternion( 1, 0, 0, -Math.PI / 4 ) } ); var rightFrontWheel = new CANNON.Body({ mass: 1, material: w_mat, shape: ws, position: { x: 5, y: -5+20, z: 0 }, quaternion: new CANNON.Quaternion( 1, 0, 0, Math.PI / 4 ) } ); var leftRearWheel = new CANNON.Body({ mass: 1, material: w_mat, shape: ws, position: { x:-5, y: 5+20, z: 0 }, quaternion: new CANNON.Quaternion( 1, 0, 0, -Math.PI / 4 ) } ); var rightRearWheel = new CANNON.Body({ mass: 1, material: w_mat, shape: ws, position: { x:-5, y: -5+20, z: 0 }, quaternion: new CANNON.Quaternion( 1, 0, 0, Math.PI / 4 ) } ); // シャシー var chassis = new CANNON.Body({ mass: 5, shape: new CANNON.Box( new CANNON.Vec3( 5, 2, 0.5 ) ), position: { x: 0, y: 20, z: 0 } }) //制約 //前輪は、やや斜めにして接続(ハンドルを切った状態) var constraint_leftFront = new CANNON.HingeConstraint( chassis, leftFrontWheel, { pivotA: new CANNON.Vec3( 5, 5, 0 ), axisA: new CANNON.Vec3( 1, 1, 0 ), pivotB: new CANNON.Vec3(), axisB: new CANNON.Vec3( 0, 0, -1 ) } ); cannon_phy.cannon_world.addConstraint( constraint_leftFront ); var constraint_rightFront = new CANNON.HingeConstraint( chassis, rightFrontWheel, { pivotA: new CANNON.Vec3( 5, -5, 0 ), axisA: new CANNON.Vec3( 1, 1, 0 ), pivotB: new CANNON.Vec3(), axisB: new CANNON.Vec3( 0, 0, -1 ) } ); cannon_phy.cannon_world.addConstraint( constraint_rightFront ); var constraint_leftRear = new CANNON.HingeConstraint( chassis, leftRearWheel, { pivotA: new CANNON.Vec3( -5, 5, 0 ), axisA: new CANNON.Vec3( 0, 1, 0 ), pivotB: new CANNON.Vec3(), axisB: new CANNON.Vec3( 0, 0, -1 ) } ); cannon_phy.cannon_world.addConstraint( constraint_leftRear ); var constraint_rightRear = new CANNON.HingeConstraint( chassis, rightRearWheel, { pivotA: new CANNON.Vec3( -5, -5, 0 ), axisA: new CANNON.Vec3( 0, 1, 0 ), pivotB: new CANNON.Vec3(), axisB: new CANNON.Vec3( 0, 0, -1, ) } ); cannon_phy.cannon_world.addConstraint( constraint_rightRear ); //前輪駆動として回転させる constraint_leftFront.enableMotor(); constraint_rightFront.enableMotor(); constraint_leftFront.setMotorSpeed( 7 ); constraint_rightFront.setMotorSpeed( -7 ); for ( const body of [ chassis, leftFrontWheel, rightFrontWheel, leftRearWheel, rightRearWheel ] ){ cannon_phy.add_body( body, 0x556677 ) } function animate(){ cannon_phy.render( 1 / 60 ) window.requestAnimationFrame( animate ) } window.requestAnimationFrame( animate ) </script> </body> </html>
先程の「three.js + cannon.js 3 - ヒンジによるタイヤ接合」では、 HingeConstraint により、車体とタイヤを接続しましたが、 以下では、CANNON.PointToPointConstraint により、板を接合しています。
元々、cannon.js の examples にあったものの、写経 + 少々、リファクタリングです。
https://github.com/schteppe/cannon.js/tree/master/examples
https://schteppe.github.io/cannon.js/examples/threejs_fps.html
https://end0tknr.github.io/sandbox/cannonjs_examples/threejs_fps.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>cannon.js + three.js physics shooter</title> <style> #blocker { position: absolute; width: 100%; height: 100%; background-color: rgba(0,0,0,0.5); } #instructions { width: 100%; height: 100%; color: #ffffff; text-align: center; font-size:20px; padding-top:20px; cursor: pointer; } </style> <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/68/three.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/cannon@0.6.2/build/cannon.min.js"></script> <!-- マウスによるカメラ制御 --> <!-- https://developer.mozilla.org/ja/docs/Web/API/Pointer_Lock_API --> <script src="js/PointerLockControls.js"></script> </head> <body> <div id="blocker"> <div id="instructions"> Click to play<br/> (W,A,S,D = Move, SPACE = Jump, MOUSE = Look, CLICK = Shoot) </div> </div> <script> var world; var camera; var scene; var renderer; var sphereShape; var sphereBody; var physicsMaterial; var walls=[]; var balls=[]; var ballMeshes=[]; var boxes=[]; var boxMeshes=[]; var geometry; var material; var mesh; var controls,time = Date.now(); var blocker = document.getElementById( 'blocker' ); // 操作方法の表示 var instructions = document.getElementById( 'instructions' ); if ( 'pointerLockElement' in document ) { main(); } else { instructions.innerHTML = 'Your browser doesn\'t seem to support Pointer Lock API'; } function main(){ var element = document.body; document.addEventListener( 'pointerlockchange', function ( event ) { if ( document.pointerLockElement === element ) { controls.enabled = true; blocker.style.display = 'none'; } else { controls.enabled = false; blocker.style.display = 'box'; instructions.style.display = ''; } }, false ); document.addEventListener( 'pointerlockerror', function(event){instructions.style.display = ''; }, false ); instructions.addEventListener( 'click', function ( event ) { instructions.style.display = 'none'; // Ask the browser to lock the pointer element.requestPointerLock = element.requestPointerLock; element.requestPointerLock(); }, false ); initCannon(); init(); animate(); } function initCannon(){ // Setup our world world = new CANNON.World(); world.quatNormalizeSkip = 0; world.quatNormalizeFast = false; var solver = new CANNON.GSSolver(); //接触式の剛性 world.defaultContactMaterial.contactEquationStiffness = 1e9 //接触式の緩和性 world.defaultContactMaterial.contactEquationRelaxation = 4; solver.iterations = 7; solver.tolerance = 0.1; world.solver = new CANNON.SplitSolver(solver); world.gravity.set(0,-20,0); world.broadphase = new CANNON.NaiveBroadphase(); // Create a slippery material (friction coefficient = 0.0) physicsMaterial = new CANNON.Material("slipperyMaterial"); var physicsContactMaterial = new CANNON.ContactMaterial(physicsMaterial, physicsMaterial, 0.0, // friction coefficient 0.3 // restitution ); // We must add the contact materials to the world world.addContactMaterial(physicsContactMaterial); // 自分自身を表す球体 var mass = 5; var radius = 2; sphereShape = new CANNON.Sphere(radius); sphereBody = new CANNON.Body({ mass: mass }); sphereBody.addShape(sphereShape); sphereBody.position.set(0, 5, 0); sphereBody.linearDamping = 0.9; world.addBody(sphereBody); // 物理的な床面 var groundShape = new CANNON.Plane(); var groundBody = new CANNON.Body({ mass: 0 }); groundBody.addShape(groundShape); groundBody.quaternion.setFromAxisAngle(new CANNON.Vec3(1,0,0),-Math.PI/2); world.addBody(groundBody); } function init() { camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ); scene = new THREE.Scene(); scene.fog = new THREE.Fog( 0x000000, 0, 500 ); var ambient = new THREE.AmbientLight( 0x111111 ); scene.add( ambient ); light = new THREE.SpotLight( 0xffffff ); light.position.set( 10, 30, 20 ); light.target.position.set( 0, 0, 0 ); if(true){ light.castShadow = true; light.shadowCameraNear = 20; light.shadowCameraFar = 50;//camera.far; light.shadowCameraFov = 40; light.shadowMapBias = 0.1; light.shadowMapDarkness = 0.7; light.shadowMapWidth = 2*512; light.shadowMapHeight = 2*512; //light.shadowCameraVisible = true; } scene.add( light ); controls = new PointerLockControls( camera , sphereBody ); scene.add( controls.getObject() ); // 画面上の床面 geometry = new THREE.PlaneGeometry( 300, 300, 50, 50 ); geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) ); material = new THREE.MeshLambertMaterial( { color: 0xdddddd } ); mesh = new THREE.Mesh( geometry, material ); mesh.castShadow = true; mesh.receiveShadow = true; scene.add( mesh ); renderer = new THREE.WebGLRenderer(); renderer.shadowMapEnabled = true; renderer.shadowMapSoft = true; renderer.setSize( window.innerWidth, window.innerHeight ); renderer.setClearColor( scene.fog.color, 1 ); document.body.appendChild( renderer.domElement ); window.addEventListener( 'resize', onWindowResize, false ); // 的となる箱の追加 var halfExtents = new CANNON.Vec3(1,1,1); var boxShape = new CANNON.Box(halfExtents); var boxGeometry = new THREE.BoxGeometry(halfExtents.x*2,halfExtents.y*2,halfExtents.z*2); for(var i=0; i<15; i++){ var x = (Math.random()-0.5)*20; var y = 1 + (Math.random()-0.5)*1; var z = (Math.random()-0.5)*20; var boxBody = new CANNON.Body({ mass: 5 }); boxBody.addShape(boxShape); var boxMesh = new THREE.Mesh( boxGeometry, material ); world.addBody(boxBody); scene.add(boxMesh); boxBody.position.set(x,y,z); boxMesh.position.set(x,y,z); boxMesh.castShadow = true; boxMesh.receiveShadow = true; boxes.push(boxBody); boxMeshes.push(boxMesh); } // 的となる「連結された箱」の追加 var size = 0.5; var he = new CANNON.Vec3(size,size,size*0.1); var boxShape = new CANNON.Box(he); var mass = 0; var space = 0.1 * size; var N = 5; var last; var boxGeometry = new THREE.BoxGeometry(he.x*2,he.y*2,he.z*2); for(var i=0; i<N; i++){ var boxbody = new CANNON.Body({ mass: mass }); boxbody.addShape(boxShape); var boxMesh = new THREE.Mesh(boxGeometry, material); boxbody.position.set(5,(N-i)*(size*2+2*space) + size*2+space,0); boxbody.linearDamping = 0.01; boxbody.angularDamping = 0.01; // boxMesh.castShadow = true; boxMesh.receiveShadow = true; world.addBody(boxbody); scene.add(boxMesh); boxes.push(boxbody); boxMeshes.push(boxMesh); if(i!=0){ // 板の両端で連結 var c1 = new CANNON.PointToPointConstraint( boxbody, new CANNON.Vec3(-size, size+space,0), last, new CANNON.Vec3(-size,-size-space,0)); var c2 = new CANNON.PointToPointConstraint( boxbody, new CANNON.Vec3(size, size+space,0), last, new CANNON.Vec3(size,-size-space,0)); world.addConstraint(c1); world.addConstraint(c2); } else { mass=0.3; } last = boxbody; } } function onWindowResize() { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize( window.innerWidth, window.innerHeight ); } var dt = 1/60; function animate() { requestAnimationFrame( animate ); if(controls.enabled){ world.step(dt); // Update ball positions for(var i=0; i<balls.length; i++){ ballMeshes[i].position.copy(balls[i].position); ballMeshes[i].quaternion.copy(balls[i].quaternion); } // Update box positions for(var i=0; i<boxes.length; i++){ boxMeshes[i].position.copy(boxes[i].position); boxMeshes[i].quaternion.copy(boxes[i].quaternion); } } controls.update( Date.now() - time ); renderer.render( scene, camera ); time = Date.now(); } var ballShape = new CANNON.Sphere(0.2); var ballGeometry = new THREE.SphereGeometry(ballShape.radius, 32, 32); var shootDirection = new THREE.Vector3(); var shootVelo = 15; var projector = new THREE.Projector(); function getShootDir(targetVec){ var vector = targetVec; targetVec.set(0,0,1); projector.unprojectVector(vector, camera); var ray = new THREE.Ray( sphereBody.position, vector.sub(sphereBody.position).normalize() ); targetVec.copy(ray.direction); } window.addEventListener("click",function(e){ if(controls.enabled==true){ var x = sphereBody.position.x; var y = sphereBody.position.y; var z = sphereBody.position.z; var ballBody = new CANNON.Body({ mass: 1 }); ballBody.addShape(ballShape); var ballMesh = new THREE.Mesh( ballGeometry, material ); world.addBody(ballBody); scene.add(ballMesh); ballMesh.castShadow = true; ballMesh.receiveShadow = true; balls.push(ballBody); ballMeshes.push(ballMesh); getShootDir(shootDirection); ballBody.velocity.set( shootDirection.x * shootVelo, shootDirection.y * shootVelo, shootDirection.z * shootVelo); // Move the ball outside the player sphere x += shootDirection.x * (sphereShape.radius*1.02 + ballShape.radius); y += shootDirection.y * (sphereShape.radius*1.02 + ballShape.radius); z += shootDirection.z * (sphereShape.radius*1.02 + ballShape.radius); ballBody.position.set(x,y,z); ballMesh.position.set(x,y,z); } }); </script> </body> </html>
以下は、 Three.jsとCANNON.jsで作る「VR3D脱出迷路アプリ」作成(その2) - Qiita の写経 + 少々、リファクタリングです。
実際の動作は、github pages の以下でお試し下さい。
https://end0tknr.github.io/sandbox/threejs_cannonjs_3d_maze
<!DOCTYPE html> <html> <head> <title>Three.js + Cannon.js 3D maze</title> <meta charset="utf-8"> <script src="https://cdnjs.cloudflare.com/ajax/libs/cannon.js/0.6.2/cannon.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r71/three.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <style> body {margin:0; padding:0; border:0; } img {position: absolute; width:100px; height:100px} </style> </head> <body> <!-- 移動ボタン --> <img id="forward" src="img/forward_btn.png"> <img id="stop" src="img/stop_btn.png"> <img id="back" src="img/back_btn.png"> <img id="jump" src="img/jump_btn.png"> <img id="turn_right" src="img/right_btn.png"> <img id="turn_left" src="img/left_btn.png"> <script src="cannonjs_3d_maze.js"></script> </body> </html>
// refer to https://qiita.com/DAI788/items/1b302ed9840c65e0193c //迷路の地図データ // ┌─────┬──────┬───┬─────┐ // │ │ │ │ 【START】│ // │ ┌─┐ │ ───┐ │ │ │ ────┤ // │ │ │ │ │ │ │ │ // │ │ │ │ ┐ │ ──── │ // │ │ │ │ │ │ │ // │ └─┬──┤ ──┘ └────┐ │ // │ │ │ │ │ // ├─── │ │ │ ───┐ │ │ // │ │ │ │ │ // │ ────┐ │ │ └────┤ // │ │ │ │ │ │ // ├─ └──┤ └─┤ ┌─────┐ │ // │ │ │ │ │ // │ ┌─── │ │ ──┐ │ ─┘ │ // │ │ │ │ │ │ // │ └─┐ │ │ │ ────┤ // │ │ │ ─── │ │ // ├─ │ │ │ ─────── │ // │ │ │ │ │ // │ ──┴──┴─────┴─────────┘ var mapData = [ "50_10","49_10","48_10","47_10","46_10","45_10","44_10","43_10","42_10", "41_10","40_10","39_10","38_10","37_10","36_10","35_10","34_10","33_10", "32_10","31_10","30_10","29_10","28_10","27_10","26_10","25_10","24_10", "23_10","22_10","21_10","20_10","19_10","18_10","17_10","16_10","15_10", "14_10","13_10","12_10","11_10","10_10","50_11","33_11","25_11","14_11", "50_12","33_12","25_12","14_12","50_13","33_13","25_13","14_13","50_14", "46_14","45_14","44_14","43_14","42_14","41_14","40_14","39_14","38_14", "37_14","33_14","29_14","25_14","21_14","20_14","19_14","18_14","10_14", "50_15","46_15","33_15","29_15","21_15","18_15","10_15","50_16","46_16", "33_16","29_16","21_16","18_16","10_16","50_17","46_17","45_17","44_17", "43_17","42_17","41_17","40_17","39_17","38_17","37_17","33_17","29_17", "21_17","18_17","17_17","16_17","15_17","14_17","13_17","12_17","11_17", "10_17","50_18","37_18","29_18","21_18","10_18","50_19","37_19","29_19", "10_19","50_20","37_20","29_20","10_20","50_21","49_21","48_21","47_21", "46_21","45_21","44_21","43_21","42_21","41_21","37_21","36_21","35_21", "34_21","33_21","29_21","28_21","27_21","26_21","25_21","10_21","50_22", "37_22","25_22","21_22","20_22","19_22","18_22","17_22","16_22","15_22", "14_22","13_22","12_22","11_22","10_22","50_23","37_23","25_23","10_23", "50_24","37_24","25_24","10_24","50_25","46_25","41_25","37_25","25_25", "10_25","50_26","46_26","41_26","40_26","39_26","38_26","37_26","36_26", "35_26","34_26","30_26","29_26","28_26","27_26","26_26","25_26","24_26", "23_26","22_26","21_26","10_26","50_27","46_27","15_27","10_27","50_28", "46_28","15_28","10_28","50_29","46_29","15_29","10_29","50_30","46_30", "45_30","44_30","43_30","42_30","38_30","34_30","33_30","32_30","31_30", "30_30","29_30","28_30","27_30","21_30","15_30","10_30","50_31","38_31", "27_31","21_31","10_31","50_32","38_32","27_32","21_32","10_32","50_33", "38_33","27_33","21_33","10_33","50_34","49_34","48_34","47_34","46_34", "45_34","41_34","40_34","39_34","38_34","34_34","30_34","29_34","28_34", "27_34","26_34","25_34","21_34","20_34","19_34","18_34","17_34","16_34", "15_34","14_34","13_34","12_34","11_34","10_34","50_35","34_35","10_35", "50_36","34_36","10_36","50_37","34_37","10_37","50_38","46_38","45_38", "44_38","43_38","42_38","41_38","40_38","39_38","38_38","34_38","33_38", "32_38","31_38","27_38","26_38","25_38","24_38","23_38","22_38","21_38", "20_38","19_38","10_38","50_39","38_39","27_39","15_39","10_39","50_40", "38_40","27_40","15_40","10_40","50_41","38_41","27_41","15_41","10_41", "50_42","49_42","48_42","47_42","46_42","42_42","38_42","34_42","33_42", "32_42","31_42","27_42","15_42","10_42","50_43","42_43","38_43","31_43", "27_43","23_43","19_43","15_43","10_43","50_44","42_44","38_44","31_44", "27_44","23_44","19_44","15_44","10_44","50_45","42_45","38_45","31_45", "27_45","23_45","19_45","15_45","10_45","50_46","46_46","42_46","38_46", "37_46","36_46","35_46","31_46","27_46","26_46","25_46","24_46","23_46", "19_46","15_46","10_46","50_47","46_47","31_47","19_47","10_47","50_48", "46_48","31_48","19_48","10_48","50_49","46_49","31_49","19_49","10_49", "50_50","49_50","48_50","47_50","46_50","45_50","44_50","43_50","42_50", "41_50","40_50","39_50","38_50","37_50","36_50","35_50","34_50","33_50", "32_50","31_50","30_50","29_50","28_50","27_50","26_50","25_50","24_50", "23_50","22_50","21_50","20_50","19_50","18_50","17_50","16_50","15_50", "14_50","13_50","12_50","11_50","10_50"]; //描画sizeは、ブラウザ全体 var wSizeWidth = window.innerWidth; var wSizeHeight = window.innerHeight; //迷路内を移動する自分自身 var selfData = new Object(); selfData.angle = 270; selfData.height = 2; selfData.speed = 5; //スタート位置 var startPos = "48_48"; var sPos = startPos.split("_"); selfData.posX = Number(sPos[0]); selfData.posY = Number(sPos[1]); //地図データ var boxObjArray = []; for(var i = 0; i < mapData.length; i++){ var wall = mapData[i].split("_"); //XとZのデータを分割 boxObjArray[i] = createBoxObject( [Number(wall[0]), 1, Number(wall[1]) ] ); } var thrBoxArray = []; var selfObj; //Texture--------------------------------------------------------------- var ground_texture = THREE.ImageUtils.loadTexture( 'img/ground.jpg' ); ground_texture.wrapS = ground_texture.wrapT = THREE.RepeatWrapping; ground_texture.repeat.set( 64, 64 ); var wall_texture = THREE.ImageUtils.loadTexture( 'img/wall.jpg' ); var world = setPhysics(); //物理情報設定 var ret_vals = setView(); var renderer = ret_vals[0]; var scene = ret_vals[1]; var camera = ret_vals[2]; animate(); function setPhysics() { var world = new CANNON.World(); world.gravity.set(0, -9.82, 0); //重力設定 //衝突している剛体の判定. //物理演算は処理の重いものなので、全てを計算するのではなく、 //ぶつかっている可能性のあるものをピックアップし、 //その後実際に計算. // https://qiita.com/o_tyazuke/items/3481ef1a31b2a4888f5d world.broadphase = new CANNON.NaiveBroadphase(); world.solver.iterations = 10; //反復計算回数 world.solver.tolerance = 0.1; //許容値 //地面を作成 var groundMat = new CANNON.Material('groundMat'); groundMat.friction = 0.3; //摩擦係数 groundMat.restitution = 0.5; //反発係数 var phyPlane = new CANNON.Body({mass: 0}); phyPlane.material = groundMat; phyPlane.addShape(new CANNON.Plane()); //回転 phyPlane.quaternion.setFromAxisAngle(new CANNON.Vec3(1, 0, 0), -Math.PI / 2 ); world.add(phyPlane); //物理世界に追加 //Cannon Box-------------------------------------------------------------- //壁オブジェクト var canBoxArray = []; for( cnt=0; cnt<boxObjArray.length; cnt++){ canBoxArray[cnt] = makeCannonBox( [boxObjArray[cnt].posX, boxObjArray[cnt].posY, boxObjArray[cnt].posZ], [boxObjArray[cnt].sizeX, boxObjArray[cnt].sizeY, boxObjArray[cnt].sizeZ], [boxObjArray[cnt].velocX, boxObjArray[cnt].velocY, boxObjArray[cnt].velocZ], [boxObjArray[cnt].angVelocX, boxObjArray[cnt].angVelocY, boxObjArray[cnt].angVelocZ], boxObjArray[cnt].mass, boxObjArray[cnt].dampVal); world.add(canBoxArray[cnt]); } //自分自身を表す球体オブジェクトを作成 sphereShape = new CANNON.Sphere(1); //半径1の球体を作成 var sphereMat = new CANNON.Material('sphereMat'); sphereMat.friction = 0.8; //摩擦係数 sphereMat.restitution = 0.5; //反発係数 selfObj = new CANNON.Body({mass: 1}); //ボディを作成 selfObj.material = sphereMat; //ボディにマテリアルを設定 selfObj.addShape(sphereShape); //球体を作成 selfObj.position.x = selfData.posX; //初期位置を設定 selfObj.position.y = selfData.height; //初期位置を設定 selfObj.position.z = selfData.posY; //初期位置を設定 world.add(selfObj); //物理世界に追加 return world; } function setView() { var scene = new THREE.Scene(); //Three.jsの世界(シーン)を作成 scene.fog = new THREE.Fog(0x000000, 1, 100); //フォグ(黒色)を作成 //カメラ var camera = new THREE.PerspectiveCamera(90, 800 / 600, 0.1, 10000); //カメラの位置を設定 camera.position.set(Math.cos(Math.PI / 5) * 30, 5, Math.sin(Math.PI / 5) * 80); changeLookAt( camera ); //カメラの注視点を設定 scene.add(camera); //ライト var light = new THREE.DirectionalLight(0xffffff, 0.5); light.position.set(10, 10, -10); //光源位置 light.castShadow = true; //影を作る light.shadowMapWidth = 2024; //影の精細さ(解像度) light.shadowMapHeight = 2024; light.shadowCameraLeft = -50; //ライト視点方向の影の表示度合い light.shadowCameraRight = 50; light.shadowCameraTop = 50; light.shadowCameraBottom = -50; light.shadowCameraFar = 100; //影の範囲 light.shadowCameraNear = 0; light.shadowDarkness = 0.5; //影の透明度 scene.add(light); var amb = new THREE.AmbientLight(0xffffff); //全体に光を当てる光源 scene.add(amb); //壁オブジェクト作成 for( cnt2=0; cnt2<boxObjArray.length; cnt2++){ thrBoxArray[cnt2] = makeThreeBox( [boxObjArray[cnt2].posX, boxObjArray[cnt2].posY, boxObjArray[cnt2].posZ ], [boxObjArray[cnt2].sizeX, boxObjArray[cnt2].sizeY, boxObjArray[cnt2].sizeZ] ); scene.add(thrBoxArray[cnt2]); } //地面の形状 var graMeshGeometry = new THREE.PlaneGeometry(300, 300); var graMaterial = new THREE.MeshBasicMaterial({ map: ground_texture }); var viewPlane = new THREE.Mesh(graMeshGeometry, graMaterial); viewPlane.rotation.x = -Math.PI / 2; //地面を回転 viewPlane.position.y = 1 / 2; //地面の位置を設定 viewPlane.receiveShadow = true; //地面に影を表示する scene.add(viewPlane); //レンダラー var renderer = new THREE.WebGLRenderer({antialias: true}); //描画sizeは、ブラウザ全体 renderer.setSize(wSizeWidth, wSizeHeight); renderer.setClearColor(0xffffff, 1); renderer.shadowMapEnabled = true; document.body.appendChild(renderer.domElement); renderer.render(scene, camera); return [renderer, scene, camera]; } function animate() { requestAnimationFrame(animate); // 物理エンジンの時間を進行 world.step(1 / 60); //カメラ位置の設定 camera.position.set(selfObj.position.x, selfObj.position.y + 1.6, selfObj.position.z); // レンダリング renderer.render(scene, camera); } //操作ボタン changeBtnPos(wSizeWidth,wSizeHeight); //ボタン位置の変更 $('#forward').click(function(e) { forward(); }); $('#stop').click(function(e) { stop(); }); $('#back').click(function(e) { back(); }); $('#jump').click(function(e) { stop(); selfObj.velocity.y = 10; //ジャンプ時の上方向加速度 }); $('#turn_right').click(function(e) { selfData.angle += 5; stop(); changeLookAt(camera); }); $('#turn_left').click(function(e) { selfData.angle -= 5; stop(); changeLookAt(camera); }); //前進 function forward(){ var theta = selfData.angle / 180 * Math.PI; selfObj.velocity.x = Math.cos(theta) * selfData.speed; selfObj.velocity.z = Math.sin(theta) * selfData.speed; } //停止 function stop(){ selfObj.velocity.x = 0; selfObj.velocity.z = 0; } //後進 function back(){ var theta = selfData.angle / 180 * Math.PI; selfObj.velocity.x = -1 * Math.cos(theta); selfObj.velocity.z = -1 * Math.sin(theta); } //注視点を設定 function changeLookAt(camera){ var theta = selfData.angle / 180 * Math.PI; var posX = selfData.posX + Math.cos(theta) * 10000; var posY = selfData.posY + Math.sin(theta) * 10000; camera.lookAt(new THREE.Vector3(posX, 0, posY)); } //ボタン位置の変更 function changeBtnPos(wSizeWidth,wSizeHeight){ var btn_size = 100; //set button position $('#turn_right').css('top', wSizeHeight - (btn_size + 5)); $('#turn_right').css('left', (btn_size + 10)); $('#turn_left').css('top', wSizeHeight - (btn_size + 5)); $('#turn_left').css('left', 5); $('#back').css('top', (wSizeHeight - btn_size) - 5); $('#back').css('left', (wSizeWidth - btn_size) - 5); $('#stop').css('top', (wSizeHeight - (btn_size * 2)) - (5 * 2)); $('#stop').css('left', (wSizeWidth - btn_size) - 5); $('#forward').css('top', (wSizeHeight - (btn_size * 3)) - (5 * 3)); $('#forward').css('left', (wSizeWidth - btn_size) - 5); $('#jump').css('top', (wSizeHeight - (btn_size * 4)) - (5 * 4)); $('#jump').css('left', (wSizeWidth - btn_size) - 5); } // mode==0 function makeThreeBox( pos_xyz, size_xyz ){ var retObj = null; var thrBox = null; var canBox = null; //Three.jsのオブジェクトを作成 thrBox = new THREE.Mesh( new THREE.BoxGeometry(size_xyz[0],size_xyz[1],size_xyz[2], 10, 10), new THREE.MeshBasicMaterial( {map: wall_texture, //color: color }) ); thrBox.castShadow = true; thrBox.receiveShadow = true; thrBox.position.x = pos_xyz[0]; thrBox.position.y = pos_xyz[1] + ( pos_xyz[1] /2 ); thrBox.position.z = pos_xyz[2]; return thrBox; } function makeCannonBox( pos_xyz, size_xyz, veloc_xyz, angVeloc_xyz, mass, dampVal){ //cannon.jsのオブジェクトを作成 var canBox = new CANNON.Body({mass: mass}); canBox.addShape( new CANNON.Box( new CANNON.Vec3(size_xyz[0]/2, size_xyz[1]/2, size_xyz[2]/2) ) ); canBox.position.set(pos_xyz[0],pos_xyz[1],pos_xyz[2]); canBox.velocity.set(veloc_xyz[0],veloc_xyz[1],veloc_xyz[2]); canBox.angularVelocity.set( angVeloc_xyz[0],angVeloc_xyz[1],angVeloc_xyz[2] ); canBox.angularDamping = dampVal; return canBox; } function createBoxObject( pos_xyz ){ var box = {}; box.posX = pos_xyz[0]; box.posY = pos_xyz[1]; box.posZ = pos_xyz[2]; box.sizeX = 1; box.sizeY = 3; box.sizeZ = 1; box.velocX = box.velocY = box.velocZ = 0; box.angVelocX = box.angVelocY = box.angVelocZ = 0; box.mass = 0; box.dampVal = 0; box.color = 0x000000; return box; }
独自domain & aws s3 の 静的ウェブサイトホスティング に対し、 httpsを有効にするには、cloud front 経由とする必要がありますが、 cloud frontの構成は、自身で構築実績がなかった為、hands-on 。
▲以下に順を記載していますが、細かい点で理解できていない部分もあります。
▲httpへの接続requestを強制的?に、https化したかったのですが、実施方法不明
目次
cloud front 経由の構築に慣れていませんので、以下のステップで進めます。
※太線部は、前STEPからの変更箇所です
┌──────────────────────────────────┐ │【AWS S3】 │ │bucket name: s3webtest.end0tknr.com │ │url; s3webtest.end0tknr.com.s3-website-ap-northeast-1.amazonaws.com │ └─┬────────────────────────────────┘ │http ┌─┴────────────────────────────────┐ │【USER】 │ └──────────────────────────────────┘
┌──────────────────────────────────┐ │【AWS S3】 │ │bucket name: s3webtest.end0tknr.com │ │url; s3webtest.end0tknr.com.s3-website-ap-northeast-1.amazonaws.com │ └─┬────────────────────────────────┘ │http ┏━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃【Route 53】DNS ┃ ┃s3webtest.end0tknr.com ┃ ┃ -(CNAME)-> s3-website-ap-northeast-1.amazonaws.com ┃ ┗━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │http ┌─┴────────────────────────────────┐ │【USER】 │ └──────────────────────────────────┘
┌──────────────────────────────────┐ │【AWS S3】 │ │bucket name: s3webtest.end0tknr.com │ │url; s3webtest.end0tknr.com.s3-website-ap-northeast-1.amazonaws.com │ └─┬────────────────────────────────┘ │http ┏━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃【Cloud Front】CDN ┃ ┃Origin domain: ┃ ┃ s3webtest.end0tknr.com.s3.ap-northeast-1.amazonaws.com ┃ ┗━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │http(s) ┌─┴────────────────────────────────┐ │【USER】 │ └──────────────────────────────────┘
┌──────────────────────────────────┐ │【AWS S3】 │ │bucket name: s3webtest.end0tknr.com │ │url; s3webtest.end0tknr.com.s3-website-ap-northeast-1.amazonaws.com │ └─┬────────────────────────────────┘ │http ┌──────────────────────────────────┐ │【Cloud Front】CDN │ │Origin domain: │ │ s3webtest.end0tknr.com.s3.ap-northeast-1.amazonaws.com │ └─┬────────────────────────────────┘ │http(s) ┏━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃【Route 53】DNS ┃ ┃s3webtest.end0tknr.com ┃ ┃ -(CNAME)-> s3-website-ap-northeast-1.amazonaws.com ┃ ┗━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┏━┷━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃【 Certificate Manager】SSL ┃ ┃for s3webtest.end0tknr.com at N. Virginia , us-east-1 ┃ ┗━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ │http(s) ┌─┴────────────────────────────────┐ │【USER】 │ └──────────────────────────────────┘
します。
今回は、「独自domain」=「バケット名」=「s3webtest.end0tknr.com」で進めます。
バケット名以外の「プロパティ」や「アクセス許可」は、 この後、設定変更しますので、全てdefaultで作成してかまいません。
します。
バケットプロパティ画面の下部に、静的ウェブサイトホスティングの欄がありますので、 以下の内容で設定してください。
項目 | 内容 |
---|---|
静的ウェブサイトホスティング | 有効にする |
ホスティングタイプ | 静的ウェブサイトをホストする |
インデックスドキュメント | index.html error.html |
リダイレクトルール オプション | ※ 以下、参照 |
今回の場合、リダイレクトルール オプションにおいて ファイルが見つからない404エラー時に、error.html へredirectさせています。
[ { "Condition": {"HttpErrorCodeReturnedEquals": "404"}, "Redirect" : {"ReplaceKeyWith": "error.html" } } ]
その他のS3によるリダイレクトルールは、 例えば、以下のurlが分かりやすいです。
s3でURLリダイレクトするときの設定まとめ - Qiita
↑この画面を下へスクロースすると、↓この設定欄が現れます。
「このバケットのブロックパブリックアクセス設定」では 【内容を理解していませんが】全て OFFとしています。
また「バケットポリシー」では、以下を設定します。
※ Resource にあるバケット名以外は、他でも流用可能なルールです。
{ "Version":"2012-10-17", "Statement":[ { "Sid":"TestAwsS3WebHosting", "Effect":"Allow", "Principal": "*", "Action":["s3:GetObject"], "Resource":["arn:aws:s3:::s3webtest.end0tknr.com/*"] } ] }
バケットプロパティにおける静的ウェブサイトホスティング設定が完了すると、 以下のようなurlが発行されます。
http://s3webtest.end0tknr.com.s3-website-ap-northeast-1.amazonaws.com
先程のSTEP1.3までで、s3 のみの web hosting設定は完了していますので、 index.html , error.html をupload し、ブラウザで http://s3webtest.end0tknr.com.s3-website-ap-northeast-1.amazonaws.com へ、アクセスし、index.html , error.htmlが閲覧できることを確認してください。
STEP1で作成した S3 に独自domainでアクセスする為、 Route53で以下のように設定するだけです。
設定完了後、独自ドメインである http://s3webtest.end0tknr.com へ、 アクセスできることを確認してください。
項目 | 内容 |
---|---|
レコード名 | s3webtest.end0tknr.com |
レコードタイプ | CNAME |
値 | s3-website-ap-northeast-1.amazonaws.com |
このステップでは、Cloud Front → s3 連携を有効にし、 Cloud Front独自のurlで s3へ、アクセスできる状態にします。
Cloud Frontの管理画面にある「Create distribution」ボタンをクリックし、 以下の内容で設定します。
※ 実際の設定画面には、以下の他に様々な項目がありますが、 以下に記載がないものは、デフォルト値で問題ないと思います。
項目 | 値 |
---|---|
Origin domain | s3webtest.end0tknr.com.s3.ap-northeast-1.amazonaws.com |
Origin path | null |
Name | s3webtest.end0tknr.com.s3.ap-northeast-1.amazonaws.com |
S3 bucket access | No |
Enable Origin Shield | No |
項目 | 値 |
---|---|
Path pattern | Default (*) |
Viewer protocol policy | HTTP and HTTPS |
Allowed HTTP methods | GET, HEAD |
項目 | 値 |
---|---|
Price class | Use all edge locations |
AWS WAF web ACL | none |
Supported HTTP versions | HTTP/2 On |
Default root object | index.html |
上記 STEP 3.1 により、Cloud Frontによるurlが発行されますので、 http , https のそれぞれで接続テストを行って下さい。以下、url例
最後に、Cloud Frontに対し、独自domainや、ssl証明書を紐づけます。
まず、Route53で作成済の s3web.end0tknr.com に関する dnsレコードを変更します。
項目 | 値 |
---|---|
レコード名 | s3webtest.end0tknr.com |
レコードタイプ | CNAME |
値 【old】 | s3-website-ap-northeast-1.amazonaws.com |
〃 【new】 | d1ytryj2mno8x5.cloudfront.net |
cloud frontで独自ドメインを利用するには SSL証明書が必要ですので、 Croud Frontの設定画面の Custom SSL certificate 直下にある 「Request certificate」リンクをクリックし、 以下の画面のようにSSL証明書やDNS検証を行ってください。
▲ 画面の注釈の通り、証明書は、 US East (N. Virginia , us-east-1).にある必要があります。
s3web.end0tknr.com を追加し、次の画面で「DNSの検証」を実行。
「DNSの検証」完了後、「Custom SSL certificate」にて取得できたssl証明書を選択.
▼▼▼▼ ▼▼▼▼ ▼▼▼▼ ▼▼▼▼ ▼▼▼▼
SSL証明書が発行されば、Croud Frontの設定画面で、 CNAME & SSL証明書を登録し、全ての作業が完了です。
最後に http , https のそれぞれで接続テストを行って下さい。以下、url例
ほ~ 初回はそんなに遅くなるんですね。
wgetの --save-cookies オプション により、以下のようなタブ区切りファイルで cookieが保存されますが、同様の書式で cookies.txt を準備します。
# HTTP Cookie File # Generated by Wget on 2021-07-29 13:22:10. # Edit at your own risk. .sexy.co.jp FALSE / FALSE 1830124283 neoxmileauthticket3766 hogehogeticket .sexy.co.jp FALSE / FALSE 1830124283 neoxmilesearchinittype user
以下の通りで、 cygwin に付属する wget でも同様に動作します。
$ wget --mirror \ --keep-session-cookies \ --load-cookies=cookies.txt \ --secure-protocol tlsv1 \ --no-check-certificate \ --random-wait \ --tries=5 \ --timestamping \ --convert-links \ --convert-file-only \ --page-requisites \ --reject=pdf,zip,xls,xlsx,xlsm,ppt,pptx,doc,docx,mp3,mp4,wmv,wav,mov,mpg,tif,exe \ --user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Firefox/78.0" \ http://www.jbnk.sexy.co.jp/jb/index_a.html
更?に、上記2 entryの続きです。
内容は、上記entryに似ていますが、osが前回のcent に対し、今回のrhelですので、 微妙に異なる点がありました。
以下を yum インストール。
$ sudo yum install gcc $ sudo yum install git $ sudo yum install openssl-devel $ sudo yum install ncurses-devel $ sudo yum install libtirpc-devel
cmakeは、新しいverが欲しかった為、srcより、インストール。
$ wget https://github.com/Kitware/CMake/releases/download/v3.21.0/cmake-3.21.0.tar.gz $ tar -xvf cmake-3.21.0.tar.gz $ cd cmake-3.21.0 $ ./configure $ make $ make test $ sudo make install
centosにおいて rpcgen ( rpcsvc-proto )は、devtoolset に含まれるようですが、 rhelにおける devtoolset のインストールが不明でしたので、srcよりインストール。
$ sudo yum install automake $ sudo yum install gettext* $ wget https://github.com/thkukuk/rpcsvc-proto/archive/refs/tags/v1.4.2.tar.gz $ tar -xvf v1.4.2.tar.gz $ cd rpcsvc-proto-1.4.2 $ ./autogen.sh $ ./configure $ make $ make test $ sudo make install
$ tar -xvf mysql-boost-5.7.34.tar.gz $ cd /home/end0tknr/tmp/mysql-5.7.34 $ /usr/local/bin/cmake . \ -DCMAKE_INSTALL_PREFIX=/usr/local/mysql \ -DDEFAULT_CHARSET=utf8 \ -DDEFAULT_COLLATION=utf8_general_ci \ -DENABLED_LOCAL_INFILE=true \ -DWITH_INNOBASE_STORAGE_ENGINE=1 \ -DWITH_EXTRA_CHARSETS=all \ -DWITH_READLINE=ON \ -DDOWNLOAD_BOOST=ON \ -DWITH_BOOST=/home/end0tknr/tmp/mysql-5.7.34/boost \ -DFORCE_INSOURCE_BUILD=1 \ -DWITH_SYSTEMD=ON $ make $ make test $ sudo make install
mysql5.7 をsrcからinstall - end0tknr's kipple - web写経開発
上記エントリと同様ですので、省略します。
$ sudo groupadd mysql $ sudo useradd -r -g mysql mysql
以前、行った際のosと異なることの影響でしょうか、 いくつか mkdir しました。
# su - mysql $ mkdir /home/mysql/data
# mkdir /var/run/mysqld # chown mysql:mysql /var/run/mysqld
$ sudo su - mysql $ /usr/local/mysql/bin/mysqld --initialize
# cd /etc/systemd/system # cp /home/end0tknr/tmp/mysql-5.7.34/scripts/mysqld.service . # systemctl enable mysqld # systemctl start mysqld
mysql8と異なり、pwなしで、すぐに接続できます。
$ /usr/local/mysql/bin/mysql mysql> create database test; Query OK, 1 row affected (0.00 sec) mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sys | | test | +--------------------+ 5 rows in set (0.01 sec)
install java6 to rhel8 , use via alternatimes - end0tknr's kipple - web写経開発
上記エントリの続きです。
と言っても、apache-tomcat-6.0.53.tar.gz のダウンロード & 解凍のみ。
$ sudo su - # cd /usr/local # mkdir tomcat # cd tomcat # wget https://archive.apache.org/dist/tomcat/tomcat-6/v6.0.53/bin/apache-tomcat-6.0.53.tar.gz # tar -xvf apache-tomcat-6.0.53.tar.gz
# alternatives --install /usr/local/tomcat_home tomcat_home /usr/local/tomcat/apache-tomcat-6.0.53 1 # alternatives --config tomcat_home
特にJAVA_HOMEを必要としますので、setenv.sh を作成
# /usr/local/tomcat_home/bin/setenv.sh export JAVA_HOME=/usr/local/java_home export PATH=$JAVA_HOME/bin:$PATH export CATALINA_HOME=/usr/local/tomcat_home/ # chmod 755 /usr/local/tomcat_home/bin/setenv.sh
# useradd -s /sbin/nologin tomcat # chown -R tomcat:tomcat /usr/local/tomcat
# vi /etc/systemd/system/tomcat.service [Unit] Description=Apache Tomcat 6 After=network.target [Service] User=tomcat Group=tomcat Type=oneshot PIDFile=/usr/local/tomcat_home/tomcat.pid RemainAfterExit=yes ExecStart=/usr/local/tomcat_home/bin/startup.sh ExecStop=/usr/local/tomcat_home/bin/shutdown.sh [Install] WantedBy=multi-user.target # chmod 755 /etc/systemd/system/tomcat.service # systemctl enable tomcat # systemctl start tomcat
# vi /usr/local/tomcat_home/conf/tomcat-users.xml 以下、2行を追加 <role rolename="manager-gui"/> <user username="admin" password="ないしょ" roles="manager-gui"/> # systemctl restart tomcat
以上
$ cat /etc/redhat-release Red Hat Enterprise Linux release 8.4 (Ootpa) $ uname --all Linux rhel8.a5.jp 4.18.0-305.el8.x86_64 #1 SMP Thu Apr 29 08:54:30 EDT 2021 x86_64 x86_64 x86_64 GNU/Linux
download java6 from https://www.oracle.com/java/technologies/oracle-java-archive-downloads.html
と言っても、自己解凍ファイルの jdk-6u45-linux-x64.bin を実行するだけ。
$ sudo su - # cd /usr/local # mkdir java # cd java # cp ~end0tknr/tmp/jdk-6u45-linux-x64.bin . # ./jdk-6u45-linux-x64.bin Unpacking... Checksumming... Extracting... UnZipSFX 5.50 of 17 February 2002, by Info-ZIP (Zip-Bugs@lists.wku.edu). creating: jdk1.6.0_45/ creating: jdk1.6.0_45/db/ creating: jdk1.6.0_45/db/bin/ inflating: jdk1.6.0_45/db/bin/ij inflating: jdk1.6.0_45/db/bin/NetworkServerControl inflating: jdk1.6.0_45/db/bin/setNetworkClientCP.bat inflating: jdk1.6.0_45/db/bin/setEmbeddedCP.bat <略> creating: jdk1.6.0_45/include/linux/ inflating: jdk1.6.0_45/include/linux/jawt_md.h inflating: jdk1.6.0_45/include/linux/jni_md.h inflating: jdk1.6.0_45/include/jvmti.h inflating: jdk1.6.0_45/include/jawt.h inflating: jdk1.6.0_45/include/jdwpTransport.h inflating: jdk1.6.0_45/include/classfile_constants.h inflating: jdk1.6.0_45/COPYRIGHT Creating jdk1.6.0_45/jre/lib/rt.jar Creating jdk1.6.0_45/jre/lib/jsse.jar Creating jdk1.6.0_45/jre/lib/charsets.jar Creating jdk1.6.0_45/lib/tools.jar Creating jdk1.6.0_45/jre/lib/ext/localedata.jar Creating jdk1.6.0_45/jre/lib/plugin.jar Creating jdk1.6.0_45/jre/lib/javaws.jar Creating jdk1.6.0_45/jre/lib/deploy.jar Done. #
rhel8では、libnsl.so が含まれなくなったらしく、 以下を参考に yum で、これをインストール。
RHEL 8へのインストール中に「libnsl.so.1 が必要ですが、見つかりません」メッセージが表示される
$ /usr/local/java/jdk1.6.0_45/bin/java -version Error occurred during initialization of VM Unable to load native library: libnsl.so.1: cannot open shared object file: No such file or directory $ sudo yum install /lib64/libnsl.so.1 $ /usr/local/java/jdk1.6.0_45/bin/java -version java version "1.6.0_45" Java(TM) SE Runtime Environment (build 1.6.0_45-b06) Java HotSpot(TM) 64-Bit Server VM (build 20.45-b01, mixed mode)
# alternatives --install /usr/local/java_home java_home /usr/local/java/jdk1.6.0_45 1 # alternatives --config java_home There is 1 program that provides 'java_home'. Selection Command ----------------------------------------------- *+ 1 /usr/local/java/jdk1.6.0_45 # vi /etc/bashrc export JAVA_HOME=/usr/local/java_home export PATH=$PATH:$JAVA_HOME/bin export CLASSPATH=.:$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jar $ which java /usr/local/java_home/bin/java
Red Hat Enterprise Linux 8 を試用しますが、今後もきっと、忘れるので、メモ
$ cat /etc/redhat-release Red Hat Enterprise Linux release 8.4 (Ootpa) $ sudo yum install samba Updating Subscription Management repositories. Unable to read consumer identity This system is not registered to Red Hat Subscription Management. You can use subscription-manager to register. Error: There are no enabled repositories in "/etc/yum.repos.d", "/etc/yum/repos.d", "/etc/distro.repos.d".
ブラウザで redhatへ、アクセスすることでも可能なようですが、試していません
$ sudo subscription-manager register [sudo] password for end0tknr: Registering to: subscription.rhsm.redhat.com:443/subscription Username: end0tknr Password: The system has been registered with ID: 74cc7463-bffe-4e49-b8c6-f97088a30def The registered system name is: rhel8.a5.jp [end0tknr@rhel8 tmp]$ sudo subscription-manager list +-------------------------------------------+ Installed Product Status +-------------------------------------------+ Product Name: Red Hat Enterprise Linux for x86_64 Product ID: 479 Version: 8.4 Arch: x86_64 Status: Not Subscribed Status Details: Not supported by a valid subscription. Starts: Ends: $ sudo subscription-manager list --available +-------------------------------------------+ Available Subscriptions +-------------------------------------------+ Subscription Name: Red Hat Developer Subscription for Individuals Provides: Red Hat Developer Tools (for RHEL Server for ARM) Red Hat Software Collections (for RHEL Server for ARM) Red Hat Ansible Engine JBoss Enterprise Application Platform from RHUI Red Hat CodeReady Linux Builder for IBM z Systems - Extended Update Support Red Hat JBoss AMQ Interconnect JBoss Enterprise Application Platform JBoss Enterprise Web Server from RHUI Red Hat Enterprise Linux for IBM z Systems - Extended Update Support Red Hat Container Development Kit Red Hat Beta RHEL for SAP (for IBM Power LE) - Update Services for SAP Solutions Red Hat OpenShift Container Platform MRG Realtime Red Hat JBoss Data Grid dotNET on RHEL (for RHEL Server) Red Hat CodeReady Linux Builder for x86_64 - Extended Update Support Red Hat OpenShift Enterprise JBoss A-MQ add-on Red Hat OpenShift Application Runtimes Beta Red Hat Enterprise Linux High Availability - Update Services for SAP Solutions Oracle Java (for RHEL Server) Red Hat Enterprise Linux Resilient Storage for x86_64 Red Hat Software Collections (for RHEL Server) Red Hat Enterprise Linux for ARM 64 JBoss Enterprise Web Platform Red Hat Enterprise Linux for Real Time Red Hat CodeReady Linux Builder for ARM 64 Red Hat Developer Tools (for RHEL Server) Red Hat Developer Tools Beta (for RHEL Server) Red Hat Enterprise Linux for x86_64 Red Hat Enterprise Linux Resilient Storage for IBM z Systems - Extended Update Support Red Hat Enterprise Linux High Performance Networking (for RHEL Compute Node) Red Hat S-JIS Support (for RHEL Server) - Extended Update Support dotNET on RHEL Beta (for RHEL Server) Red Hat CodeReady Linux Builder for x86_64 Red Hat Enterprise Linux for SAP HANA for x86_64 RHEL for SAP HANA - Update Services for SAP Solutions Red Hat Enterprise Linux Scalable File System (for RHEL Server) - Extended Update Support RHEL for SAP HANA - Extended Update Support Red Hat Container Images Beta Red Hat Ansible Automation Platform Red Hat Enterprise Linux Atomic Host Beta Red Hat JBoss Core Services Red Hat Container Images Red Hat Enterprise Linux Load Balancer (for RHEL Server) Red Hat Developer Suite v.3 Red Hat CodeReady Workspaces for OpenShift Red Hat OpenShift Enterprise JBoss EAP add-on Red Hat Openshift Application Runtimes for IBM Power LE Red Hat EUCJP Support (for RHEL Server) - Extended Update Support Red Hat Enterprise Linux High Availability for x86_64 Red Hat Enterprise Linux Load Balancer (for RHEL Server) - Extended Update Support Red Hat Openshift Application Runtimes Red Hat Enterprise Linux High Availability (for IBM z Systems) - Extended Update Support Red Hat Enterprise Linux Resilient Storage for x86_64 - Extended Update Support Red Hat Enterprise Linux High Availability for x86_64 - Extended Update Support Red Hat Enterprise Linux Server - Update Services for SAP Solutions Red Hat JBoss Middleware Red Hat Migration Toolkit Red Hat Enterprise Linux High Performance Networking (for RHEL Server) Red Hat Enterprise Linux Scalable File System (for RHEL Server) Red Hat Enterprise Linux High Performance Networking (for RHEL Server) - Extended Update Support Red Hat Enterprise Linux EUS Compute Node RHEL for SAP - Update Services for SAP Solutions Oracle Java (for RHEL Server) - Extended Update Support Red Hat Enterprise Linux Atomic Host OpenJDK Java (for Middleware) JBoss Operations Network from RHUI Red Hat JBoss AMQ Clients Red Hat 3scale API Management Platform Red Hat Software Collections Beta (for RHEL Server) Red Hat Enterprise Linux Server Red Hat Enterprise Linux for SAP Applications for x86_64 Red Hat Enterprise Linux for x86_64 - Extended Update Support RHEL for SAP - Extended Update Support Red Hat Developer Toolset (for RHEL Server) Red Hat Software Collections Beta (for RHEL Server for ARM) Red Hat JBoss Core Services from RHUI Red Hat Developer Tools Beta (for RHEL Server for ARM) Red Hat OpenShift Enterprise JBoss FUSE add-on Red Hat Build of Quarkus Red Hat OpenShift Enterprise JBoss EAP add-on Beta SKU: RH00798 Contract: Pool ID: 2c9280817a7d8db6017ab9bdb6281e5b Provides Management: No Available: 16 Suggested: 1 Service Type: Roles: Red Hat Enterprise Linux Server Red Hat Enterprise Linux Workstation Red Hat Enterprise Linux Compute Node Service Level: Self-Support Usage: Development/Test Add-ons: Subscription Type: Standard Starts: 07/18/2021 Ends: 07/18/2022 Entitlement Type: Physical Subscription Name: 60 Day Product Trial of Red Hat Enterprise Linux Server with Smart Management, Monitoring, and all Add-Ons, Self-Supported (Physical or Virtual Nodes) Provides: dotNET on RHEL Beta (for RHEL Server) Red Hat Satellite Red Hat CodeReady Linux Builder for x86_64 Red Hat Ansible Engine Red Hat Enterprise Linux Scalable File System (for RHEL Server) - Extended Update Support Red Hat Container Images Beta Red Hat Enterprise Linux Atomic Host Beta Red Hat Container Images Red Hat Enterprise Linux Load Balancer (for RHEL Server) Red Hat Beta Red Hat Enterprise Linux High Availability for x86_64 Red Hat Enterprise Linux Load Balancer (for RHEL Server) - Extended Update Support dotNET on RHEL (for RHEL Server) Red Hat CodeReady Linux Builder for x86_64 - Extended Update Support Red Hat Enterprise Linux Resilient Storage for x86_64 - Extended Update Support Red Hat Enterprise Linux High Availability for x86_64 - Extended Update Support Oracle Java (for RHEL Server) Red Hat Enterprise Linux Resilient Storage for x86_64 Red Hat Software Collections (for RHEL Server) Red Hat Satellite Capsule Red Hat Enterprise Linux High Performance Networking (for RHEL Server) Red Hat Enterprise Linux Scalable File System (for RHEL Server) Red Hat Enterprise Linux High Performance Networking (for RHEL Server) - Extended Update Support Oracle Java (for RHEL Server) - Extended Update Support Red Hat Enterprise Linux Atomic Host Red Hat Developer Tools (for RHEL Server) Red Hat Software Collections Beta (for RHEL Server) Red Hat Enterprise Linux Server Red Hat Developer Tools Beta (for RHEL Server) Red Hat Enterprise Linux for x86_64 Red Hat Enterprise Linux for x86_64 - Extended Update Support Red Hat Developer Toolset (for RHEL Server) SKU: RH00066 Contract: 12738638 Pool ID: 8a85f99f7aaf7dc9017ab861e8f33915 Provides Management: Yes Available: 2 Suggested: 1 Service Type: Roles: Red Hat Enterprise Linux Server Service Level: Self-Support Usage: Development/Test Add-ons: Subscription Type: Instance Based Starts: 07/18/2021 Ends: 09/16/2021 Entitlement Type: Physical $ sudo subscription-manager subscribe --pool=8a85f99f7aaf7dc9017ab861e8f33915 ※ subscribeは attach だったかも Successfully attached a subscription for: 60 Day Product Trial of Red Hat Enterprise Linux Server with Smart Management, Monitoring, and all Add-Ons, Self-Supported (Physical or Virtual Nodes) $ sudo subscription-manager list +-------------------------------------------+ Installed Product Status +-------------------------------------------+ Product Name: Red Hat Enterprise Linux for x86_64 Product ID: 479 Version: 8.4 Arch: x86_64 Status: Subscribed Status Details: Starts: 07/18/2021 Ends: 09/16/2021
$ sudo yum install samba Updating Subscription Management repositories. Red Hat Enterprise Linux 8 for x86_64 - BaseOS (RPMs) 17 MB/s | 34 MB 00:02 Red Hat Enterprise Linux 8 for x86_64 - AppStream (RPMs) 16 MB/s | 31 MB 00:01 Dependencies resolved. ========================================================================================== Package Arch Version Repository Size ========================================================================================== Installing: samba x86_64 4.13.3-3.el8 rhel-8-for-x86_64-baseos-rpms 846 k Installing dependencies: avahi-libs x86_64 0.7-20.el8 rhel-8-for-x86_64-baseos-rpms 62 k cups-libs x86_64 1:2.2.6-38.el8 rhel-8-for-x86_64-baseos-rpms 433 k libicu x86_64 60.3-2.el8_1 rhel-8-for-x86_64-baseos-rpms 8.8 M libwbclient x86_64 4.13.3-3.el8 rhel-8-for-x86_64-baseos-rpms 119 k samba-client-libs x86_64 4.13.3-3.el8 rhel-8-for-x86_64-baseos-rpms 5.4 M samba-common noarch 4.13.3-3.el8 rhel-8-for-x86_64-baseos-rpms 218 k samba-common-libs x86_64 4.13.3-3.el8 rhel-8-for-x86_64-baseos-rpms 171 k samba-common-tools x86_64 4.13.3-3.el8 rhel-8-for-x86_64-baseos-rpms 498 k samba-libs x86_64 4.13.3-3.el8 rhel-8-for-x86_64-baseos-rpms 168 k Transaction Summary ========================================================================================== Install 10 Packages Total download size: 17 M Installed size: 58 M Is this ok [y/N]: y Downloading Packages: <以降、省略>
世の中、GA4への移行が進みつつありますが、 以下は前バージョンである UA(Universal Analytics analytics.js)の 内容です。
高度な設定 - ウェブ トラッキング(analytics.js) | Analytics for Web (analytics.js) | Google Developers
google analytics の UA(Universal Analytics) において コンバージョンの目標(到達ページ)を次のように指定した場合、 ブラウザで指定urlにアクセスすることで、GAにコンバージョンが通知されます。
ですが、入力→確認→完了のurlが変わらず、ページ遷移するような画面では、 以下のように ga('create',~); と ga('send','pageview',~); を呼ぶことで、 アクセスした(コンバージョンした)と見なしてくれるらしい。
<!doctype html> <html lang="ja"> <head> <meta charset="utf-8"> <!-- Google Tag Manager --> <script>(function(w,d,s,l,i){ w[l]=w[l]||[];w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'}); var f=d.getElementsByTagName(s)[0], j=d.createElement(s),dl=l!='dataLayer'?'&l=' +l:'';j.async=true;j.src= 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); })(window,document,'script','dataLayer','GTM-ないしょ'); </script><!-- End Google Tag Manager --> </head> <body> <form> <div class="mb-3"> <label for="exampleInputEmail1" class="form-label">Email address</label> <input type="email" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp"/> <div id="emailHelp" class="form-text"> We'll never share your email with anyone else.</div> </div> <button type="button" class="btn btn-primary" onClick="done_contact();">Submit</button> </form> <script> function done_contact(){ var dummy_path = location.pathname + '?status=comp'; ga('create','UA-ないしょ-3','auto'); ga('send', 'pageview', {'page': dummy_path}); } </script> </body> </html>