简而言之,我开发了一个关于太阳系的小型three.js项目,在该项目中我导入了每颗行星的模型。我想让每个星球都可以点击,最终将相机放大到点击的星球上,并显示它的最新图像(图像将显示在3d模型旁边(。
所以基本上我的问题是:如何让导入的模型可以点击,为它们添加功能?
我试着添加光线投射,但我运气不好,有点乱。
这是我到目前为止的代码:
import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
const renderer = new THREE.WebGLRenderer({
canvas: document.querySelector('#bg'),
});
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 20000);
scene.add(camera)
const directionalLight = new THREE.DirectionalLight(0xffffff, 0);
directionalLight.position.set(0,1,0);
scene.add(directionalLight)
renderer.setClearColor(0x000000)
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
camera.position.set(-700, 1000, 600);
// Loader
const loader = new GLTFLoader();
// sun
loader.load( 'sun.glb', function ( gltf ) {
console.log(gltf)
let sun = gltf.scene;
sun.scale.set(0.2, 0.2, 0.2);
sun.position.set(-300, 0, 0);
function animate() {
requestAnimationFrame(animate);
sun.rotation.y += 0.002;
renderer.render(scene, camera);
}
scene.add( gltf.scene );
animate()
}, undefined, function ( error ) {
console.error( error );
} );
// Mercury
loader.load( 'mercury.glb', function ( gltf ) {
console.log(gltf)
let mercury = gltf.scene;
mercury.scale.set(0.03, 0.03, 0.03);
mercury.position.set(-100, 0, 0);
function animate() {
requestAnimationFrame(animate);
mercury.rotation.y += 0.002;
renderer.render(scene, camera);
}
scene.add( gltf.scene );
animate()
}, undefined, function ( error ) {
console.error( error );
} );
// venus
loader.load( 'venus.glb', function ( gltf ) {
console.log(gltf)
let venus = gltf.scene;
venus.scale.set(0.04, 0.04, 0.04);
venus.position.set(30, 0, 0);
function animate() {
requestAnimationFrame(animate);
venus.rotation.y += 0.002;
renderer.render(scene, camera);
}
scene.add( gltf.scene );
animate()
}, undefined, function ( error ) {
console.error( error );
} );
// earth
loader.load( 'earth.glb', function ( gltf ) {
console.log(gltf)
let earth = gltf.scene;
earth.scale.set(0.04, 0.04, 0.04);
earth.position.set(140, 0, 0);
function animate() {
requestAnimationFrame(animate);
earth.rotation.y += 0.002;
renderer.render(scene, camera);
}
scene.add( gltf.scene );
animate()
}, undefined, function ( error ) {
console.error( error );
} );
// mars
loader.load( 'mars.glb', function ( gltf ) {
console.log(gltf)
let mars = gltf.scene;
mars.scale.set(0.015, 0.015, 0.015);
mars.position.set(230, 0, 0);
function animate() {
requestAnimationFrame(animate);
mars.rotation.y += 0.002;
renderer.render(scene, camera);
}
scene.add( gltf.scene );
animate()
}, undefined, function ( error ) {
console.error( error );
} );
// juptier
loader.load( 'jupiter.glb', function ( gltf ) {
console.log(gltf)
let jupiter = gltf.scene;
jupiter.scale.set(0.08, 0.08, 0.08);
jupiter.position.set(350, 0, 0);
function animate() {
requestAnimationFrame(animate);
jupiter.rotation.y += 0.002;
renderer.render(scene, camera);
}
scene.add( gltf.scene );
animate()
}, undefined, function ( error ) {
console.error( error );
} );
// saturn
loader.load( 'saturn.glb', function ( gltf ) {
console.log(gltf)
let saturn = gltf.scene;
saturn.scale.set(0.07, 0.07, 0.07);
saturn.position.set(530, 0, 0);
function animate() {
requestAnimationFrame(animate);
saturn.rotation.y += 0.002;
renderer.render(scene, camera);
}
scene.add( gltf.scene );
animate()
}, undefined, function ( error ) {
console.error( error );
} );
// uranus
loader.load( 'uranus.glb', function ( gltf ) {
console.log(gltf)
let uranus = gltf.scene;
uranus.scale.set(0.05, 0.05, 0.05);
uranus.position.set(700, 0, 0);
function animate() {
requestAnimationFrame(animate);
uranus.rotation.y += 0.002;
renderer.render(scene, camera);
}
scene.add( gltf.scene );
animate()
}, undefined, function ( error ) {
console.error( error );
} );
// neptune
loader.load( 'neptune.glb', function ( gltf ) {
console.log(gltf)
let neptune = gltf.scene;
neptune.scale.set(0.045, 0.045, 0.045);
neptune.position.set(850, 0, 0);
function animate() {
requestAnimationFrame(animate);
neptune.rotation.y += 0.002;
renderer.render(scene, camera);
}
scene.add( gltf.scene );
animate()
}, undefined, function ( error ) {
console.error( error );
} );
// stars
function addstar() {
const geometry = new THREE.SphereGeometry(0.25, 24, 24);
const material = new THREE.MeshStandardMaterial({ color: 0xffffff })
const star = new THREE.Mesh(geometry, material);
const [x, y, z] = Array(3).fill().map(() => THREE.MathUtils.randFloatSpread(3000));
star.position.set(x,y,z);
scene.add(star)
}
Array(1000).fill().forEach(addstar)
// background
const background = new THREE.TextureLoader().load('background.jpg')
scene.background = background
//controls
let controls = new OrbitControls(camera, renderer.domElement)
controls.update()
// lighting
let light = new THREE.AmbientLight(0xffffff, 2)
scene.add(light)
// Resize
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
// Event Listener
window.addEventListener( 'resize', onWindowResize, false );
// animate
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
场景中针对模型/网格的光线投射通过各种三个js示例得到了很好的记录。请查看光线投射器文档,特别是针对网格的光线投射示例。
此外,作为改进的建议:试着从一开始就构建代码,否则所有的threej东西很快就会变得一团糟。尝试创建一个加载模型的通用函数,避免大量的复制&粘贴代码。
此外,请随时分享你迄今为止为做你想做的事情所做的努力。在这种情况下,你应该提供光线投射代码片段以及错误消息等。