本文代码基于Vue-cli4和使用WebGL的地图引擎Cesium,主要内容为三维场景下不同对象的动态材质构建。

参考了很多文章,链接附在文末。

为不同的几何对象添加动态材质

不知道这一小节的名称概况是否准确,在我的理解中Cesium中的集合实体分成两类:Primitive和Entity,一般翻译成图元和实体,图元更接近底层,实体是封装后的高级对象,使用更加简便,这里不对使用场景进行分析,但会介绍如果为这两种集合对象添加材质。

使用Primitive生成泛光墙

一般来说,Primitive的使用相对繁琐,相比Entity需要使用者自己初始化更多对象,包括外观、地理信息等,但正因为如此,为Primitive添加材质要方便很多,因为可以直接操作几何体的外观部分。首先我们初始化一个墙几何体:

  1. var wallInstance = new Cesium.GeometryInstance({
  2. geometry: Cesium.WallGeometry.fromConstantHeights({
  3. positions: Cesium.Cartesian3.fromDegreesArray([
  4. 97.0,
  5. 43.0,
  6. 107.0,
  7. 43.0,
  8. 107.0,
  9. 40.0,
  10. 97.0,
  11. 40.0,
  12. 97.0,
  13. 43.0,
  14. ]),
  15. maximumHeight: 100000.0,
  16. vertexFormat: Cesium.MaterialAppearance.VERTEX_FORMAT,
  17. }),
  18. })
  19. viewer.scene.primitives.add(
  20. new Cesium.Primitive({
  21. geometryInstances: [wallInstance],
  22. appearance: new Cesium.MaterialAppearance(),
  23. })
  24. )

上文代码所创建的是一个只有基础外观的“墙”, 实例化 Cesium.MaterialAppearance() 这个类不传参数所得到的的就是下图的样子:

官方文档中我们可以查到有如下参数:

这里我们关注的是 material ,也就是所谓的“材质”,接下来补充上材质的代码:

  1. let image = '/static/images/colors1.png', //选择自己的动态材质图片
  2. color = new Cesium.Color.fromCssColorString('rgba(0, 255, 255, 1)'),
  3. speed = 0,
  4. source =
  5. 'czm_material czm_getMaterial(czm_materialInput materialInput)\n\
  6. {\n\
  7. czm_material material = czm_getDefaultMaterial(materialInput);\n\
  8. vec2 st = materialInput.st;\n\
  9. vec4 colorImage = texture2D(image, vec2(fract((st.t - speed*czm_frameNumber*0.005)), st.t));\n\
  10. vec4 fragColor;\n\
  11. fragColor.rgb = color.rgb / 1.0;\n\
  12. fragColor = czm_gammaCorrect(fragColor);\n\
  13. material.alpha = colorImage.a * color.a;\n\
  14. material.diffuse = (colorImage.rgb+color.rgb)/2.0;\n\
  15. material.emission = fragColor.rgb;\n\
  16. return material;\n\
  17. }'
  18. let material = new Cesium.Material({
  19. fabric: {
  20. type: 'PolylinePulseLink',
  21. uniforms: {
  22. color: color,
  23. image: image,
  24. speed: speed,
  25. },
  26. source: source,
  27. },
  28. translucent: function () {
  29. return true
  30. },
  31. })
  32. viewer.scene.primitives.add(
  33. new Cesium.Primitive({
  34. geometryInstances: [greenWallInstance],
  35. appearance: new Cesium.MaterialAppearance({
  36. material: material,
  37. }),
  38. })
  39. )

应用材质的效果图:

材质文件colros1.png:

通过上面的代码和截图可以看出材质文件和最后表现出的结果还是有很大差异的,而且变量source中的代码看起来似乎很难理解,这些内容会在下文进行说明,本节还是针对材质如何应用进行说明。

使用Entity生成流动线

