前言:光带原理在旋转弹跳四棱锥这篇文章里早已经阐述过,但还是有不少靓仔靓女可能会感到疑惑,在3Dtilesets里怎么使用?为啥我在网上看到的为数不多的代码示例我看不懂?是由于没理解透彻导致的。借此机会,提供一个小示例,从头到尾的应用一下。

效果

加载Cesium3Dtilesets

// viewer 实例生成
const viewer = initViewer()
const tileset = new Cesium.Cesium3DTileset({url: Cesium.IonResource.fromAssetId(75343) // 或者一些你保存的测试的tileset 的url
})
viewer.scene.primitives.add(tileset)

上述代码即创建了一个tileset,但通常来说,我们会在readyPromise里面进行操作,主要是因为 这个加载过程是异步的,在此之前我们读取tileset下加载完成处理的变量是读取不到的。因此

tileset.readyPromise.then((tileset) => {// do sth
})

customShader

customShader 是Cesium 在1.87版本 推出的 一个功能类,主要的目的是在于以前的版本中,我们想要对加载出来的3dtiles编写自定义shader的时候 往往是只能修改源码。而现在我们可以直接通过调用此类传入customShader中,对顶点着色器与片源着色器进行修改,当然也包括uniforms 的传值。 那么在开始之前,有几个注意事项,以及一些需要了解的前置内容。

在开始之前呢,你可以先下载cesium的源码,目录结构在下图所示,对比应证

首先从官网给出的例子来看 有啥参数,以及参数大致是用来干啥的。

const customShader = new CustomShader({uniforms: {u_colorIndex: {type: Cesium.UniformType.FLOAT,value: 1.0},u_normalMap: {type: Cesium.UniformType.SAMPLER_2D,value: new Cesium.TextureUniform({url: "http://example.com/normal.png"})}},varyings: {v_selectedColor: Cesium.VaryingType.VEC3},vertexShaderText: `void vertexMain(VertexInput vsInput, inout czm_modelVertexOutput vsOutput) {v_selectedColor = mix(vsInput.attributes.color_0, vsInput.attributes.color_1, u_colorIndex);vsOutput.positionMC += 0.1 * vsInput.attributes.normal;}`,fragmentShaderText: `void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {material.normal = texture2D(u_normalMap, fsInput.attributes.texCoord_0);material.diffuse = v_selectedColor;}`
});

那么可以看到,能供我们去处理的,只有传值uniforms,varyings 即 从顶点着色器传到片元着色器的传递变量。

特别地: vertexMain 以及 fragmentMain 的参数 变量 以及相关处理

一个一个说,接着往下

customShader uniforms

  • uniforms 中需要在customShader的构造器中定义才可通过customShader.setUniform去进行更改,这点在源码以及说明文档中也有提及。
  • uniformType 即 支持的类型
    -

customShader varyings

  • varyingType 支持的类型

customShader vertexShaderText

这个的话得稍微打多点字了,作者在此提出以下几个问题进行探索。

1、为何只能在vertexMain 内部 编写着色器代码?
2、cesium 封装的变量 vertexInput 以及vsOutput里面有什么?
3、如何像原生webgl那样在顶点着色器中输出位置信息?

其实搞懂了这三个问题就已经足够了。下面分别解释。


先观察注释, 首先vertexInput 跟 这个初始化的inputStuct (input的结构体)是根据JS 动态生成的, 我们其实并不太关心其中的实现,有一件事是可以肯定的,Cesium 内部 必然是 有一个根据各种各样的状态拼接着色器代码的一个渲染管线, 在这里 ,customShader的渲染管线 如上图所示,读者若有兴趣可自行研究,这里不多赘述。


那么可以看到 vertexMain 这个 变量 是作为一个函数执行的。 省去大部分内容,我们大致可以理解成以下过程

// ...
void main(){// deal variablevertexMain(vsInput,vsOutput);
}

