Newer
Older
2024-Tsubasa / system / threejs_test / video_resume_set_test.html
@tsubasa tsubasa on 24 Jul 2024 15 KB add; file api file
<!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>video_resume_set_test</title>
    <link rel="stylesheet" href="../css/dot.css" type="text/css" />
</head>

<body>
    <div id="WebGL-output">
        <div class="point"></div>
    </div>

    <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";
        import { FBXLoader } from "https://unpkg.com/three@0.126.1/examples/jsm/loaders/FBXLoader.js";

        let camera;
        let scene;
        let renderer;
        let model;
        let moveForward = false;
        let moveBackward = false;
        let moveLeft = false;
        let moveRight = false;
        let moveUp = false;
        let moveDown = false;
        let controls;

        function init() {
            //シーンの作成
            scene = new THREE.Scene();
            scene.background = new THREE.Color(0x111111); // 背景色

            //カメラの作成
            camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
            //カメラセット
            camera.position.set(0, 0, 0); // カメラの位置
            camera.lookAt(new THREE.Vector3(0, 0, 0));

            //ライトの作成
            const light = new THREE.SpotLight(0xffffff, 1.0);
            light.position.set(100, 500, 500);
            scene.add(light);
            light.castShadow = true;

            // 補助線
            // const axesHelper = new THREE.AxesHelper(500);
            // scene.add(axesHelper);
            // const gridHelper = new THREE.GridHelper(15, 15);
            // scene.add(gridHelper);

            // カメラコントロールの作成
            controls = new PointerLockControls(camera, document.body);
            document.addEventListener("click", function () {
                controls.lock();
            });
            // controls.addEventListener("lock", function () { });
            // controls.addEventListener("unlock", function () { });

            // キーボードのキーを押したの際の処理
            document.addEventListener("keydown", function (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 "e":
                        moveUp = true;
                        break;
                    case "q":
                        moveDown = true;
                        break;
                }
            });

            // キーボードのキーを離した際の処理
            document.addEventListener("keyup", function (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;
                    case "e":
                        moveUp = false;
                        break;
                    case "q":
                        moveDown = false;
                        break;
                }
            });

            // レンダラーの作成
            renderer = new THREE.WebGLRenderer({
                alpha: true,
                antialias: true,
            });
            renderer.setSize(window.innerWidth, window.innerHeight);
            renderer.physicallyCorrectLight = true;

            // const mouse = new THREE.Vector2();
            let resumePageCounter = {}; // Class 資料のページ数を記録する
            let videoPlayPauseFlag = {} // Videoの再生停止状況を監視する

            // load videoAndResume.csv
            fetch("../csv/videoAndResume.csv")
                .then((response) => {
                    return response.text();
                })
                .then((data) => {
                    let result = data.split(/\r?\n|\r/).map((e) => {
                        return e.split(",");
                    });
                    console.log(result);
                    console.log(result[1].length);
                    //オブジェクトの作成(初期化)
                    for (let makeNumber = 1; makeNumber < result.length; makeNumber++) {
                        // for (let makeNumber = 1; makeNumber < result.length; makeNumber++) {
                        let videoMesh = makeVideo(makeNumber, result[makeNumber][0], result[makeNumber][1])
                        let resumeMesh = makeResume(result[makeNumber][7], makeNumber)
                        makeGroup(makeNumber, videoMesh, resumeMesh, result[makeNumber][2], result[makeNumber][3],result[makeNumber][4], result[makeNumber][5], result[makeNumber][6]);
                    }
                    console.log(resumePageCounter);

                    // raycaster 
                    document.addEventListener("click", (event) => {
                        event.preventDefault();
                        const raycaster = new THREE.Raycaster();
                        const mouse = new THREE.Vector2();
                        mouse.x = 0;
                        mouse.y = 0;
                        raycaster.setFromCamera(mouse, camera);
                        const intersects = raycaster.intersectObjects(scene.children, true);
                        if (intersects.length > 0) {
                            console.log(intersects[0].object);
                            //resumeのページ切替
                            for (let number = 1; number < result.length; number++) {
                                if (intersects[0].object.name == result[number][7]) { //result[1][0]はmakeNumberと同じ数字になる(result"[1]"[0]の"[1]"の部分は後で変数にする)
                                    resumePageCounter[number] += 1; //resumePageCounter = {makeNumber: pageNumber}
                                    const resumeMesh = makeResume(result[number][resumePageCounter[number] + 7], number);
                                    intersects[0].object.parent.add(resumeMesh);
                                    // console.log(resumePageCounter);
                                }
                                if (resumePageCounter[number] == result[1].length - 8) {
                                    resumePageCounter[number] = -1;
                                    // console.log(resumePageCounter);
                                }
                            }
                            // const planeGeometry = new THREE.PlaneGeometry(16.25, 10);
                            // const planeMaterial = new THREE.MeshBasicMaterial({ color: 0xffff00 });
                            // const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial);
                            // planeMesh.position.set(0, 0, -0.001);
                            // scene.add(planeMesh);
                            //video
                            for (let number = 1; number <= Object.keys(videoPlayPauseFlag).length; number++) {
                                if (intersects[0].object.name == number) {
                                    // console.log(intersects[0].object.children);
                                    let audio = intersects[0].object.children;
                                    let videoTagId = document.getElementById(`${number}`);
                                    // console.log(document.getElementById(number));
                                    startStopVideoAndAudio(number, videoTagId, audio);
                                }
                            }

                        }
                    })
                })
                .catch((error) => {
                    console.log(error);
                });

            function makeGroup(makeNumber, videoMesh, resumeMesh, rotationX, rotationY, x, y, z) {
                resumePageCounter[makeNumber] = 0
                videoPlayPauseFlag[makeNumber] = false

                // videoMeshとresumeMeshのgroup化
                const group = new THREE.Group();
                group.add(videoMesh);
                group.add(resumeMesh);
                group.rotation.x = THREE.MathUtils.degToRad(rotationX)
                group.rotation.y = THREE.MathUtils.degToRad(rotationY);
                group.position.set(x, y, z);
                group.name = `group${makeNumber}`
                scene.add(group);
                console.log(group);

                //objectのサイズとその中心位置を調べる
                // const box3 = new THREE.Box3().setFromObject(group);
                // const objectSize = new THREE.Vector3();
                // box3.getSize(objectSize);
                // console.log(objectSize);
                // box3.getCenter(objectSize);
                // console.log(objectSize);
            }

            function makeVideo(objName, videoPath, audioPath) {
                // 動画オブジェクトの作成
                const video = document.createElement("video"); // videoタグの作成
                document.body.appendChild(video); // videoタグをbodyタグに追加(DOM)
                video.style.display = "none"; // videoがweb画面に表示させないようにする
                video.src = videoPath;
                video.autoplay = false; // 検索エンジンの規約に違反するため自動再生しないようにする
                video.preload = "auto";
                video.loop = true;
                video.muted = true; // 検索エンジンの規約に違反するため動画は動画、音は音で作成する必要があるためミュートにする
                video.id = objName; //idを一意に決定する
                const videoTexture = new THREE.VideoTexture(video);
                videoTexture.minFilter = THREE.LinearFilter;
                videoTexture.magFilter = THREE.LinearFilter;
                videoTexture.wrapS = THREE.ClampToEdgeWrapping;
                videoTexture.wrapT = THREE.ClampToEdgeWrapping;

                const videoGeometry = new THREE.PlaneGeometry(3, 2);
                const videoMaterial = new THREE.MeshBasicMaterial({ map: videoTexture, color: 0xffffff });
                const videoMesh = new THREE.Mesh(videoGeometry, videoMaterial);
                videoMesh.position.set(-0.875, 0, 0);
                videoMesh.name = objName;
                scene.add(videoMesh);
                // console.log(videoMesh);
                // console.log(videoMesh.geometry.parameters.width); //objectの幅

                const audioListener = new THREE.AudioListener();
                camera.add(audioListener);
                const audioLoader = new THREE.AudioLoader();
                const positionalAudio = new THREE.PositionalAudio(audioListener);
                audioLoader.load(audioPath, function (buffer) {
                    positionalAudio.setBuffer(buffer);
                    positionalAudio.setRefDistance(100);
                    positionalAudio.pause(); // 自動再生しないように停止しておく
                    positionalAudio.name = objName; // nameを一意に決定する
                });
                videoMesh.add(positionalAudio);

                return videoMesh
            }

            function makeResume(texturePath, makeNumber) {
                // 資料オブジェクトの作成
                const resumeGeometry = new THREE.BoxGeometry(1.5, 1.5 * Math.sqrt(2), 0.01);
                const loadPhoto = new THREE.TextureLoader().load(texturePath);
                let resumeMaterial = new THREE.MeshBasicMaterial({ map: loadPhoto });
                const resumeMesh = new THREE.Mesh(resumeGeometry, resumeMaterial);
                resumeMesh.castShadow = true;
                resumeMesh.position.set(1.625, 0, 0);
                resumeMesh.name = texturePath;
                scene.add(resumeMesh);
                // console.log(resumeMesh.geometry.parameters.width); //objectの幅

                return resumeMesh;
            }

            // let flag = false;
            function startStopVideoAndAudio(flagNumber, videoTagId, audio) { // trueなら停止 falseなら再生
                if (videoPlayPauseFlag[flagNumber] == false) {
                    videoTagId.play();
                    audio[0].play();
                    videoPlayPauseFlag[flagNumber] = true;
                } else {
                    videoTagId.pause();
                    audio[0].pause();
                    videoPlayPauseFlag[flagNumber] = false;
                }
            }

            //Box Helper
            function boxHelper(object) {
                let box = new THREE.BoxHelper(object, 0xffff00);
                scene.add(box);
            }
            // boxHelper(resumeMesh);
            // boxHelper(videoMesh);
            // boxHelper(group);

            const planeGeometry = new THREE.PlaneGeometry(20, 20);
            const flooringTexture = new THREE.TextureLoader().load("../texture_photo/flooring.jpg")
            flooringTexture.wrapS = THREE.RepeatWrapping;
            flooringTexture.wrapT = THREE.RepeatWrapping;
            flooringTexture.repeat.set(15, 15);
            const planeMaterial = new THREE.MeshBasicMaterial({ map: flooringTexture });
            const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial);
            planeMesh.rotation.x = THREE.MathUtils.degToRad(-90);
            planeMesh.position.set(0, -1.5, 0);
            scene.add(planeMesh);

            // 画面の大きさが変更されたときに動的に修正
            function onWindowResize() {
                camera.aspect = window.innerWidth / window.innerHeight;
                camera.updateProjectionMatrix();
                renderer.setSize(window.innerWidth, window.innerHeight);
            }
            window.addEventListener("resize", onWindowResize);

            document
                .getElementById("WebGL-output")
                .appendChild(renderer.domElement);
        }

        function animate() {
            requestAnimationFrame(animate);
            updateCameraPosition();
            renderer.render(scene, camera);
        }

        function updateCameraPosition() {
            const speed = 0.1; // 移動速度
            //.moveForward(Number) で前、.moveRightで右に
            if (moveForward) controls.moveForward(speed);
            if (moveBackward) controls.moveForward(-speed);
            if (moveRight) controls.moveRight(speed);
            if (moveLeft) controls.moveRight(-speed);
            //getObject()で直接カメラの操作
            //controls.getObject()の時点でカメラのプロパティに切り替わる
            if (moveUp) controls.getObject().position.y += speed;
            if (moveDown) controls.getObject().position.y -= speed;
        }

        // 関数の実行
        window.onload = function () {
            init();
            animate();
        }

    </script>
</body>

</html>