参考Primitive的流程,我们先创建一个实体对象,这次我们换一个场景,改为创建流动线,参考的文章 流动线纹理

  1. create(viewer) {
  2. //创建射线
  3. var data = {
  4. center: {
  5. id: 0,
  6. lon: 114.302312702,
  7. lat: 30.598026044,
  8. size: 20,
  9. color: Cesium.Color.PURPLE,
  10. },
  11. points: [
  12. {
  13. id: 1,
  14. lon: 115.028495718,
  15. lat: 30.200814617,
  16. color: Cesium.Color.YELLOW,
  17. size: 15,
  18. },
  19. {
  20. id: 2,
  21. lon: 110.795000473,
  22. lat: 32.638540762,
  23. color: Cesium.Color.RED,
  24. size: 15,
  25. },
  26. {
  27. id: 3,
  28. lon: 111.267729446,
  29. lat: 30.698151246,
  30. color: Cesium.Color.BLUE,
  31. size: 15,
  32. },
  33. {
  34. id: 4,
  35. lon: 112.126643144,
  36. lat: 32.058588576,
  37. color: Cesium.Color.GREEN,
  38. size: 15,
  39. },
  40. {
  41. id: 5,
  42. lon: 114.885884938,
  43. lat: 30.395401912,
  44. color: Cesium.Color.BLUE,
  45. size: 15,
  46. },
  47. {
  48. id: 6,
  49. lon: 112.190419415,
  50. lat: 31.043949588,
  51. color: Cesium.Color.BLUE,
  52. size: 15,
  53. },
  54. {
  55. id: 7,
  56. lon: 113.903569642,
  57. lat: 30.93205405,
  58. color: Cesium.Color.BLUE,
  59. size: 15,
  60. },
  61. {
  62. id: 8,
  63. lon: 112.226648859,
  64. lat: 30.367904255,
  65. color: Cesium.Color.BLUE,
  66. size: 15,
  67. },
  68. {
  69. id: 9,
  70. lon: 114.86171677,
  71. lat: 30.468634833,
  72. color: Cesium.Color.BLUE,
  73. size: 15,
  74. },
  75. {
  76. id: 10,
  77. lon: 114.317846048,
  78. lat: 29.848946148,
  79. color: Cesium.Color.BLUE,
  80. size: 15,
  81. },
  82. {
  83. id: 11,
  84. lon: 113.371985426,
  85. lat: 31.70498833,
  86. color: Cesium.Color.BLUE,
  87. size: 15,
  88. },
  89. {
  90. id: 12,
  91. lon: 109.468884533,
  92. lat: 30.289012191,
  93. color: Cesium.Color.BLUE,
  94. size: 15,
  95. },
  96. {
  97. id: 13,
  98. lon: 113.414585069,
  99. lat: 30.368350431,
  100. color: Cesium.Color.SALMON,
  101. size: 15,
  102. },
  103. {
  104. id: 14,
  105. lon: 112.892742589,
  106. lat: 30.409306203,
  107. color: Cesium.Color.WHITE,
  108. size: 15,
  109. },
  110. {
  111. id: 15,
  112. lon: 113.16085371,
  113. lat: 30.667483468,
  114. color: Cesium.Color.SALMON,
  115. size: 15,
  116. },
  117. {
  118. id: 16,
  119. lon: 110.670643354,
  120. lat: 31.74854078,
  121. color: Cesium.Color.PINK,
  122. size: 15,
  123. },
  124. ],
  125. options: {
  126. name: '',
  127. polyline: {
  128. width: 2,
  129. material: [Cesium.Color.GREEN, 3000],
  130. },
  131. },
  132. }
  133. this.createFlyLines(data, viewer)
  134. },
  135. createFlyLines(data, viewer) {
  136. const center = data.center
  137. const cities = data.points
  138. const startPoint = Cesium.Cartesian3.fromDegrees(
  139. center.lon,
  140. center.lat,
  141. 0
  142. )
  143. //中心点
  144. viewer.entities.add({
  145. position: startPoint,
  146. point: {
  147. pixelSize: center.size,
  148. color: center.color,
  149. },
  150. })
  151. //大批量操作时,临时禁用事件可以提高性能
  152. viewer.entities.suspendEvents() //散点
  153. cities.map((city) => {
  154. let material = new Cesium.PolylineTrailMaterialProperty({
  155. color: Cesium.Color.RED,
  156. duration: 3000,
  157. trailImage: '/static/images/colors1.png',
  158. })
  159. const endPoint = Cesium.Cartesian3.fromDegrees(city.lon, city.lat, 0)
  160. viewer.entities.add({
  161. position: endPoint,
  162. point: {
  163. pixelSize: city.size - 10,
  164. color: city.color,
  165. },
  166. })
  167. viewer.entities.add({
  168. polyline: {
  169. positions: this.generateCurve(startPoint, endPoint),
  170. width: 2,
  171. material: material,
  172. },
  173. })
  174. })
  175. viewer.entities.resumeEvents()
  176. viewer.flyTo(viewer.entities)
  177. },
  178. /**
  179. * 生成流动曲线
  180. * @param startPoint 起点
  181. * @param endPoint 终点
  182. * @returns {Array}
  183. */
  184. generateCurve(startPoint, endPoint) {
  185. let addPointCartesian = new Cesium.Cartesian3()
  186. Cesium.Cartesian3.add(startPoint, endPoint, addPointCartesian)
  187. let midPointCartesian = new Cesium.Cartesian3()
  188. Cesium.Cartesian3.divideByScalar(addPointCartesian, 2, midPointCartesian)
  189. let midPointCartographic = Cesium.Cartographic.fromCartesian(
  190. midPointCartesian
  191. )
  192. midPointCartographic.height =
  193. Cesium.Cartesian3.distance(startPoint, endPoint) / 5
  194. let midPoint = new Cesium.Cartesian3()
  195. Cesium.Ellipsoid.WGS84.cartographicToCartesian(
  196. midPointCartographic,
  197. midPoint
  198. )
  199. let spline = new Cesium.CatmullRomSpline({
  200. times: [0.0, 0.5, 1.0],
  201. points: [startPoint, midPoint, endPoint],
  202. })
  203. let curvePoints = []
  204. for (let i = 0, len = 200; i < len; i++) {
  205. curvePoints.push(spline.evaluate(i / len))
  206. }
  207. return curvePoints
  208. },

