如何让我的三个.js网站在场景之间切换

How can I get my three.js website to switch between scenes

提问人:Hula J 提问时间:11/16/2023 更新时间:11/16/2023 访问量:22

问:

我有一个三.js网站,它有html,first.js,second.js和一个基本的main.css。

我希望每个场景在自己的 js 文件(first.js/second.js)上完全不同,并且每个新场景都有一个新按钮,用于转到下一个选择的场景。

场景会有所不同,具有不同的导入,不同的元素,无论是三个几何形状、动画和照明,还是带有动画的 glb 加载器和来自 hdr 的 RGBE 背景照明,包括不同的灯光等。

我想要一个简单的逻辑,我可以加载一个全新的场景,并且每次单击按钮时都不会保留任何旧场景。

目前,控制台日志告诉我,这两个场景正在竞争为他们的场景制作动画,一个接一个,但没有严重的控制台错误。

我基本上想执行它,只使用 three.js,而不是暂时使用其他库。

我尝试阅读了很多文档,但找不到任何似乎有效的内容,就像教别人的查询一样。

我尝试将场景 js 文件中的所有内容添加到导出函数 LoadScene1(2、3、4 等)中,以及加载场景、清除场景、加载新场景、为新场景添加导入等的函数。目前,它们很相似,用于发短信。

这是我的文件:

[HTML全文]

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>My three.js app</title>
        <style>
            body { margin: 0; }
        </style>
        <script async src="https://unpkg.com/[email protected]/dist/es-module-shims.js"></script>
        <script type="importmap">
            {
                "imports": {
                    "three": "/node_modules/three/build/three.module.js",
                    "three/addons/": "/node_modules/three/examples/jsm/"
                }
            }
        </script>
    </head>
    <body>
        <div id="container"></div>
        
        <script type="module">
            import * as firstScene from './first.js';
            firstScene.loadScene1();
          </script>
          
    </body>
</html>

第一个.js

import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { RGBELoader } from 'three/addons/loaders/RGBELoader.js';
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';
import { AnimationMixer } from 'three';
import { loadScene2 } from './second.js';


