three.jsで3Dの太陽系をつくってみました。
惑星をクリックすると、回答がでます。
サンプル
HTML
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>太陽系</title>
</head>
<body>
<div id="app">
<div class="question">
<h1>地球はどれですか?</h1>
</div>
<div class="myCanvass">
<canvas id="myCanvas"></canvas>
<p id="kaitou">画像の中の地球をクリックしてください。</p>
</div>
<!-- three.jsを読み込む -->
<script src="https://unpkg.com/three@0.139.2/build/three.min.js"></script>
<script src="https://unpkg.com/three@0.131.3/examples/js/controls/OrbitControls.js"></script>
</div>
</body>
</html>
CSS
* {
margin: 0;
padding: 0;
list-style: none;
box-sizing: border-box;
text-decoration: none
}
.pointer {
cursor: pointer
}
.myCanvass {
position: relative
}
.myCanvass #kaitou {
position: absolute;
bottom: 0;
left: 0;
padding: 25px;
font-size: 24px;
color: #fff;
z-index: 100
}
JavaScript
/* IE11に対応させるためes5にて書いてます。 */
"use strict";
var width,
height,
renderer,
camera,
canvas,
controls,
revolution_speed = 0,
meshList = [],
earthElement,
renderer,
planet = -1,
planet_stop = 0,
box = [],
texture,
loader,
geometry,
material,
stars,
satellite;
// リサイズイベント発生時に実行
onResize();
window.addEventListener("resize", onResize);
// 初期化のために実行
window.addEventListener("DOMContentLoaded", init);
//主要関数
function init() {
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2(); // canvas 要素の参照を取得する
// シーンを作成
var scene = new THREE.Scene();
// カメラコントローラーを作成
controls = new THREE.OrbitControls(camera, earthElement);
//惑星の関数
function Planet(
scr,
planetPosition,
scale,
tex,
satellite,
satellite_src,
satellite_position,
satellite_scale
) {
//惑星
geometry = new THREE.SphereGeometry(scale, scale, scale);
loader = new THREE.TextureLoader();
texture = loader.load(scr);
if (tex) {
material = new THREE.MeshBasicMaterial({
color: 0xffffff,
side: THREE.DoubleSide,
map: texture,
});
} else {
material = new THREE.MeshLambertMaterial({
map: texture,
});
}
box[0] = new THREE.Mesh(geometry, material);
box[0].receiveShadow = true;
box[0].position.x = planetPosition;
scene.add(box[0]);
meshList.push(box[0]);
//衛星
if (satellite) {
geometry = new THREE.SphereGeometry(
satellite_scale,
satellite_scale,
satellite_scale
);
loader = new THREE.TextureLoader();
texture = loader.load(satellite_src);
material = new THREE.MeshLambertMaterial({
map: texture,
});
box[1] = new THREE.Mesh(geometry, material);
box[1].receiveShadow = true;
box[1].position.x = satellite_position;
scene.add(box[1]);
meshList.push(box[1]);
}
}
Planet(baseUrl + "/img/sunmap.jpg", 0, 150, true);
Planet(
baseUrl + "/img/land_ocean_ice_cloud_2048.jpg",
1000,
80,
false,
true,
baseUrl + "/img/moon.jpg",
1500,
50
);
Planet(baseUrl + "/img/image_3337_1e-Jupiter-Map.jpg", 2000, 120, false);
Planet(baseUrl + "/img/saturnmap.jpg", 3000, 80, false);
var boxs = new THREE.Group();
//星
star(1000, 1);
function star(star_count, star_size) {
for (var i = 0; i < star_count; i++) {
geometry = new THREE.SphereGeometry(star_size, star_size, star_size);
material = new THREE.MeshBasicMaterial({
color: 0xffffff,
});
stars = new THREE.Mesh(geometry, material);
stars.position.x = Math.random() * 5000 - 3000;
stars.position.z = Math.random() * 5000 - 3000;
stars.position.y = Math.random() * 5000 - 3000;
scene.add(stars);
}
}
// 平行光源
var light = new THREE.DirectionalLight(0xffffff);
light.intensity = 2; // 光の強さを倍に
light.position.set(1, 100, 1); // シーンに追加
// scene.add(light);
var light2 = new THREE.PointLight(0xffffff, 1.5, 0, 0);
light2.position.set(300, 300, 300);
light.castShadow = true;
scene.add(light2);
// 初回実行
tick();
earthElement.addEventListener("mousemove", handleMouseMove);
function handleMouseMove(event) {
var element = event.currentTarget;
// canvas要素上のXY座標
var x = event.clientX - element.offsetLeft;
var y =
event.clientY -
element.offsetTop -
document.querySelector(".question").getBoundingClientRect().height;
// canvas要素の幅・高さ
var w = element.offsetWidth;
var h = element.offsetHeight;
// -1〜+1の範囲で現在のマウス座標を登録する
mouse.x = (x / w) * 2 - 1;
mouse.y = -(y / h) * 2 + 1;
}
//アニメーションの関数
function tick() {
var intersects = raycaster.intersectObjects(meshList);
requestAnimationFrame(tick);
revolution_speed += 0.001;
// カメラコントローラーを更新
controls.update();
//revolutionHover();
meshList.forEach(function (box) {
box.rotation.y += 0.01;
});
for (var i = 0; i < meshList.length; i++) {
meshList[i].position.x =
Math.cos(revolution_speed + i * 10 * -10) *
(i * 50000) *
(Math.PI / 180);
meshList[i].position.z =
Math.sin(revolution_speed + i * 10 * -10) *
(i * 50000) *
(Math.PI / 180);
meshList[i].rotation.y += 0.001;
}
// レンダリング
renderer.render(scene, camera);
meshList.forEach(function (box) {
box.material.transparent = true;
if (
intersects.length > 0 &&
box === intersects[0].object //&&
//meshList.indexOf(box) > 0
) {
// 透明にする
box.material.opacity = 0.6;
earthElement.classList.add("pointer");
//if(meshList.indexOf(intersects[0]))
planet_stop = 1;
} else {
// それ以外は元の色にする
earthElement.classList.remove("pointer");
box.material.opacity = 1;
}
if (planet_stop == 1) {
planet = meshList.indexOf(box);
planet_stop = 0;
}
console.log("test");
});
//camera.lookAt(meshList[2].position);
raycaster.setFromCamera(mouse, camera);
}
earthElement.addEventListener("click", function () {
var kaitou = document.querySelector("#kaitou");
if (planet == 0) {
kaitou.innerHTML = "それは太陽です";
} else if (planet == 1) {
kaitou.innerHTML = "正解";
} else {
kaitou.innerHTML = "不正解";
}
planet == -1;
});
}
function onResize() {
// カメラを作成
camera = new THREE.PerspectiveCamera(45, width / height, 1, 100000);
camera.position.set(0, 0, +2500);
// レンダラーを作成
earthElement = document.querySelector("#myCanvas");
renderer = new THREE.WebGLRenderer({
canvas: earthElement,
});
// サイズを取得
width = window.innerWidth;
height = window.innerHeight - 100;
// レンダラーのサイズを調整する
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(width, height);
//レンダラーの影を有効
renderer.shadowMap.enabled = true;
// カメラのアスペクト比を正す
camera.aspect = width / height;
camera.updateProjectionMatrix();
}