这就解释了第一个内容。Cesium 做处理的时候 就是把 我们填入的vertexShadertext 内的字符串 解析作为一个函数执行的。因此,我们必须声明vertexMain 这个函数 并且只能在这个函数里面编写代码。

那这里其实也等于回答了 fragmentMain 为何只能在里面编写代码。意思是相同的,所以下文也不会再提。

接着回答第二个问题,cesium 封装的变量 vertexInput 以及vsOutput里面有什么?即使通过上面的着色器代码可以管中窥豹,可是很显然的,它存的都是一系列的结构体(本文这里说只是为了准确,实际上照JS程序员的理解,你可以把它比作对象:有属性,有值)

  • vertexInput

    当然,上图也能看到,vertexInput 下 有3个 结构体(对象),本文只探索attributes,因为比较常见,且常用。

    上表其实也说明了fragmentInput中的属性.不需记住,随时查阅即可。
// 例如 在顶点着色器中 读取 positionMC变量
void vertexMain(VertexInput vsInput, inout czm_modelVertexOutput vsOutput) {vsInput.attributes.positionMC // 这能正常读取vsInput.attributes.positionWC // 不可正常读取 , 因为在vsInput中 这个值 未被计算.
}

接着回答第三个问题,如何输出位置信息?
Cesium对输出进行了以下包装

其实从结构上来说,跟原生webgl 差别不大。 同样是 pointSize 以及一个position 。
概念大致相同,区别只是需要对这个Output 结构体里面的positionMC 写入位置信息,然后由cesium 进去处理、计算(什么世界坐标啊,根据眼睛的法向量坐标啊等等。)

那重点来了这里肯定还有疑问,即 positionMC 跟 我们通常理解上的gl_Position 即顶点坐标 是否是同一个意思?

简单翻译下重点 ,customShader 可能会修改这个positionMC 即(position Model Coordinates 译为模型坐标),这个结果会被用作计算gl_Position ,即顶点位置,所以两者并不是一个概念!这里注意了。也就是说,你实际修改的positionMC 它并不等同于 我们在原生webgl 上的 顶点位置信息,这是一个踩坑点!

回答问题: 输出顶点的模型位置.修改 如

vsOutput.positionMC = ?

customShader fragmentShaderText

照样在此处提出问题

1、czm_modelMaterial 有什么属性?分别是什么含义?

这里本该有两个问题,即fragmentInput 是啥 , 有啥属性,那么在之前也已经阐述过了,结构体 几乎是完全一样的,不再说明。

解决上面的问题很简单,其实只要找到它的声明文件,代码的注释已经写的很明白了,我这里就简单的说明一下我们通常关心的填色

之前在webgl 的片元着色器中 我们填色 是通过 输出gl_FragColor = vec4(?); 完成的。
在customShader 中 ,我们想要做到跟gl_FragColor一样的功能,只需声明diffuse 跟alpha 即可,当然 这是在不设置emissive 的 颜色下。 有关于反射光的东西 其实我害没深入的去学,这里就不妄加解释。

OK , 前置内容 就说明完成了,如果你有充分的webgl 的基础,相信在上面的内容里,你已经完全能理解你如何编写在customShader 里的代码,下面做个小示例 去具体的感受一下。

下面代码应该可以直接跑。对了,记得把defaultAccessToken 加上。