代码要多很多,但主要是点位信息,并且曲线实体的创建要更加复杂,我们着重关注 createFlyLines 这个方法就可以了,可以看到其中创建 material 的部分与Primitive略有不同,实例化的是一个自定义的类 PolylineTrailMaterialProperty

  1. let material = new Cesium.PolylineTrailMaterialProperty({
  2. color: Cesium.Color.WHITE,
  3. duration: 3000,
  4. trailImage: '/static/images/colors1.png',
  5. })

具体原因我们还是从官方文档来看,可以发现与Primitive不同,传入material的不再是Material类,而是MaterialProperty类。

Cesium提供了一些MaterialProperty,分别代表不同的效果,但显然不能满足我们多样的业务需求,所以这时需要我们自定义这个MaterialProperty。

MaterialProperty

创建 PolylineTrailMaterialProperty.js 文件并导入:

  1. import PolylineTrailMaterialProperty from '@/utils/cesium/PolylineTrailMaterialProperty'
  1. import * as Cesium from 'cesium/Cesium'
  2. export class PolylineTrailMaterialProperty {
  3. constructor(options) {
  4. options = Cesium.defaultValue(options, Cesium.defaultValue.EMPTY_OBJECT)
  5. this._definitionChanged = new Cesium.Event()
  6. this._color = undefined
  7. this._colorSubscription = undefined
  8. this._time = performance.now()
  9. this.color = options.color
  10. this.duration = options.duration
  11. this.trailImage = options.trailImage
  12. }
  13. }
  14. Object.defineProperties(PolylineTrailMaterialProperty.prototype, {
  15. isConstant: {
  16. get: function () {
  17. return false
  18. },
  19. },
  20. definitionChanged: {
  21. get: function () {
  22. return this._definitionChanged
  23. },
  24. },
  25. color: Cesium.createPropertyDescriptor('color'),
  26. })
  27. PolylineTrailMaterialProperty.prototype.getType = function () {
  28. return 'PolylineTrail'
  29. }
  30. PolylineTrailMaterialProperty.prototype.getValue = function (time, result) {
  31. if (!Cesium.defined(result)) {
  32. result = {}
  33. }
  34. result.color = Cesium.Property.getValueOrClonedDefault(
  35. this._color,
  36. time,
  37. Cesium.Color.WHITE,
  38. result.color
  39. )
  40. result.image = this.trailImage
  41. result.time =
  42. ((performance.now() - this._time) % this.duration) / this.duration
  43. return result
  44. }
  45. PolylineTrailMaterialProperty.prototype.equals = function (other) {
  46. return (
  47. this === other ||
  48. (other instanceof PolylineTrailMaterialProperty &&
  49. Cesium.Property.equals(this._color, other._color))
  50. )
  51. }
  52. Cesium.Material.PolylineTrailType = 'PolylineTrail'
  53. Cesium.Material.PolylineTrailImage = '/static/images/colors1.png'
  54. Cesium.Material.PolylineTrailSource =
  55. 'czm_material czm_getMaterial(czm_materialInput materialInput)\n\
  56. {\n\
  57. czm_material material = czm_getDefaultMaterial(materialInput);\n\
  58. vec2 st = materialInput.st;\n\
  59. vec4 colorImage = texture2D(image, vec2(fract(st.s - time), st.t));\n\
  60. material.alpha = colorImage.a * color.a;\n\
  61. material.diffuse = (colorImage.rgb+color.rgb)/2.0;\n\
  62. return material;\n\
  63. }'
  64. Cesium.Material._materialCache.addMaterial(Cesium.Material.PolylineTrailType, {
  65. fabric: {
  66. type: Cesium.Material.PolylineTrailType,
  67. uniforms: {
  68. color: new Cesium.Color(1.0, 0.0, 0.0, 0.5),
  69. image: Cesium.Material.PolylineTrailImage,
  70. time: 0,
  71. },
  72. source: Cesium.Material.PolylineTrailSource,
  73. },
  74. translucent: function () {
  75. return true
  76. },
  77. })
  78. Cesium.PolylineTrailMaterialProperty = PolylineTrailMaterialProperty