export function loadScene1() {
    let camera1, scene1, renderer1, mixer1, currentModel;
    let isPaused = true;
    let container1;
    let orbitControls;

    const gltfPath = 'models/gltf/VinylCover/glTF/';

    init();
    startAnimation();

    function createButton(text, onClick) {
        const button = document.createElement('button');
        button.innerHTML = text;
        button.style.position = 'absolute';
        button.style.top = '10px';
        button.style.left = '10px';
        button.addEventListener('click', () => onClick());
        return button;
    }
    

    function startAnimation() {
        if (isPaused) {
            isPaused = false;
            mixer1.timeScale = 1;
        } else {
            isPaused = true;
            mixer1.timeScale = 0;
        }
    }

    function init() {
        container1 = document.createElement('container');
        document.body.appendChild(container1);
        console.log('Container element:', container1);

        camera1 = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.25, 20);
        camera1.position.set(30, 30, 30);
        console.log('Camera Created:', camera1);

        scene1 = new THREE.Scene();

        const hemiLight1 = new THREE.HemisphereLight(0xffffff, 0xffffff, 1);
        hemiLight1.color.setHSL(0.6, 1, 0.6);
        hemiLight1.groundColor.setHSL(0.095, 1, 0.75);
        hemiLight1.position.set(0, 50, 0);
        scene1.add(hemiLight1);
        console.log('hemilight created:', container1);

        const dirLight1 = new THREE.DirectionalLight(0xffffff, 2);
        dirLight1.color.setHSL(0.1, 1, 0.95);
        dirLight1.position.set(0.5, 0.5, 2);
        dirLight1.position.multiplyScalar(30);
        scene1.add(dirLight1);
        console.log('dirlight created:', container1);

        dirLight1.castShadow = true;
        dirLight1.shadow.mapSize.width = 2048;
        dirLight1.shadow.mapSize.height = 2048;

        const d = 50;
        dirLight1.shadow.camera.left = -d;
        dirLight1.shadow.camera.right = d;
        dirLight1.shadow.camera.top = d;
        dirLight1.shadow.camera.bottom = -d;
        dirLight1.shadow.camera.far = 3500;
        dirLight1.shadow.bias = -0.0001;

        new RGBELoader()
            .setPath('textures/equirectangular/')
            .load('sky14k.hdr', function (texture) {
                texture.mapping = THREE.EquirectangularReflectionMapping;
                scene1.background = texture;
                scene1.environment = texture;

                loadModel();
            });

        renderer1 = new THREE.WebGLRenderer({ antialias: true });
        renderer1.setPixelRatio(window.devicePixelRatio);
        renderer1.setSize(window.innerWidth, window.innerHeight);
        renderer1.toneMapping = THREE.ACESFilmicToneMapping;
        renderer1.toneMappingExposure = 1;
        container1.appendChild(renderer1.domElement);
        console.log('Renderer Created:', container1);

        window.addEventListener('resize', onWindowResize);

        orbitControls = new OrbitControls(camera1, renderer1.domElement);
        orbitControls.minDistance = 2;
        orbitControls.maxDistance = 10;
        orbitControls.target.set(0, 0, -0.2);
        orbitControls.update();

        mixer1 = new AnimationMixer();

        const loadnextScene1Button = createButton('Next Scene', () => clearScene({ scene: scene1, mixer: mixer1, orbitControls: orbitControls, currentModel: currentModel }));
        document.body.appendChild(loadnextScene1Button);
        console.log('Button Created:', loadnextScene1Button);

        animate({
            scene: scene1,
            mixer: mixer1,
            orbitControls: orbitControls,
            isPaused: isPaused,
        });
    }

    function loadModel() {
        console.log('Loading GLB model:', loadModel);
        const dracoLoader = new DRACOLoader();
        dracoLoader.setDecoderPath('node_modules/three/examples/jsm/libs/draco/');
        const gltfLoader = new GLTFLoader();
        gltfLoader.setDRACOLoader(dracoLoader);

        const loader = gltfLoader.setPath(gltfPath);

        loader.load('VinylCover.glb', function (gltf) {
            console.log('Model loaded successfully:', gltf);

            const newModel = gltf.scene;
            scene1.add(newModel);
            newModel.position.y = -1;

            mixer1 = new AnimationMixer(newModel);
            currentModel = newModel; // Set currentModel here

            if (gltf.animations && gltf.animations.length > 0) {
                const allActions = gltf.animations.map(clip => mixer1.clipAction(clip));
                allActions.forEach((action) => {
                    action.play();
                });

                isPaused = false;
            }

            orbitControls.enabled = true;

            console.log('New model added to the scene.');
            console.log(scene1);
        },
        null,
        (error) => {
            console.error('An error occurred while loading the model:', error);
        });
    }

    function animate() {
        requestAnimationFrame(animate);
    
        if (mixer1) {
            mixer1.update(0.01);
        }
    
        if (!isPaused) {
            render();
        }
    
        if (orbitControls.enabled) {
            orbitControls.update();
        }
    
        console.log('Animating first scene');
    }
    

    function render() {
        if (renderer1) {
            renderer1.render(scene1, camera1);
        }
    }

    function onWindowResize() {
        camera1.aspect = window.innerWidth / window.innerHeight;
        camera1.updateProjectionMatrix();

        if (renderer1) {
            renderer1.setSize(window.innerWidth, window.innerHeight);
        }
        render();
    }
    function clearScene(scene) {
        // Stop and clear the animations
        if (scene.mixer) {
            scene.mixer.stopAllAction();
            scene.mixer.uncacheAction(scene.currentModel);
            scene.mixer = null;
        }
    
        // Remove the current model from the scene
        if (scene.currentModel) {
            scene.currentModel.traverse((obj) => {
                if (obj.isMesh) {
                    obj.geometry.dispose();
                    obj.material.dispose();
                }
            });
    
            scene.scene.remove(scene.currentModel);
            scene.currentModel = null;
        }
    
        // Dispose renderer resources
        if (scene.renderer) {
            scene.renderer.dispose();
        }
    
        // Clear the scene
        scene.scene = new THREE.Scene();
    
        // Re-initialize other components as needed
        init(scene);
    
        // Load the next scene
        loadScene2();
    }
    
    
    
    
    


}

第二个.js

import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { RGBELoader } from 'three/addons/loaders/RGBELoader.js';
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';
import { AnimationMixer } from 'three';
import { loadScene3 } from './third.js';