泛光(或者说光带)效果

   const viewer = new Cesium.Viewer("earthContainer", {});const scene = viewer.scene;scene.globe.depthTestAgainstTerrain = true;// Set the initial camera view to look at Manhattanconst initialPosition = Cesium.Cartesian3.fromDegrees(-74.01881302800248,40.69114333714821,753);const initialOrientation = new Cesium.HeadingPitchRoll.fromDegrees(21.27879878293835,-21.34390550872461,0.0716951918898415);scene.camera.setView({destination: initialPosition,orientation: initialOrientation,endTransform: Cesium.Matrix4.IDENTITY,});Cesium.ExperimentalFeatures.enableModelExperimental = true;//       // Load the NYC buildings tileset.const tileset = new Cesium.Cesium3DTileset({url: Cesium.IonResource.fromAssetId(75343),customShader: new Cesium.CustomShader({lightingModel: Cesium.LightingModel.UNLIT,uniforms: {maxHeight: {type: Cesium.UniformType.FLOAT,value: 0.0,},minHeight: {type: Cesium.UniformType.FLOAT,value: 0.0,},},fragmentShaderText: `void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) {float curz = fsInput.attributes.positionMC.z;float d = (curz - minHeight) / (maxHeight - minHeight);float r = 0.01;r = fract(r * czm_frameNumber);float c = smoothstep(r, r+0.03, d) - smoothstep(r + 0.035,r + 0.04, d);vec3 linearColor = mix(vec3(1.0,1.0,1.0) ,vec3(255.0,48.0,48.0)/255.0,r);vec3 renderColor = mix(vec3(0.0,0.96,1.0) ,linearColor,c);material.diffuse = renderColor;}`,}),backFaceCulling:  false,});// 547.75 -11.89// let [maxHeight,minHeight] = [tileset._properties.Height.maximum,tileset._properties.Height.minimum]tileset.readyPromise.then((tileset) => {console.log(tileset);let [maxheight, minheight] = [tileset.properties.Height.maximum,tileset.properties.Height.minimum,];tileset.customShader.setUniform("maxHeight", maxheight);tileset.customShader.setUniform("minHeight", minheight);console.log(`Maximum building height: ${maxheight}`);console.log(`Minimum building height: ${minheight}`);});console.log(tileset);scene.primitives.add(tileset);

光带在cesium3dtilesets的效果原理思路解读

参考我的之前的光带原理解读这篇文章,其实本质上来说,观察我的着色器代码

float d = (curz - minHeight) / (maxHeight - minHeight);

这篇光带原理解读文章后面的实现是比较潦草的,只是用以 空间裁剪坐标 的增加 控制整个 光带的移动,而此时这个呢,你可以稍微对比一下, 它其实就是 把从空间裁剪坐标的终点1 变为了 它的最高点。这么说可能有点模糊,上图。

之前的实现

现在的实现

所以我说本质上,这跟之前的还是一个内容。其实并不想多做阐述。但无奈确实可能一开始不太好理解,希望你们看到此图能恍然大悟。 意味着,从直接的对整个webgl空间的光带,变成了一条只在模型的盒子范围内的光带扫描。

结尾闲聊

今天又是摸鱼的一天,今后这篇文章会又造福了不少靓仔,真想快点到国庆回家,心已疲倦,好想躺平,可是没钱,还得继续当码畜,不知道各位看本文的靓仔靓女有无富婆介绍?年龄在 20 - 28 之间,俺不想码了,不想努力了!

