大家好,我是日拱一卒的攻城师不浪,致力于技术与艺术的融合。这是2024年输出的第44/100篇文章。
天际线
,这个场景我不晓得大家在项目开发中有没有涉及过这个概念。
简单来说,天际线效果就是让你的建筑物边缘
在视觉上更加突出,就像给建筑物描了个边一样。这种效果在城市规划、建筑设计等领域非常有用。
主要应用场景如下:
-
地理信息系统(GIS):在GIS领域,天际线分析可以用于评估城市景观的
视觉影响
,帮助决策者理解城市发展对景观的影响; -
城市规划与设计:天际线效果可以帮助规划师和设计师更清晰地展示城市的轮廓,特别是在高楼大厦较多的城市环境中,天际线效果能够突出建筑物的轮廓,
增强视觉效果
;
在Cesium中,我们可以通过编写GLSL着色器
代码来实现这个效果。
着色器代码是运行在显卡(GPU)
上的,用来告诉显卡如何渲染图像。
创建天际线类
首先,我们定义了一个SkyLineAnalysis
类。
export default class SkyLineAnalysis {
constructor(viewer) {
// 接收viewer参数
this.viewer = viewer;
}
}
2. 开启天际线效果
在open
方法中,我们首先检查是否已经开启了天际线效果,如果已经开启了,就直接返回。
如果没有开启,我们就创建一些后处理阶段(PostProcessStages
),用来处理图像。
open() {
if (this.skylineAnayStages) {
this.silhouette.enabled = true;
return;
}
// ...创建后处理阶段
this.skylineAnayStages = this.viewer.scene.postProcessStages;
let edgeDetection = Cesium.PostProcessStageLibrary.createEdgeDetectionStage();
}
着色器代码
接下来,我们来看最关键的部分——着色器
代码。
着色器1:检测深度
uniform sampler2D colorTexture;
uniform sampler2D depthTexture;
in vec2 v_textureCoordinates;
out vec4 fragColor;
void main(void) {
float depth = czm_readDepth(depthTexture, v_textureCoordinates);
vec4 color = texture(colorTexture, v_textureCoordinates);
if (depth < 1.0 - 0.000001) {
fragColor = color;
} else {
fragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
}
这段代码的作用是读取深度纹理
,如果深度值小于1(这里我们留了一点点误差空间),我们就保留原来的颜色,否则就将该像素渲染成红色。这个红色的像素就是我们天际线的边缘。
着色器2:混合颜色
uniform sampler2D colorTexture;
uniform sampler2D redTexture;
uniform sampler2D silhouetteTexture;
in vec2 v_textureCoordinates;
out vec4 fragColor;
void main(void) {
vec4 redcolor = texture(redTexture, v_textureCoordinates);
vec4 silhouetteColor = texture(silhouetteTexture, v_textureCoordinates);
vec4 color = texture(colorTexture, v_textureCoordinates);
if (redcolor.r == 1.0) {
fragColor = mix(color, vec4(5.0, 0.0, 0.0, 1.0), silhouetteColor.a);
} else {
fragColor = color;
}
}
这段代码的作用是混合颜色。如果检测到红色(天际线边缘),我们就将颜色混合成更深的红色,以此来突出天际线。
后处理组合
this.silhouette = new Cesium.PostProcessStageComposite({
// PostProcessStage要按顺序执行的stage或组合的数组。
stages: [edgeDetection, postProccessStage, postProccesStage_1],
// 是否执行每个后处理阶段,其中一个阶段的输入是前一个阶段的输出。
// 否则每个包含阶段的输入是组合之前执行的阶段的输出
inputPreviousStageTexture: false,
// 后处理阶段uniforms的别名
uniforms: edgeDetection.uniforms
});
这段代码是Cesium中用于创建一个后处理阶段组合(PostProcessStageComposite)
。
PostProcessStageComposite
是Cesium提供的一个类,允许我们将多个后处理阶段(PostProcessStage
)组合在一起,以便按顺序执行这些阶段,从而对场景的渲染结果进行进一步的处理。
-
stages
:这是一个数组,包含了需要按顺序执行的后处理阶段。在这个例子中,我们有三个阶段:edgeDetection
、postProccessStage
和postProccesStage_1
。这些阶段将按照它们在数组中的顺序被执行。 -
inputPreviousStageTexture
:接收一个布尔值,用于指定每个阶段的输入纹理来源。如果设置为true
,则每个阶段的输入纹理是前一个阶段的输出纹理。如果设置为false
(如这段代码所示),则所有阶段的输入纹理都是相同的,即它们都是原始场景渲染到的输出纹理。 -
uniforms
:这是一组uniform变量,用于传递给着色器程序。在这个例子中,我们使用了edgeDetection
阶段的uniforms。Uniforms是GLSL着色器中的一种变量类型,用于在顶点着色器和片段着色器之间传递数据。
关闭天际线效果
最后,我们还有一个close
方法,用来关闭天际线效果。
close() {
this.silhouette.enabled = false;
}
最后
以上我们解析了在Cesium中渲染天际线的主要流程,如果想要更完整的代码可以查看作者的开源项目:github.com/tingyuxuan2…
如果认为有帮助请给予我们一个star
支持鼓励我们开源更多!
如果想系统学习Cesium,可以了解下作者的Cesium系列教程
《Cesium从入门到实战》
,将Cesium的知识点进行串联,让不了解Cesium的小伙伴拥有一个完整的学习路线,并最终完成一个智慧城市
的完整项目,+作者:brown_7778(备注来意)了解教程细节。
有需要进
可视化&Webgis交流群
可以加我:brown_7778(备注来意)。