<!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>Document</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div id="WebGL-output"></div>
<button id="play-animation">("Ü")</button>
<script type="module">
import * as THREE from "https://unpkg.com/three@0.126.1/build/three.module.js";
import { PointerLockControls } from "https://unpkg.com/three@0.126.1/examples/jsm/controls/PointerLockControls.js";
import { GLTFLoader } from "https://unpkg.com/three@0.126.1/examples/jsm/loaders/GLTFLoader.js";
let camera;
let scene;
let renderer;
let controls;
let moveForward = false;
let moveBackward = false;
let moveLeft = false;
let moveRight = false;
let bChanLoaded = false;
let classroomModel, blackboardModel, bchanModel;
let mixer;
let action;
let clock;
function init() {
scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff);
camera = new THREE.PerspectiveCamera(
45,
window.innerWidth / window.innerHeight,
0.1,
1000
);
camera.position.set(1, 5, 5);
camera.lookAt(new THREE.Vector3(0, 0, 0));
// rendererの初期化を先に行う
renderer = new THREE.WebGLRenderer({
alpha: true,
antialias: true,
});
renderer.setSize(window.innerWidth * 0.8, window.innerHeight * 0.8);
renderer.domElement.style.position = 'absolute';
renderer.domElement.style.left = '10%';
renderer.domElement.style.top = '10%';
document.getElementById("WebGL-output").appendChild(renderer.domElement);
// controlsの初期化
controls = new PointerLockControls(camera, renderer.domElement);
// イベントリスナーの追加
renderer.domElement.addEventListener("click", function () {
controls.lock();
});
const light = new THREE.SpotLight(0xffffff, 1.0);
light.position.set(100, 500, 500);
scene.add(light);
light.castShadow = true;
const loader = new GLTFLoader();
loader.load(
'https://www.yatex.org/gitbucket/j2311/about-Leaflet/raw/main/class_room_final.glb',
function (gltf) {
classroomModel = gltf.scene;
scene.add(classroomModel);
},
function (xhr) {
console.log((xhr.loaded / xhr.total * 100) + '% loaded');
},
function (error) {
console.error('An error happened', error);
}
);
loader.load(
'https://www.yatex.org/gitbucket/j2311/about-Leaflet/raw/main/black_board.glb',
function (gltf) {
blackboardModel = gltf.scene;
scene.add(blackboardModel);
},
function (xhr) {
console.log((xhr.loaded / xhr.total * 100) + '% loaded');
},
function (error) {
console.error('An error happened', error);
}
);
loader.load(
'https://www.yatex.org/gitbucket/j2311/about-Leaflet/raw/main/B-chan_plus_feel.gltf',
function (gltf) {
bchanModel = gltf.scene;
scene.add(bchanModel);
bChanLoaded = true;
mixer = new THREE.AnimationMixer(bchanModel);
if (gltf.animations.length > 0) {
action = mixer.clipAction(gltf.animations[0]);
}
},
function (xhr) {
console.log((xhr.loaded / xhr.total * 100) + '% loaded');
},
function (error) {
console.error('An error happened', error);
}
);
controls = new PointerLockControls(camera, renderer.domElement);
renderer.domElement.addEventListener("click", function () {
controls.lock();
});
document.addEventListener("keydown", handleKeyDown);
document.addEventListener("keyup", handleKeyUp);
renderer = new THREE.WebGLRenderer({
alpha: true,
antialias: true,
});
renderer.setSize(window.innerWidth * 0.8, window.innerHeight * 0.8);
renderer.domElement.style.position = 'absolute';
renderer.domElement.style.left = '10%';
renderer.domElement.style.top = '10%';
document.getElementById("WebGL-output").appendChild(renderer.domElement);
clock = new THREE.Clock();
document.getElementById('play-animation').addEventListener('click', playAnimation);
}
function handleKeyDown(event) {
switch (event.key) {
case "w":
case "ArrowUp":
moveForward = true;
break;
case "s":
case "ArrowDown":
moveBackward = true;
break;
case "a":
case "ArrowLeft":
moveLeft = true;
break;
case "d":
case "ArrowRight":
moveRight = true;
break;
case "g":
if (bChanLoaded) {
bchanModel.position.z -= 0.5;
}
break;
case "b":
if (bChanLoaded) {
bchanModel.position.z += 0.5;
}
break;
case "f":
if (bChanLoaded) {
bchanModel.position.x -= 0.5;
}
break;
case "h":
if (bChanLoaded) {
bchanModel.position.x += 0.5;
}
break;
}
}
function handleKeyUp(event) {
switch (event.key) {
case "w":
case "ArrowUp":
moveForward = false;
break;
case "s":
case "ArrowDown":
moveBackward = false;
break;
case "a":
case "ArrowLeft":
moveLeft = false;
break;
case "d":
case "ArrowRight":
moveRight = false;
break;
}
}
function updateCameraPosition() {
const speed = 5;
const direction = new THREE.Vector3();
const { x, y, z } = controls.getObject().position;
direction.x = Number(moveRight) - Number(moveLeft);
direction.z = Number(moveBackward) - Number(moveForward);
direction.normalize();
const delta = speed * 0.1;
controls.getObject().translateX(direction.x * delta);
controls.getObject().translateZ(direction.z * delta);
}
function animate() {
requestAnimationFrame(animate);
updateCameraPosition();
if (mixer) {
mixer.update(clock.getDelta());
}
renderer.render(scene, camera);
}
function playAnimation() {
if (action) {
action.reset();
action.play();
}
}
document.addEventListener("dblclick", function (event) {
event.preventDefault();
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects(scene.children, true);
if (intersects.length > 0) {
if (intersects[0].object.name === "blackboard_main") {
window.open("https://www.yatex.org/gitbucket/j2311/about-Leaflet/pages/HELPLIST-web.html");
}
console.log(intersects[0]);
}
});
init();
animate();
</script>
</body>
</html>