You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

S3MContentParser.js 9.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. import DDSTexture from './DDSTexture.js'
  2. import MaterialPass from './MaterialPass.js'
  3. import S3MContentFactory from './Factory/S3MContentFactory.js'
  4. import VertexCompressOption from './Enum/VertexCompressOption.js'
  5. const { Cesium } = DC.Namespace
  6. function S3MContentParser() {}
  7. function parseMaterial(context, content, tile) {
  8. let materialTable = {}
  9. let materials = content.materials.material
  10. for (let i = 0, j = materials.length; i < j; i++) {
  11. let material = materials[i].material
  12. let materialCode = material.id
  13. let materialPass = new MaterialPass()
  14. materialTable[materialCode] = materialPass
  15. let ambient = material.ambient
  16. materialPass.ambientColor = new Cesium.Color(
  17. ambient.r,
  18. ambient.g,
  19. ambient.b,
  20. ambient.a
  21. )
  22. let diffuse = material.diffuse
  23. materialPass.diffuseColor = new Cesium.Color(
  24. diffuse.r,
  25. diffuse.g,
  26. diffuse.b,
  27. diffuse.a
  28. )
  29. let specular = material.specular
  30. materialPass.specularColor = new Cesium.Color(
  31. specular.r,
  32. specular.g,
  33. specular.b,
  34. specular.a
  35. )
  36. materialPass.shininess = material.shininess
  37. materialPass.bTransparentSorting = material.transparentsorting
  38. let textureStates = material.textureunitstates
  39. let len = textureStates.length
  40. for (let k = 0; k < len; k++) {
  41. let textureState = textureStates[k].textureunitstate
  42. let textureCode = textureState.id
  43. let wrapS =
  44. textureState.addressmode.u === 0
  45. ? Cesium.TextureWrap.REPEAT
  46. : Cesium.TextureWrap.CLAMP_TO_EDGE
  47. let wrapT =
  48. textureState.addressmode.v === 0
  49. ? Cesium.TextureWrap.REPEAT
  50. : Cesium.TextureWrap.CLAMP_TO_EDGE
  51. materialPass.texMatrix = Cesium.Matrix4.unpack(textureState.texmodmatrix)
  52. let textureInfo = content.texturePackage[textureCode]
  53. if (
  54. Cesium.defined(textureInfo) &&
  55. textureInfo.arrayBufferView.byteLength > 0
  56. ) {
  57. textureInfo.wrapS = wrapS
  58. textureInfo.wrapT = wrapT
  59. let keyword = tile.fileName + textureCode
  60. let texture = context.textureCache.getTexture(keyword)
  61. if (!Cesium.defined(texture)) {
  62. if (
  63. Cesium.PixelFormat.isCompressedFormat(textureInfo.internalFormat)
  64. ) {
  65. texture = new DDSTexture(context, textureCode, textureInfo)
  66. } else {
  67. let isPowerOfTwo =
  68. Cesium.Math.isPowerOfTwo(textureInfo.width) &&
  69. Cesium.Math.isPowerOfTwo(textureInfo.height)
  70. texture = new Cesium.Texture({
  71. context: context,
  72. source: {
  73. width: textureInfo.width,
  74. height: textureInfo.height,
  75. arrayBufferView: textureInfo.arrayBufferView
  76. },
  77. sampler: new Cesium.Sampler({
  78. minificationFilter: isPowerOfTwo
  79. ? context._gl.LINEAR_MIPMAP_LINEAR
  80. : context._gl.LINEAR,
  81. wrapS: wrapS,
  82. wrapT: wrapT
  83. })
  84. })
  85. if (isPowerOfTwo) {
  86. texture.generateMipmap(Cesium.MipmapHint.NICEST)
  87. }
  88. }
  89. context.textureCache.addTexture(keyword, texture)
  90. }
  91. materialPass.textures.push(texture)
  92. }
  93. }
  94. }
  95. return materialTable
  96. }
  97. function calcBoundingVolumeForNormal(vertexPackage, modelMatrix) {
  98. let boundingSphere = new Cesium.BoundingSphere()
  99. let v1 = new Cesium.Cartesian3()
  100. let positionAttr = vertexPackage.vertexAttributes[0]
  101. let dim = positionAttr.componentsPerAttribute
  102. let isCompress =
  103. Cesium.defined(vertexPackage.compressOptions) &&
  104. (vertexPackage.compressOptions & VertexCompressOption.SVC_Vertex) ===
  105. VertexCompressOption.SVC_Vertex
  106. let normConstant = 1.0
  107. let minVertex
  108. let vertexTypedArray
  109. if (isCompress) {
  110. normConstant = vertexPackage.vertCompressConstant
  111. minVertex = new Cesium.Cartesian3(
  112. vertexPackage.minVerticesValue.x,
  113. vertexPackage.minVerticesValue.y,
  114. vertexPackage.minVerticesValue.z
  115. )
  116. vertexTypedArray = new Uint16Array(
  117. positionAttr.typedArray.buffer,
  118. positionAttr.typedArray.byteOffset,
  119. positionAttr.typedArray.byteLength / 2
  120. )
  121. } else {
  122. vertexTypedArray = new Float32Array(
  123. positionAttr.typedArray.buffer,
  124. positionAttr.typedArray.byteOffset,
  125. positionAttr.typedArray.byteLength / 4
  126. )
  127. }
  128. let vertexArray = []
  129. for (let t = 0; t < vertexPackage.verticesCount; t++) {
  130. Cesium.Cartesian3.fromArray(vertexTypedArray, dim * t, v1)
  131. if (isCompress) {
  132. v1 = Cesium.Cartesian3.multiplyByScalar(v1, normConstant, v1)
  133. v1 = Cesium.Cartesian3.add(v1, minVertex, v1)
  134. }
  135. vertexArray.push(Cesium.Cartesian3.clone(v1))
  136. }
  137. Cesium.BoundingSphere.fromPoints(vertexArray, boundingSphere)
  138. Cesium.BoundingSphere.transform(boundingSphere, modelMatrix, boundingSphere)
  139. vertexArray.length = 0
  140. return boundingSphere
  141. }
  142. let scratchCenter = new Cesium.Cartesian3()
  143. function calcBoundingVolumeForInstance(vertexPackage) {
  144. let boundingSphere = new Cesium.BoundingSphere()
  145. let boundingsValues = vertexPackage.instanceBounds
  146. if (!Cesium.defined(boundingsValues)) {
  147. return boundingSphere
  148. }
  149. let pntLU = new Cesium.Cartesian3(
  150. boundingsValues[0],
  151. boundingsValues[1],
  152. boundingsValues[2]
  153. )
  154. let pntRD = new Cesium.Carteisan3(
  155. boundingsValues[3],
  156. boundingsValues[4],
  157. boundingsValues[5]
  158. )
  159. let center = new Cesium.Cartesian3.lerp(pntLU, pntRD, 0.5, scratchCenter)
  160. let radius = new Cesium.Cartesian3.distance(center, pntLU)
  161. boundingSphere.center = center
  162. boundingSphere.radius = radius
  163. return boundingSphere
  164. }
  165. function calcBoundingVolume(vertexPackage, modelMatrix) {
  166. if (vertexPackage.instanceIndex > -1) {
  167. return calcBoundingVolumeForInstance(vertexPackage)
  168. }
  169. return calcBoundingVolumeForNormal(vertexPackage, modelMatrix)
  170. }
  171. function parseGeodes(layer, content, materialTable, pagelodNode, pagelod) {
  172. let geoMap = {}
  173. let geodeList = pagelodNode.geodes
  174. for (let i = 0, j = geodeList.length; i < j; i++) {
  175. let geodeNode = geodeList[i]
  176. let geoMatrix = geodeNode.matrix
  177. let modelMatrix = Cesium.Matrix4.multiply(
  178. layer.modelMatrix,
  179. geoMatrix,
  180. new Cesium.Matrix4()
  181. )
  182. let boundingSphere
  183. if (Cesium.defined(pagelod.boundingVolume)) {
  184. boundingSphere = new Cesium.BoundingSphere(
  185. pagelod.boundingVolume.sphere.center,
  186. pagelod.boundingVolume.sphere.radius
  187. )
  188. Cesium.BoundingSphere.transform(
  189. boundingSphere,
  190. layer.modelMatrix,
  191. boundingSphere
  192. )
  193. }
  194. let skeletonNames = geodeNode.skeletonNames
  195. for (let m = 0, n = skeletonNames.length; m < n; m++) {
  196. let geoName = skeletonNames[m]
  197. let geoPackage = content.geoPackage[geoName]
  198. let vertexPackage = geoPackage.vertexPackage
  199. let arrIndexPackage = geoPackage.arrIndexPackage
  200. let pickInfo = geoPackage.pickInfo
  201. let material
  202. if (arrIndexPackage.length > 0) {
  203. material = materialTable[arrIndexPackage[0].materialCode]
  204. }
  205. let geodeBoundingVolume = Cesium.defined(boundingSphere)
  206. ? boundingSphere
  207. : calcBoundingVolume(vertexPackage, modelMatrix)
  208. geoMap[geoName] = S3MContentFactory[layer.fileType]({
  209. layer: layer,
  210. vertexPackage: vertexPackage,
  211. arrIndexPackage: arrIndexPackage,
  212. pickInfo: pickInfo,
  213. modelMatrix: modelMatrix,
  214. geoMatrix: geoMatrix,
  215. boundingVolume: geodeBoundingVolume,
  216. material: material,
  217. edgeGeometry: geoPackage.edgeGeometry,
  218. geoName: geoName
  219. })
  220. }
  221. }
  222. if (Object.keys(geoMap).length < 1) {
  223. return
  224. }
  225. if (!Cesium.defined(pagelod.boundingVolume)) {
  226. let arr = []
  227. for (let key in geoMap) {
  228. if (geoMap.hasOwnProperty(key)) {
  229. arr.push(geoMap[key].boundingVolume)
  230. }
  231. }
  232. pagelod.boundingVolume = {
  233. sphere: Cesium.BoundingSphere.fromBoundingSpheres(arr)
  234. }
  235. }
  236. pagelod.geoMap = geoMap
  237. }
  238. function parsePagelods(layer, content, materialTable) {
  239. let groupNode = content.groupNode
  240. let pagelods = []
  241. for (let i = 0, j = groupNode.pageLods.length; i < j; i++) {
  242. let pagelod = {}
  243. let pagelodNode = groupNode.pageLods[i]
  244. pagelod.rangeMode = pagelodNode.rangeMode
  245. pagelod.rangeDataList = pagelodNode.childTile
  246. pagelod.rangeList = pagelodNode.rangeList
  247. let center = pagelodNode.boundingSphere.center
  248. let radius = pagelodNode.boundingSphere.radius
  249. if (pagelod.rangeDataList !== '') {
  250. pagelod.boundingVolume = {
  251. sphere: {
  252. center: new Cesium.Cartesian3(center.x, center.y, center.z),
  253. radius: radius
  254. }
  255. }
  256. } else {
  257. pagelod.isLeafTile = true
  258. }
  259. parseGeodes(layer, content, materialTable, pagelodNode, pagelod)
  260. if (Cesium.defined(pagelod.geoMap)) {
  261. pagelods.push(pagelod)
  262. }
  263. }
  264. return pagelods
  265. }
  266. S3MContentParser.parse = function(layer, content, tile) {
  267. if (!Cesium.defined(content)) {
  268. return
  269. }
  270. let materialTable = parseMaterial(layer.context, content, tile)
  271. let pagelods = parsePagelods(layer, content, materialTable)
  272. return pagelods
  273. }
  274. export default S3MContentParser