尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

Cesium高级教程-3D高斯泼溅-Splat-高斯数据渲染

Cesium高级教程-3D高斯泼溅-Splat-高斯数据渲染
📅 发布时间:2026/6/23 14:43:47

Cesium高级教程-3D高斯泼溅-Splat-高斯数据渲染

数据加载完成后下一步我们应该做的是排序操作,但是现在我们先省略排序的步骤直接先进行数据的渲染,因为排序只会影响绘制图形的前后(遮挡)关系,并不会影响图形的变换及着色结果,并且排序的结果是否正确只有渲染出来才能验证,所以我们先将数据渲染出来,再看排序对渲染结果的影响。

实例化渲染准备

在开始渲染Splat数据之前我们需要先准备好图形实例化渲染的基本环境,相关内容前面百万级图形渲染一章已经介绍得非常详细了,这里就不再重复阐述,实例化渲染一个矩形的基本代码如下

// z// | /y// |/// o------xconstpositions=newFloat32Array([-2,-2,2,-2,2,2,-2,2]);constvertexBuffer=Cesium.Buffer.createVertexBuffer({context:viewer.scene.context,typedArray:positions,usage:Cesium.BufferUsage.STATIC_DRAW});constattributes=[{index:0,vertexBuffer:vertexBuffer,componentsPerAttribute:2,componentDatatype:Cesium.ComponentDatatype.FLOAT,}];constvertexArray=newCesium.VertexArray({context:viewer.scene.context,attributes:attributes});constvs=`...`constfs=`...`constshaderProgram=Cesium.ShaderProgram.fromCache({context:viewer.scene.context,vertexShaderSource:vs,fragmentShaderSource:fs,attributeLocations:{position:0,}})letposition=Cesium.Cartesian3.fromDegrees(105.41883,26.68244,0);letmodelMatrix=Cesium.Transforms.eastNorthUpToFixedFrame(position);letcommand=newCesium.DrawCommand({modelMatrix:modelMatrix,vertexArray:vertexArray,shaderProgram:shaderProgram,renderState:Cesium.RenderState.fromCache({depthTest:{enabled:true,}}),pass:Cesium.Pass.OPAQUE,instanceCount:vertexCount,uniformMap:{}})classMyPrimitive{constructor(){}update(frameState){frameState.commandList.push(command);}isDestroyed(){returnfalse;}}letp=newMyPrimitive();viewer.scene.primitives.add(p);

代码中我们省略了着色器代码,缺省代码可以在前面章节中获取,因为这里我们只先准备一个基本骨架。因为我们最终需要将结果渲染在地球上的某个位置,所以需要指定一个从世界坐标原点到该位置的变换矩阵modelMatrix,这里可以自行定义该位置的坐标值。

instanceCount属性初始值为0,当vertexCount变化后记得更新instanceCount

数据纹理与索引

接下来我们按照 Splat Viewer 中的代码先将高斯数据打包到一张纹理图里面去,因为打包过程是在WebWorker中进行的,所以我们需要将数据传入Worker并注册消息事件接收结果。

letdataTexture=newCesium.Texture({context:viewer.scene.context,width:1,height:1,pixelFormat:Cesium.PixelFormat.RGBA_INTEGER,pixelDatatype:Cesium.PixelDatatype.UNSIGNED_INT,sampler:newCesium.Sampler({minificationFilter:Cesium.TextureMinificationFilter.NEAREST,magnificationFilter:Cesium.TextureMagnificationFilter.NEAREST})});functioncreateTexture(texdata,texwidth,texheight){returnnewCesium.Texture({context:viewer.scene.context,width:texwidth,height:texheight,pixelFormat:Cesium.PixelFormat.RGBA_INTEGER,pixelDatatype:Cesium.PixelDatatype.UNSIGNED_INT,source:{arrayBufferView:texdata,width:texwidth,height:texheight,},sampler:newCesium.Sampler({minificationFilter:Cesium.TextureMinificationFilter.NEAREST,magnificationFilter:Cesium.TextureMagnificationFilter.NEAREST})});}letcommand=newCesium.DrawCommand({...uniformMap:{u_texture:()=>{returndataTexture;},}})...

上面的代码中我们先创建了一张默认的纹理图,当我们接收到WebWorker的打包结果后再覆写其内容。现在我们需要手动触发纹理打包操作,因为Splat Viewer中默认是排序时才会打包纹理,而我们现在并没有开启排序。

要触发纹理打包操作我们需要修改两处代码,一是在接收到网络请求的高斯数据后将其推送到WebWorker,二是在WebWorker中接收到数据后调用generateTexture函数进行纹理打包。

functioncreateWorker(self){...letsortRunning;self.onmessage=(e)=>{if(e.data.buffer){buffer=e.data.buffer;vertexCount=e.data.vertexCount;}elseif(e.data.vertexCount){vertexCount=e.data.vertexCount;}elseif(e.data.view){viewProj=e.data.view;throttledSort();}};}...while(true){...if(vertexCount>lastVertexCount){worker.postMessage({buffer:splatData.buffer,vertexCount:Math.floor(bytesRead/rowLength),});lastVertexCount=vertexCount;}}

