InvertClassification.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  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. "uniform sampler2D colorTexture;\n" +
  118. "uniform sampler2D depthTexture;\n" +
  119. "uniform sampler2D classifiedTexture;\n" +
  120. "in vec2 v_textureCoordinates;\n" +
  121. "void main()\n" +
  122. "{\n" +
  123. " vec4 color = texture(colorTexture, v_textureCoordinates);\n" +
  124. " if (color.a == 0.0)\n" +
  125. " {\n" +
  126. " discard;\n" +
  127. " }\n" +
  128. " bool isClassified = all(equal(texture(classifiedTexture, v_textureCoordinates), vec4(0.0)));\n" +
  129. "#ifdef UNCLASSIFIED\n" +
  130. " vec4 highlightColor = czm_invertClassificationColor;\n" +
  131. " if (isClassified)\n" +
  132. " {\n" +
  133. " discard;\n" +
  134. " }\n" +
  135. "#else\n" +
  136. " vec4 highlightColor = vec4(1.0);\n" +
  137. " if (!isClassified)\n" +
  138. " {\n" +
  139. " discard;\n" +
  140. " }\n" +
  141. "#endif\n" +
  142. " out_FragColor = color * highlightColor;\n" +
  143. " gl_FragDepth = texture(depthTexture, v_textureCoordinates).r;\n" +
  144. "}\n";
  145. const opaqueFS =
  146. "uniform sampler2D colorTexture;\n" +
  147. "in vec2 v_textureCoordinates;\n" +
  148. "void main()\n" +
  149. "{\n" +
  150. " vec4 color = texture(colorTexture, v_textureCoordinates);\n" +
  151. " if (color.a == 0.0)\n" +
  152. " {\n" +
  153. " discard;\n" +
  154. " }\n" +
  155. "#ifdef UNCLASSIFIED\n" +
  156. " out_FragColor = color * czm_invertClassificationColor;\n" +
  157. "#else\n" +
  158. " out_FragColor = color;\n" +
  159. "#endif\n" +
  160. "}\n";
  161. InvertClassification.prototype.update = function (
  162. context,
  163. numSamples,
  164. globeFramebuffer
  165. ) {
  166. const texture = this._fbo.getColorTexture();
  167. const previousFramebufferChanged =
  168. this.previousFramebuffer !== this._previousFramebuffer;
  169. this._previousFramebuffer = this.previousFramebuffer;
  170. const samplesChanged = this._numSamples !== numSamples;
  171. const width = context.drawingBufferWidth;
  172. const height = context.drawingBufferHeight;
  173. const textureChanged =
  174. !defined(texture) || texture.width !== width || texture.height !== height;
  175. if (textureChanged || previousFramebufferChanged || samplesChanged) {
  176. this._numSamples = numSamples;
  177. this._depthStencilTexture =
  178. this._depthStencilTexture && this._depthStencilTexture.destroy();
  179. this._depthStencilRenderbuffer =
  180. this._depthStencilRenderbuffer &&
  181. this._depthStencilRenderbuffer.destroy();
  182. if (!defined(this._previousFramebuffer)) {
  183. this._depthStencilTexture = new Texture({
  184. context: context,
  185. width: width,
  186. height: height,
  187. pixelFormat: PixelFormat.DEPTH_STENCIL,
  188. pixelDatatype: PixelDatatype.UNSIGNED_INT_24_8,
  189. });
  190. if (numSamples > 1) {
  191. this._depthStencilRenderbuffer = new Renderbuffer({
  192. context: context,
  193. width: width,
  194. height: height,
  195. format: RenderbufferFormat.DEPTH24_STENCIL8,
  196. numSamples: numSamples,
  197. });
  198. }
  199. }
  200. }
  201. if (
  202. !defined(this._fbo.framebuffer) ||
  203. textureChanged ||
  204. previousFramebufferChanged ||
  205. samplesChanged
  206. ) {
  207. this._fbo.destroy();
  208. this._fboClassified.destroy();
  209. let depthStencilTexture;
  210. let depthStencilRenderbuffer;
  211. if (defined(this._previousFramebuffer)) {
  212. depthStencilTexture = globeFramebuffer.getDepthStencilTexture();
  213. depthStencilRenderbuffer = globeFramebuffer.getDepthStencilRenderbuffer();
  214. } else {
  215. depthStencilTexture = this._depthStencilTexture;
  216. depthStencilRenderbuffer = this._depthStencilRenderbuffer;
  217. }
  218. this._fbo.setDepthStencilTexture(depthStencilTexture);
  219. if (defined(depthStencilRenderbuffer)) {
  220. this._fbo.setDepthStencilRenderbuffer(depthStencilRenderbuffer);
  221. }
  222. this._fbo.update(context, width, height, numSamples);
  223. if (!defined(this._previousFramebuffer)) {
  224. this._fboClassified.setDepthStencilTexture(depthStencilTexture);
  225. this._fboClassified.update(context, width, height);
  226. }
  227. }
  228. if (!defined(this._rsUnclassified)) {
  229. this._rsUnclassified = RenderState.fromCache(rsUnclassified);
  230. this._rsClassified = RenderState.fromCache(rsClassified);
  231. this._rsDefault = RenderState.fromCache(rsDefault);
  232. }
  233. if (
  234. !defined(this._unclassifiedCommand) ||
  235. previousFramebufferChanged ||
  236. samplesChanged
  237. ) {
  238. if (defined(this._unclassifiedCommand)) {
  239. this._unclassifiedCommand.shaderProgram =
  240. this._unclassifiedCommand.shaderProgram &&
  241. this._unclassifiedCommand.shaderProgram.destroy();
  242. this._classifiedCommand.shaderProgram =
  243. this._classifiedCommand.shaderProgram &&
  244. this._classifiedCommand.shaderProgram.destroy();
  245. }
  246. const fs = defined(this._previousFramebuffer) ? opaqueFS : translucentFS;
  247. const unclassifiedFSSource = new ShaderSource({
  248. defines: ["UNCLASSIFIED"],
  249. sources: [fs],
  250. });
  251. const classifiedFSSource = new ShaderSource({
  252. sources: [fs],
  253. });
  254. this._unclassifiedCommand = context.createViewportQuadCommand(
  255. unclassifiedFSSource,
  256. {
  257. renderState: defined(this._previousFramebuffer)
  258. ? this._rsUnclassified
  259. : this._rsDefault,
  260. uniformMap: this._uniformMap,
  261. owner: this,
  262. }
  263. );
  264. this._classifiedCommand = context.createViewportQuadCommand(
  265. classifiedFSSource,
  266. {
  267. renderState: defined(this._previousFramebuffer)
  268. ? this._rsClassified
  269. : this._rsDefault,
  270. uniformMap: this._uniformMap,
  271. owner: this,
  272. }
  273. );
  274. if (defined(this._translucentCommand)) {
  275. this._translucentCommand.shaderProgram =
  276. this._translucentCommand.shaderProgram &&
  277. this._translucentCommand.shaderProgram.destroy();
  278. }
  279. if (!defined(this._previousFramebuffer)) {
  280. this._translucentCommand = context.createViewportQuadCommand(
  281. PassThrough,
  282. {
  283. renderState: this._rsUnclassified,
  284. uniformMap: this._uniformMap,
  285. owner: this,
  286. }
  287. );
  288. }
  289. }
  290. };
  291. InvertClassification.prototype.prepareTextures = function (
  292. context,
  293. blitStencil
  294. ) {
  295. if (this._fbo._numSamples > 1) {
  296. this._fbo.prepareTextures(context, blitStencil);
  297. }
  298. };
  299. InvertClassification.prototype.clear = function (context, passState) {
  300. if (defined(this._previousFramebuffer)) {
  301. this._fbo.clear(context, this._clearColorCommand, passState);
  302. } else {
  303. this._fbo.clear(context, this._clearCommand, passState);
  304. this._fboClassified.clear(context, this._clearCommand, passState);
  305. }
  306. };
  307. InvertClassification.prototype.executeClassified = function (
  308. context,
  309. passState
  310. ) {
  311. if (!defined(this._previousFramebuffer)) {
  312. const framebuffer = passState.framebuffer;
  313. this.prepareTextures(context, true);
  314. passState.framebuffer = this._fboClassified.framebuffer;
  315. this._translucentCommand.execute(context, passState);
  316. passState.framebuffer = framebuffer;
  317. }
  318. this._classifiedCommand.execute(context, passState);
  319. };
  320. InvertClassification.prototype.executeUnclassified = function (
  321. context,
  322. passState
  323. ) {
  324. this._unclassifiedCommand.execute(context, passState);
  325. };
  326. InvertClassification.prototype.isDestroyed = function () {
  327. return false;
  328. };
  329. InvertClassification.prototype.destroy = function () {
  330. this._fbo.destroy();
  331. this._fboClassified.destroy();
  332. this._depthStencilTexture =
  333. this._depthStencilTexture && this._depthStencilTexture.destroy();
  334. this._depthStencilRenderbuffer =
  335. this._depthStencilRenderbuffer && this._depthStencilRenderbuffer.destroy();
  336. if (defined(this._unclassifiedCommand)) {
  337. this._unclassifiedCommand.shaderProgram =
  338. this._unclassifiedCommand.shaderProgram &&
  339. this._unclassifiedCommand.shaderProgram.destroy();
  340. this._classifiedCommand.shaderProgram =
  341. this._classifiedCommand.shaderProgram &&
  342. this._classifiedCommand.shaderProgram.destroy();
  343. }
  344. return destroyObject(this);
  345. };
  346. export default InvertClassification;