Cesium中的体渲染

上篇介绍了Cesium中的BoxGeometry的本地坐标获取方法,获取了本地坐标后,我们就可以开始做体渲染相关的东西了。将相机坐标也换算到模型本地坐标,即可计算得到以相机为起点的到立方体的射线。体渲染相关的内容参看这篇文章,里面说明了ThreeJS中体渲染的相关内容。

先上图

模型本地坐标

Cesium中的BoxGeometry渲染流程,及模型本地坐标

这次模型使用自定义的primitive来实现,直接通过Cesium内置的position来获取本地坐标,不再通过编码后的变量计算。

相机本地坐标

Cesium中内置的变量中提供相机对于模型的本地坐标,czm_encodedCameraPositionMCHighczm_encodedCameraPositionMCLow,两个为编码后的相机模型坐标。射线起点即为相机的模型坐标

vOrigin=czm_encodedCameraPositionMCHigh+czm_encodedCameraPositionMCLow;

每条射线朝向

有了模型本地坐标和相机本地坐标,即可计算,相机到每个顶点的朝向。

vDirection=position-vOrigin;

体渲染,正式开始

核心思想和在ThreeJS中实现体渲染是一样的,通过射线计算同射线相交的体数据,这里采用ThreeJS官方例子中的体数据生成的方法,柏林噪声的体渲染例子。在ThreeJS中我们可以通过3D纹理的方式直接提交体数据,然后通过采样函数直接采样3D纹理。

但是在Cesium里面,我目前没有发现可以直接使用sampler3D方法,查看了Texture.js里面的代码发现没有支持构造3D纹理的函数,仅支持2D纹理和纹理数组。

不支持sampler3D

虽然目前不支持使用smapler3D,但是,看到常量文件里面已经列出了WebGL2的一些内容,应该在不久之后就可以支持直接使用3D纹理了。

粗略看了一下代码,Cesium是支持通过requestWebgl2来使用glsl 3.0的。其中modernizeShader.js中实现了从glsl 1.0迁移到3.0的方法。这一部分还没看完,后续看完后,试试支持一下3D纹理。先埋个坑,有时间再填。

既然不支持3D纹理,只能将生成的3D纹理通过2D纹理传入GPU,来进行采样。有如下两个方法:

  • 使用纹理数组,将体数据以切片方式传入GPU中,如128 * 128 * 128的体数据,构造128张128 * 128 的纹理传入显卡中
  • 将体数据存入单张二维纹理中

以上两种方法,第一种方法,很容易就遇到纹理单元不够用的情况,除非数据量非常小,不然没法使用。考虑使用第二种方法,直接构造一张二维纹理,存储所有体数据。

体数据 --> 2D纹理

三维数据存储到二维中,我选择逐各方式存储到纹理中,即逐切片遍历,将每个切片依次逐行存储。如下伪代码。

for z to sizefor y to sizefor z to sizedata[i++]=volumn[x,y,z]

二维纹理的尺寸通过三维数据的个数开根号来计算得到,保证宽高一样,简化计算。

ceil(sqrt(size * size *size))

数据准备好后,只要在shader中实现采样即可在Cesium中实现体渲染。

代理几何体

代理几何体通过自定义primitive方式实现。自定义primitive的内容可以参看[这篇文章](Cesium 高性能扩展之DrawCommand(一):入门 - 知乎 (zhihu.com)),文章也介绍了drawcommand相关的东西,我这里就不在啰嗦了。

这里重点说一下shader中的采样方法。顶点着色器中没什么好说的了,计算射线起点,射线朝向,就没了。重点看片元着色器。

几何体提供的纹理一定不要开mipmap,我们只使用原始的像素值,因为我们将三维数据放到二维纹理中,GPU对纹理多级缓存后,混合后的像素会和我们预期的效果差很多。因此一定要设置FilterNEAREST, LINEAR 这两种,也不要提供miplevel,防止使用mipmap。

FragmentShader中采样体数据

这里简化计算,代理几何体采用的边长为1,且为轴对齐立方体,同样采用AABB,计算射线进入射出的位置。

迭代步长计算,和采样后着色都使用ThreeJS里面的代码不做修改。

