javascript - 在 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);
});
解决方案
推荐阅读
- javascript - 将 processing.js 文件链接到画布
- sql - 基于计算列的值的累积列
- java - 从 Java 中的扫描仪读取多行
- google-apps-script - 如何允许访问写入 Google Drive 电子表格的 Google Web 应用
- sql-server - 停用基于两个分组列的重复数据,检查不为空
- csv - Gephi 上传 csv 文件或在 Gephi 的打开页面选择示例 Les Miserables.gexf 抛出 java.util.MissingResourceException 错误
- c - a 是什么意思?运算符的意思是如果放在变量前面?
- python - ValueError:无法将字符串转换为浮点数:GradientBoostingRegressor 中 .predict 的“错误”
- python - 使用 lambda 的数据框内容子集使用 pandas 应用
- vue.js - 如何减少包含 AWS 开发工具包的 Vue.js / Nuxt.js 项目的 webpack 包大小?