现在纹理数据已经有了,但是我们还得为其准备一个默认的索引(排序),这里我们直接将0,1,2,3,4...设置为其默认的索引即可,索引数据需要通过Buffer来传递,所以我们需要修改一下前面默认的VAO。

constinitialIndices=newUint32Array(x);for(leti=0;i<x;i++)initialIndices[i]=i;letindexBuffer=Cesium.Buffer.createVertexBuffer({context:viewer.scene.context,typedArray:initialIndices,usage:Cesium.BufferUsage.STATIC_DRAW});constattributes=[{index:0,vertexBuffer:vertexBuffer,componentsPerAttribute:2,componentDatatype:Cesium.ComponentDatatype.FLOAT,},{index:1,vertexBuffer:indexBuffer,componentsPerAttribute:1,instanceDivisor:1,componentDatatype:Cesium.ComponentDatatype.UNSIGNED_INT}];

着色器代码修改

现在我们把Splat Viewer中的两个着色器代码片段直接拷贝进来替换vs与fs,fs代码基本不需要进行任何修改,而vs代码中我们需要一些修改才能正常运行。首先是视图矩阵(view)、投影矩阵(projection)以及视口大小(viewport)需要改为Cesium内置的变量,其次是focal参数(焦距)Cesium中并没有内置的,我们可以通过vec2(viewport.y / 2.0) * abs(projection[1][1]);或vec2(czm_viewport.z * czm_projection[0][0])来获取,其余代码保持不变。

constvs=`... uniform highp usampler2D u_texture; // uniform mat4 projection, view; // uniform vec2 focal; // uniform vec2 viewport; in vec2 position; in float splatIndex;//Cesium中不支持int类,我们可以先用float,后面再进行类型转换 out vec4 vColor; out vec2 vPosition; void main () { int index=int(splatIndex); mat4 view=czm_modelView; mat4 projection=czm_projection; vec2 viewport=czm_viewport.zw; vec2 focal = vec2(viewport.y / 2.0) * abs(projection[1][1]); uvec4 cen = texelFetch(u_texture, ivec2((uint(index) & 0x3ffu) << 1, uint(index) >> 10), 0); vec4 cam = view * vec4(uintBitsToFloat(cen.xyz), 1); vec4 pos2d = projection * cam; ... }`.trim();

示例效果可到 xt3d 官网 运行查看

至此就可以运行页面查看渲染结果,不出意外的话现在看到的就是一堆带有颜色的椭圆,这些椭圆都是由高斯椭球投影而来,因为现在没有开启颜色混合,所以看起来和原始效果差别有点大。

颜色混合与轴向

开启颜色混合选项需要修改绘制指令的渲染状态属性,混合模式有很多种(Cesium内置的),这里我们选择与Splat Viewer中比较近似的一种PRE_MULTIPLIED_ALPHA_BLEND,当然也可以自定义混合模式。

letcommand=newCesium.DrawCommand({modelMatrix:modelMatrix,vertexArray:vertexArray,shaderProgram:shaderProgram,...})

示例效果可到 xt3d 官网 运行查看

现在颜色渲染基本上正确了,但是看上去是倾斜的,这是因为默认的Splat数据是Y轴朝上的,我们只需要将其绕X轴旋转一下即可。

letposition=Cesium.Cartesian3.fromDegrees(105.41883,26.68244,0);letmodelMatrix=Cesium.Transforms.eastNorthUpToFixedFrame(position);letrotation=Cesium.Matrix4.fromRotationTranslation(Cesium.Matrix3.fromRotationX(Cesium.Math.toRadians(-90)));Cesium.Matrix4.multiply(modelMatrix,rotation,modelMatrix);

示例效果可到 xt3d 官网 运行查看

更多内容见 Cesium高级教程-教程简介

相关新闻

  • 「铝镁双驱·智铸未来」马路科技携全域解决方案重磅登陆上海压铸展(7/15-17)
  • Cesium 地形教程
  • 网易云音乐无损下载终极指南:3步永久保存你的歌单

最新新闻

  • PyTorch模型微调实战指南
  • 从合规视角看开发资产凭证管理:一个被忽略的控制点
  • 奥迪 AUDI 案例:母品牌和新业务怎么拆?
  • 2026年第一、二季度最新最全热门网站建设工具全面对比评测
  • 微信 iPad 协议登录认证与鉴权机制深度解析
  • SpringCloud Alibaba Sentinel 限流+熔断完整实战教程

日新闻

  • Arduino-ESP32项目深度解析:解锁隐藏芯片支持与架构演进
  • 2026年 系统窗厂家/品牌推荐榜单:隔音系统窗+高端系统门窗的核心优势与选购指南 - 品牌发掘
  • NVBench:首个双语非言语发声语音合成评测基准详解与实践

周新闻

  • Visual C++运行库修复终极指南:5分钟快速解决Windows软件启动错误
  • 手把手教你构建统计局地区经济数据爬虫:从环境搭建到数据持久化全指南
  • 2026多Agent深度解析:用AI团队替代单一模型,四种架构实战落地

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号