Cesium3Dtilesets 使用customShader的解读以及泛光效果示例相关推荐

  1. [cesium] 基于Cesium的动态泛光效果示例

    抽空将之前的功能单独抽出来写成一个模块,方便单独调用,配合单个模块写了一些示例 可以兼容各个基于cesium底层库的三方框架,引入即可. 效果 模型光源模拟 动态泛光墙 泛光面 城市泛光线 建筑物调整 ...

  2. Cesium 1.87+实现建筑泛光效果

    Cesium 1.87+实现建筑泛光效果 Cesium 1.87+增加了customShader自定义着色器,实现建筑泛光效果示例代码如下: <!DOCTYPE html><meta ...

  3. Cesium实现UnrealBloom泛光效果

    关注[三维网格3D],分享更多3D心得 泛光(Bloom)是一种常用的后期处理特效,游戏中更是随处可见,这里直接上我们的效果图. 图1.UnrealBloom泛光效果 Cesium内置的bloom后期 ...

  4. cesium实现立体墙(垂直、水平)渐变泛光效果

    文章目录 1.实现效果 2.实现方法 2.1材质文件 2.2代码调用 2.3其他类型 2.3.1立体向下 2.3.2水平逆时针 2.3.3水平顺时针 Cesium实战系列文章总目录: 传送门 1.实现 ...

  5. Three.js 后期处理-泛光效果-BloomPass-相机分层渲染

    Three.js 后期处理-泛光效果-BloomPass-相机分层渲染 概述 步骤 概述 本文介绍如何使用three.js的后期处理来制作处泛光效果,先来看效果图 注意: **camera的默认lay ...

  6. Post Processing的Bloom泛光效果

    Post Processing的Bloom泛光效果 实现的效果 方法一.Post-Process Volume 1. 下载资源包:Window -> Package Manager 2. 在摄像 ...

  7. three.js后期处理-使用UnrealBloomPass通道在场景中添加泛光效果,三维物体表面发光效果(vue中使用three.js85)

    使用UnrealBloomPass通道在场景中添加泛光效果 1.demo效果 2. 重要知识点 2.1 回顾要点 2.2 UnrealBloomPass通道介绍 3. 实现要点 3.1 相关文件引入 ...

  8. ajax 文件上传 iframe,AJAX_iframe实现Ajax文件上传效果示例,复制代码 代码如下: span styl - phpStudy...

    iframe实现Ajax文件上传效果示例 avascript部分 ajax 文件上传~~ window.οnlοad=function(){ var form=document.getElements ...

  9. KITTI数据集上MaskRCNN检测效果示例

    KITTI数据集上MaskRCNN检测效果示例 在Semantic Instance Segmentation Evaluation中,MaskRCNN性能效果排名第一. Test Image 0 I ...

最新文章

  1. React 项目--创建组件(7)
  2. ZOJ 3776 A - Pokemon Master 签到水题
  3. C语言中的各输出格式含义
  4. c语言数组方式实现静态循环队列
  5. php邮件html模板下载,PHP Mailer与HTML模板和发送变量
  6. java学习_5_23
  7. lua4.0中实现% 取余操作
  8. Spring之RMI 远程方法调用 (Remote Method Invocation)
  9. HDU2003 求绝对值【入门】
  10. 视频流中的 I帧 P帧 B帧 .
  11. oracle orderby多个字段,Oracle Order By用法详解
  12. 【深入理解TcaplusDB技术】详细介绍TDR 表中Tcaplus的相关属性
  13. 个人发卡网全开源修复版源码
  14. python胶水语言为什么_为什么只有python是胶水语言?
  15. 6-23 sdust-Java-可实现多种排序的Book类 (20 分)
  16. 青木的书籍,--股票
  17. 在Python中如何判断一个对象的类型?
  18. 百度广告屏蔽;百度新闻屏蔽;百度推送屏蔽
  19. 谈谈老衲对闭包的理解!!综合了我在网上看的资料,把我的理解跟大家分享
  20. C++知识库(可能包含一些非C++这门语言的知识体系、Java知识)

热门文章

  1. java baas_GitHub - JavaBaas/JavaBaasServer at 2c4c9a2de05059984f513a976041c5787bf8edc2
  2. 企业网站防CC攻击软件防火墙和WEB防火墙大比较
  3. vue中eslint报Disallow self-closing on HTML void elements格式错误时的解决方案
  4. 用sourecttree从Teambition上clone项目到本地
  5. 视频资源网站采集-视频资源API采集教程
  6. QUAKE 3源代码评测:架构
  7. 网易上线短视频创作平台“网易知识公路“
  8. 睿智的目标检测28——YoloV4当中的Mosaic数据增强方法
  9. 毕业设计--20200301--domoticz的智能家居设备---esp8266(micropython)+MQTT 做一个可控开关
  10. 【OpenCV 例程200篇】220.对图像进行马赛克处理