InvertClassification.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. import Color from '../Core/Color.js';
  2. import defined from '../Core/defined.js';
  3. import defineProperties from '../Core/defineProperties.js';
  4. import destroyObject from '../Core/destroyObject.js';
  5. import PixelFormat from '../Core/PixelFormat.js';
  6. import ClearCommand from '../Renderer/ClearCommand.js';
  7. import Framebuffer from '../Renderer/Framebuffer.js';
  8. import PixelDatatype from '../Renderer/PixelDatatype.js';
  9. import RenderState from '../Renderer/RenderState.js';
  10. import Sampler from '../Renderer/Sampler.js';
  11. import ShaderSource from '../Renderer/ShaderSource.js';
  12. import Texture from '../Renderer/Texture.js';
  13. import TextureMagnificationFilter from '../Renderer/TextureMagnificationFilter.js';
  14. import TextureMinificationFilter from '../Renderer/TextureMinificationFilter.js';
  15. import TextureWrap from '../Renderer/TextureWrap.js';
  16. import PassThrough from '../Shaders/PostProcessStages/PassThrough.js';
  17. import BlendingState from './BlendingState.js';
  18. import StencilConstants from './StencilConstants.js';
  19. import StencilFunction from './StencilFunction.js';
  20. import StencilOperation from './StencilOperation.js';
  21. /**
  22. * @private
  23. */
  24. function InvertClassification() {
  25. this.previousFramebuffer = undefined;
  26. this._previousFramebuffer = undefined;
  27. this._texture = undefined;
  28. this._classifiedTexture = undefined;
  29. this._depthStencilTexture = undefined;
  30. this._fbo = undefined;
  31. this._fboClassified = undefined;
  32. this._rsUnclassified = undefined;
  33. this._rsClassified = undefined;
  34. this._unclassifiedCommand = undefined;
  35. this._classifiedCommand = undefined;
  36. this._translucentCommand = undefined;
  37. this._clearColorCommand = new ClearCommand({
  38. color : new Color(0.0, 0.0, 0.0, 0.0),
  39. owner : this
  40. });
  41. this._clearCommand = new ClearCommand({
  42. color : new Color(0.0, 0.0, 0.0, 0.0),
  43. depth : 1.0,
  44. stencil : 0
  45. });
  46. var that = this;
  47. this._uniformMap = {
  48. colorTexture : function() {
  49. return that._texture;
  50. },
  51. depthTexture : function() {
  52. return that._depthStencilTexture;
  53. },
  54. classifiedTexture : function() {
  55. return that._classifiedTexture;
  56. }
  57. };
  58. }
  59. defineProperties(InvertClassification.prototype, {
  60. unclassifiedCommand : {
  61. get : function() {
  62. return this._unclassifiedCommand;
  63. }
  64. }
  65. });
  66. InvertClassification.isTranslucencySupported = function(context) {
  67. return context.depthTexture && context.fragmentDepth;
  68. };
  69. var rsUnclassified = {
  70. depthMask : false,
  71. stencilTest : {
  72. enabled : true,
  73. frontFunction : StencilFunction.EQUAL,
  74. frontOperation : {
  75. fail : StencilOperation.KEEP,
  76. zFail : StencilOperation.KEEP,
  77. zPass : StencilOperation.KEEP
  78. },
  79. backFunction : StencilFunction.NEVER,
  80. reference : 0,
  81. mask : StencilConstants.CLASSIFICATION_MASK
  82. },
  83. blending : BlendingState.ALPHA_BLEND
  84. };
  85. var rsClassified = {
  86. depthMask : false,
  87. stencilTest : {
  88. enabled : true,
  89. frontFunction : StencilFunction.NOT_EQUAL,
  90. frontOperation : {
  91. fail : StencilOperation.KEEP,
  92. zFail : StencilOperation.KEEP,
  93. zPass : StencilOperation.KEEP
  94. },
  95. backFunction : StencilFunction.NEVER,
  96. reference : 0,
  97. mask : StencilConstants.CLASSIFICATION_MASK
  98. },
  99. blending : BlendingState.ALPHA_BLEND
  100. };
  101. // Set the 3D Tiles bit when rendering back into the scene's framebuffer. This is only needed if
  102. // invert classification does not use the scene's depth-stencil texture, which is the case if the invert
  103. // classification color is translucent.
  104. var rsDefault = {
  105. depthMask : true,
  106. depthTest : {
  107. enabled : true
  108. },
  109. stencilTest : StencilConstants.setCesium3DTileBit(),
  110. stencilMask : StencilConstants.CESIUM_3D_TILE_MASK,
  111. blending : BlendingState.ALPHA_BLEND
  112. };
  113. var translucentFS =
  114. '#extension GL_EXT_frag_depth : enable\n'+
  115. 'uniform sampler2D colorTexture;\n' +
  116. 'uniform sampler2D depthTexture;\n' +
  117. 'uniform sampler2D classifiedTexture;\n' +
  118. 'varying vec2 v_textureCoordinates;\n' +
  119. 'void main()\n' +
  120. '{\n' +
  121. ' vec4 color = texture2D(colorTexture, v_textureCoordinates);\n' +
  122. ' if (color.a == 0.0)\n' +
  123. ' {\n' +
  124. ' discard;\n' +
  125. ' }\n' +
  126. ' bool isClassified = all(equal(texture2D(classifiedTexture, v_textureCoordinates), vec4(0.0)));\n' +
  127. '#ifdef UNCLASSIFIED\n' +
  128. ' vec4 highlightColor = czm_invertClassificationColor;\n' +
  129. ' if (isClassified)\n' +
  130. ' {\n' +
  131. ' discard;\n' +
  132. ' }\n' +
  133. '#else\n' +
  134. ' vec4 highlightColor = vec4(1.0);\n' +
  135. ' if (!isClassified)\n' +
  136. ' {\n' +
  137. ' discard;\n' +
  138. ' }\n' +
  139. '#endif\n' +
  140. ' gl_FragColor = color * highlightColor;\n' +
  141. ' gl_FragDepthEXT = texture2D(depthTexture, v_textureCoordinates).r;\n' +
  142. '}\n';
  143. var opaqueFS =
  144. 'uniform sampler2D colorTexture;\n' +
  145. 'varying vec2 v_textureCoordinates;\n' +
  146. 'void main()\n' +
  147. '{\n' +
  148. ' vec4 color = texture2D(colorTexture, v_textureCoordinates);\n' +
  149. ' if (color.a == 0.0)\n' +
  150. ' {\n' +
  151. ' discard;\n' +
  152. ' }\n' +
  153. '#ifdef UNCLASSIFIED\n' +
  154. ' gl_FragColor = color * czm_invertClassificationColor;\n' +
  155. '#else\n' +
  156. ' gl_FragColor = color;\n' +
  157. '#endif\n' +
  158. '}\n';
  159. InvertClassification.prototype.update = function(context) {
  160. var texture = this._texture;
  161. var previousFramebufferChanged = !defined(texture) || this.previousFramebuffer !== this._previousFramebuffer;
  162. this._previousFramebuffer = this.previousFramebuffer;
  163. var width = context.drawingBufferWidth;
  164. var height = context.drawingBufferHeight;
  165. var textureChanged = !defined(texture) || texture.width !== width || texture.height !== height;
  166. if (textureChanged || previousFramebufferChanged) {
  167. this._texture = this._texture && this._texture.destroy();
  168. this._classifiedTexture = this._classifiedTexture && this._classifiedTexture.destroy();
  169. this._depthStencilTexture = this._depthStencilTexture && this._depthStencilTexture.destroy();
  170. this._texture = new Texture({
  171. context : context,
  172. width : width,
  173. height : height,
  174. pixelFormat : PixelFormat.RGBA,
  175. pixelDatatype : PixelDatatype.UNSIGNED_BYTE,
  176. sampler : new Sampler({
  177. wrapS : TextureWrap.CLAMP_TO_EDGE,
  178. wrapT : TextureWrap.CLAMP_TO_EDGE,
  179. minificationFilter : TextureMinificationFilter.LINEAR,
  180. magnificationFilter : TextureMagnificationFilter.LINEAR
  181. })
  182. });
  183. if (!defined(this._previousFramebuffer)) {
  184. this._classifiedTexture = new Texture({
  185. context : context,
  186. width : width,
  187. height : height,
  188. pixelFormat : PixelFormat.RGBA,
  189. pixelDatatype : PixelDatatype.UNSIGNED_BYTE,
  190. sampler : new Sampler({
  191. wrapS : TextureWrap.CLAMP_TO_EDGE,
  192. wrapT : TextureWrap.CLAMP_TO_EDGE,
  193. minificationFilter : TextureMinificationFilter.LINEAR,
  194. magnificationFilter : TextureMagnificationFilter.LINEAR
  195. })
  196. });
  197. this._depthStencilTexture = new Texture({
  198. context : context,
  199. width : width,
  200. height : height,
  201. pixelFormat : PixelFormat.DEPTH_STENCIL,
  202. pixelDatatype : PixelDatatype.UNSIGNED_INT_24_8
  203. });
  204. }
  205. }
  206. if (!defined(this._fbo) || textureChanged || previousFramebufferChanged) {
  207. this._fbo = this._fbo && this._fbo.destroy();
  208. this._fboClassified = this._fboClassified && this._fboClassified.destroy();
  209. var depthStencilTexture;
  210. var depthStencilRenderbuffer;
  211. if (defined(this._previousFramebuffer)) {
  212. depthStencilTexture = this._previousFramebuffer.depthStencilTexture;
  213. depthStencilRenderbuffer = this._previousFramebuffer.depthStencilRenderbuffer;
  214. } else {
  215. depthStencilTexture = this._depthStencilTexture;
  216. }
  217. this._fbo = new Framebuffer({
  218. context : context,
  219. colorTextures : [this._texture],
  220. depthStencilTexture : depthStencilTexture,
  221. depthStencilRenderbuffer : depthStencilRenderbuffer,
  222. destroyAttachments : false
  223. });
  224. if (!defined(this._previousFramebuffer)) {
  225. this._fboClassified = new Framebuffer({
  226. context : context,
  227. colorTextures : [this._classifiedTexture],
  228. depthStencilTexture : depthStencilTexture,
  229. destroyAttachments : false
  230. });
  231. }
  232. }
  233. if (!defined(this._rsUnclassified)) {
  234. this._rsUnclassified = RenderState.fromCache(rsUnclassified);
  235. this._rsClassified = RenderState.fromCache(rsClassified);
  236. this._rsDefault = RenderState.fromCache(rsDefault);
  237. }
  238. if (!defined(this._unclassifiedCommand) || previousFramebufferChanged) {
  239. if (defined(this._unclassifiedCommand)) {
  240. this._unclassifiedCommand.shaderProgram = this._unclassifiedCommand.shaderProgram && this._unclassifiedCommand.shaderProgram.destroy();
  241. this._classifiedCommand.shaderProgram = this._classifiedCommand.shaderProgram && this._classifiedCommand.shaderProgram.destroy();
  242. }
  243. var fs = defined(this._previousFramebuffer) ? opaqueFS : translucentFS;
  244. var unclassifiedFSSource = new ShaderSource({
  245. defines : ['UNCLASSIFIED'],
  246. sources : [fs]
  247. });
  248. var classifiedFSSource = new ShaderSource({
  249. sources : [fs]
  250. });
  251. this._unclassifiedCommand = context.createViewportQuadCommand(unclassifiedFSSource, {
  252. renderState : defined(this._previousFramebuffer) ? this._rsUnclassified : this._rsDefault,
  253. uniformMap : this._uniformMap,
  254. owner : this
  255. });
  256. this._classifiedCommand = context.createViewportQuadCommand(classifiedFSSource, {
  257. renderState : defined(this._previousFramebuffer) ? this._rsClassified : this._rsDefault,
  258. uniformMap : this._uniformMap,
  259. owner : this
  260. });
  261. if (defined(this._translucentCommand)) {
  262. this._translucentCommand.shaderProgram = this._translucentCommand.shaderProgram && this._translucentCommand.shaderProgram.destroy();
  263. }
  264. if (!defined(this._previousFramebuffer)) {
  265. this._translucentCommand = context.createViewportQuadCommand(PassThrough, {
  266. renderState : this._rsUnclassified,
  267. uniformMap : this._uniformMap,
  268. owner : this
  269. });
  270. }
  271. }
  272. };
  273. InvertClassification.prototype.clear = function(context, passState) {
  274. var framebuffer = passState.framebuffer;
  275. if (defined(this._previousFramebuffer)) {
  276. passState.framebuffer = this._fbo;
  277. this._clearColorCommand.execute(context, passState);
  278. } else {
  279. passState.framebuffer = this._fbo;
  280. this._clearCommand.execute(context, passState);
  281. passState.framebuffer = this._fboClassified;
  282. this._clearCommand.execute(context, passState);
  283. }
  284. passState.framebuffer = framebuffer;
  285. };
  286. InvertClassification.prototype.executeClassified = function(context, passState) {
  287. if (!defined(this._previousFramebuffer)) {
  288. var framebuffer = passState.framebuffer;
  289. passState.framebuffer = this._fboClassified;
  290. this._translucentCommand.execute(context, passState);
  291. passState.framebuffer = framebuffer;
  292. }
  293. this._classifiedCommand.execute(context, passState);
  294. };
  295. InvertClassification.prototype.executeUnclassified = function(context, passState) {
  296. this._unclassifiedCommand.execute(context, passState);
  297. };
  298. InvertClassification.prototype.isDestroyed = function() {
  299. return false;
  300. };
  301. InvertClassification.prototype.destroy = function() {
  302. this._fbo = this._fbo && this._fbo.destroy();
  303. this._texture = this._texture && this._texture.destroy();
  304. this._depthStencilTexture = this._depthStencilTexture && this._depthStencilTexture.destroy();
  305. if (defined(this._unclassifiedCommand)) {
  306. this._unclassifiedCommand.shaderProgram = this._unclassifiedCommand.shaderProgram && this._unclassifiedCommand.shaderProgram.destroy();
  307. this._classifiedCommand.shaderProgram = this._classifiedCommand.shaderProgram && this._classifiedCommand.shaderProgram.destroy();
  308. }
  309. return destroyObject(this);
  310. };
  311. export default InvertClassification;