Three.js Cannon.es 調査資料 - スピードメーターとコース地図の表示
この記事のスナップショット
スピードウィンドウあり版
コース地図とスピードのウィンドウあり版
ソース
- ソース一式を WEB サーバ上に配置してください
- 車の操作法
- カーソル上 .. アクセル
- カーソル下 .. バック
- カーソル左、カーソル右 .. ハンドル
- 'b' .. ブレーキ
- 'c' .. カメラ視点の変更
- 'r' .. 姿勢を戻す
- マウス操作 .. カメラ位置の変更
- '1' .. 車変更:FR低出力(デフォルト)
- '2' .. 車変更:FR高出力
- '3' .. 車変更:FF低出力
- '4' .. 車変更:FF高出力
- '5' .. 車変更:4WD低出力
- '6' .. 車変更:4WD高出力
概要
次の記事の布石(エンジンの挙動を確認)として、スピードメーター(デジタル)を表示します。
さらにウィンドウ表示関連として、コース地図(トップビュー:上空から見下ろした視点)を表示します。
やったこと
物理モデル RaycastVehicle には属性に currentVehicleSpeedKmHour があるので、これを走行画面に重ねて表示します。
html 側に スピードメーター表示用の canvas を用意します。
<body>
...
<canvas id="speedCanvas" style="position:fixed; bottom:25px; right:20px; width:200px; height:40px; z-index: 100; background-color:rgba(0,0,255, 0.2);"></canvas>
</body>
javascript 側で 上記のHTML要素を取り出し、2Dコンテキストとして、文字列を表示させます。
function setSpeed(speed) {
const canvas = document.getElementById('speedCanvas');
const ctxspd = canvas.getContext('2d');
canvas.width = 200;
canvas.height = 40;
ctxspd.font = '20px bold sans-serif';
ctxspd.textBaseline = 'alphabetic';
ctxspd.textAlign = 'start';
ctxspd.fillStyle = 'white';
ctxspd.fillText("speed: "+speed, 20, 22);
};
スピードメータの表示例
さて、スピードメーターのウィンドウを重ねられるなら、同様にコース地図(トップビュー:上空から見下ろした視点)も重ねられるよね!
ということでやってみました。
トップビューについては
「Three.js Cannon.es 調査資料 - オフライン化(ライブラリのローカル配置)」
で記事にしてますが、さらに引き(より上空から)の視点とします。
html 側に コース地図用の canvas を用意します。
<body>
...
<canvas id="mapCanvas" style="position:fixed; bottom:25px; left:5px; width:25%; height:25%; z-index: 101; background-color:rgba(0,255,0, 0.2);"></canvas>
</body>
javascript 側では コース地図用の カメラ、シーン、レンダラーを用意します。
function setupWorld2() {
var camera2;
var scene2;
var renderer2;
{
const width = window.innerWidth/4 - 24;
const height = window.innerHeight/4 - 24;
// Camera
camera2 = new THREE.PerspectiveCamera(24, width / height, 5, 2000)
camera2.position.set(0, 20, 30)
camera2.lookAt(0, 0, 0)
// Scene
scene2 = new THREE.Scene()
// Renderer
const canvasElement = document.querySelector("#mapCanvas");
renderer2 = new THREE.WebGLRenderer({ canvas: canvasElement, antialias: true })
renderer2.setSize(width, height);
renderer2.shadowMap.enabled = true
renderer2.shadowMap.type = THREE.PCFSoftShadowMap
// Lights
const ambientLight = new THREE.AmbientLight(0xffffff, 0.2)
scene2.add(ambientLight)
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.15)
directionalLight.position.set(-30, 10000, 30)
directionalLight.target.position.set(0, 0, 0)
scene2.add(directionalLight)
}
return {camera2, scene2, renderer2};
}
コース地図用のシーンに、車代わりのマーカーと地図を追加します。
// scene2 用の車代わりのマーカー
const viVehicleMarkerGeo = new THREE.SphereGeometry(3);
const viVehicleMarkerMtr = new THREE.MeshBasicMaterial({color:0xffffff});
const viVehicleMarkerMesh = new THREE.Mesh(viVehicleMarkerGeo, viVehicleMarkerMtr);
scene2.add(viVehicleMarkerMesh);
const viGround2Geo2 = new THREE.BoxGeometry(grndw*2, 1, grndh*2);
const texture2 = new THREE.TextureLoader().load('./pic/test_course.png');
const viGround2Mtr2 = new THREE.MeshBasicMaterial({map: texture2, transparent: true, opacity: 0.4});
const viGround2Mesh2 = new THREE.Mesh(viGround2Geo2, viGround2Mtr2);
scene2.add(viGround2Mesh2);
あとは、メイン画面の描画更新の後に続けて、コース地図用の更新を追加するだけです。
function animate() {
const timeStep = 1 / 60;
world.step(timeStep)
...
// メイン画面側のレンダラー
renderer.render(scene, camera);
{
// 左下のスピードメーター欄 更新
var speed = vehicle.getSpeed();
speed = parseInt(speed*10)/10.0;
setSpeed(speed);
}
{
viVehicleMarkerMesh.position.copy(vposi);
// 左上 マップ欄 更新
camera2.position.set(vposi.x, vposi.y + 400, vposi.z);
camera2.lookAt(new THREE.Vector3(vposi.x, vposi.y, vposi.z));
var veuler = new CANNON.Vec3(0, 0, 0);
vquat.toEuler(veuler);
var viecleRotY = veuler.y + Math.PI / 2; // X軸負の方向を向いて作成したので、上を向くよう90度ずらす
camera2.rotation.z = viecleRotY;
renderer2.render(scene2, camera2);
}
コース地図の表示例
感想
これを応用すれば以下のようなことも...
- バックミラーで後方の視点を表示
- 両サイドにななめ前方の視点のシーンを配置して、疑似的に広角でワイドな画面
ちょっと夢が広がるとも思ったけど、バックミラーの小さなウィンドウにはコスパが悪いし、広角にしたところで運転時には無駄だなぁと思い至った次第。
リプレイ機能をつけて、見せ方の一つに広角やマルチアングルとかはありかな?
Discussion