我正在构建一个交互式Web应用程序。我已经将glb文件加载到场景中,现在我想添加2个功能:
onMouseover
在对象中的一个元素上,我想更改该元素的颜色。 我的困惑是,我是否可以仅通过使用raycaster来做到这一点,还是需要进一步遍历Texture_Group并为此开发一种if if else逻辑,以及如何做到这些? 我猜我需要使用光线投射器并遍历场景,但是我有点卡住了。谢谢您的帮助,如果我需要提供其他任何内容,请让我现在解决,这是我的第一个问题。
我已经在网上找到了一些代码,在console.log中遍历了场景,并根据情况进行了一些调整。
这是我的app.js代码:
/*jshint esversion: 6 */
let scene, camera, renderer, h, controls, raycaster, mouse;
function init() {
scene = new THREE.Scene();
//Camera
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 6, 6);
const myCanvas = document.getElementById('myCanvas');
//Renderer
renderer = new THREE.WebGLRenderer({
canvas: myCanvas,
antialias: true,
});
renderer.setClearColor(0xcfd4d8);
renderer.setPixelRatio(window.deviceSPixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
//Controls
controls = new THREE.OrbitControls(camera, myCanvas);
controls.target.set(0, 6, 0);
controls.update();
controls.enableDamping = true;
controls.dampingFactor = 0.25;
controls.screenSpacePanning = false;
controls.minDistance = -20;
controls.maxDistance = 100;
controls.maxPolarAngle = Math.PI;
controls.enableZoom = true;
controls.rotateSpeed = 0.3;
controls.zoomSpeed = 10.0;
//Lights
const light = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(light);
const light2 = new THREE.PointLight(0xffffff, 0.5);
scene.add(light2);
//Loader
const loader = new THREE.GLTFLoader();
loader.load(
'content/hajdukzagltf.glb',
function (gltf) {
h = scene.add(gltf.scene);
h.position.set(6, -2, 1);
console.log(dumpObject(h).join('\n'));
console.log(gltf);
}
);
}
init();
//Render Loop
render();
function render() {
requestAnimationFrame(render);
controls.update();
renderer.render(scene, camera);
}
//windowResize
function windowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
window.addEventListener('resize', windowResize, false);
//consol log traverse
function dumpVec3(v3, precision = 3) {
return `${v3.x.toFixed(precision)}, ${v3.y.toFixed(precision)}, ${v3.z.toFixed(precision)}`;
}
function dumpObject(obj, lines = [], isLast = true, prefix = '') {
const localPrefix = isLast ? '└─' : '├─';
lines.push(`${prefix}${prefix ? localPrefix : ''}${obj.name || '*no-name*'} [${obj.type}]`);
const dataPrefix = obj.children.length
? (isLast ? ' │ ' : '│ │ ')
: (isLast ? ' ' : '│ ');
lines.push(`${prefix}${dataPrefix} pos: ${dumpVec3(obj.position)}`);
lines.push(`${prefix}${dataPrefix} rot: ${dumpVec3(obj.rotation)}`);
lines.push(`${prefix}${dataPrefix} scl: ${dumpVec3(obj.scale)}`);
const newPrefix = prefix + (isLast ? ' ' : '│ ');
const lastNdx = obj.children.length - 1;
obj.children.forEach((child, ndx) => {
const isLast = ndx === lastNdx;
dumpObject(child, lines, isLast, newPrefix);
});
return lines;
}
console.log:
*no-name* [Scene]
│ pos: 6.0000, -2.0000, 1.0000
│ rot: 0.0000, 0.0000, 0.0000
│ scl: 1.0000, 1.0000, 1.0000
├─*no-name* [AmbientLight]
│ pos: 0.0000, 0.0000, 0.0000
│ rot: 0.0000, 0.0000, 0.0000
│ scl: 1.0000, 1.0000, 1.0000
├─*no-name* [PointLight]
│ pos: 0.0000, 0.0000, 0.0000
│ rot: 0.0000, 0.0000, 0.0000
│ scl: 1.0000, 1.0000, 1.0000
└─*no-name* [Scene]
│ pos: 0.0000, 0.0000, 0.0000
│ rot: 0.0000, 0.0000, 0.0000
│ scl: 1.0000, 1.0000, 1.0000
├─Camera_(2) [PerspectiveCamera]
│ pos: -12.5626, 8.9117, -9.9300
│ rot: -0.1273, -0.2253, -0.0286
│ scl: 1.0000, 1.0000, 1.0000
├─Texture_Group [Object3D]
│ pos: 0.0000, 0.0000, 0.0000
│ rot: 0.0000, 0.0000, 0.0000
│ scl: 1.0000, 1.0000, 1.0000
├─b [Mesh]
│ pos: 2.6200, 3.9200, -19.2000
│ rot: 0.0000, 0.0000, 0.0000
│ scl: 1.0000, 1.0000, 1.0000
├─z [Mesh]
│ pos: 0.0000, 0.0000, 0.0000
│ rot: 0.0000, 0.0000, 0.0000
│ scl: 1.0000, 1.0000, 1.0000
└─bg [Mesh]
pos: 0.0000, 0.0000, 0.0000
rot: 0.0000, 0.0000, 0.0000
scl: 1.0000, 1.0000, 1.0000
答案 0 :(得分:0)
如评论部分所述,可以使用简单的Raycaster来实现所有功能。
为了检测鼠标何时悬停在场景中的一组对象上,您可以将它们组合在包含子网格的THREE.Group
或THREE.Object3D
中。
您将mousemove
事件绑定到更新包含视口鼠标位置的全局变量mouse
的函数。
function onMouseMove( event ) {
event.preventDefault();
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
}
在动画循环内,在给定当前鼠标位置的情况下执行光线投射,并检查该光线是否与所述组包含的任何对象相交。然后,您要处理这些对象的颜色更新或在不相交时恢复它们的颜色。
function raycast() {
raycaster.setFromCamera( mouse, camera );
var intersects = raycaster.intersectObjects( group.children );
if ( intersects.length > 0 ) {
if ( INTERSECTED != intersects[ 0 ].object ) {
if ( INTERSECTED ) INTERSECTED.material.color.setHex( INTERSECTED.currentHex );
INTERSECTED = intersects[ 0 ].object;
INTERSECTED.currentHex = INTERSECTED.material.color.getHex();
INTERSECTED.material.color.setHex( 0xd4d4d4 );
}
} else {
if ( INTERSECTED ) INTERSECTED.material.color.setHex( INTERSECTED.currentHex );
INTERSECTED = null;
}
}
最后,如果对象当前与射线相交,则将click
事件绑定到另一个执行所需功能的功能。
function onMouseClick( event ) {
if ( INTERSECTED !== null ) clickFunction( INTERSECTED ); // perform object operation
}
此JSFiddle example显示了这些功能正常工作。
让我知道是否有不清楚的地方。
如果TEXTURE_GROUP
中的对象不是很好地按照网格组织的,建议您先将每个字母打包到一个网格中,然后遍历时将它们添加到Object3D
或{ {1}}(如果尚未存在)。