InvertClassification.js 12 KB

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