在定义自己的 MaterialProperty 时,需要设置几个公共的方法,分别是:getValueisConstantdefinitionChangedequals

  1. getValue:用来获取某个时间点的特定属性值,包括两个参数:type和result,分别是用于传递时间点和存储属性值。
  2. isConstant:用来判断该属性是否会随时间变化,是一个bool类型。Cesium会通过这个变量来决定是否需要在场景更新的每一帧中都获取该属性的数值,从而来更新三维场景中的物体。如果isConstant为true,则只会获取一次数值,除非definitionChanged事件被触发。
  3. definitionChanged:是一个事件,可以通过该事件,来监听该Property自身所发生的变化,比如数值发生修改。
  4. equals:用来检测属性值是否相等。

具体参考 Cesium自定义材质

实际效果见下图:

材质是如何“炼”成的

Fabric

MaterialProperty 之前的代码主要是构建弧线,然后为弧线添加动态效果,至于效果什么样,就全部取决于MaterialProperty这个类如何运作,可以看到与上文为Primitive添加的 Material 相似,它们都包含一个 fabric 对象,这个单词直译为“织物”,也就是说它是覆盖在模型上的一层衣服,它有颜色(color)和图片(image),如果想让这层效果动起来,还需要一个时间变量,比如在泛光墙的例子中的“speed”,流动线例子中的“time”。Cesium的官方文档中定义它为一个用于生成材质的JSON对象。

WebGL的shader(着色器)

那如何将我们定义的几个变量变成想象中的材质呢?这里就涉及到上文代码中最晦涩难懂的那两段字符串,这是一种从属于WebGL技术的独立语法,叫做shader(着色器),从这里开始已经步入了图形学的领域,我虽然很有兴趣但是暂时还没打算入坑,可以看下这篇 【Cesium 颜狗初步】fabric 材质定义与自定义着色器实践,比较通俗易懂,也有示例。

以我的粗浅理解来看,WebGL作为HTML5的API为我们提供了一个更好的与客户端硬件图形部分的交互,来实现更好的视觉效果。

动态墙和流动线shader的简单说明

如果不想看长篇大论,还是希望能直接实现效果可以参考上面的代码,如果只是想微调效果也不需要细致学习shader的用法,我们仔细看下就能看出规律。Fabric 一节中我们提到时间变量,但是泛光墙的例子中似乎与时间无关,实际上这也是个动态材质,将speed设置为正数后,墙面会有上下移动的效果。

