Cesium3Dtilesets 使用customShader的解读以及泛光效果示例

news2024/11/18 19:38:14

前言:光带原理在旋转弹跳四棱锥这篇文章里早已经阐述过,但还是有不少靓仔靓女可能会感到疑惑,在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 variable
	vertexMain(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 Manhattan
      const 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 之间,俺不想码了,不想努力了!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/409438.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SocketIO介绍+SpringBoot整合SocketIO完成实时通信

Socket.IO笔记 即时通信是基于TCP长连接,建立连接之后,客户段/服务器可以无限次随时向对端发送数据,实现服务器数据发送的即时性 HTTP HTTP是短链接,设计的目的是减少服务器的压力 HTTP伪即时通讯 轮询 emmet长轮询 long pulling…

vue打包之后出现空白页的原因以及解决方式

路由模式 history 新建项目什么都不动,路由模式:history, 直接npm run build打包 打包之后,直接打开dist文件里面的ndex.html可以看到页面是空白的,控制台是这样的。 再看看网页源码, 对比dist文件夹结构可以看到资源路径的引入…

【前端】React使用react-markdown+antd实现引入渲染markdown文件

项目中遇见一个需求,要求直接在浏览器打开markdown文件进行预览,初次使用遇见一些坎坷,以下记录实现过程,将其封装成了一个组件。 1.下载依赖 yarn add react-markdown//其余样式插件: yarn add remark-gfm yarn …

vue+springboot使用文件流实现文件下载

前言 本次将使用vue和springboot通过文件流的方式教大家怎么去实现文件的下载,那么话不多说,我们直接开始 相关vue导出文件 以下链接为我其他vue进行下载导出文件文章 vue实现把字符串导出为txt 步骤 文件路径 要进行下载的话,我们肯定…

WEB核心【案例:文件下载,案例:点击切换验证码,几种获取properties资源方式】第十二章

目录 1.文件下载 1.1超链接下载: 1.2自定义servlet下载 1.3小结 2.点击切换验证码 2.1前置只是-验证码生成 2.2分析及代码实现 2.3需求2:点击切换验证码-绕过缓存 3.几种获取preperties资源方式 💟作者简介:大家好呀&…

CTF中Web题目的各种基础的思路-----入门篇十分的详细

我期间也考察很多人的,但搞这个的确实有点少,希望这篇可以大家一点帮助,这篇文章也借鉴一些人的文章,还有很多东西,我没搞,确实有点麻烦,但以后还会不断更新的,希望大家在web这里少走…

Web系统常见安全漏洞介绍及解决方案-CSRF攻击

🐳博客主页:拒绝冗余 – 生命不息,折腾不止 🌐订阅专栏:『Web安全』 📰如觉得博主文章写的不错或对你有所帮助的话,还望大家多多支持呀! 👉关注✨、点赞👍、收…

CSS基本布局——grid布局

grid布局简介: Grid布局是将容器划分成“行”和“列”,产生单元格,然后指定“项目所在”的单元格,可以看作是二维布局。 基本概念: 容器(container)——有容器属性项目(items&…

vite项目优化

首先在讲述vite优化之前,我们先来分析一下和传统的项目管理构建工具的区别,以webpack为例,它是利用plugin插件和loader加载器对项目的所有模块和依赖统一通过入口文件进行编译,从而变成我们html所需要的js格式渲染我们的页面。 随…

Vue项目目录结构介绍(三)

前言 本章我们会对一个 Vue 项目的目录结构进行讲解,解释各子目录以及文件的作用,前端的模块化,Vue 单文件组件规范等。 1、基础目录和文件介绍 在上一章,我们通过 vue-cli 创建了一个新的项目,生成的项目目录里已经包…

tauri+vite+vue3开发环境下创建、启动运行和打包发布

目录 1.创建项目 2.安装依赖 3.启动项目 4.打包生成windows安装包 5.安装打包生成的安装包 1.创建项目 运行下面命令创建一个tauri项目 pnpm create tauri-app 我创建该项目时的node版本为16.15.0 兼容性注意 Vite 需要 Node.js 版本 14.18,16。然而&#x…

【玩转CSS】这些高级技巧,你都会吗

🔥一个人走得远了,就会忘记自己为了什么而出发,希望你可以不忘初心,不要随波逐流,一直走下去🎶 🦋 欢迎关注🖱点赞👍收藏🌟留言🐾 🦄 …

js去掉两个数组相同的元素、js删除数组中某一个对象、js快速查找数组中重复项下标

一、js去掉两个数组相同的元素 注意:这里并非是数组去重,数组去重是去掉一个数组中相同的元素,这里是比较两个数组,过滤掉二者相同的,留下不同的。 通过 some() 在对方数组里面查找相同元素,再利用filter…

老老实实的程序员该如何描述自己的缺点

答辩的时候,晋升的时候,面试的时候,你有没有经常遇到一个问题,那就是你觉得自己有什么缺点吗? 目录 1. 每个人都有缺点 2. 这道题在考什么? 3. 我之前是怎么回答的 4. 你可以这样回答试一试 5. 总结 …

浅析<router-view> v-slot事例

官方关于<router-link> 的 v-slot的相关介绍: https://router.vuejs.org/zh/api/#router-view-%E7%9A%84-v-slot 并给出了一个例子&#xff1a; <router-view v-slot"{ Component, route }"><transition :name"route.meta.transition || fade&q…

selenium驱动Firefox安装和环境配置

目录 一、前言 二、版本 三、配置环境 四、在pycharm中添加selenium 五、测试代码&#xff0c;成功打开百度&#xff0c;则配置成功 一、前言 根据多篇文章总结了一下自己操作过程&#xff0c;主要是想记录一下。 二、版本 1.查看自己的Firefox的版本&#xff0c;在浏览器…

Web视频video自动播放(移动端及PC端)

做了个关于视频播放的活动&#xff0c;被各种问题折腾得精疲力竭。为了日后能够轻松点&#xff0c;特记录下出现的各种问题及解决方法。 活动要适配移动端&#xff08;IPhone、Android&#xff09;和PC端&#xff08;Chrome&#xff09; 需要解决的问题&#xff1a;移动端禁止全…

vue echarts饼图环形 (随着legend动态显示数据总数)

目录 1.安装echarts 2.引入echarts 3.创建要放入echarts实例的一个盒子 4.创建echarts实例 5.随着legend动态显示数据总数 效果视频 1.安装echarts npm install echarts --save 2.引入echarts 在 当前vue文件中引入 echarts 如下图所示&#xff1a; 3.创建要放入echa…

Vue项目实战——【基于 Vue3.x + Vant UI】实现一个多功能记账本(搭建开发环境)

基于 Vue3.x Vant UI 的多功能记账本&#xff08;二&#xff09; 文章目录基于 Vue3.x Vant UI 的多功能记账本&#xff08;二&#xff09;搭建开发环境项目演示1、创建项目2、配置路由3、添加 Vant UI 组件库4、移动端 rem 配置5、添加 iconfont 文字图标库6、二次封装 Axio…

Vue实现鼠标悬浮隐藏与显示图片效果 @mouseenter 和 @mouseleave事件

前言 前端vue 有个功能是鼠标移动到指定item上显示出来一个编辑和删除的图标 鼠标悬停在列表那么需要有悬浮显示的列表编辑和删除icon 文字不好描述&#xff0c;因为是web端录屏也比较麻烦 这里用截图说明 图片说明 功能实现 之前没做过这种效果&#xff0c;问了一下我的组长…