赞
踩
最近公司有个项目,要做一个3D的仓库展示,然后点击仓库中的一个储位,能显示出储位上具体存放哪些东西。这里我选用Three.js来实现
前面都还顺利,之前没接触过前端3D方面的知识,但根据Three.js官方文档 花了一点时间,在UI的支持下(模型为UI用3DMAX导出的obj模型),顺利的加载出了模型,加上一些基础的灯光、材质、贴图,效果如下:
接下来只要用raycaster捕获一下点击的模型,绑定点击事件展示出来就万事大吉了。
然而接下来却出现了这样一个问题
关键代码:
//2D坐标转换3D坐标
mouse.x =( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
// 通过鼠标点的位置和当前相机的矩阵计算出raycaster
raycaster.setFromCamera( mouse, camera );
// 获取raycaster直线和所有模型相交的数组集合
var intersects = raycaster.intersectObjects( scene.children );
//将第一个触发事件的模型改变为红色
if (intersects.length > 0) {
intersects[ 0 ].object.material.color.set( 0xff0000 );
}
本意是点击某个储位,就先把储位渲染为高亮红色,可实际效果却影响到了周围所有模型,如图:
文档上没找到原因,最后一位贴吧老哥的留言点醒了我
threejs中的网格物体对材质的是引用传递,不是值传递,如果material1 被 mesh1和mesh2用到了,改变 mesh1.material.color,则mesh2的材质颜色也改了
结论很明显就是在解析obj模型的时候,所有的储位模型都用了一个material,如此便有了以下猜想:
如果在ObjLoader加载模型后,给每个储位模型都重新赋予一个material,是否就能解决问题呢?
找到关键代码略加修改
改动前:
objLoader.load('ck-1-1.obj', function (object) {
object.scale.multiplyScalar(1);
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
//给name为A开头的模型贴图
if(child.name.indexOf("A")==0){
child.material.map = texture;
}
}
} );
改动后:
objLoader.load('ck-1-1.obj', function (object) {
object.scale.multiplyScalar(1);
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
//给name为A开头的模型贴图
if(child.name.indexOf("A")==0){
//每个储位单独赋予一个基础材质
child.material=
new THREE.MeshBasicMaterial({color: 0xFFFFFF});
child.material.map = texture;
}
}
} );
最后效果:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。