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