#javascript #three.js
Вопрос:
На моем сайте у меня есть плавучий остров и камера, которая следует по кривой. Я бы хотел, чтобы эта камера, следующая по кривой, появлялась только при загрузке веб-сайта. Таким образом, это немного похоже на экскурсию с гидом для пользователя, но как только она закончится, я хотел бы, чтобы она остановилась там, где она есть, и вернула контроль пользователю.
Прямо сейчас в моем коде камера просто отлично повторяет кривую, но она зацикливается. Как только камера достигает конца, она возвращается к началу и воспроизводится снова. Ниже приведен мой код:
import "./style.css"; import * as THREE from "three"; import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"; import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js"; let camera, scene, renderer, mixerA, mixerB, mixerC, mixerD, delta, raycaster, mouse, reqAnim; var clock = new THREE.Clock(); var atStart = true; init(); animate(); function init() { //scene scene = new THREE.Scene(); scene.background = new THREE.Color(0x87ceeb); //renderer renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); //camera camera = new THREE.PerspectiveCamera( 5, window.innerWidth / window.innerHeight, 1, 10000 ); camera.position.set(80, 55, 80); camera.lookAt(-0.3, 0.4, -0.25); //sphere for sun var geometry1 = new THREE.SphereGeometry(0.22); var material1 = new THREE.MeshLambertMaterial({ transparent: true, opacity: 0.5, }); var sphere1 = new THREE.Mesh(geometry1, material1); sphere1.position.set(5, 2.5, 10); //sphere for rect angle light var geometry2 = new THREE.SphereGeometry(0.25); var material2 = new THREE.MeshLambertMaterial({ transparent: true, opacity: 0, }); var sphere2 = new THREE.Mesh(geometry2, material2); sphere2.position.set(-0.5, 0.75, 0); //sphere for arm clickbox var geometry3 = new THREE.SphereGeometry(0.08); var material3 = new THREE.MeshLambertMaterial({ transparent: true, opacity: 0.5, }); var sphere3 = new THREE.Mesh(geometry3, material3); sphere3.position.set(-0.25, 0.4, -0.4); scene.add(sphere3); sphere3.userData.name = "ARM_SPHERE"; //sphere for laptop clickbox var geometry4 = new THREE.SphereGeometry(0.08); var material4 = new THREE.MeshLambertMaterial({ transparent: true, opacity: 0.5, }); var sphere4 = new THREE.Mesh(geometry4, material4); sphere4.position.set(-0.3, 0.4, -0.25); scene.add(sphere4); sphere4.userData.name = "LAPTOP_SPHERE"; //loader let loader = new GLTFLoader(); loader.load("FloatingIsland.gltf", function (gltf) { const model = gltf.scene; model.scale.set(3, 3, 3); mixerA = new THREE.AnimationMixer(model); console.log(gltf.animations); mixerA.clipAction(gltf.animations[0]).play(); scene.add(model, sphere1, sphere2); }); loader.load("circle.glb", function (gltf) { const model2 = gltf.scene; mixerB = new THREE.AnimationMixer(model2); mixerB.clipAction(gltf.animations[0]).play(); model2.position.set(-0.9, 0, 0.15); model2.lookAt(-10, 0.5); model2.scale.set(0.5, 0.5, 0.5); scene.add(model2); }); loader.load("circle.glb", function (gltf) { const model3 = gltf.scene; mixerC = new THREE.AnimationMixer(model3); mixerC.clipAction(gltf.animations[0]).play(); model3.position.set(-0.9, 0, 0.4); model3.lookAt(-10, 0.5); model3.scale.set(0.5, 0.5, 0.5); scene.add(model3); }); //laptop screen video var video01 = document.getElementById("video01"); video01.addEventListener("click", playArmVideo, false); const videoTexture01 = new THREE.VideoTexture(video01); const geometry = new THREE.BoxGeometry(0, 1, 1); const material = new THREE.MeshBasicMaterial({ map: videoTexture01 }); const cube = new THREE.Mesh(geometry, material); cube.position.set(-0.245, 0.41, -0.25); cube.scale.set(0.1, 0.09, 0.14); cube.rotateZ(Math.PI / -23); video01.play(); scene.add(cube); // lights const directionalLight = new THREE.PointLight(0xcb6015, 1); directionalLight.castShadow = true; directionalLight.position.set(-500, 300, 50); scene.add(directionalLight); const directionalLight2 = new THREE.DirectionalLight(0xcb6015, 1.4); directionalLight2.castShadow = true; directionalLight2.position.set(5, 2.5, 10); scene.add(directionalLight2); sphere1.add(directionalLight2); const rectLight = new THREE.RectAreaLight(0xffffff, 1, 3, 3); rectLight.position.set(-0.5, 0.75, 0); rectLight.lookAt(0, 0, 0); scene.add(rectLight); sphere2.add(rectLight); //dynamic resize window.addEventListener("resize", onWindowResize, false); //orbit controls const controls = new OrbitControls(camera, renderer.domElement); controls.enablePan = false; controls.update(); var rightmousemove; document.addEventListener("mousemove", function (event) { if (rightmousemove === true) { // Use stopImmediatePropagation to stop the other handeller from trigerring event.stopImmediatePropagation(); } }); // raycaster raycaster = new THREE.Raycaster(); mouse = new THREE.Vector2(); window.addEventListener("click", (e) =gt; { mouse.x = (e.clientX / window.innerWidth) * 2 - 1; mouse.y = -(e.clientY / window.innerHeight) * 2 1; raycaster.setFromCamera(mouse, camera); const found = raycaster.intersectObjects(scene.children); if (found.length gt; 0 amp;amp; found[0].object.userData.name == "LAPTOP_SPHERE") { playArmVideo(); } }); renderPath(); render(); } function renderPath() { var curve = new THREE.CubicBezierCurve3( new THREE.Vector3(200, 200, 800), new THREE.Vector3(100, 150, -200), new THREE.Vector3(-50, 10, -150), new THREE.Vector3(-50, 10, 0), new THREE.Vector3(-20, 0, 10) ); // Create the final object to add to the scene var clock2 = new THREE.Clock(); clock2.start(); var speed = 0.1; var pathTarget = new THREE.Vector3(0, 10, 0); curve.getPoint((clock.getElapsedTime() * speed) % 1.0, pathTarget); camera.position.copy(pathTarget); camera.lookAt(0, 0, 0); requestAnimationFrame(renderPath); } function onWindowResize() { var width = window.innerWidth; var height = window.innerHeight; renderer.setSize(width, height); camera.aspect = width / height; camera.updateProjectionMatrix(); } function animate() { reqAnim = requestAnimationFrame(animate); delta = clock.getDelta(); if (mixerA) mixerA.update(delta); if (mixerB) mixerB.update(delta); if (mixerC) mixerC.update(delta); if (mixerD) mixerC.update(delta); // required if controls.enableDamping or controls.autoRotate are set to true render(); } function playArmVideo() { var video02 = document.getElementById("video02"); const videoTexture02 = new THREE.VideoTexture(video02); const geometry5 = new THREE.BoxGeometry(0, 1, 1); const material5 = new THREE.MeshBasicMaterial({ map: videoTexture02 }); const cube2 = new THREE.Mesh(geometry5, material5); cube2.position.set(1, 1, 1); cube2.scale.set(0.4, 0.4, 0.4); video02.play(); scene.add(cube2); setTimeout(() =gt; scene.remove(cube2), 7100); } function render() { renderer.render(scene, camera); }