isosurface.ts 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. /**
  2. * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. */
  6. import { createComputeRenderable } from '../../renderable';
  7. import { WebGLContext } from '../../webgl/context';
  8. import { createComputeRenderItem } from '../../webgl/render-item';
  9. import { Values, TextureSpec, UniformSpec } from '../../renderable/schema';
  10. import { Texture } from '../../../mol-gl/webgl/texture';
  11. import { ShaderCode } from '../../../mol-gl/shader-code';
  12. import { ValueCell } from '../../../mol-util';
  13. import { Vec3, Vec2, Mat4 } from '../../../mol-math/linear-algebra';
  14. import { QuadSchema, QuadValues } from '../util';
  15. import { HistogramPyramid } from '../histogram-pyramid/reduction';
  16. import { getTriIndices } from './tables';
  17. import quad_vert from '../../../mol-gl/shader/quad.vert';
  18. import isosurface_frag from '../../../mol-gl/shader/marching-cubes/isosurface.frag';
  19. const IsosurfaceSchema = {
  20. ...QuadSchema,
  21. tTriIndices: TextureSpec('image-uint8', 'alpha', 'ubyte', 'nearest'),
  22. tActiveVoxelsPyramid: TextureSpec('texture', 'rgba', 'float', 'nearest'),
  23. tActiveVoxelsBase: TextureSpec('texture', 'rgba', 'float', 'nearest'),
  24. tVolumeData: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'),
  25. uIsoValue: UniformSpec('f'),
  26. uSize: UniformSpec('f'),
  27. uLevels: UniformSpec('f'),
  28. uCount: UniformSpec('f'),
  29. uGridDim: UniformSpec('v3'),
  30. uGridTexDim: UniformSpec('v3'),
  31. uGridTransform: UniformSpec('m4'),
  32. uScale: UniformSpec('v2'),
  33. };
  34. const IsosurfaceName = 'isosurface';
  35. function getIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Texture, activeVoxelsBase: Texture, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, transform: Mat4, isoValue: number, levels: number, scale: Vec2, count: number, height: number) {
  36. if (ctx.namedComputeRenderables[IsosurfaceName]) {
  37. const v = ctx.namedComputeRenderables[IsosurfaceName].values;
  38. ValueCell.update(v.uQuadScale, Vec2.create(1, height / Math.pow(2, levels)));
  39. ValueCell.update(v.tActiveVoxelsPyramid, activeVoxelsPyramid);
  40. ValueCell.update(v.tActiveVoxelsBase, activeVoxelsBase);
  41. ValueCell.update(v.tVolumeData, volumeData);
  42. ValueCell.updateIfChanged(v.uIsoValue, isoValue);
  43. ValueCell.updateIfChanged(v.uSize, Math.pow(2, levels));
  44. ValueCell.updateIfChanged(v.uLevels, levels);
  45. ValueCell.updateIfChanged(v.uCount, count);
  46. ValueCell.update(v.uGridDim, gridDim);
  47. ValueCell.update(v.uGridTexDim, gridTexDim);
  48. ValueCell.update(v.uGridTransform, transform);
  49. ValueCell.update(v.uScale, scale);
  50. ctx.namedComputeRenderables[IsosurfaceName].update();
  51. } else {
  52. ctx.namedComputeRenderables[IsosurfaceName] = createIsosurfaceRenderable(ctx, activeVoxelsPyramid, activeVoxelsBase, volumeData, gridDim, gridTexDim, transform, isoValue, levels, scale, count, height);
  53. }
  54. return ctx.namedComputeRenderables[IsosurfaceName];
  55. }
  56. function createIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Texture, activeVoxelsBase: Texture, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, transform: Mat4, isoValue: number, levels: number, scale: Vec2, count: number, height: number) {
  57. // console.log('uSize', Math.pow(2, levels))
  58. const values: Values<typeof IsosurfaceSchema> = {
  59. ...QuadValues,
  60. tTriIndices: ValueCell.create(getTriIndices()),
  61. uQuadScale: ValueCell.create(Vec2.create(1, height / Math.pow(2, levels))),
  62. tActiveVoxelsPyramid: ValueCell.create(activeVoxelsPyramid),
  63. tActiveVoxelsBase: ValueCell.create(activeVoxelsBase),
  64. tVolumeData: ValueCell.create(volumeData),
  65. uIsoValue: ValueCell.create(isoValue),
  66. uSize: ValueCell.create(Math.pow(2, levels)),
  67. uLevels: ValueCell.create(levels),
  68. uCount: ValueCell.create(count),
  69. uGridDim: ValueCell.create(gridDim),
  70. uGridTexDim: ValueCell.create(gridTexDim),
  71. uGridTransform: ValueCell.create(transform),
  72. uScale: ValueCell.create(scale),
  73. };
  74. const schema = { ...IsosurfaceSchema };
  75. const shaderCode = ShaderCode('isosurface', quad_vert, isosurface_frag, { drawBuffers: 'required' });
  76. const renderItem = createComputeRenderItem(ctx, 'triangles', shaderCode, schema, values);
  77. return createComputeRenderable(renderItem, values);
  78. }
  79. function setRenderingDefaults(ctx: WebGLContext) {
  80. const { gl, state } = ctx;
  81. state.disable(gl.CULL_FACE);
  82. state.disable(gl.BLEND);
  83. state.disable(gl.DEPTH_TEST);
  84. state.disable(gl.SCISSOR_TEST);
  85. state.depthMask(false);
  86. state.colorMask(true, true, true, true);
  87. state.clearColor(0, 0, 0, 0);
  88. }
  89. export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Texture, volumeData: Texture, histogramPyramid: HistogramPyramid, gridDim: Vec3, gridTexDim: Vec3, transform: Mat4, isoValue: number, vertexGroupTexture?: Texture, normalTexture?: Texture) {
  90. const { gl, resources } = ctx;
  91. const { pyramidTex, height, levels, scale, count } = histogramPyramid;
  92. // console.log('iso', 'gridDim', gridDim, 'scale', scale, 'gridTexDim', gridTexDim)
  93. // console.log('iso volumeData', volumeData)
  94. if (!ctx.namedFramebuffers[IsosurfaceName]) {
  95. ctx.namedFramebuffers[IsosurfaceName] = resources.framebuffer();
  96. }
  97. const framebuffer = ctx.namedFramebuffers[IsosurfaceName];
  98. const w = pyramidTex.getWidth();
  99. const h = pyramidTex.getHeight();
  100. if (!vertexGroupTexture) {
  101. vertexGroupTexture = resources.texture('image-float32', 'rgba', 'float', 'nearest');
  102. }
  103. vertexGroupTexture.define(w, h);
  104. if (!normalTexture) {
  105. normalTexture = resources.texture('image-float32', 'rgba', 'float', 'nearest');
  106. }
  107. normalTexture.define(w, h);
  108. // const infoTex = createTexture(ctx, 'image-float32', 'rgba', 'float', 'nearest')
  109. // infoTex.define(pyramidTex.width, pyramidTex.height)
  110. // const pointTexA = createTexture(ctx, 'image-float32', 'rgba', 'float', 'nearest')
  111. // pointTexA.define(pyramidTex.width, pyramidTex.height)
  112. // const pointTexB = createTexture(ctx, 'image-float32', 'rgba', 'float', 'nearest')
  113. // pointTexB.define(pyramidTex.width, pyramidTex.height)
  114. // const coordTex = createTexture(ctx, 'image-float32', 'rgba', 'float', 'nearest')
  115. // coordTex.define(pyramidTex.width, pyramidTex.height)
  116. // const indexTex = createTexture(ctx, 'image-float32', 'rgba', 'float', 'nearest')
  117. // indexTex.define(pyramidTex.width, pyramidTex.height)
  118. const renderable = getIsosurfaceRenderable(ctx, pyramidTex, activeVoxelsBase, volumeData, gridDim, gridTexDim, transform, isoValue, levels, scale, count, height);
  119. ctx.state.currentRenderItemId = -1;
  120. vertexGroupTexture.attachFramebuffer(framebuffer, 0);
  121. normalTexture.attachFramebuffer(framebuffer, 1);
  122. // infoTex.attachFramebuffer(framebuffer, 1)
  123. // pointTexA.attachFramebuffer(framebuffer, 2)
  124. // pointTexB.attachFramebuffer(framebuffer, 3)
  125. // coordTex.attachFramebuffer(framebuffer, 4)
  126. // indexTex.attachFramebuffer(framebuffer, 5)
  127. const { drawBuffers } = ctx.extensions;
  128. if (!drawBuffers) throw new Error('need WebGL draw buffers');
  129. drawBuffers.drawBuffers([
  130. drawBuffers.COLOR_ATTACHMENT0,
  131. drawBuffers.COLOR_ATTACHMENT1,
  132. // drawBuffers.COLOR_ATTACHMENT2,
  133. // drawBuffers.COLOR_ATTACHMENT3,
  134. // drawBuffers.COLOR_ATTACHMENT4,
  135. // drawBuffers.COLOR_ATTACHMENT5
  136. ]);
  137. setRenderingDefaults(ctx);
  138. gl.viewport(0, 0, w, h);
  139. gl.clear(gl.COLOR_BUFFER_BIT);
  140. renderable.render();
  141. gl.flush();
  142. // const vgt = readTexture(ctx, vertexGroupTexture, pyramidTex.width, height)
  143. // console.log('vertexGroupTexture', vgt.array.subarray(0, 4 * count))
  144. // const vt = readTexture(ctx, verticesTex, pyramidTex.width, height)
  145. // console.log('vt', vt)
  146. // const vertices = new Float32Array(3 * compacted.count)
  147. // for (let i = 0; i < compacted.count; ++i) {
  148. // vertices[i * 3] = vt.array[i * 4]
  149. // vertices[i * 3 + 1] = vt.array[i * 4 + 1]
  150. // vertices[i * 3 + 2] = vt.array[i * 4 + 2]
  151. // }
  152. // console.log('vertices', vertices)
  153. // const it = readTexture(ctx, infoTex, pyramidTex.width, height)
  154. // console.log('info', it.array.subarray(0, 4 * compacted.count))
  155. // const pat = readTexture(ctx, pointTexA, pyramidTex.width, height)
  156. // console.log('point a', pat.array.subarray(0, 4 * compacted.count))
  157. // const pbt = readTexture(ctx, pointTexB, pyramidTex.width, height)
  158. // console.log('point b', pbt.array.subarray(0, 4 * compacted.count))
  159. // const ct = readTexture(ctx, coordTex, pyramidTex.width, height)
  160. // console.log('coord', ct.array.subarray(0, 4 * compacted.count))
  161. // const idxt = readTexture(ctx, indexTex, pyramidTex.width, height)
  162. // console.log('index', idxt.array.subarray(0, 4 * compacted.count))
  163. // const { field, idField } = await fieldFromTexture2d(ctx, volumeData, gridDimensions)
  164. // console.log({ field, idField })
  165. // const valuesA = new Float32Array(compacted.count)
  166. // const valuesB = new Float32Array(compacted.count)
  167. // for (let i = 0; i < compacted.count; ++i) {
  168. // valuesA[i] = field.space.get(field.data, pat.array[i * 4], pat.array[i * 4 + 1], pat.array[i * 4 + 2])
  169. // valuesB[i] = field.space.get(field.data, pbt.array[i * 4], pbt.array[i * 4 + 1], pbt.array[i * 4 + 2])
  170. // }
  171. // console.log('valuesA', valuesA)
  172. // console.log('valuesB', valuesB)
  173. return { vertexGroupTexture, normalTexture, vertexCount: count };
  174. }