Cesium地形开挖实现原理
地形裁剪是通过剔除裁剪⾯的组合空间范围内的⽚源实现
第⼀步:构建裁剪⾯,这⾥我们根据地理坐标的范围点实现裁剪⾯的创建(⽤户代码)
1)计算传⼊的点范围的顺序是逆时针还是顺时针 [isR=true]表⽰点的顺序是逆时针。
1var x1 = polygon[0].longitude;
2
3var y1 = polygon[0].latitude;
4
5var x2 = polygon[1].longitude;
6
7var y2 = polygon[1].latitude;
8
9var x3 = polygon[2].longitude;
10
11var y3 = polygon[2].latitude;
12
13
14
15var dirRes = (x2 - x1) * (y3 - y2) - (y2 - y1) * (x3 - x2);
16
17var isR = dirRes > 0;
逆时针则按照原本顺序存储点,否则从后往前依次存储点。
1var points = [];
2
3if (isR) {
4
5for (var ii = 0; ii < polygon.length; ii++) {
6
7                    points[ii] = Cesium.Cartesian3.fromDegrees(polygon[ii].longitude, polygon[ii].latitude);
8
9                }
10
11            } else {float up
12
13var count = 0;
14
15for (var ii = polygon.length - 1; ii >= 0; ii--) {
16
17                    points[count] = Cesium.Cartesian3.fromDegrees(polygon[ii].longitude, polygon[ii].latitude);
18
19                    count++;
20
21                }
22
23            }
2)分别计算由三点确定的⾯(其中第三个点为原点,裁剪⾯经过原点),midpoint为两点直线连线的中点,up是单位向量,从原点
(0,0,0)出发经过midpoint射线⽅向的单位向量。right为第⼀个点到第⼆点⽅向的单位向量。normal为垂直于裁剪⾯的法线向量。originCenteredPlane是法向量normal经过原点的⾯,distance是中点到originCenteredPlane⾯的距离,由distance和normal即可确定两点构成的裁剪⾯。
1var pointsLength = points.length;
2
3var clippingPlanes = [];
4
5for (var i = 0; i < pointsLength; ++i) {
6
7var nextIndex = (i + 1) % pointsLength;
8
9var midpoint = Cesium.Cartesian3.add(points[i], points[nextIndex], new Cesium.Cartesian3());
10
11                midpoint = Cesium.Cartesian3.multiplyByScalar(midpoint, 0.5, midpoint);
12
13
14
15var up = alize(midpoint, new Cesium.Cartesian3());
17var right = Cesium.Cartesian3.subtract(points[nextIndex], midpoint, new Cesium.Cartesian3());
18
19                right = alize(right, right);
20
21
22
23var normal = ss(right, up, new Cesium.Cartesian3());
24
25                normal = alize(normal, normal);
26
27
28
29var originCenteredPlane = new Cesium.Plane(normal, 0.0);
30
31var distance = PointDistance(originCenteredPlane, midpoint);
32
33
34
35                clippingPlanes.push(new Cesium.ClippingPlane(normal, distance));
36
37            }
第⼆步:Cesium内部实现裁剪⾯相关参数存储,裁剪⾯clippingPlanes的参数存储在纹理中,具体解析如下:1)计算存储裁剪⾯相关参数所需的纹理宽度和⾼度⼤⼩,pixelsNeeded存储裁剪⾯参数所需的纹理的⼤
⼩,ContextLimits.maximumTextureSize = 8192,纹理最⼤宽度限制。
1var pixelsNeeded = useFloatTexture ? this.length : this.length * 2;
2
3
4
5function computeTextureResolution(pixelsNeeded, result) {
6
7var maxSize = ContextLimits.maximumTextureSize;
8
9        result.x = Math.min(pixelsNeeded, maxSize);
10
11        result.y = il(pixelsNeeded / result.x);
12
13return result;
14
15    }
2)创建裁剪纹理
1            requiredResolution.y *= 2;//分配所需空间的两倍,以避免频繁的纹理重新分配
2
3
4
5var sampler = new Sampler({
6
7                wrapS : TextureWrap.CLAMP_TO_EDGE,
8
9                wrapT : TextureWrap.CLAMP_TO_EDGE,
10
11                minificationFilter : TextureMinificationFilter.NEAREST,
12
13                magnificationFilter : TextureMagnificationFilter.NEAREST
14
15            });
16
17
18
19if (useFloatTexture) {
20
21                clippingPlanesTexture = new Texture({
22
23                    context : context,
24
25                    width : requiredResolution.x,
26
27                    height : requiredResolution.y,
28
29                    pixelFormat : PixelFormat.RGBA,
30
31                    pixelDatatype : PixelDatatype.FLOAT,
33                    sampler : sampler,
34
35                    flipY : false
36
37                });
38
39this._float32View = new Float32Array(requiredResolution.x * requiredResolution.y * 4); 40
41            } else {
42
43                clippingPlanesTexture = new Texture({
44
45                    context : context,
46
47                    width : requiredResolution.x,
48
49                    height : requiredResolution.y,
50
51                    pixelFormat : PixelFormat.RGBA,
52
53                    pixelDatatype : PixelDatatype.UNSIGNED_BYTE,
54
55                    sampler : sampler,
56
57                    flipY : false
58
59                });
60
61this._uint8View = new Uint8Array(requiredResolution.x * requiredResolution.y * 4);
62
63            }
64
65
3)封装纹理数据
1function packPlanesAsFloats(clippingPlaneCollection, startIndex, endIndex) {
2
3var float32View = clippingPlaneCollection._float32View;
4
5var planes = clippingPlaneCollection._planes;
6
7
8
9var floatIndex = 0;
10
11for (var i = startIndex; i < endIndex; ++i) {
12
13var plane = planes[i];
14
15var normal = al;
16
17
18
19            float32View[floatIndex] = normal.x;
20
21            float32View[floatIndex + 1] = normal.y;
22
23            float32View[floatIndex + 2] = normal.z;
24
25            float32View[floatIndex + 3] = plane.distance;
26
27
28
29            floatIndex += 4; // each plane is 4 floats
30
31        }
32
33    }
34
35
36
37 packPlanesAsFloats(this, 0, this._planes.length);
38
39
40
pyFrom({
42
43                width : clippingPlanesTexture.width,
44
45                height : clippingPlanesTexture.height,
46
47                arrayBufferView : this._float32View
48
49            });
第三步:构建globe时,向globe着⾊器代码中添加裁剪⾯着⾊器代码,部分代码省略,其中width为存储裁剪⾯纹理的宽度和⾼度  1function getClippingPlaneFloat(width, height) {
2
3var pixelWidth = 1.0 / width;
4
5var pixelHeight = 1.0 / height;
6
7
8
9var pixelWidthString = pixelWidth + '';
10
11if (pixelWidthString.indexOf('.') === -1) {
12
13            pixelWidthString += '.0';
14
15        }
16
17var pixelHeightString = pixelHeight + '';
18
19if (pixelHeightString.indexOf('.') === -1) {
20
21            pixelHeightString += '.0';
22
23        }
24
25
26
27var functionString =
28
29            'vec4 getClippingPlane(sampler2D packedClippingPlanes, int clippingPlaneNumber, mat4 transform)\n' +
30
31            '{\n' +
32
33            '    int pixY = clippingPlaneNumber / ' + width + ';\n' +
34
35            '    int pixX = clippingPlaneNumber - (pixY * ' + width + ');\n' +
36
37            '    float u = (float(pixX) + 0.5) * ' + pixelWidthString + ';\n' + // sample from center of pixel
38
39            '    float v = (float(pixY) + 0.5) * ' + pixelHeightString + ';\n' +
40
41            '    vec4 plane = texture2D(packedClippingPlanes, vec2(u, v));\n' +
42
43            '    return czm_transformPlane(plane, transform);\n' +
44
45            '}\n';
46
47return functionString;
48
49    }
50
51
52
53
54
55function clippingFunctionIntersect(clippingPlanesLength) {
56
57var functionString =
58
59            'float clip(vec4 fragCoord, sampler2D clippingPlanes, mat4 clippingPlanesMatrix)\n' +
60
61            '{\n' +
62
63            '    bool clipped = true;\n' +
64
65            '    vec4 position = czm_windowToEyeCoordinates(fragCoord);\n' +
66
67            '    vec3 clipNormal = vec3(0.0);\n' +
68
69            '    vec3 clipPosition = vec3(0.0);\n' +
70
71            '    float clipAmount = 0.0;\n' +
72
73            '    float pixelWidth = czm_metersPerPixel(position);\n' +
74
75
76
77            '    for (int i = 0; i < ' + clippingPlanesLength + '; ++i)\n' +
78
79            '    {\n' +
80
81            '        vec4 clippingPlane = getClippingPlane(clippingPlanes, i, clippingPlanesMatrix);\n' +
82
83
84
85            '        clipNormal = ;\n' +
86
87            '        clipPosition = -clippingPlane.w * clipNormal;\n' +
88
89
90
91            '        float amount = dot(clipNormal, ( - clipPosition)) / pixelWidth;\n' +
92
93            '        clipAmount = max(amount, clipAmount);\n' +
94
95
96
97            '        clipped = clipped && (amount <= 0.0);\n' +
98
99            '    }\n' +
100
101
102
103            '    if (clipped)\n' +
104
105            '    {\n' +
106
107            '        discard;\n' +
108
109            '    }\n' +
110
111
112
113            '    return clipAmount;\n' +
114
115            '}\n';
116
117return functionString;
118
119    }
代码解析:
vec4 position = czm_windowToEyeCoordinates(fragCoord) 待检测的点
clipNormal =   垂直于裁剪⾯的法线向量
clipPosition = -clippingPlane.w * clipNormal; 法向量与裁剪⾯的交点
float amount = dot(clipNormal, ( - clipPosition)) / pixelWidth; 待待测点与裁剪⾯上某⼀点构成的⽅向向
量, dot(clipNormal, ( - clipPosition)) ⽅向向量在裁剪⾯法线⽅向上的投影长度(|clipNormal| | - clipPosition| *cos∠(clipNormal, ( - clipPosition))),除以pixelWidth得到投影长度的单位长度。
clipAmount = max(amount, clipAmount);
clipped = clipped && (amount <= 0.0);
判断分量符号是否发⽣变化,如果最终结果改变则不再范围内,如果最终结果不变则在范围内。
注意:⾯的存储顺序是逆序时,判断代码如上。所以在做裁剪时外部需要传⼊逆时针存储的⾯。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。