https://mp.weixin.qq.com/s/-pDyfHWmj08CfBuKQq7hCg
https://gitee.com/m3d/cesium-for-fluid
01
—
Cesium基础大气雾
基于ShaderToy的基础大气散射雾效果样例
比较基础的大气散射雾效,主要是对瑞利/米氏空气散射的近似模拟
// 基于屏幕空间的Ray Marching球面近似大气散射
vec4 get_incident_light(_in(ray_t) ray) {
vec3 dir = ray.direction;
vec3 start = ray.origin;
float a = dot( dir, dir);
float b = 2.0 * dot(dir, start);
float radius2 = atmosphere.radius * atmosphere.radius;
float c = dot(start, start) - radius2;
float d = (b * b) - 4.0 * a * c;
if (d < 0.0) return vec4(0.0);
float squaredD = sqrt(d);
vec2 ray_length = vec2(
max((-b - squaredD) / (2.0 * a), 0.0), min((-b + squaredD) / (2.0 * a), plane.distance)
);
if (ray_length.x > ray_length.y) return vec4(0.0);
float march_step = (ray_length.y - ray_length.x) / float(num_samples);
float mu = dot(ray.direction, normalize(czm_sunPositionWC));
float phaseR = rayleigh_phase_func(mu);
float phaseM =
#if 1
henyey_greenstein_phase_func(mu);
#else
schlick_phase_func(mu);
#endif
float optical_depthR = 0.;
float optical_depthM = 0.;
vec3 sumR = vec3(0);
vec3 sumM = vec3(0);
float march_pos = 0.;
for (int i = 0; i < num_samples; i++) {
vec3 s = ray.origin +
ray.direction * (march_pos + 0.5 * march_step);
float height = length(s) - 6360e3;
float hr = exp(-height / hR) * march_step;
float hm = exp(-height / hM) * march_step;
optical_depthR += hr;
optical_depthM += hm;
ray_t light_ray = _begin(ray_t)
s, normalize(czm_sunPositionWC)
_end;
float optical_depth_lightR = 0.;
float optical_depth_lightM = 0.;
bool overground = get_sun_light(
light_ray,
optical_depth_lightR,
optical_depth_lightM);
if (overground) {
vec3 tau =
betaR * (optical_depthR + optical_depth_lightR) +
betaM * 1.1 * (optical_depthM + optical_depth_lightM);
vec3 attenuation = exp(-tau);
sumR += hr * attenuation;
sumM += hm * attenuation;
}
march_pos += march_step;
}
float attenuation = length(exp(-((betaM * optical_depthM)
+ (betaR * optical_depthR)) * 4.));
return vec4(
23. *
(sumR * phaseR * betaR +
sumM * phaseM * betaM), 1.0-attenuation);
}
02
—
Cesium地形高度图
基于Cesium实时地形绘制当前视角的地形高度图样例
生成高度图的方式有很多,这里提供一种比较快捷且性能尚可的方案,通过提取当前场景的地形Command创建新的深度derivedProgram,做一次rtt绘制到深度纹理中,快速实现一次rtt深度图的流程。
样例代码:
// 生成高度图纹理
_generateHeightMapTexture() {
const context = this.viewer.scene.context;
const fbo = RenderUtil.createDepthFramebuffer(
context,
this.config.resolution.x,
this.config.resolution.y
);
// 保存原始状态
const passState = this.viewer.scene._view.passState;
const originalCamera = this.viewer.scene.camera;
const originalFramebuffer = context._currentFramebuffer;
const originalViewport = passState.viewport;
// 配置渲染状态
passState.viewport.x = 0;
passState.viewport.y = 0;
passState.viewport.width = this.config.resolution.x
passState.viewport.height = this.config.resolution.y
passState.framebuffer = fbo;
this.viewer.scene.camera = this.heightMapCamera;
// 在渲染深度预处理前添加着色器处理
this._processHeightMapShaders();
// 执行深度渲染
this._renderDepthPrepass(passState);
// 创建高度图纹理
const heightMap = RenderUtil.createTexture({
context: context,
width: this.config.resolution.x,
height: this.config.resolution.y,
flipY: false,
pixelFormat: Cesium.PixelFormat.RGBA,
pixelDatatype: Cesium.PixelDatatype.FLOAT
});
// 拷贝数据到高度图纹理
const copyFBO = RenderUtil.createFramebuffer(context, heightMap);
this._copyTexture(fbo.getColorTexture(0), copyFBO);
// 恢复原始状态
passState.framebuffer = originalFramebuffer;
passState.viewport = originalViewport;
this.viewer.scene.camera = originalCamera;
return heightMap;
}
// 执行深度预渲染
_renderDepthPrepass(passState) {
const frameState = this.viewer.scene.frameState;
// 更新相机状态
frameState.camera = this.heightMapCamera;
this.viewer.scene.frameState.context.uniformState.updateCamera(this.heightMapCamera);
// 执行渲染命令
const commands = this._getDepthRenderCommands();
commands.forEach(cmd => cmd.execute(this.viewer.scene.context, passState));
}
03
—
Cesium流体体渲染
基于ShaderToy的流体体渲染迁移至Cesium合并样例
这里是对之前的Cesium for Fluid样例的完善和补充,增加了Cesium自身的地形结合原生的体渲染法进行流体的体渲染和展示。
ShaderToy: https://www.shadertoy.com/view/7tSSDD
Cesium for Fluid: https://gitee.com/m3d/gis-shadertoy-fluid
// 设置渲染管线
setupRenderPipeline() {
this.createComputePasses();
this.createMainRenderPass();
this.startRenderLoop();
}
// 创建计算通道
_createComputePasses() {
const commonUniforms = {
iTime: () => this._time,
iFrame: () => this._frameCount,
resolution: () => this.config.resolution,
waterSize: () => this.config.waterSize,
fluidParam: () => this.config.fluidParams,
customParam: () => this.config.customParams,
minHeight: () => this.config.heightRange.min,
maxHeight: () => this.config.heightRange.max,
heightMap: () => this._heightMap,
};
this.computePasses = [
this._createComputePass('A', {
uniforms: {
...commonUniforms,
iChannel0: () => this.textures.C,
iChannel1: () => this.textures.D
},
shaderSource: BufferA
}),
this._createComputePass('B', {
uniforms: {
...commonUniforms,
iChannel0: () => this.textures.A,
iChannel1: () => this.textures.D
},
shaderSource: BufferB
}),
this._createComputePass('C', {
uniforms: {
...commonUniforms,
iChannel0: () => this.textures.A,
iChannel1: () => this.textures.B
},
shaderSource: BufferC
}),
this._createComputePass('D', {
uniforms: {
...commonUniforms,
iChannel0: () => this.textures.C,
iChannel1: () => this.textures.B
},
shaderSource: BufferD
})
];
}
// 计算通道工厂方法
_createComputePass(outputTextureName, { uniforms, shaderSource }) {
return new CustomPrimitive({
commandType: 'Compute',
uniformMap: uniforms,
fragmentShaderSource: new Cesium.ShaderSource({
sources: [Command, shaderSource]
}),
geometry: RenderUtil.getFullscreenQuad(),
outputTexture: this.textures[outputTextureName],
preExecute: (cmd) => cmd.commandToExecute.outputTexture = this.textures[outputTextureName]
});
}
// 创建主渲染通道
_createMainRenderPass() {
const modelMatrix = generateModelMatrix([...this.config.lonLat, this.config.dimensions.z / 2], [90, 0, 0], [this.config.dimensions.x, this.config.dimensions.z, this.config.dimensions.y])
this.mainRenderPass = new CustomPrimitive({
commandType: 'Draw',
uniformMap: this._getMainRenderUniforms(),
vertexShaderSource: this._getVertexShader(),
fragmentShaderSource: new Cesium.ShaderSource({
sources: [Command, renderShaderSource]
}),
geometry: this._createBoxGeometry(),
modelMatrix: modelMatrix,
attributeLocations: this._getAttributeLocations(),
rawRenderState: this._createRenderState()
});
}
// 获取主渲染Uniform
_getMainRenderUniforms() {
return {
iTime: () => this._time,
iFrame: () => this._frameCount,
iResolution: () => this.config.resolution,
iChannel0: () => this.textures.C,
heightMap: () => this._heightMap,
customParam: () => this.config.customParams,
colorTexture: () => this.viewer.scene.view.globeDepth.colorFramebufferManager._colorTextures[0]
};
}
// 启动渲染循环
_startRenderLoop() {
this.postRenderHandler = this.viewer.scene.postRender.addEventListener(() => {
if (!this._isActive) return;
this._time = performance.now() / 1000;
this._frameCount += this.config.timeStep;
});
this.computePasses.forEach(p => this.viewer.scene.primitives.add(p));
this.viewer.scene.primitives.add(this.mainRenderPass);
}
仓库地址:
https://gitee.com/m3d/cesium-for-fluid
在线源码: