DrawCommand 是 Cesium 渲染器的核心类,常用的接口 EntityPrimitiveCesium3DTileSet,以及地形和影像的渲染等等,底层都是一个个 DrawCommand 完成的。在进行扩展开发、视觉特效提升、性能优化、渲染到纹理(RTT),甚至基于 Cesium 封装自己的开发框架,定义独家数据格式等等,都需要开发人员对 DrawCommand 熟练掌握。而这部分接口,Cesium 官方文档没有公开,网上的相关资料也比较少,学习起来比较困难,所以接下来我们用几期文章,由浅入深,实用为主,力求全面地介绍 DrawCommand 及相关类的运用。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mSrbkn8L-1641533139912)(./drawCommand2.png)]

上一期(《Cesium 高性能扩展之DrawCommand(一):入门》)介绍 DrawCommand 基本属性,相信大家已经能够轻松创建一个可用的DrawCommand自定义Primitive了。那么自定义Primitive有什么用呢?还有没有必要深入学习呢?

这一期我们先不增加知识点,综合运用上一期介绍的基本属性,以及前几期介绍的Osgb解析技术(参考文章[《如何在Web上直接浏览大规模OSGB格式倾斜模型(一):解析OSGB,附源码
》、《如何在Web上直接浏览大规模OSGB格式倾斜模型(二):转换OSGB》),实现在不依赖Three.js的情况下,直接创建DrawCommand来显示Osgb倾斜摄影模型。

很容易总结出关键步骤:

  • Osgb几何体转成Cesium.Geometry
  • Osgb纹理贴图转为Cesium.Texture
  • Shader中读取纹理贴图。

1、将Osgb几何体转成Cesium.Geometry

我们直接基于转换OSGB这篇文章的代码,稍微修改一下就可以实现。

  • Cesium.GeometryAttribute 替代 THREE.BufferAttribute
  • Cesium.Geometry 替代 THREE.BufferGeometry
  • uv属性我们按照Cesium的命名规则,改成st
  • 索引数组,根据最大值来选择相应的数组类型,可以节省内存。
function parseGeometry(osgGeometry) {//顶点属性var positions = new Float32Array(osgGeometry.VertexArray.flat());var uvs = new Float32Array(osgGeometry.TexCoordArray[0].flat());//索引var primitiveSet = osgGeometry.PrimitiveSetList[0]var indices = primitiveSet.data;if (primitiveSet.value == 7) {let newIndices = [];for (let i = 0; i < indices.length; i += 4) {let i0 = indices[i], i1 = indices[i + 1], i2 = indices[i + 2], i3 = indices[i + 3];newIndices.push(i0, i1, i3, i1, i2, i3);}indices = newIndices;}if (indices) {//根据最大值来选择相应的数组类型,可以节省内存var max = Math.max.apply(null, indices)if (max > 65535) {indices = new Uint32Array(indices)} else {indices = new Uint16Array(indices)}}//构造Cesium几何体var geometry = new Cesium.Geometry({attributes: {position: {componentDatatype: Cesium.ComponentDatatype.FLOAT,componentsPerAttribute: 3,values: positions},st: {componentDatatype: Cesium.ComponentDatatype.FLOAT,componentsPerAttribute: 2,values: uvs}},indices: indices})return geometry
}

2、将Osgb纹理贴图转为Cesium.Texture

我们还是基于转换OSGB这篇文章的代码进行修改,不过我们只要提取纹理贴图。

这里需要注意,Cesium创建纹理贴图对象时会立即将贴图数据绑定到绘图上下文,所以不能必须在获取context之后,也就是渲染循环开始之后才能创建。这点和Three.js不同,THREE.Texture只封装贴图数据和参数,绑定是渲染器层负责的(Three.js的渲染器可有多个实现,比如WebGLRendererWebGPURendererCSSRendererSVGRenderer等等),所以可以在渲染循环开始之前创建。

function parseTexture(osgStateSet, context) {var osgImage = osgStateSet.TextureAttributeList[0].value.StateAttribute.Imagevar fileName = osgImage.Name;const isJPEG = fileName.search(/\.jpe?g($|\?)/i) > 0const isPNG = fileName.search(/\.png($|\?)/i) > 0if (!isPNG && !isJPEG) return;var mimeType = isPNG ? 'image/png' : 'image/jpeg';var imageUri = new Blob([osgImage.Data], { type: mimeType });imageUri = URL.createObjectURL(imageUri)//加载图片return Cesium.Resource.fetchImage(imageUri).then(img => {//创建纹理贴图对象var texture = new Cesium.Texture({context: context,source: img,width: img.width,height: img.height});return texture});
}

3、在Shader中读取纹理贴图

我们改动一下上一期的shader代码,增加st属性,并将stvertexShader传到fragmentShader,当然,这对于老手来说是基本操作了。
vertexShader

attribute vec3 position;
attribute vec2 st;
//向fragmentShader传递
varying vec2 v_st;
void main(){//接收js传来的值v_st=st;gl_Position = czm_projection  * czm_modelView * vec4( position , 1. );
}

fragmentShader

uniform sampler2D map;
//接收vertexShader传来的值
varying vec2 v_st;
void main(){gl_FragColor=texture2D( map , v_st);
}

可以看出,纹理贴图map需要通过uniform传递,所以uniformMap也需要调整。

//处理纹理贴图,先生成一个默认的空白贴图,等模型纹理贴图转换完成,再替换掉
var map = new Cesium.Texture({context: context,width: 2, height: 2
})
parseTexture(this.osgGeometry.StateSet, context).then(texture => {//释放默认纹理贴图map.destroy();//使用转换好的模型纹理贴图map = texture;
})var uniformMap = {map() {return map}
}

4、完整代码

构造自定义Primitive时需要传入osg::Geometry类型节点对象,在创建DrawCommand的时调用转换几何体和纹理贴图的函数。

function parseGeometry(osgGeometry) {var positions = new Float32Array(osgGeometry.VertexArray.flat());var uvs = new Float32Array(osgGeometry.TexCoordArray[0].flat());var primitiveSet = osgGeometry.PrimitiveSetList[0]var indices = primitiveSet.data;if (primitiveSet.value == 7) {let newIndices = [];for (let i = 0; i < indices.length; i += 4) {let i0 = indices[i], i1 = indices[i + 1], i2 = indices[i + 2], i3 = indices[i + 3];newIndices.push(i0, i1, i3, i1, i2, i3);}indices = newIndices;}if (indices) {var max = Math.max.apply(null, indices)if (max > 65535) {indices = new Uint32Array(indices)} else {indices = new Uint16Array(indices)}}var geometry = new Cesium.Geometry({attributes: {position: {componentDatatype: Cesium.ComponentDatatype.FLOAT,componentsPerAttribute: 3,values: positions},st: {componentDatatype: Cesium.ComponentDatatype.FLOAT,componentsPerAttribute: 2,values: uvs}},indices: indices})return geometry
}function parseTexture(osgStateSet, context) {var osgImage = osgStateSet.TextureAttributeList[0].value.StateAttribute.Imagevar fileName = osgImage.Name;const isJPEG = fileName.search(/\.jpe?g($|\?)/i) > 0const isPNG = fileName.search(/\.png($|\?)/i) > 0if (!isPNG && !isJPEG) return;var mimeType = isPNG ? 'image/png' : 'image/jpeg';var imageUri = new Blob([osgImage.Data], { type: mimeType });imageUri = URL.createObjectURL(imageUri)return Cesium.Resource.fetchImage(imageUri).then(img => {var texture = new Cesium.Texture({context: context,source: img,width: img.width,height: img.height});return texture});
}class MyPrimitive {constructor(modelMatrix, osgGeometry) {this.modelMatrix = modelMatrix || Cesium.Matrix4.IDENTITY.clone()this.drawCommand = null;this.osgGeometry = osgGeometry}createCommand(context) {var modelMatrix = this.modelMatrix;//转换几何体var geometry = parseGeometry(this.osgGeometry)var attributeLocations = Cesium.GeometryPipeline.createAttributeLocations(geometry)var va = Cesium.VertexArray.fromGeometry({context: context,geometry: geometry,attributeLocations: attributeLocations});var vs = `attribute vec3 position;attribute vec2 st;varying vec2 v_st;void main(){v_st=st;gl_Position = czm_projection  * czm_modelView * vec4( position , 1. );}`;var fs = `uniform sampler2D map; varying vec2 v_st;void main(){gl_FragColor=texture2D( map , v_st);}`;var shaderProgram = Cesium.ShaderProgram.fromCache({context: context,vertexShaderSource: vs,fragmentShaderSource: fs,attributeLocations: attributeLocations})//处理纹理贴图,先生成一个默认的空白贴图,等模型纹理贴图转换完成,再替换掉var map = new Cesium.Texture({context: context,width: 2, height: 2})parseTexture(this.osgGeometry.StateSet, context).then(texture => {//释放默认纹理贴图map.destroy();//使用转换好的模型纹理贴图map = texture; })var uniformMap = {map() {return map}}var renderState = Cesium.RenderState.fromCache({cull: {enabled: true,face:Cesium.CullFace.BACK},depthTest: {enabled: true}})this.drawCommand = new Cesium.DrawCommand({modelMatrix: modelMatrix,vertexArray: va,shaderProgram: shaderProgram,uniformMap: uniformMap,renderState: renderState,pass: Cesium.Pass.OPAQUE})}/*** * @param {Cesium.FrameState} frameState */update(frameState) {if (!this.drawCommand) {this.createCommand(frameState.context)}frameState.commandList.push(this.drawCommand)}}

5、调用示例及效果

解析,遍历节点,处理类型为osg::Geometry的节点,创建一个自定义Primitive来展示该节点。

import * as osg from 'osg-serializer-browser';var origin = Cesium.Cartesian3.fromDegrees(106, 26, 0)
var modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(origin)var url = '../../assets/sampleData/models/tile_0_0_0_tex_children.osgb';
Cesium.Resource.fetchArrayBuffer(url).then(buf => {var osgObj = osg.readBuffer(buf)osg.TraverseNodes(osgObj, node => {if (node.Type == 'osg::Geometry') {var primitive = new MyPrimitive(modelMatrix, node);viewer.scene.primitives.add(primitive)}})
})

效果如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vAFgWUYZ-1641533139913)(./drawCommand2.png)]

至此,大家对于文章开头的两个问题应该都有自己的答案了,我们下期继续!

两个字:快,稳!
欢迎咨询,后台回复【商务合作】,获取联系方式!
欢迎关注微信公众号【三维网格3D】,第一时间获取最新文章

Cesium 高性能扩展之DrawCommand(二):OSGB倾斜模型展示应用相关推荐

  1. 后端传输大量log数据_京东智联云MySQL读写分离最佳实践 ,轻松搞定数据库高性能扩展...

    数字化时代,数据库对任何企业而言都是其应用的核心资源.MySQL作为当前最流行的关系型数据库,虽然是开源软件,但是其简单易懂.易于部署管理,且具有ACID特性.强大的SQL查询等特点,被各种业务系统作 ...

  2. 京东智联云MySQL读写分离最佳实践 ,轻松搞定数据库高性能扩展

    云妹导读: 互联网公司业务往往都有着高并发.大数据量等特点,为了在激烈的市场竞争中占得先机,需要不断推陈出新,并做大量的促销运营活动.但由于互联网的特殊性,企业无法提前预判这些活动给技术架构带来的压力 ...

  3. spring扩展点之二:spring中关于bean初始化、销毁等使用汇总,ApplicationContextAware将ApplicationContext注入...

    <spring扩展点之二:spring中关于bean初始化.销毁等使用汇总,ApplicationContextAware将ApplicationContext注入> <spring ...

  4. Thingworx自定义扩展开发(二)- Widget Demo Coding

    系列 Thingworx自定义扩展开发(一)- 开发环境搭建.Extension Demo Coding Thingworx自定义扩展开发(二)- Widget Demo Coding Thingwo ...

  5. 谷歌地球倾斜模型3Dtiles格式cesium格式一键导入查看

    谷歌地球倾斜模型3Dtiles格式cesium格式一键导入查看 台湾省倾斜模型ceisum 3Dtiles格式谷歌地球谷歌地 大家好我是谷谷GIS的开发者,为大家分享一下这个台湾省的,倾斜模型3Dti ...

  6. Cesium 体积测量支持倾斜模型(不支持地形)

    使用方法操作简单如图所示: 清除数据操作如图所示: 操作说明:左键开始绘制,右键开始结束 效果: 操作说明:我是引入truf,将不规则的多边形切割一个个三角形行的 如果报如下错误,请查看turf官方引 ...

  7. 从根上理解高性能、高并发(二):深入操作系统,理解I/O与零拷贝技术

    1.系列文章引言 1.1 文章目的 作为即时通讯技术的开发者来说,高性能.高并发相关的技术概念早就了然与胸,什么线程池.零拷贝.多路复用.事件驱动.epoll等等名词信手拈来,又或许你对具有这些技术特 ...

  8. 黑马程序员全套Java教程_Java基础教程_异常(含扩展)(二十三)

    黑马程序员全套Java教程_Java基础教程_异常(含扩展)(二十三) 1.1 异常概述与异常体系结构 1.2 JVM遇到异常时的默认处理方案 1.3 异常处理 1.4 异常处理之try--catch ...

  9. 倾斜模型数据及激光雷达点云数据在EPS中联动生产高精度1:500地形图

    生产过激光雷达点云数据的朋友们肯定知道如果生产1:500高精度数据,只使用激光雷达数据在很多时候只能满足高程数据精准这一需求,很多地物的绘制只能借助于正射影像来进行绘制,这对于测区中有房屋区域的测区, ...

  10. 倾斜模型单体化的研究

    倾斜摄影三维建模及应用是近年来测绘领域关注的热点,产业链上下游的企业为此都在积极探索,以推动该项技术的健康发展和落地应用.然而,什么样的技术才是真正符合用户实际应用需求的?在这里,我们要和大家讲解倾斜 ...

最新文章

  1. 2022-2028年中国激光全息膜行业市场现状调研及市场需求潜力报告
  2. 如何让AI机器人的对话更加自然?
  3. WIN32练习项目(函数调用监视器)
  4. Kibana功能一览
  5. codeforces1471 D. Strange Definition
  6. 【算法学习】双调欧几里得旅行商问题(动态规划)
  7. [Editor][002][Emacs] 从零到高级的进阶 - 实践开发 - 帮助菜单主页
  8. 2批量批量查询数据插入数据_不吹牛!Mysql 千万数据10秒批量插入只需三步
  9. 实战丨基于接口的银行系统自动化测试实践
  10. 人脸方向学习(六):Face Recognition-Center Loss 解读
  11. 下载速度MB/s与Mb/s的区别
  12. 手机的模拟,有耗电和充电方法, 有电量的属性
  13. 1分钟告诉你用MOE模拟200000个分子要花多少钱
  14. Hadoop小兵笔记【六】hadoop2.2.0伪分布式环境搭建疑难-JobHistory显示Job信息为空
  15. Android技术内幕.系统卷
  16. Python综合小应用 —— 胖子老板香烟管理系统
  17. 免疫组库vdj的数据处理(TCR/BCR)
  18. 关键帧提取——帧差法提取关键帧(2)
  19. 计算机系统基础 - Lab1
  20. 使用photoshop 修复旧照片

热门文章

  1. 西安电子科技大学出版社 线性代数 参考答案 刘三阳
  2. origin做相关性分析图_Origin9.1科技绘图及数据分析
  3. Javashop 7.0 统一登录unionID问题修改
  4. Python GUI之tkinter 教程大集合
  5. MS Project的开源替代品 OpenProj
  6. Python tinypng 压缩脚本
  7. 2020-6 android kernel vulnerability
  8. Autodesk HSMWorks Ultimate 2019 Crack 破解版
  9. 关于stdafx.h的错误
  10. a59s刷机包卡刷 oppo_OPPO A59S刷机包