智慧水务管理系统 - 精河县供水工程综合管理平台

processVoxelProperties.js 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. import defined from "../Core/defined.js";
  2. import MetadataType from "./MetadataType.js";
  3. import ShaderDestination from "../Renderer/ShaderDestination.js";
  4. /**
  5. * Update the shader with defines, structs, and functions to handle
  6. * voxel properties and statistics
  7. * @function
  8. *
  9. * @param {VoxelRenderResources} renderResources
  10. * @param {VoxelPrimitive} primitive
  11. *
  12. * @private
  13. */
  14. function processVoxelProperties(renderResources, primitive) {
  15. const { shaderBuilder } = renderResources;
  16. const { names, types, componentTypes, minimumValues, maximumValues } =
  17. primitive._provider;
  18. const attributeLength = types.length;
  19. const hasStatistics = defined(minimumValues) && defined(maximumValues);
  20. shaderBuilder.addDefine(
  21. "METADATA_COUNT",
  22. attributeLength,
  23. ShaderDestination.FRAGMENT,
  24. );
  25. if (hasStatistics) {
  26. shaderBuilder.addDefine(
  27. "STATISTICS",
  28. undefined,
  29. ShaderDestination.FRAGMENT,
  30. );
  31. }
  32. // PropertyStatistics structs
  33. for (let i = 0; i < attributeLength; i++) {
  34. const name = names[i];
  35. const glslType = getGlslType(types[i]);
  36. const propertyStatisticsStructId = `PropertyStatistics_${name}`;
  37. const propertyStatisticsStructName = `PropertyStatistics_${name}`;
  38. shaderBuilder.addStruct(
  39. propertyStatisticsStructId,
  40. propertyStatisticsStructName,
  41. ShaderDestination.FRAGMENT,
  42. );
  43. shaderBuilder.addStructField(propertyStatisticsStructId, glslType, "min");
  44. shaderBuilder.addStructField(propertyStatisticsStructId, glslType, "max");
  45. }
  46. // MetadataStatistics struct
  47. const metadataStatisticsStructId = "MetadataStatistics";
  48. const metadataStatisticsStructName = "MetadataStatistics";
  49. const metadataStatisticsFieldName = "metadataStatistics";
  50. shaderBuilder.addStruct(
  51. metadataStatisticsStructId,
  52. metadataStatisticsStructName,
  53. ShaderDestination.FRAGMENT,
  54. );
  55. for (let i = 0; i < attributeLength; i++) {
  56. const name = names[i];
  57. const propertyStructName = `PropertyStatistics_${name}`;
  58. const propertyFieldName = name;
  59. shaderBuilder.addStructField(
  60. metadataStatisticsStructId,
  61. propertyStructName,
  62. propertyFieldName,
  63. );
  64. }
  65. // Metadata struct
  66. const metadataStructId = "Metadata";
  67. const metadataStructName = "Metadata";
  68. const metadataFieldName = "metadata";
  69. shaderBuilder.addStruct(
  70. metadataStructId,
  71. metadataStructName,
  72. ShaderDestination.FRAGMENT,
  73. );
  74. for (let i = 0; i < attributeLength; i++) {
  75. const glslType = getGlslType(types[i]);
  76. shaderBuilder.addStructField(metadataStructId, glslType, names[i]);
  77. }
  78. // Attributes struct
  79. const attributesStructId = "Attributes";
  80. const attributesStructName = "Attributes";
  81. const attributesFieldName = "attributes";
  82. shaderBuilder.addStruct(
  83. attributesStructId,
  84. attributesStructName,
  85. ShaderDestination.FRAGMENT,
  86. );
  87. shaderBuilder.addStructField(attributesStructId, "vec3", "positionEC");
  88. shaderBuilder.addStructField(attributesStructId, "vec3", "normalEC");
  89. // Voxel struct
  90. const voxelStructId = "Voxel";
  91. const voxelStructName = "Voxel";
  92. const voxelFieldName = "voxel";
  93. shaderBuilder.addStruct(
  94. voxelStructId,
  95. voxelStructName,
  96. ShaderDestination.FRAGMENT,
  97. );
  98. shaderBuilder.addStructField(voxelStructId, "vec3", "viewDirUv");
  99. shaderBuilder.addStructField(voxelStructId, "float", "travelDistance");
  100. shaderBuilder.addStructField(voxelStructId, "int", "stepCount");
  101. shaderBuilder.addStructField(voxelStructId, "int", "tileIndex");
  102. shaderBuilder.addStructField(voxelStructId, "int", "sampleIndex");
  103. shaderBuilder.addStructField(voxelStructId, "float", "distanceToDepthBuffer");
  104. // FragmentInput struct
  105. const fragmentInputStructId = "FragmentInput";
  106. const fragmentInputStructName = "FragmentInput";
  107. shaderBuilder.addStruct(
  108. fragmentInputStructId,
  109. fragmentInputStructName,
  110. ShaderDestination.FRAGMENT,
  111. );
  112. shaderBuilder.addStructField(
  113. fragmentInputStructId,
  114. metadataStatisticsStructName,
  115. metadataStatisticsFieldName,
  116. );
  117. shaderBuilder.addStructField(
  118. fragmentInputStructId,
  119. metadataStructName,
  120. metadataFieldName,
  121. );
  122. shaderBuilder.addStructField(
  123. fragmentInputStructId,
  124. attributesStructName,
  125. attributesFieldName,
  126. );
  127. shaderBuilder.addStructField(
  128. fragmentInputStructId,
  129. voxelStructName,
  130. voxelFieldName,
  131. );
  132. // Properties struct
  133. const propertiesStructId = "Properties";
  134. const propertiesStructName = "Properties";
  135. const propertiesFieldName = "properties";
  136. shaderBuilder.addStruct(
  137. propertiesStructId,
  138. propertiesStructName,
  139. ShaderDestination.FRAGMENT,
  140. );
  141. for (let i = 0; i < attributeLength; i++) {
  142. const glslType = getGlslType(types[i]);
  143. shaderBuilder.addStructField(propertiesStructId, glslType, names[i]);
  144. }
  145. // Fragment shader functions
  146. // clearProperties function
  147. {
  148. const functionId = "clearProperties";
  149. shaderBuilder.addFunction(
  150. functionId,
  151. `${propertiesStructName} clearProperties()`,
  152. ShaderDestination.FRAGMENT,
  153. );
  154. shaderBuilder.addFunctionLines(functionId, [
  155. `${propertiesStructName} ${propertiesFieldName};`,
  156. ]);
  157. for (let i = 0; i < attributeLength; i++) {
  158. const glslType = getGlslType(types[i], componentTypes[i]);
  159. shaderBuilder.addFunctionLines(functionId, [
  160. `${propertiesFieldName}.${names[i]} = ${glslType}(0.0);`,
  161. ]);
  162. }
  163. shaderBuilder.addFunctionLines(functionId, [
  164. `return ${propertiesFieldName};`,
  165. ]);
  166. }
  167. // sumProperties function
  168. {
  169. const functionId = "sumProperties";
  170. shaderBuilder.addFunction(
  171. functionId,
  172. `${propertiesStructName} sumProperties(${propertiesStructName} propertiesA, ${propertiesStructName} propertiesB)`,
  173. ShaderDestination.FRAGMENT,
  174. );
  175. shaderBuilder.addFunctionLines(functionId, [
  176. `${propertiesStructName} ${propertiesFieldName};`,
  177. ]);
  178. for (let i = 0; i < attributeLength; i++) {
  179. const name = names[i];
  180. shaderBuilder.addFunctionLines(functionId, [
  181. `${propertiesFieldName}.${name} = propertiesA.${name} + propertiesB.${name};`,
  182. ]);
  183. }
  184. shaderBuilder.addFunctionLines(functionId, [
  185. `return ${propertiesFieldName};`,
  186. ]);
  187. }
  188. // scaleProperties function
  189. {
  190. const functionId = "scaleProperties";
  191. shaderBuilder.addFunction(
  192. functionId,
  193. `${propertiesStructName} scaleProperties(${propertiesStructName} ${propertiesFieldName}, float scale)`,
  194. ShaderDestination.FRAGMENT,
  195. );
  196. shaderBuilder.addFunctionLines(functionId, [
  197. `${propertiesStructName} scaledProperties = ${propertiesFieldName};`,
  198. ]);
  199. for (let i = 0; i < attributeLength; i++) {
  200. shaderBuilder.addFunctionLines(functionId, [
  201. `scaledProperties.${names[i]} *= scale;`,
  202. ]);
  203. }
  204. shaderBuilder.addFunctionLines(functionId, [`return scaledProperties;`]);
  205. }
  206. // mixProperties
  207. {
  208. const functionId = "mixProperties";
  209. shaderBuilder.addFunction(
  210. functionId,
  211. `${propertiesStructName} mixProperties(${propertiesStructName} propertiesA, ${propertiesStructName} propertiesB, float mixFactor)`,
  212. ShaderDestination.FRAGMENT,
  213. );
  214. shaderBuilder.addFunctionLines(functionId, [
  215. `${propertiesStructName} ${propertiesFieldName};`,
  216. ]);
  217. for (let i = 0; i < attributeLength; i++) {
  218. const name = names[i];
  219. shaderBuilder.addFunctionLines(functionId, [
  220. `${propertiesFieldName}.${name} = mix(propertiesA.${name}, propertiesB.${name}, mixFactor);`,
  221. ]);
  222. }
  223. shaderBuilder.addFunctionLines(functionId, [
  224. `return ${propertiesFieldName};`,
  225. ]);
  226. }
  227. // copyPropertiesToMetadata
  228. {
  229. const functionId = "copyPropertiesToMetadata";
  230. shaderBuilder.addFunction(
  231. functionId,
  232. `void copyPropertiesToMetadata(in ${propertiesStructName} ${propertiesFieldName}, inout ${metadataStructName} ${metadataFieldName})`,
  233. ShaderDestination.FRAGMENT,
  234. );
  235. for (let i = 0; i < attributeLength; i++) {
  236. const name = names[i];
  237. shaderBuilder.addFunctionLines(functionId, [
  238. `${metadataFieldName}.${name} = ${propertiesFieldName}.${name};`,
  239. ]);
  240. }
  241. }
  242. // setStatistics function
  243. if (hasStatistics) {
  244. const functionId = "setStatistics";
  245. shaderBuilder.addFunction(
  246. functionId,
  247. `void setStatistics(inout ${metadataStatisticsStructName} ${metadataStatisticsFieldName})`,
  248. ShaderDestination.FRAGMENT,
  249. );
  250. for (let i = 0; i < attributeLength; i++) {
  251. const name = names[i];
  252. const type = types[i];
  253. const componentCount = MetadataType.getComponentCount(type);
  254. for (let j = 0; j < componentCount; j++) {
  255. const glslField = getGlslField(type, j);
  256. const minimumValue = minimumValues[i][j];
  257. const maximumValue = maximumValues[i][j];
  258. if (!defined(minimumValue) || !defined(maximumValue)) {
  259. continue;
  260. }
  261. shaderBuilder.addFunctionLines(functionId, [
  262. `${metadataStatisticsFieldName}.${name}.min${glslField} = ${getGlslNumberAsFloat(
  263. minimumValue,
  264. )};`,
  265. `${metadataStatisticsFieldName}.${name}.max${glslField} = ${getGlslNumberAsFloat(
  266. maximumValue,
  267. )};`,
  268. ]);
  269. }
  270. }
  271. }
  272. // getPropertiesFromMegatextureAtUv
  273. {
  274. const functionId = "getPropertiesFromMegatextureAtUv";
  275. shaderBuilder.addFunction(
  276. functionId,
  277. `${propertiesStructName} getPropertiesFromMegatextureAtUv(vec3 texcoord)`,
  278. ShaderDestination.FRAGMENT,
  279. );
  280. shaderBuilder.addFunctionLines(functionId, [
  281. `${propertiesStructName} ${propertiesFieldName};`,
  282. ]);
  283. for (let i = 0; i < attributeLength; i++) {
  284. const type = types[i];
  285. const componentType = componentTypes[i];
  286. const glslTextureSwizzle = getGlslTextureSwizzle(type, componentType);
  287. shaderBuilder.addFunctionLines(functionId, [
  288. `properties.${names[i]} = texture(u_megatextureTextures[${i}], texcoord)${glslTextureSwizzle};`,
  289. ]);
  290. }
  291. shaderBuilder.addFunctionLines(functionId, [
  292. `return ${propertiesFieldName};`,
  293. ]);
  294. }
  295. }
  296. /**
  297. * Converts a {@link MetadataType} to a GLSL type.
  298. *
  299. * @function
  300. *
  301. * @param {MetadataType} type The {@link MetadataType}.
  302. * @returns {string} The GLSL type.
  303. *
  304. * @private
  305. */
  306. function getGlslType(type) {
  307. if (type === MetadataType.SCALAR) {
  308. return "float";
  309. } else if (type === MetadataType.VEC2) {
  310. return "vec2";
  311. } else if (type === MetadataType.VEC3) {
  312. return "vec3";
  313. } else if (type === MetadataType.VEC4) {
  314. return "vec4";
  315. }
  316. }
  317. /**
  318. * Gets the GLSL swizzle when reading data from a texture.
  319. *
  320. * @function
  321. *
  322. * @param {MetadataType} type The {@link MetadataType}.
  323. * @returns {string} The GLSL swizzle.
  324. *
  325. * @private
  326. */
  327. function getGlslTextureSwizzle(type) {
  328. if (type === MetadataType.SCALAR) {
  329. return ".r";
  330. } else if (type === MetadataType.VEC2) {
  331. return ".ra";
  332. } else if (type === MetadataType.VEC3) {
  333. return ".rgb";
  334. } else if (type === MetadataType.VEC4) {
  335. return "";
  336. }
  337. }
  338. /**
  339. * GLSL needs to have `.0` at the end of whole number floats or else it's
  340. * treated like an integer.
  341. *
  342. * @function
  343. *
  344. * @param {number} number The number to convert.
  345. * @returns {string} The number as floating point in GLSL.
  346. *
  347. * @private
  348. */
  349. function getGlslNumberAsFloat(number) {
  350. let numberString = number.toString();
  351. if (numberString.indexOf(".") === -1) {
  352. numberString = `${number}.0`;
  353. }
  354. return numberString;
  355. }
  356. /**
  357. * Gets the GLSL field
  358. *
  359. * @function
  360. *
  361. * @param {MetadataType} type
  362. * @param {number} index
  363. * @returns {string}
  364. *
  365. * @private
  366. */
  367. function getGlslField(type, index) {
  368. if (type === MetadataType.SCALAR) {
  369. return "";
  370. }
  371. return `[${index}]`;
  372. }
  373. export default processVoxelProperties;