首页 > 解决方案 > 在 onclick 事件期间重新定位相机(OrbitControls)

问题描述

我正在学习专注于threeJS的Javascript,并希望实现一个特定的功能:

设置:

我在三个 JS 中创建了一个场景,其中包含一个 .glb 模型、多个位于模型周围的精灵(标记)。Raycaster 确定 Sprite 元素是否悬停。

我想添加的功能:

当单击 Sprite 时,相机应以捕捉 Sprite 正下方模型部分的特写镜头的方式定位自身。最佳情况:此过渡使用 Tween.JS(或类似的)以获得平滑的外观,并在再次单击特写场景时将相机位置重置回单击精灵之前的位置。

我尝试了什么:

我在我的项目中添加了three.interactive,因为它似乎是向场景中的特定对象添加事件的最简单方法。我将 onclick 事件附加到第一个 Sprite 对象,到目前为止它可以工作。在这种情况下,我camera.controls.set(x,y,z)使用我使用延迟的 console.log 获得的坐标进行设置,这使我能够打开我的文档,根据需要定位相机并复制新的 x、y、z 值。

sprite.addEventListener("click", (event) => {
        camera.position.set(-4,1,2);
    });

单击指定的 Sprite 会移动相机。但结果与之前上演的场景并不相同。我相信这是由于一些我目前还不了解的全局位置值。

THREE.js 文件(非常感谢一般反馈,新手在这里)

//CREATE SCENE
const scene = new THREE.Scene();

//CREATE CAMERA
const camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 0.1, 2000);

//CREATE RENDERER
const renderer = new THREE.WebGLRenderer({antialias: true, alpha: true});
renderer.toneMapping = THREE.CineonToneMapping;
renderer.toneMappingExposure = 1.0;
renderer.shadowMap.enabled = true;
renderer.setClearColor( 0xFFF8F3, 0);
renderer.setSize(window.innerWidth,window.innerHeight);
//PIN RENDERER TO DIV ID "model"
document.getElementById("model").appendChild(renderer.domElement);

//INTERACTIVE MANAGER THROUGH THREE INTERACTIVE
    const interactionManager = new THREE.InteractionManager(
        renderer,
        camera,
        renderer.domElement
    );

//ADD LIGHT TO SCENE
    let light = new THREE.HemisphereLight(0x949494, 0x616161, 1)
    scene.add(light);
    let directionallight_1 = new THREE.DirectionalLight(0xFFFFFF, 1);
    directionallight_1.castShadow = true;
    scene.add(directionallight_1);
    directionallight_1.position.set(15,3,-6.5)
    let spotLight_1 = new THREE.SpotLight(0xFDF1DF, 1);
    spotLight_1.position.set(-15,-3,6.5)
    scene.add(spotLight_1);
    let spotLight_2 = new THREE.SpotLight(0xFDF1DF, 1);
    spotLight_2.position.set(15,-3,-6.5)
    scene.add(spotLight_2);

//LOAD 3D MODEL
let loader = new THREE.GLTFLoader();
let obj;
loader.load("src/assets/models/plugger/new_Plugger.glb", function (gltf) {
    obj = gltf.scene;
    scene.add(gltf.scene);
    obj.position.set(0, -0.85, 0);
});

//LOAD SPRITE
    const map = new THREE.TextureLoader().load( './src/assets/svg/map-marker-alt-solid.svg' );
    //UNIQUE MATERIAL FOR EACH SPRITE TO DISTINGUISH THEM DURING RAYCASTING
    const material_1 = new THREE.SpriteMaterial( { map: map } );
    const material_2 = new THREE.SpriteMaterial( { map: map } );
    const material_3 = new THREE.SpriteMaterial( { map: map } );
    const material_4 = new THREE.SpriteMaterial( { map: map } );

    //CREATE SPRITE
    const sprite = new THREE.Sprite( material_1 );
    sprite.position.set(-1.500, 0.753, -1.600);
    sprite.scale.set(0.200,0.266,0.200);
    sprite.material.transparent = true;
    sprite.material.opacity = 1;
    sprite.name = "sprite_1";
    sprite.castShadow = true;
    interactionManager.add(sprite);
    sprite.addEventListener("click", (event) => {
        camera.position.set(-4,0.18,1.98);
    });
    scene.add( sprite );

//LOAD ORBIT CONTROLS
const controls = new THREE.OrbitControls( camera, renderer.domElement );
//controls.update() must be called after any manual changes to the camera's transform
camera.position.set( -4.44, 2.25, 3.50)
controls.enableZoom = true;
controls.enableRotate = true;
controls.rotateSpeed = 1.0;
controls.maxPolarAngle =  Math.PI * 0.5;
controls.minPolarAngle =  0.8;
controls.update();

//RESIZE SCENE ON WINDOW-RESIZE
window.addEventListener( 'resize', onWindowResize, false );

function onWindowResize(){

    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();

    renderer.setSize( window.innerWidth, window.innerHeight );

}

//ANIMATE THE SCENE + MISC. FUNCTIONS
let animate = function(callback) {
    function loop(time) {
        callback(time);

        let raycaster = new THREE.Raycaster();

        let direction = new THREE.Vector3()
            .copy(mouse)
            .unproject(camera)
            .sub(camera.position)
            .normalize();
        raycaster.setFromCamera(mouse,camera);
        raycaster.set(camera.position, direction);

        scene.children.forEach(function (child) {
            if (child instanceof THREE.Sprite)
                child.material.opacity = 1.0;
        });
        let intersects = raycaster.intersectObjects(scene.children, true);
        intersects.forEach(function (element) {
            let object = element.object;
            if (object instanceof THREE.Sprite)
                object.material.opacity = 0.5;
        })
        interactionManager.update();
        requestAnimationFrame(loop);
    }
    requestAnimationFrame(loop);
}

// RENDER THE SCENE
animate(() => {    
    renderer.render(scene,camera);

});

标签: javascriptthree.js

解决方案


推荐阅读