mirror of
https://github.com/jiawanlong/Cesium-Examples.git
synced 2025-07-04 15:17:36 +00:00
模型压平功能(可以按照多边形进行不同高度压平)
This commit is contained in:
parent
866c624ec3
commit
fa6b55da28
71
examples/cesiumEx/3.1.7、模型压平.html
Normal file
71
examples/cesiumEx/3.1.7、模型压平.html
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<!--********************************************************************
|
||||||
|
* by jiawanlong
|
||||||
|
*********************************************************************-->
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="stylesheet" href="./../../libs/cesium/Cesium1.98/Widgets/widgets.css">
|
||||||
|
<script type="text/javascript" src="./../../libs/cesium/Cesium1.98/Cesium.js"></script>
|
||||||
|
<script src="./flat.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body style="margin: 0; overflow: hidden; background: #fff; width: 100%; height: 100%; position: absolute; top: 0">
|
||||||
|
<div id="map" style="margin: 0 auto; width: 100%; height: 100%"></div>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI3ZjQ5ZGUzNC1jNWYwLTQ1ZTMtYmNjYS05YTY4ZTVmN2I2MDkiLCJpZCI6MTE3MTM4LCJpYXQiOjE2NzY0NDUyODB9.ZaNSBIfc1sGLhQd_xqhiSsc0yr8oS0wt1hAo9gbke6M'
|
||||||
|
const viewer = new Cesium.Viewer('map', {});
|
||||||
|
// 开启帧率
|
||||||
|
viewer.scene.debugShowFramesPerSecond = true;
|
||||||
|
|
||||||
|
const tileset = new Cesium.Cesium3DTileset({
|
||||||
|
url: "http://mapgl.com/data/model/qx-simiao/tileset.json",
|
||||||
|
maximumScreenSpaceError: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
viewer.terrainProvider = new Cesium.CesiumTerrainProvider({
|
||||||
|
url: 'http://data.mars3d.cn/terrain'
|
||||||
|
});
|
||||||
|
|
||||||
|
tileset.readyPromise
|
||||||
|
.then(function (tileset) {
|
||||||
|
|
||||||
|
viewer.scene.primitives.add(tileset);
|
||||||
|
viewer.zoomTo(tileset)
|
||||||
|
|
||||||
|
var cartographic = Cesium.Cartographic.fromCartesian(tileset.boundingSphere.center);
|
||||||
|
var surface = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, 0.0);
|
||||||
|
var offset = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, 80);
|
||||||
|
var translation = Cesium.Cartesian3.subtract(offset, surface, new Cesium.Cartesian3());
|
||||||
|
tileset.modelMatrix = Cesium.Matrix4.fromTranslation(translation.clone());
|
||||||
|
|
||||||
|
let arr = [
|
||||||
|
new Cesium.Cartesian3( -2580727.5168023095, 4650258.972413558, 3508953.4819122115 ),
|
||||||
|
new Cesium.Cartesian3( -2581252.4920162656, 4650087.404390791, 3508794.900735431 ),
|
||||||
|
new Cesium.Cartesian3( -2581254.813624642, 4649950.479168881, 3508978.370871617 ),
|
||||||
|
new Cesium.Cartesian3( -2580723.027766725, 4650025.757869746, 3509279.009217198 ),
|
||||||
|
]
|
||||||
|
|
||||||
|
let flatTool = new Flat(tileset, {
|
||||||
|
flatHeight: -30
|
||||||
|
})
|
||||||
|
flatTool.addRegion({
|
||||||
|
positions: arr,
|
||||||
|
id: new Date().getTime()
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(function (error) {
|
||||||
|
console.log(error);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
@ -548,6 +548,7 @@ var exampleConfig = {
|
|||||||
thumbnail: "2.4.6、点击获取子节点.jpg",
|
thumbnail: "2.4.6、点击获取子节点.jpg",
|
||||||
fileName: "2.4.6、点击获取子节点"
|
fileName: "2.4.6、点击获取子节点"
|
||||||
},
|
},
|
||||||
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -596,6 +597,12 @@ var exampleConfig = {
|
|||||||
thumbnail: "3.1.6、点击获取属性.jpg",
|
thumbnail: "3.1.6、点击获取属性.jpg",
|
||||||
fileName: "3.1.6、点击获取属性"
|
fileName: "3.1.6、点击获取属性"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "3.1.7、模型压平",
|
||||||
|
name_en: "3.1.7、模型压平",
|
||||||
|
thumbnail: "3.1.7、模型压平.jpg",
|
||||||
|
fileName: "3.1.7、模型压平"
|
||||||
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
217
examples/cesiumEx/flat.js
Normal file
217
examples/cesiumEx/flat.js
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
/**
|
||||||
|
* @class
|
||||||
|
* @description 3dtiles模型压平
|
||||||
|
*/
|
||||||
|
class Flat {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Cesium.Cesium3DTileset} tileset 三维模型
|
||||||
|
* @param {Object} opt
|
||||||
|
* @param {Number} opt.flatHeight 压平高度
|
||||||
|
*/
|
||||||
|
constructor(tileset, opt) {
|
||||||
|
if (!tileset) return;
|
||||||
|
this.tileset = tileset;
|
||||||
|
this.opt = opt || {};
|
||||||
|
this.flatHeight = this.opt.flatHeight || 0;
|
||||||
|
|
||||||
|
this.center = tileset.boundingSphere.center.clone();
|
||||||
|
|
||||||
|
|
||||||
|
this.matrix = Cesium.Transforms.eastNorthUpToFixedFrame(this.center.clone());
|
||||||
|
this.localMatrix = Cesium.Matrix4.inverse(this.matrix, new Cesium.Matrix4());
|
||||||
|
|
||||||
|
// 多面的坐标数组
|
||||||
|
this.regionList = [];
|
||||||
|
// 多个面坐标转为局部模型坐标
|
||||||
|
this.localPositionsArr = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加压平面
|
||||||
|
* @param {Object} attr 参数
|
||||||
|
* @param {Cesium.Cartesian3[]} attr.positions 压平面坐标
|
||||||
|
* @param {Number} attr.height 压平深度,当前不支持单独设置
|
||||||
|
* @param {Number} attr.id 唯一标识
|
||||||
|
*/
|
||||||
|
addRegion(attr) {
|
||||||
|
let { positions, height, id } = attr || {};
|
||||||
|
// this.flatHeight = height;
|
||||||
|
if (!id) id = (new Date()).getTime() + "" + Number(Math.random() * 1000).toFixed(0);
|
||||||
|
this.regionList.push(attr);
|
||||||
|
for (let i = 0; i < this.regionList.length; i++) {
|
||||||
|
let item = this.regionList[i];
|
||||||
|
const positions = item.positions;
|
||||||
|
let localCoor = this.cartesiansToLocal(positions);
|
||||||
|
this.localPositionsArr.push(localCoor);
|
||||||
|
}
|
||||||
|
|
||||||
|
const funstr = this.getIsinPolygonFun(this.localPositionsArr);
|
||||||
|
let str = ``;
|
||||||
|
for (let i = 0; i < this.localPositionsArr.length; i++) {
|
||||||
|
const coors = this.localPositionsArr[i];
|
||||||
|
const n = coors.length;
|
||||||
|
let instr = ``;
|
||||||
|
coors.forEach((coordinate, index) => {
|
||||||
|
instr += `points_${n}[${index}] = vec2(${coordinate[0]}, ${coordinate[1]});\n`;
|
||||||
|
})
|
||||||
|
str += `
|
||||||
|
${instr}
|
||||||
|
if(isPointInPolygon_${n}(position2D)){
|
||||||
|
vec4 tileset_local_position_transformed = vec4(tileset_local_position.x, tileset_local_position.y, ground_z, 1.0);
|
||||||
|
vec4 model_local_position_transformed = czm_inverseModel * u_tileset_localToWorldMatrix * tileset_local_position_transformed;
|
||||||
|
vsOutput.positionMC.xy = model_local_position_transformed.xy;
|
||||||
|
vsOutput.positionMC.z = model_local_position_transformed.z+ modelMC.z*0.002;
|
||||||
|
return;
|
||||||
|
}`;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateShader(funstr, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据id删除压平的面
|
||||||
|
* @param {String} id 唯一标识
|
||||||
|
*/
|
||||||
|
removeRegionById(id) {
|
||||||
|
if (!id) return;
|
||||||
|
|
||||||
|
this.regionList = this.regionList.filter((attr) => {
|
||||||
|
return attr.id != id;
|
||||||
|
})
|
||||||
|
|
||||||
|
this.localPositionsArr = [];
|
||||||
|
for (let i = 0; i < this.regionList.length; i++) {
|
||||||
|
let item = this.regionList[i];
|
||||||
|
const positions = item.positions;
|
||||||
|
let localCoor = this.cartesiansToLocal(positions);
|
||||||
|
this.localPositionsArr.push(localCoor);
|
||||||
|
}
|
||||||
|
|
||||||
|
const funstr = this.getIsinPolygonFun(this.localPositionsArr);
|
||||||
|
let str = ``;
|
||||||
|
for (let i = 0; i < this.localPositionsArr.length; i++) {
|
||||||
|
const coors = this.localPositionsArr[i];
|
||||||
|
const n = coors.length;
|
||||||
|
let instr = ``;
|
||||||
|
coors.forEach((coordinate, index) => {
|
||||||
|
instr += `points_${n}[${index}] = vec2(${coordinate[0]}, ${coordinate[1]});\n`;
|
||||||
|
})
|
||||||
|
str += `
|
||||||
|
${instr}
|
||||||
|
if(isPointInPolygon_${n}(position2D)){
|
||||||
|
vec4 tileset_local_position_transformed = vec4(tileset_local_position.x, tileset_local_position.y, ground_z, 1.0);
|
||||||
|
vec4 model_local_position_transformed = czm_inverseModel * u_tileset_localToWorldMatrix * tileset_local_position_transformed;
|
||||||
|
vsOutput.positionMC.xy = model_local_position_transformed.xy;
|
||||||
|
vsOutput.positionMC.z = model_local_position_transformed.z+ modelMC.z*0.002;
|
||||||
|
return;
|
||||||
|
}`;
|
||||||
|
|
||||||
|
}
|
||||||
|
this.updateShader(funstr, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 销毁
|
||||||
|
*/
|
||||||
|
destroy() {
|
||||||
|
this.tileset.customShader = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据数组长度,构建 判断点是否在面内 的压平函数
|
||||||
|
*/
|
||||||
|
getIsinPolygonFun(polygons) {
|
||||||
|
let pmap = polygons.map((polygon) => polygon.length);
|
||||||
|
let uniqueArray = this.getUniqueArray(pmap);
|
||||||
|
let str = ``;
|
||||||
|
uniqueArray.forEach(length => {
|
||||||
|
str += `
|
||||||
|
vec2 points_${length}[${length}];
|
||||||
|
bool isPointInPolygon_${length}(vec2 point){
|
||||||
|
int nCross = 0; // 交点数
|
||||||
|
const int n = ${length};
|
||||||
|
for(int i = 0; i < n; i++){
|
||||||
|
vec2 p1 = points_${length}[i];
|
||||||
|
vec2 p2 = points_${length}[int(mod(float(i+1),float(n)))];
|
||||||
|
if(p1[1] == p2[1]){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(point[1] < min(p1[1], p2[1])){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(point[1] >= max(p1[1], p2[1])){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
float x = p1[0] + ((point[1] - p1[1]) * (p2[0] - p1[0])) / (p2[1] - p1[1]);
|
||||||
|
if(x > point[0]){
|
||||||
|
nCross++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return int(mod(float(nCross), float(2))) == 1;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
})
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
|
updateShader(vtx1, vtx2) {
|
||||||
|
let flatCustomShader = new Cesium.CustomShader({
|
||||||
|
uniforms: {
|
||||||
|
u_tileset_localToWorldMatrix: {
|
||||||
|
type: Cesium.UniformType.MAT4,
|
||||||
|
value: this.matrix,
|
||||||
|
},
|
||||||
|
u_tileset_worldToLocalMatrix: {
|
||||||
|
type: Cesium.UniformType.MAT4,
|
||||||
|
value: this.localMatrix,
|
||||||
|
},
|
||||||
|
u_flatHeight: {
|
||||||
|
type: Cesium.UniformType.FLOAT,
|
||||||
|
value: this.flatHeight,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
vertexShaderText: `
|
||||||
|
// 所有isPointInPolygon函数
|
||||||
|
${vtx1}
|
||||||
|
void vertexMain(VertexInput vsInput, inout czm_modelVertexOutput vsOutput){
|
||||||
|
vec3 modelMC = vsInput.attributes.positionMC;
|
||||||
|
vec4 model_local_position = vec4(modelMC.x, modelMC.y, modelMC.z, 1.0);
|
||||||
|
vec4 tileset_local_position = u_tileset_worldToLocalMatrix * czm_model * model_local_position;
|
||||||
|
vec2 position2D = vec2(tileset_local_position.x,tileset_local_position.y);
|
||||||
|
float ground_z = 0.0 + u_flatHeight;
|
||||||
|
// 多个多边形区域
|
||||||
|
${vtx2}
|
||||||
|
}`,
|
||||||
|
});
|
||||||
|
this.tileset.customShader = flatCustomShader;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 数组去重,不能处理嵌套的数组
|
||||||
|
getUniqueArray = (arr) => {
|
||||||
|
return arr.filter(function (item, index, arr) {
|
||||||
|
//当前元素,在原始数组中的第一个索引==当前索引值,否则返回当前元素
|
||||||
|
return arr.indexOf(item, 0) === index;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 世界坐标转数组局部坐标
|
||||||
|
cartesiansToLocal(positions) {
|
||||||
|
let arr = [];
|
||||||
|
for (let i = 0; i < positions.length; i++) {
|
||||||
|
let position = positions[i];
|
||||||
|
let localp = Cesium.Matrix4.multiplyByPoint(
|
||||||
|
this.localMatrix,
|
||||||
|
position.clone(),
|
||||||
|
new Cesium.Cartesian3()
|
||||||
|
)
|
||||||
|
arr.push([localp.x, localp.y]);
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
BIN
examples/cesiumEx/img/3.1.7、模型压平.jpg
Normal file
BIN
examples/cesiumEx/img/3.1.7、模型压平.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.9 KiB |
Loading…
Reference in New Issue
Block a user