其实看下参数就明白,它们都有在shader中出场:

  1. uniforms: {
  2. color: color,
  3. image: image,
  4. speed: speed,
  5. },

只不过shader会以它独特的方法来解析这些我们传入的图形和参数,比如这里修改speed后面乘的数值,可以改变动态图像每一单位的变化速度,修改下面fragColor的部分可以改变颜色的处理方式,在原本的例子中这里其实是混合了传入的颜色和一个基本的颜色,我这里改成了除1,也就是传入什么颜色就用什么颜色,不过还要考虑与图片素材的混合,另外,shader的数字基本都是使用浮点型,比如这里要用“1.0”,用“1”就会报错。流动线的shader类似,其实差别不大,因为我这里也是只用了两个简单的例子。

轻松应用复杂特效:EarthSDK

如果既不想研究WebGL又不想要5毛钱的特效,有没有办法呢?也不是没有,涉及到比较垂直的领域,就需要有乐于奉献的大佬提供开发包了,这里我推荐EarthSDK,简单展示一下实现的效果:

出于图片大小的考虑,这里限制了帧数,实际效果要更好,这里使用的是测试用的shp文件,根据坐标绘制形状,再根据层高拉升模型的高度,之后只要应用SDK中的效果就可以了,这里贴下部分配置,url做了代理,这里用的是我自己部署的shp文件:

  1. {
  2. ref: 'tileset1',
  3. czmObject: {
  4. xbsjType: 'Tileset',
  5. xbsjGuid: '739ae1b9-bf61-455a-89d4-280668ed6f3c',
  6. name: '白模测试1',
  7. url: '/tileset/tileset.json',
  8. xbsjStyle: 'var style = {\n color: "vec4(0, 0.5, 1.0,1)"\n}',
  9. xbsjClippingPlanes: {},
  10. xbsjCustomShader: {
  11. fsBody: this.fsBody,
  12. },
  13. },
  14. },
  15. {
  16. ref: 'scaneline',
  17. czmObject: {
  18. xbsjType: 'Scanline',
  19. xbsjGuid: 'c827bdc1-c14b-4452-81de-7b2ce427b786',
  20. name: '扫描线',
  21. position: [2.1201528021066163, 0.5451706303633767, 0],
  22. show: true,
  23. radius: 1000,
  24. timeDuration: '3',
  25. currentTime: 0,
  26. color: [0.5, 0.8, 1.0, 1.0],
  27. },
  28. },

配置并不算难,详细内容看文档就可以EarthSDK官网

另外他们家的另一个产品CesiumLab在GIS开发中也很实用。

参考资料

流动线纹理

Cesium动态立体墙效果

Cesium自定义材质

【Cesium 颜狗初步】fabric 材质定义与自定义着色器实践

除了上面提到的,还有一些不错的参考

Cesium参考资源

Cesium官方教程12--材质(Fabric)

【三维GIS可视化】基于Vue+Cesium+Supermap实现智慧城市(四)

这个系列作者写得很详细,学到了很多

