wboit.ts 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. /**
  2. * Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Áron Samuel Kovács <aron.kovacs@mail.muni.cz>
  5. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  6. */
  7. import { QuadSchema, QuadValues } from '../../mol-gl/compute/util';
  8. import { ComputeRenderable, createComputeRenderable } from '../../mol-gl/renderable';
  9. import { TextureSpec, UniformSpec, Values } from '../../mol-gl/renderable/schema';
  10. import { ShaderCode } from '../../mol-gl/shader-code';
  11. import { WebGLContext } from '../../mol-gl/webgl/context';
  12. import { createComputeRenderItem } from '../../mol-gl/webgl/render-item';
  13. import { Texture } from '../../mol-gl/webgl/texture';
  14. import { ValueCell } from '../../mol-util';
  15. import { quad_vert } from '../../mol-gl/shader/quad.vert';
  16. import { evaluateWboit_frag } from '../../mol-gl/shader/evaluate-wboit.frag';
  17. import { Framebuffer } from '../../mol-gl/webgl/framebuffer';
  18. import { Vec2 } from '../../mol-math/linear-algebra';
  19. import { isDebugMode, isTimingMode } from '../../mol-util/debug';
  20. import { isWebGL2 } from '../../mol-gl/webgl/compat';
  21. import { Renderbuffer } from '../../mol-gl/webgl/renderbuffer';
  22. const EvaluateWboitSchema = {
  23. ...QuadSchema,
  24. tWboitA: TextureSpec('texture', 'rgba', 'float', 'nearest'),
  25. tWboitB: TextureSpec('texture', 'rgba', 'float', 'nearest'),
  26. uTexSize: UniformSpec('v2'),
  27. };
  28. const EvaluateWboitShaderCode = ShaderCode('evaluate-wboit', quad_vert, evaluateWboit_frag);
  29. type EvaluateWboitRenderable = ComputeRenderable<Values<typeof EvaluateWboitSchema>>
  30. function getEvaluateWboitRenderable(ctx: WebGLContext, wboitATexture: Texture, wboitBTexture: Texture): EvaluateWboitRenderable {
  31. const values: Values<typeof EvaluateWboitSchema> = {
  32. ...QuadValues,
  33. tWboitA: ValueCell.create(wboitATexture),
  34. tWboitB: ValueCell.create(wboitBTexture),
  35. uTexSize: ValueCell.create(Vec2.create(wboitATexture.getWidth(), wboitATexture.getHeight())),
  36. };
  37. const schema = { ...EvaluateWboitSchema };
  38. const renderItem = createComputeRenderItem(ctx, 'triangles', EvaluateWboitShaderCode, schema, values);
  39. return createComputeRenderable(renderItem, values);
  40. }
  41. //
  42. export class WboitPass {
  43. private readonly renderable: EvaluateWboitRenderable;
  44. private readonly framebuffer: Framebuffer;
  45. private readonly textureA: Texture;
  46. private readonly textureB: Texture;
  47. private readonly depthRenderbuffer: Renderbuffer;
  48. private _supported = false;
  49. get supported() {
  50. return this._supported;
  51. }
  52. bind() {
  53. const { state, gl } = this.webgl;
  54. this.framebuffer.bind();
  55. state.clearColor(0, 0, 0, 1);
  56. gl.clear(gl.COLOR_BUFFER_BIT);
  57. state.disable(gl.DEPTH_TEST);
  58. state.blendFuncSeparate(gl.ONE, gl.ONE, gl.ZERO, gl.ONE_MINUS_SRC_ALPHA);
  59. state.enable(gl.BLEND);
  60. }
  61. render() {
  62. if (isTimingMode) this.webgl.timer.mark('WboitPass.render');
  63. const { state, gl } = this.webgl;
  64. state.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
  65. state.enable(gl.BLEND);
  66. this.renderable.update();
  67. this.renderable.render();
  68. if (isTimingMode) this.webgl.timer.markEnd('WboitPass.render');
  69. }
  70. setSize(width: number, height: number) {
  71. const [w, h] = this.renderable.values.uTexSize.ref.value;
  72. if (width !== w || height !== h) {
  73. this.textureA.define(width, height);
  74. this.textureB.define(width, height);
  75. this.depthRenderbuffer.setSize(width, height);
  76. ValueCell.update(this.renderable.values.uTexSize, Vec2.set(this.renderable.values.uTexSize.ref.value, width, height));
  77. }
  78. }
  79. reset() {
  80. if (this._supported) this._init();
  81. }
  82. private _init() {
  83. const { extensions: { drawBuffers } } = this.webgl;
  84. this.framebuffer.bind();
  85. drawBuffers!.drawBuffers([
  86. drawBuffers!.COLOR_ATTACHMENT0,
  87. drawBuffers!.COLOR_ATTACHMENT1,
  88. ]);
  89. this.textureA.attachFramebuffer(this.framebuffer, 'color0');
  90. this.textureB.attachFramebuffer(this.framebuffer, 'color1');
  91. this.depthRenderbuffer.attachFramebuffer(this.framebuffer);
  92. }
  93. static isSupported(webgl: WebGLContext) {
  94. const { extensions: { drawBuffers, textureFloat, colorBufferFloat, depthTexture } } = webgl;
  95. if (!textureFloat || !colorBufferFloat || !depthTexture || !drawBuffers) {
  96. if (isDebugMode) {
  97. const missing: string[] = [];
  98. if (!textureFloat) missing.push('textureFloat');
  99. if (!colorBufferFloat) missing.push('colorBufferFloat');
  100. if (!depthTexture) missing.push('depthTexture');
  101. if (!drawBuffers) missing.push('drawBuffers');
  102. console.log(`Missing "${missing.join('", "')}" extensions required for "wboit"`);
  103. }
  104. return false;
  105. } else {
  106. return true;
  107. }
  108. }
  109. constructor(private webgl: WebGLContext, width: number, height: number) {
  110. if (!WboitPass.isSupported(webgl)) return;
  111. const { resources, gl } = webgl;
  112. this.textureA = resources.texture('image-float32', 'rgba', 'float', 'nearest');
  113. this.textureA.define(width, height);
  114. this.textureB = resources.texture('image-float32', 'rgba', 'float', 'nearest');
  115. this.textureB.define(width, height);
  116. this.depthRenderbuffer = isWebGL2(gl)
  117. ? resources.renderbuffer('depth32f', 'depth', width, height)
  118. : resources.renderbuffer('depth16', 'depth', width, height);
  119. this.renderable = getEvaluateWboitRenderable(webgl, this.textureA, this.textureB);
  120. this.framebuffer = resources.framebuffer();
  121. this._supported = true;
  122. this._init();
  123. }
  124. }