射线相交可得到立方体上某一个点的三维坐标,这里需要通过三维坐标从二维纹理中取到对应的体数据。下面代码中``p为射线相交的立方体上某点,slice_size`为体数据的一个维度的尺寸。

  • 第一步先将[0,1]之间的数据放大到同体数据相同的维度,所以这里乘以slice_size,尤其要注意**clamp**,这个方法不能忽略,对于0附近的值,其真实值可能是各负数,导致计算得到的数值不在[0,slice_size) 范围内,对应的就会出现类似z-filghting一样的现象,同一个平面,有些是0,有些是负数,如下类似雪花一样的结果。所以一定要用clamp将计算后的坐标限制到[0,slice_size-1]范围内。
vec3 p=clamp(floor(pos*slice_size),0.,slice_size-1.);

  • 接下来需要计算三维中这个点对应二维纹理中的第几个像素,直接乘一乘就好了。
float idx=p.x+p.y*slice_size+p.z*slice_size*slice_size;
  • 知道了是第几个像素,就可以计算这个像素所在的行列,取模就是一行中的第几个,除一下就是第几行,然后再归一化一下,下面st即为二维的纹理坐标。
vec2 st=vec2(0.0);
st.s=floor(mod(idx,lxs_tex_size));
st.t=floor(idx / lxs_tex_size);
st/=(lxs_tex_size-1.);

到这里所有的工作基本就做完了,复用ThreeJS中的采样方法,这里还有个坑,WebGL中循环必须是固定次数的,即循环上限必须是一个常量。这里我固定写了500,然后循环中判断射线是否出了立方体,来结束循环。代码中的normal为ThreeJS中的着色方法。

//循环最多执行500次
for(float i=0.;i<500.0;i+=1.){float d=getData(p+0.5);if(d>0.6){color.rgb=normal(p+0.5)*0.5+(p*1.5+0.25);color.a=1.;break;}p+=rayDir*delta;bounds.x+=delta;if(bounds.x>bounds.y) break; //当射线出立方体时,结束循环,停止采样
}

到此体渲染就介绍完成了。我们会发现,这里渲染结果和ThreeJS中有很大的不同,不够平滑。因为我们直接采样体数据,相当于找最近的体数据来表达一片范围,导致出现明显的马赛克,实际上做一次三线性插值就会好很多了,这里就懒得写了,后续能用sampler3D后直接用GPU内置的插值就好了。

控制代理几何体维度

上面代码中使用的代理几何体为单位立方体,使用单位立方体可以简化很多计算。实际的体数据长宽高三个维度需要各自指定。
在fs中增加halfdim uniform变量通过参数方式传入立方体维度即可。

第一步,修改hitBox中的box_minbox_max分别为最大最小维度。

        vec3 box_min = vec3( -halfdim );vec3 box_max = vec3( halfdim );

第二步,main方法中在开始步进计算射线相交的体素时,对立方体相交位置p加了0.5,用来将坐标计算到大于0。这里要加一半的维度。

float d = getData(p+halfdim);

第三步,在getData中为了简化取体素的计算,还是将p归一化。

vec3 pos = pox_lxs/(halfdim*2.);

最后,在自定义primitive中的uniformmap中增加对应的halfdim即可。

代码库

代码库地址

Cesium Volumn 体渲染相关推荐

  1. Cesium中使用Sampler3D,3D纹理,实现体渲染

    Cesium中使用Sampler3D,3D纹理,实现体渲染 Cesium目前(20221231)还不支持直接使用3D纹理,但是其实内部已经可以WebGL2,而且内置常量也有3DTexture.所以,可 ...

  2. Cesium体渲染,去除Volume中的马赛克

    Cesium中体渲染,去除Volume中的马赛克 产生马赛克的原因是所有数据都是真实数据,未对采样结果进行插值处理,上一篇文中采用的是Nearest,所有采样结果都是基于真实数据的,即在不同位置处进行 ...

  3. Cesium中实现体渲染

    体渲染 Volume Rendering 传统意义上我们构建模型都是通过构建物体的外表面去实现的,例如通过三角面构建模型,或者通过方程的形式构建隐式的表面模型. 而体渲染则是通过 3d 数据集渲染物体 ...

  4. 斯图加特大学GPU光线投射体渲染技术提携

    斯图加特大学GPU光线投射体渲染技术介绍 前言:在以往人们的印象中,美国的CG技术是一世界第一流的,而没有注意德国CG技术的发展.事实上,德国大学的CG是相当高的,与美国第一流的大学学术交往非常频繁. ...

  5. GPU Gems1 - 9 有效的阴影体渲染

    这章全面讲述了用于实时阴影渲染中常见两种流派之一的阴影体(Shadow Volumes)技术,又称模板阴影(Stencil Shadows)技术,重点是得到正确的角度的情形,减少几何图形和填充率的消耗 ...

  6. [译]基于GPU的体渲染高级技术之raycasting算法

    [译]基于GPU的体渲染高级技术之raycasting算法 PS:我决定翻译一下<Advanced Illumination Techniques for GPU-Based Volume Ra ...

  7. Q128:PBRT-V3,“体渲染”积分器的“传播方程”(15.1章节)

    对比"路径追踪"积分器和"体渲染"积分器中长度为n的路径上返回的光的计算:

  8. Q127:PBRT-V3,理解“体渲染”积分器的关键竟然是这张图

    "体渲染"积分器是在"路径追踪"积分器的基础上考虑了场景中的介质,相当于是对"路径追踪"积分器的拓展. 所以,在学习"体渲染&qu ...

  9. Q126:PBRT-V3,VolPathIntegrator(体渲染)流程概述

    最近在学体渲染,老实说,挺费劲的! Medium的原理.采样.对应的光传播函数.VolPathIntegrator的实现等等,都已经过了一遍. 现总结一下初浅的理解吧. VolPathIntegrat ...

最新文章

  1. Windows异常学习笔记(四)—— 编译器扩展SEH
  2. Python自动化运维——系统性能信息模块
  3. Matlab将一矩阵中等于某个值的元素全部替换成另一个值
  4. 全局路径规划:图搜索算法介绍2(A star)
  5. VIM使用小技巧-重新载入文件
  6. oracle控制文件加载数据,关于SQLLOAD控制文件参数的问题
  7. 下一代Jquery模板-----JsRender
  8. 419.甲板上的战舰
  9. 静态路由协议的默认管理距离是_动态路由选择原理(距离矢量路由协议RIP)
  10. 精细加工领域中超快激光的应用
  11. DB2 执行SQL报错: DB2 SQL Error: SQLCODE=-1585, SQLSTATE=54048
  12. 7-2 Rank a Linked List (25 分)
  13. Tibco Designer -- 构建EAR文件
  14. python+selenium实战搭建PO模型
  15. Kyndryl从IBM完全剥离在纽交所独立上市;新思科技收购AI驱动性能优化软件企业Concertio | 全球TMT...
  16. photoshop制作白发教程:可爱女孩黑发变白发
  17. sqlserver审计 —— 服务器与数据库审核规范
  18. 项目 --- 《水晶报表》
  19. C专家编程 第6章 运动的诗章:运行时数据结构 6.1 a.out及其传说
  20. 5位评委对参赛选手进行打分,将所有的打分结果存储到对应类型的数组中, 将所有的评分结果去除一个最低分,去除一个最高分,然后获取的平均分数为 选手的最终得分.设计程序,用键盘输入5位评委的评分,并打印输

热门文章

  1. 合肥工业大学本科毕业论文答辩和论文选题PPT模板
  2. 浙江大华软件测试面试经历
  3. 大学计算机基础及应用教程答案,《大学计算机基础教程》课后习题六答案(新)...
  4. 阿里巴巴Java开发手册(详尽版)-个人未注意到的知识点
  5. FreeBSD12.1软件包管理工具ports常见用法
  6. 2013电大c语言程序设计,2013年一月电大考试C语言程序设计(A)
  7. 在线cad版本转换_弱电机房工程设计图纸(CAD版本)
  8. W3school离线手册2019资源下载
  9. Android手机应用开发实战(一) | 展示王者荣耀英雄信息的APP
  10. 遥感计算机分类的基本原理,遥感数字图像计算机解译