分层思路
在 three.js 中,可以使用多个mesh
来实现楼栋分层渲染。
感觉和 cesium.js 的分层渲染思路,没有什么区别啊…但还是要记录一下
1、楼层数确定
具体步骤如下:
-
将楼栋的每一层分别建模成一个mesh
,并设置不同的高度和材质。 -
将每一层的mesh添加到一个数组中,按照从下往上的顺序排列。
-
使用
THREE.Group
来将每一层的mesh组合起来,形成一个楼栋。 -
将楼栋的整个Group添加到场景中。
-
使用
THREE.Raycaster
来检测用户的交互事件(例如点击),并判断用户所点击的位置是否在楼栋范围内。 -
根据用户点击的位置,计算出用户所点击的层数,并将该层的mesh设置为高亮显示状态。
示例代码:
// 因为楼层数是确定的,所以不用特地使用代码进行排序,直接在创建mesh的时候,按从下到上的顺序排序创建即可
// 创建每一层的mesh
var layer1 = new THREE.Mesh(geometry1, material1);
var layer2 = new THREE.Mesh(geometry2, material2);
var layer3 = new THREE.Mesh(geometry3, material3);
// 将每一层的mesh添加到数组中
var layers = [layer1, layer2, layer3];
// 将每一层的mesh组合成一个Group
var building = new THREE.Group();
for (var i = 0; i < layers.length; i++) {
layers[i].position.y = i * layerHeight; // 设置每一层的高度
building.add(layers[i]);
}
// 将整个楼栋的Group添加到场景中
scene.add(building);
// 监听鼠标点击事件
var raycaster = new THREE.Raycaster();
function onMouseClick(event) {
// 计算用户点击的位置
var mouse = new THREE.Vector2();
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
// 将屏幕坐标转换为三维坐标
raycaster.setFromCamera(mouse, camera);
// 检测用户点击的位置是否在楼栋范围内
var intersects = raycaster.intersectObject(building, true);
if (intersects.length > 0) {
// 计算用户所点击的层数
var layerIndex = Math.floor(intersects[0].point.y / layerHeight);
// 将该层的mesh设置为高亮显示状态
layers[layerIndex].material.color.set(0xff0000);
}
}
window.addEventListener('click', onMouseClick, false);
2、楼层数动态
具体步骤如下:
-
根据楼层数
动态创建每一层的mesh
,并设置不同的高度和材质。 -
将每一层的mesh添加到一个数组中,按照从下往上的顺序排列。
-
使用
THREE.Group
来将每一层的mesh组合起来,形成一个楼栋。 -
将楼栋的整个Group添加到场景中。
-
使用
THREE.Raycaster
来检测用户的交互事件(例如点击),并判断用户所点击的位置是否在楼栋范围内。 -
根据用户点击的位置,计算出用户所点击的层数,并将该层的mesh设置为高亮显示状态。
-
如果楼层数发生改变,需要重新创建每一层的mesh,更新楼栋的Group,并更新每一层的高度和材质。(Tips:这里不一定用得上)
下面是一个示例代码:
// 注意!!!!
// 因为是动态楼层,所以,numLayers楼层数 这里可以换成 allLayers总楼层数据-最好可以先排个序,按照从低到高
// 排序的方法就不放出来了,因为楼栋-楼层模型数据不一样,可能楼栋-楼层的命名规则不一样,排序方法也要求不同
// 动态创建每一层的mesh
var layers = [];
for (var i = 0; i < numLayers; i++) {
var layer = new THREE.Mesh(geometry, material);
layer.position.y = i * layerHeight; // 设置每一层的高度
layers.push(layer);
}
// 将每一层的mesh组合成一个Group
var building = new THREE.Group();
for (var i = 0; i < layers.length; i++) {
building.add(layers[i]);
}
// 将整个楼栋的Group添加到场景中
scene.add(building);
// 监听鼠标点击事件
var raycaster = new THREE.Raycaster();
function onMouseClick(event) {
// 计算用户点击的位置
var mouse = new THREE.Vector2();
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
// 将屏幕坐标转换为三维坐标
raycaster.setFromCamera(mouse, camera);
// 检测用户点击的位置是否在楼栋范围内
var intersects = raycaster.intersectObject(building, true);
if (intersects.length > 0) {
// 计算用户所点击的层数
var layerIndex = Math.floor(intersects[0].point.y / layerHeight);
// 将该层的mesh设置为高亮显示状态
layers[layerIndex].material.color.set(0xff0000);
}
}
window.addEventListener('click', onMouseClick, false);
// 这一段代码不一定用得上
// 如果楼层数发生改变,重新创建每一层的mesh,并更新楼栋的Group、每一层的高度和材质
function updateBuilding(numLayers, layerHeight, geometry, material) {
for (var i = 0; i < layers.length; i++) {
building.remove(layers[i]);
}
layers = [];
for (var i = 0; i < numLayers; i++) {
var layer = new THREE.Mesh(geometry, material);
layer.position.y = i * layerHeight;
layers.push(layer);
building.add(layer);
}
}