cesium水深渲染与源码解析

背景

当年使用Arcgis for js的时候,想渲染水面,一直不成功,什么结合three.js,奈何技术还不行,搞不定水面渲染。但是!今天终于实现了,可以实现高端水面渲染了。

版本说明

cesium 1.97

<script src="https://cesium.com/downloads/cesiumjs/releases/1.97/Build/Cesium/Cesium.js"></script>
<link href="https://cesium.com/downloads/cesiumjs/releases/1.97/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
    

数据准备

一张png图片,最好是黑白渐变色,这样RGB通道值都是一样的,方便渲染水深。没有png图片就用ps画一张,并且裁剪出不规则的形状。

图1 水深栅格图

解析cesium官方Water源码

使用Cesium.Material创建water,然后debug加断点,在源码框看Cesium变量,在里边翻找source,就看到源码的字符串了。如下图:

图2 Water材质源码

篡改源码,变成自己的材质器

fabric: {
                uniforms: {
                    depthMap: './images/depth_6.png',//水深截图
                    baseWaterColor: new Cesium.Color(64 / 255.0, 157 / 255.0, 253 / 255.0, 0.5),
                    blendColor: new Cesium.Color(0.0, 1.0, 0.7, 0.5),
                    // specularMap: './images/water.jpg', // Change to your specular map
                    normalMap: './images/waterNormals.jpg', // Change to your normal map
                    frequency: 800.0,
                    animationSpeed: 0.01,
                    amplitude: 3,
                    specularIntensity: 10,
                    fadeFactor: 1,
                    specularMap: "czm_defaultImage" 
                },
                source: `
                    uniform sampler2D specularMap;
                    uniform sampler2D normalMap;
                    uniform sampler2D depthMap;
                    uniform vec4 baseWaterColor;
                    uniform vec4 blendColor;
                    uniform float frequency;
                    uniform float animationSpeed;
                    uniform float amplitude;
                    uniform float specularIntensity;
                    uniform float fadeFactor;
                    czm_material czm_getMaterial(czm_materialInput materialInput)
                    {
                        czm_material material = czm_getDefaultMaterial(materialInput);
                        float time = czm_frameNumber * animationSpeed;
                        float fade = max(1.0, (length(materialInput.positionToEyeEC) / 10000000000.0) * frequency * fadeFactor);
                        float specularMapValue = texture2D(specularMap, materialInput.st).r;
                        vec4 noise = czm_getWaterNoise(normalMap, materialInput.st * frequency, time, 0.0);
                        vec3 normalTangentSpace = noise.xyz * vec3(1.0, 1.0, (1.0 / amplitude));
                        normalTangentSpace.xy /= fade;
                        normalTangentSpace = mix(vec3(0.0, 0.0, 50.0), normalTangentSpace, specularMapValue);
                        normalTangentSpace = normalize(normalTangentSpace);
                        float tsPerturbationRatio = clamp(dot(normalTangentSpace, vec3(0.0, 0.0, 1.0)), 0.0, 1.0);
                        material.alpha = mix(blendColor.a, baseWaterColor.a, specularMapValue) * specularMapValue;
                        material.diffuse = mix(blendColor.rgb, baseWaterColor.rgb, specularMapValue);
                        material.diffuse += (0.1 * tsPerturbationRatio);
                        material.diffuse = material.diffuse;
                        material.normal = normalize(materialInput.tangentToEyeMatrix * normalTangentSpace);
                        material.specular = specularIntensity;
                        material.shininess = 10.0;
                        // handle alpha to hidden other area
                        // made by dzm
                        float depthMapShow = texture2D(depthMap, materialInput.st).a;
                        if(depthMapShow < 0.5){
                            material.alpha = depthMapShow;
                        }
                        // set different color by depth
                        // you can edify code by yourself
                        float dep = texture2D(depthMap, materialInput.st).r;
                        if(dep > 0.3){
                            material.diffuse -= vec3(0.2);
                        }
                        if(dep > 0.5){
                            material.diffuse -= vec3(0.2);
                        }
                        if(dep > 0.7){
                            material.diffuse -= vec3(0.2);
                        }
                        if(dep > 0.9){
                            material.diffuse -= vec3(0.2);
                        }

                        return material;
                    }
            `
            },

效果图

图3 效果图1

图4 效果图2

中间踩坑

说到坑,那就太多了。好多个,慢慢爬出来的,坑如下:

  • Cesium结合Three.js 特地去了github上找资源,找到了两个整合版本,还有Cesium官网的版本,渲染平常的3D物体是可以,但是渲染水面,就不行了。不显示的原因很多,猜测是WebGL的兼容问题、坐标系问题(找不见)、比例问题(太小,看不见渲染到哪里去了)
  • Bilibili上找到一个水流模拟的案例,Cesium使用SPH方式的流体模拟测试_哔哩哔哩_bilibili   智智哥哥啊的案例很厉害,大佬。还看到了他的博客,讲思路,用sph实现。奈何,支持储备不够,搞不了人家那种。
  • GPT聊天,找方案,我有水深的三角数据了,怎么才能Cesium渲染呢?给了一个个的方案,都不行。
  • 中间了解到GLSL,使用两个着色器(点、片面),然后学了几天。The Book of Shaders   然后就会发现,GLSL的大佬是真的多呀,用GLSL做俄罗斯方块,复刻了!
  • 复合材质渲染,没出效果,水都出不来,原因不详。
  • 渲染栅格图,把源数据高程tif,浏览器不支持,搞成png,没经纬度了。问GPT咋办,一点点的试验,成了。所以:九品之人,AI替不了呀,看人家智智哥哥做的Cesium渲染,服!

相关知识储备

Cesium开发、GLSL、GIS基础、js调试

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值