PickDepth.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. import Cartesian4 from "../Core/Cartesian4.js";
  2. import defined from "../Core/defined.js";
  3. import destroyObject from "../Core/destroyObject.js";
  4. import PixelFormat from "../Core/PixelFormat.js";
  5. import Framebuffer from "../Renderer/Framebuffer.js";
  6. import PixelDatatype from "../Renderer/PixelDatatype.js";
  7. import RenderState from "../Renderer/RenderState.js";
  8. import ShaderSource from "../Renderer/ShaderSource.js";
  9. import Texture from "../Renderer/Texture.js";
  10. /**
  11. * @private
  12. */
  13. function PickDepth() {
  14. this._framebuffer = undefined;
  15. this._depthTexture = undefined;
  16. this._textureToCopy = undefined;
  17. this._copyDepthCommand = undefined;
  18. this._useLogDepth = undefined;
  19. this._debugPickDepthViewportCommand = undefined;
  20. }
  21. function executeDebugPickDepth(pickDepth, context, passState, useLogDepth) {
  22. if (
  23. !defined(pickDepth._debugPickDepthViewportCommand) ||
  24. useLogDepth !== pickDepth._useLogDepth
  25. ) {
  26. var fsSource =
  27. "uniform sampler2D u_texture;\n" +
  28. "varying vec2 v_textureCoordinates;\n" +
  29. "void main()\n" +
  30. "{\n" +
  31. " float z_window = czm_unpackDepth(texture2D(u_texture, v_textureCoordinates));\n" +
  32. " z_window = czm_reverseLogDepth(z_window); \n" +
  33. " float n_range = czm_depthRange.near;\n" +
  34. " float f_range = czm_depthRange.far;\n" +
  35. " float z_ndc = (2.0 * z_window - n_range - f_range) / (f_range - n_range);\n" +
  36. " float scale = pow(z_ndc * 0.5 + 0.5, 8.0);\n" +
  37. " gl_FragColor = vec4(mix(vec3(0.0), vec3(1.0), scale), 1.0);\n" +
  38. "}\n";
  39. var fs = new ShaderSource({
  40. defines: [useLogDepth ? "LOG_DEPTH" : ""],
  41. sources: [fsSource],
  42. });
  43. pickDepth._debugPickDepthViewportCommand = context.createViewportQuadCommand(
  44. fs,
  45. {
  46. uniformMap: {
  47. u_texture: function () {
  48. return pickDepth._depthTexture;
  49. },
  50. },
  51. owner: pickDepth,
  52. }
  53. );
  54. pickDepth._useLogDepth = useLogDepth;
  55. }
  56. pickDepth._debugPickDepthViewportCommand.execute(context, passState);
  57. }
  58. function destroyTextures(pickDepth) {
  59. pickDepth._depthTexture =
  60. pickDepth._depthTexture &&
  61. !pickDepth._depthTexture.isDestroyed() &&
  62. pickDepth._depthTexture.destroy();
  63. }
  64. function destroyFramebuffers(pickDepth) {
  65. pickDepth._framebuffer =
  66. pickDepth._framebuffer &&
  67. !pickDepth._framebuffer.isDestroyed() &&
  68. pickDepth._framebuffer.destroy();
  69. }
  70. function createTextures(pickDepth, context, width, height) {
  71. pickDepth._depthTexture = new Texture({
  72. context: context,
  73. width: width,
  74. height: height,
  75. pixelFormat: PixelFormat.RGBA,
  76. pixelDatatype: PixelDatatype.UNSIGNED_BYTE,
  77. });
  78. }
  79. function createFramebuffers(pickDepth, context, width, height) {
  80. destroyTextures(pickDepth);
  81. destroyFramebuffers(pickDepth);
  82. createTextures(pickDepth, context, width, height);
  83. pickDepth._framebuffer = new Framebuffer({
  84. context: context,
  85. colorTextures: [pickDepth._depthTexture],
  86. destroyAttachments: false,
  87. });
  88. }
  89. function updateFramebuffers(pickDepth, context, depthTexture) {
  90. var width = depthTexture.width;
  91. var height = depthTexture.height;
  92. var texture = pickDepth._depthTexture;
  93. var textureChanged =
  94. !defined(texture) || texture.width !== width || texture.height !== height;
  95. if (!defined(pickDepth._framebuffer) || textureChanged) {
  96. createFramebuffers(pickDepth, context, width, height);
  97. }
  98. }
  99. function updateCopyCommands(pickDepth, context, depthTexture) {
  100. if (!defined(pickDepth._copyDepthCommand)) {
  101. var fs =
  102. "uniform sampler2D u_texture;\n" +
  103. "varying vec2 v_textureCoordinates;\n" +
  104. "void main()\n" +
  105. "{\n" +
  106. " gl_FragColor = czm_packDepth(texture2D(u_texture, v_textureCoordinates).r);\n" +
  107. "}\n";
  108. pickDepth._copyDepthCommand = context.createViewportQuadCommand(fs, {
  109. renderState: RenderState.fromCache(),
  110. uniformMap: {
  111. u_texture: function () {
  112. return pickDepth._textureToCopy;
  113. },
  114. },
  115. owner: pickDepth,
  116. });
  117. }
  118. pickDepth._textureToCopy = depthTexture;
  119. pickDepth._copyDepthCommand.framebuffer = pickDepth._framebuffer;
  120. }
  121. PickDepth.prototype.executeDebugPickDepth = function (
  122. context,
  123. passState,
  124. useLogDepth
  125. ) {
  126. executeDebugPickDepth(this, context, passState, useLogDepth);
  127. };
  128. PickDepth.prototype.update = function (context, depthTexture) {
  129. updateFramebuffers(this, context, depthTexture);
  130. updateCopyCommands(this, context, depthTexture);
  131. };
  132. var scratchPackedDepth = new Cartesian4();
  133. var packedDepthScale = new Cartesian4(
  134. 1.0,
  135. 1.0 / 255.0,
  136. 1.0 / 65025.0,
  137. 1.0 / 16581375.0
  138. );
  139. PickDepth.prototype.getDepth = function (context, x, y) {
  140. // If this function is called before the framebuffer is created, the depth is undefined.
  141. if (!defined(this._framebuffer)) {
  142. return undefined;
  143. }
  144. var pixels = context.readPixels({
  145. x: x,
  146. y: y,
  147. width: 1,
  148. height: 1,
  149. framebuffer: this._framebuffer,
  150. });
  151. var packedDepth = Cartesian4.unpack(pixels, 0, scratchPackedDepth);
  152. Cartesian4.divideByScalar(packedDepth, 255.0, packedDepth);
  153. return Cartesian4.dot(packedDepth, packedDepthScale);
  154. };
  155. PickDepth.prototype.executeCopyDepth = function (context, passState) {
  156. this._copyDepthCommand.execute(context, passState);
  157. };
  158. PickDepth.prototype.isDestroyed = function () {
  159. return false;
  160. };
  161. PickDepth.prototype.destroy = function () {
  162. destroyTextures(this);
  163. destroyFramebuffers(this);
  164. if (defined(this._copyDepthCommand)) {
  165. this._copyDepthCommand.shaderProgram =
  166. defined(this._copyDepthCommand.shaderProgram) &&
  167. this._copyDepthCommand.shaderProgram.destroy();
  168. }
  169. return destroyObject(this);
  170. };
  171. export default PickDepth;