我是Three.js(和WebGL)的新手,在我的第一个项目中,我正在创建动物模型并以各种方式对其进行动画处理(即,头部旋转以跟随鼠标)。该模型由许多不同的几何构造而成,它们在各自的功能中组合在一起,例如:

var BodyFunc = function(){
this.mesh = new THREE.Object3D();
this.mesh.name = "body";

// Body
var geomBody = new THREE.SphereGeometry( 100, 150, 150 );
geomBody.applyMatrix( new THREE.Matrix4().makeScale( 1.0, 1.3, 1.0 ) );
var matBody = new THREE.MeshPhongMaterial({color:Colors.black, shading:THREE.FlatShading});
var Body = new THREE.Mesh(geomBody, matBody);
Body.castShadow = true;
Body.receiveShadow = true;
this.mesh.add(Body);

// Body (bottom)
var geomBodyBottom = new THREE.SphereGeometry( 95, 150, 150 );
geomBodyBottom.applyMatrix( new THREE.Matrix4().makeScale( 1.0, 1.0, 1.0 ) );
var matBodyBottom = new THREE.MeshPhongMaterial({color:pantsColour, shading:THREE.FlatShading});
var BodyBottom = new THREE.Mesh(geomBodyBottom, matBodyBottom);
BodyBottom.position.set(0,-40,0);
BodyBottom.castShadow = true;
BodyBottom.receiveShadow = true;
this.mesh.add(BodyBottom);

// Body (base)
var geomBodyBase = new THREE.SphereGeometry( 92, 150, 150 );
geomBodyBase.applyMatrix( new THREE.Matrix4().makeScale( 1.0, 1.0, 1.0 ) );
var matBodyBase = new THREE.MeshPhongMaterial({color:Colors.black, shading:THREE.FlatShading});
var BodyBase = new THREE.Mesh(geomBodyBase, matBodyBase);
BodyBase.position.set(0,-50,0);
BodyBase.castShadow = true;
BodyBase.receiveShadow = true;
this.mesh.add(BodyBase);

};


然后在主createAnimal()函数中调用这些函数,如下所示:

function createAnimal(){

animalBodyGroup = new THREE.Object3D();
animalGroup = new THREE.Object3D();

head = new HeadFunc();

head.mesh.scale.set(.25,.25,.25);
head.mesh.position.y = 0;
animalGroup.add(head.mesh);

body = new BodyFunc();

body.mesh.scale.set(.25,.25,.25);
body.mesh.position.y = 0;
animalBodyGroup.add(body.mesh);

armRight = new armRightFunc();

armRight.mesh.scale.set(.25,.25,.25);
armRight.mesh.position.y = 0;
animalBodyGroup.add(armRight.mesh);

armLeft = new armLeftFunc();

armLeft.mesh.scale.set(.25,.25,.25);
armLeft.mesh.position.y = 0;
animalBodyGroup.add(armLeft.mesh);

footRight = new footRightFunc();

footRight.mesh.scale.set(.25,.25,.25);
footRight.mesh.position.y = 0;
animalBodyGroup.add(footRight.mesh);

footLeft = new footLeftFunc();

footLeft.mesh.scale.set(.25,.25,.25);
footLeft.mesh.position.y = 0;
animalBodyGroup.add(footLeft.mesh);

// master group that is added to the scene (whole animal)
animalGroup.add(animalBodyGroup);

animalGroup.position.y = -40;
animalGroup.castShadow = true;
animalGroup.receiveShadow = true;

scene.add(animalGroup) }


我向您展示了模型的构建方式,主要是因为我认为这不是实现模型的最佳方法,并且认为它对于找到问题的答案很有用。

问题

我希望将“ Bottom Body”部分(BodyBottom)悬停在其上时更改颜色,但是目前,我当前的代码仅导致animalGroup投射的阴影更改颜色。我知道最好的方法是使用raycaster,但是,raycaster似乎没有检测到单个对象,甚至没有检测到主animalGroup对象。我创建了一个detectMouseMove事件侦听器,并在该函数中使用以下代码找到了鼠标的3D位置:

mousePos3D = new THREE.Vector3(( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1, 0.5 );


以下代码是我从Three.js example复制的raycaster代码。此代码也位于detectMouseMove函数中,应该吗?

var raycaster = new THREE.Raycaster();

raycaster.setFromCamera( mousePos3D, camera );

var intersects = raycaster.intersectObjects( scene.children );

console.info(INTERSECTED);

if ( intersects.length > 0 ) {
    if ( INTERSECTED != intersects[ 0 ].object ) {
        if ( INTERSECTED ) INTERSECTED.material.emissive.setHex( INTERSECTED.currentHex );
        INTERSECTED = intersects[ 0 ].object;
        INTERSECTED.currentHex = INTERSECTED.material.emissive.getHex();
        INTERSECTED.material.emissive.setHex( 0xff0000 );
    }
} else {
    if ( INTERSECTED ) INTERSECTED.material.emissive.setHex( INTERSECTED.currentHex );
    INTERSECTED = null;
}


此代码似乎仅更改投射到地板上的Animal对象的阴影的颜色(下面的代码)

function createFloor(){
    var geomFloor = new THREE.PlaneGeometry(350,350);
    var matFloor = new THREE.MeshPhongMaterial({color: 0xffffff});
    var Floor = new THREE.Mesh(geomFloor, matFloor);
    Floor.rotation.x = -Math.PI/2;
    Floor.position.y = -72.5;
    // allows shadow to be cast on floor (same for all objects)
    Floor.receiveShadow = true;
    scene.add(Floor);
}


我的猜测是,由于动物的构造方式,或者也许是当动物被调用时,光线投射器并未与之相交,但是我不知道,因此我为什么要在这里询问。

我在寻找什么:


修复以使单个对象可交叉
仅使BodyBottom相交


感谢您的帮助,如果您需要我的代码示例或其他类似的示例,请让我知道,这是我的第一个SO问题,请对我轻松一点,但是我也希望您能提出有关改善问题的反馈!谢谢。

最佳答案

原来,我要做的就是更改:

var intersects = raycaster.intersectObjects( scene.children );


至:

var intersects = raycaster.intersectObjects( scene.children, true );


感谢@WestLangley在对我的问题的评论中给出的答案,只需将其发布在此处,以便将来找到它的任何人都可以清楚地看到答案。

经过更多研究后,我发现这解决了我的问题,因为true参数使相交递归,这意味着它将与对象的所有后代相交,而不仅仅是与对象相交。我认为这是可行的,因为我将所有对象都分组到一个大的“主”组中,因此,在不相交递归的情况下,只需选择该大组即可。我仍然不确定为什么这会使阴影改变颜色而不是整个动物,所以对此的任何想法都可以在评论中找到。可以在here中找到更多信息。

10-07 19:35
查看更多