export function loadScene2() {
    let camera2, scene2, renderer2, mixer2, currentModel2;
    let isPaused = true;
    let container2;
    let orbitControls2;

    const gltfPath = 'models/gltf/VinylCover/glTF/';

    init2();
    animate2();
    startAnimation2();

    function createButton2(text, onClick) {
        const button = document.createElement('button');
        button.innerHTML = text;
        button.style.position = 'absolute';
        button.style.top = '10px';
        button.style.left = '10px';
        button.addEventListener('click', onClick);
        return button;
    }

    function startAnimation2() {
        if (isPaused) {
            isPaused = false;
            mixer2.timeScale = 1;
        } else {
            isPaused = true;
            mixer2.timeScale = 0;
        }
    }

    function init2() {
        container2 = document.createElement('div');
        document.body.appendChild(container2);
        console.log('Container element:', container2);

        camera2 = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.25, 20);
        camera2.position.set(30, 30, 30);
        console.log('Camera Created:', camera2);

        scene2 = new THREE.Scene();

        const hemiLight2 = new THREE.HemisphereLight(0xffffff, 0xffffff, 1);
        hemiLight2.color.setHSL(0.6, 1, 0.6);
        hemiLight2.groundColor.setHSL(0.095, 1, 0.75);
        hemiLight2.position.set(0, 50, 0);
        scene2.add(hemiLight2);
        console.log('hemilight created:', container2);

        const dirLight2 = new THREE.DirectionalLight(0xffffff, 2);
        dirLight2.color.setHSL(0.1, 1, 0.95);
        dirLight2.position.set(0.5, 0.5, 2);
        dirLight2.position.multiplyScalar(30);
        scene2.add(dirLight2);
        console.log('dirlight created:', container2);

        dirLight2.castShadow = true;
        dirLight2.shadow.mapSize.width = 2048;
        dirLight2.shadow.mapSize.height = 2048;

        const d = 50;
        dirLight2.shadow.camera.left = -d;
        dirLight2.shadow.camera.right = d;
        dirLight2.shadow.camera.top = d;
        dirLight2.shadow.camera.bottom = -d;
        dirLight2.shadow.camera.far = 3500;
        dirLight2.shadow.bias = -0.0001;

        new RGBELoader()
            .setPath('textures/equirectangular/')
            .load('sky14k.hdr', function (texture) {
                texture.mapping = THREE.EquirectangularReflectionMapping;
                scene2.background = texture;
                scene2.environment = texture;

                loadModel2();

                animate2({
                    scene: scene2,
                    mixer: mixer2,
                    orbitControls: orbitControls2,
                    isPaused: isPaused,
                });
            });

        renderer2 = new THREE.WebGLRenderer({ antialias: true });
        renderer2.setPixelRatio(window.devicePixelRatio);
        renderer2.setSize(window.innerWidth, window.innerHeight);
        renderer2.toneMapping = THREE.ACESFilmicToneMapping;
        renderer2.toneMappingExposure = 1;
        container2.appendChild(renderer2.domElement);
        console.log('Renderer Created:', container2);

        window.addEventListener('resize', onWindowResize);

        orbitControls2 = new OrbitControls(camera2, renderer2.domElement);
        orbitControls2.minDistance = 2;
        orbitControls2.maxDistance = 10;
        orbitControls2.target.set(0, 0, -0.2);
        orbitControls2.update();

        mixer2 = new AnimationMixer();

        const loadnextScene2Button = createButton2('Next Scene', () => clearScene2({ scene: scene2, mixer: mixer2, orbitControls: orbitControls2, currentModel: currentModel2 }));
    document.body.appendChild(loadnextScene2Button);
    console.log('Button Created:', loadnextScene2Button);
    }

    function loadModel2() {
        console.log('Loading GLB model:', loadModel2);
        const dracoLoader = new DRACOLoader();
        dracoLoader.setDecoderPath('node_modules/three/examples/jsm/libs/draco/');
        const gltfLoader = new GLTFLoader();
        gltfLoader.setDRACOLoader(dracoLoader);

        const loader = gltfLoader.setPath(gltfPath);

        loader.load('CellFragment.glb', function (gltf) {
            console.log('Model loaded successfully:', gltf);

            const newModel = gltf.scene;
            scene2.add(newModel);
            newModel.position.y = -1;

            mixer2 = new AnimationMixer(newModel);

            if (gltf.animations && gltf.animations.length > 0) {
                const allActions = gltf.animations.map(clip => mixer2.clipAction(clip));
                allActions.forEach((action) => {
                    action.play();
                });

                isPaused = false;
            }

            orbitControls2.enabled = true;

            console.log('New model added to the scene.');
            console.log(scene2);
        },
        null,
        (error) => {
            console.error('An error occurred while loading the model:', error);
        });
    }

    function animate2() {
        requestAnimationFrame(animate2);

        if (mixer2) {
            mixer2.update(0.01);
        }

        if (!isPaused) {
            render2();
        }

        if (orbitControls2.enabled) {
            orbitControls2.update();
        }

        console.log('Animating second scene');
    }

    function render2() {
        if (renderer2) {
            renderer2.render(scene2, camera2);
        }
    }

    function onWindowResize() {
        camera2.aspect = window.innerWidth / window.innerHeight;
        camera2.updateProjectionMatrix();

        if (renderer2) {
            renderer2.setSize(window.innerWidth, window.innerHeight);
        }
        render2();
    }

    function clearScene2() {
        // Stop and clear the animations
        if (mixer2) {
            mixer2.stopAllAction();
            mixer2.uncacheAction(currentModel2);
            mixer2 = null;
        }
    
        // Remove the current model from the scene
        if (currentModel2) {
            currentModel2.traverse((obj) => {
                if (obj.isMesh) {
                    obj.geometry.dispose();
                    obj.material.dispose();
                }
            });
    
            scene2.remove(currentModel2);
            currentModel2 = null;
        }
    
        // Dispose renderer resources
        if (renderer2) {
            renderer2.dispose();
        }
    
        // Clear the scene
        scene2 = new THREE.Scene();
    
        // Re-initialize other components as needed
        initScene2();
    
        // Load the next scene
        loadScene3();
    }
    
}
三个.js

评论


答: 暂无答案