前端3D引擎-Cesium自定义动态材质的更多相关文章

  1. 前端学PHP之自定义模板引擎

    前面的话 在大多数的项目组中,开发一个Web程序都会出现这样的流程:计划文档提交之后,前端工程师制作了网站的外观模型,然后把它交给后端工程师,它们使用后端代码实现程序逻辑,同时使用外观模型做成基本架构 ...

  2. 从0开发3D引擎(八):准备“搭建引擎雏形”

    大家好,现在开始本系列的第三部分,按照以下几个步骤来搭建引擎雏形: 1.分析引擎的需求 2.实现最小的3D程序 3.从中提炼引擎原型 4.一步一步地对引擎进行改进,使其具备良好的架构 5.实现与架构相 ...

  3. 关于如何学好游戏3D引擎编程的一些经验[转]

    此篇文章献给那些为了游戏编程不怕困难的热血青年,它的神秘要我永远不间断的去挑战自我,超越自我,这样才能攀登到游戏技术的最高峰 ——阿哲VS自己 QQ79134054多希望大家一起交流与沟通 这篇文章是 ...

  4. 如何学好游戏3D引擎编程

    注:本文是网上看到的一篇文章,感觉写的很好,因此收藏了下来 <如何学好游戏3D引擎编程>此篇文章献给那些为了游戏编程不怕困难的热血青年,它的神秘要我永远不间断的去挑战自我,超越自我,这样才 ...

  5. (转)关于如何学好游戏3D引擎编程的一些经验

    此篇文章献给那些为了游戏编程不怕困难的热血青年,它的神秘要我永远不间断的去挑战自我,超越自我,这样才能攀登到游戏技术的最高峰 ——阿哲VS自己 QQ79134054多希望大家一起交流与沟通 这篇文章是 ...

  6. Wonder第一期3D引擎和编辑器线下培训班报名开始啦(免费学习)

    Wonder第一次举办 针对3D底层技术的 线下培训班,免费学习,请大家多多支持-感谢- 培训地点 成都 开课时间 报名满5人开课. 报名方式 加QQ群:732861508 备注请写:报名培训 老师介 ...

  7. 从0开发3D引擎(一):开篇

    介绍 大家好,本系列带你踏上Web 3D编程之旅- 本系列是实战类型,从0开始带领读者写出"良好架构.良好扩展性.最小功能集合(MVP)" 的3D引擎. 本系列的素材来自我们的产品 ...

  8. 从0开发3D引擎(四):搭建测试环境

    目录 上一篇博文 了解自动化测试 单元测试 集成测试 端对端测试 通过打印日志来调试 了解运行测试 断点调试 通过Spector.js测试WebGL 通过log调试Shader 移动端测试 了解性能测 ...

  9. 我完成了10000小时开发3D引擎

    为什么要开始10000小时? 我以前看过一本叫<异类>的书,书的大概意思是:只要学习10000小时,任何人都可以成为一个领域的大师.这里的"学习"是指完全专注地精进学习 ...

随机推荐

  1. JAVA加解密之DES

    DES加密算法是一种分组密码,以64位为分组对数据加密,它的密钥长度是56位,加密解密用同一算法.DES加密算法是对密钥进行保密,而公开算法,包括加密和解密算法.这样,只有掌握了和发送方相同密钥的人才 ...

  2. 【LeetCode】323. Number of Connected Components in an Undirected Graph 解题报告 (C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 并查集 日期 题目地址:https://leetcod ...

  3. 【LeetCode】235. Lowest Common Ancestor of a Binary Search Tree 解题报告(Java & Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 [LeetCode] https://leet ...

  4. 【LeetCode】199. Binary Tree Right Side View 解题报告(Python)

    [LeetCode]199. Binary Tree Right Side View 解题报告(Python) 标签: LeetCode 题目地址:https://leetcode.com/probl ...

  5. 【LeetCode】842. Split Array into Fibonacci Sequence 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...

  6. The Longest Straight(FZUoj2216)

     Problem 2216 The Longest Straight Accept: 82    Submit: 203Time Limit: 1000 mSec    Memory Limit : ...

  7. 为什么加密后的数据往往都是base64输出而不是hex16进制输出

    通常加密后的数据都是字节数组,比如流行的aes128对称加密,还有Rsa非对称加密,加密后得到了一个字节数组,这个字节数组存在内存中,往往我们需要输出得到我们人眼能看到的字符. 加密aes(xxx) ...

  8. springboot中word转pdf,加盖电子印章

    概述 在开发过程中,word转pdf的方式有很多种有jar包的方式,有安装openoffice的方式,但是使用有的jar包有license认证,不然会生成水印,综合几种方法我采用了libreoffic ...

  9. Java初学者作业——定义英雄类(Hero),英雄类中的属性包括:姓名、攻击力、防御力、生命值和魔法值;方法包括:攻击、介绍。

    返回本章节 返回作业目录 需求说明: 定义英雄类(Hero),英雄类中的属性包括:姓名.攻击力.防御力.生命值和魔法值:方法包括:攻击.介绍. 实现思路: 分析类的属性及其变量类型. 分析类的方法及其 ...

  10. Java初学者作业——编写Java程序,输出1~100之间能够同时被3和4整除的最大的五个数字。

    返回本章节 返回作业目录 需求说明: 编写Java程序,输出1-100之间能够同时被3和4整除的最大的五个数字. 实现思路: 声明变量count,用于存储满足条件的数据个数,设置初始值为0. 在区间1 ...