Cesium高级教程-后处理体积云-体积云原理

Cesium高级教程-后处理体积云-体积云原理

体积云与普通材质云

体积云与普通材质云最大的区别就是体积云有厚度(体积感),能够进入云中,更加具有真实感。

普通材质云,效果可到 进阶教程-示例效果 中查看

在这里插入图片描述

示例效果可到 xt3d 官网 运行查看

体积云,本章要实现的效果

在这里插入图片描述

示例效果可到 xt3d 官网 运行查看

体积云原理

目前实现体积云最常用的方式是云图噪声+光线步进

在这里插入图片描述

通过云图噪声生成云的基本形状,然后通过光线步进采样云的密度

  1. 云图噪声

    云图噪声主要用来生成云的形状,噪声的生成可以通过glsl实时生成,也可以通过工具将其生成为2D/3D纹理数据,方便加载使用,比如 shadertoy柏林+沃利噪声

  2. 光线步进

    因为云的形状是不规则的,所以无法使用简单的几何算法判断交点,而光线步进则可以很好地解决云的求交问题。 因为光线步进的原理是模拟光的前进,所以光从哪儿前进,每次前进多少,最多前进多远这些参数的设置对程序的性能有很大影响。

    对于局部的体积云,一般使用一个Box来表示云的范围,为了提高程序性能,光线步进一般只在该Box中进行,所以对于每条光线,首先需要获取其在Box上的起点和终点。

    在这里插入图片描述

关于体积云更多的知识及原理可以参考以下文章,大部分都是基于游戏引擎的,因为体积云最早就是出现在游戏引擎中。

体积云效果的实现,游戏世界的云合雾集

虚幻引擎体积云系统剖析

体积云渲染(Volumetric Clouds),技术美术教程

体积云渲染笔记

计算机图形学笔记——光线追踪(Ray Tracing)

也可以百度搜索 `体积云` 查看更多信息

在Cesium中实现体积云

体积云不是实体,所以是没有顶点信息的,因此我们只能通过片元着色器来实现。在Cesium中主要有以下两种实现方式

  1. 图元

    基于Primitive的方式可见体渲染一章中体渲染的实现,此种方式是通过将体内的计算结果显示到Geometry表面上来,所以虽然看起来像体,但其实还是Geometry表面渲染。

  2. 后处理

    基于后处理实现体渲染,更接近真实的体渲染效果,但是此方式需要在片元着色器中还原世界坐标,相对麻烦一点,不过在后处理中还原世界坐标的相关知识,相信对于此阶段的您已不成问题,如果相关知识您还不会,可以先看看进阶教程

本章优先使用后处理进行体积云的实现,学完后您也可以使用图元的方式进行改写。

要实现体积云,我们可以先参考游戏引擎的相关代码,作者实现体积云也是参考的其他引擎的代码,所以本章的重点在于讲解在Cesium的整体实现思路,至于涉及到的着色器里面的计算原理,作者也是shader菜鸡,也只能看懂大概的执行过程,至于里面的一些数学计算方法也是懵逼得很,所以涉及到的着色器计算不会一一讲解。

更多内容见 Cesium高级教程-教程简介

### Cesium中实现全球体积效果的方法 在Cesium中实现全球体积效果,通常需要结合3D纹理(`Sampler3D`)、渲染技术以及后处理管线。以下内容将详细介绍实现方法,并提供代码示例和相关技术解析。 #### 1. 使用3D纹理与渲染 Cesium支持通过`Texture3D`来加载三维纹理数据,这些数据可以用来模拟大气层中的分布。为了实现更逼真的体积效果,需要对光线步进算法进行优化,使其能够适配地球的椭球形状[^1]。 ```javascript // 创建一个3D纹理对象 var texture3D = new Cesium.Sampler3D({ url: 'path/to/3dCloudTexture.dds', dimensions: new Cesium.Cartesian3(64, 64, 64), }); ``` #### 2. 定义体积渲染范围 全球体积的渲染范围应当基于地球的大气层结构,因此需要将其限定在一个球壳内。这可以通过调整光线步进的距离和方向来实现。具而言,光线步进的起点和终点分别对应地球表面和大气层边界[^3]。 ```javascript // 定义地球半径和大气层厚度 var earthRadius = Cesium.Ellipsoid.WGS84.radius; var atmosphereThickness = 100000.0; // 单位:米 // 计算球壳的内外半径 var innerRadius = earthRadius; var outerRadius = earthRadius + atmosphereThickness; // 确定光线步进范围 function computeRayMarchingRange(position) { var distanceToEarthCenter = Cesium.Cartesian3.magnitude(position); var start = Math.max(innerRadius, distanceToEarthCenter - atmosphereThickness); var end = Math.min(outerRadius, distanceToEarthCenter + atmosphereThickness); return { start: start, end: end }; } ``` #### 3. 实现后处理管线 为了进一步提升的效果,可以使用Cesium后处理管线功能。通过自定义着色器代码,可以为体积添加动态光照、阴影等效果[^2]。 ```javascript // 添加后处理阶段 var postProcessStage = viewer.scene.postProcessStages.add(Cesium.PostProcessStageLibrary.createEdgeDetectionStage({ edgeWidth: 2.0, color: Cesium.Color.WHITE, luminanceThreshold: 0.1, enabled: true, })); // 自定义着色器代码 postProcessStage.uniforms.cloudTexture = texture3D; postProcessStage.fragmentShader = ` uniform sampler3D cloudTexture; void main() { vec3 texCoord = v_textureCoordinates; float density = texture3D(cloudTexture, texCoord).r; gl_FragColor = vec4(density, density, density, 1.0); } `; ``` #### 4. 动态更新与性能优化 为了确保全球体积的效果流畅运行,建议采用以下优化策略: - **减少光线步进步数**:通过降低步进精度来减少计算量。 - **LOD机制**:根据观察距离调整纹理分辨率。 - **异步加载**:提前加载所需的纹理资源以避免卡顿。 ```javascript // 异步加载纹理资源 Cesium.when(texture3D.readyPromise).then(function() { console.log('3D纹理加载完成'); }).otherwise(function(error) { console.error('3D纹理加载失败:', error); }); ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xt3d

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值