diff --git a/package-lock.json b/package-lock.json index 1b6468e2567dbae6fc5e7f1fd17889ee8aceb881..ce603119b23d7d2f2eb7e9c8cb2c7c0421f37e54 100644 Binary files a/package-lock.json and b/package-lock.json differ diff --git a/src/mol-canvas3d/canvas3d.ts b/src/mol-canvas3d/canvas3d.ts index d32b4991e31a481b1e98fcf1f0338858506e1599..358c5d3908dbd662aebdd9c4b1379d1d4d86aca6 100644 --- a/src/mol-canvas3d/canvas3d.ts +++ b/src/mol-canvas3d/canvas3d.ts @@ -208,19 +208,15 @@ namespace Canvas3D { case 'pick': renderer.setViewport(0, 0, pickWidth, pickHeight); objectPickTarget.bind(); - renderer.clear() renderer.render(scene, 'pickObject'); instancePickTarget.bind(); - renderer.clear() renderer.render(scene, 'pickInstance'); groupPickTarget.bind(); - renderer.clear() renderer.render(scene, 'pickGroup'); break; case 'draw': webgl.unbindFramebuffer(); renderer.setViewport(0, 0, canvas.width, canvas.height); - renderer.clear() renderer.render(scene, variant); if (debugHelper.isEnabled) { debugHelper.syncVisibility() diff --git a/src/mol-geo/util/marching-cubes/algorithm.ts b/src/mol-geo/util/marching-cubes/algorithm.ts index d2f524f2c308399cce8f598cd8622c51b007dba8..e446ad2576f1d9a3ffc2b8afda4c0ba2f87b8c2a 100644 --- a/src/mol-geo/util/marching-cubes/algorithm.ts +++ b/src/mol-geo/util/marching-cubes/algorithm.ts @@ -173,6 +173,8 @@ class MarchingCubesState { ); this.verticesOnEdges[edgeId] = id + 1; + // TODO cache scalarField differences for slices + // TODO make calculation optional const n0x = sfg(sf, Math.max(0, li - 1), lj, lk) - sfg(sf, Math.min(this.nX - 1, li + 1), lj, lk) const n0y = sfg(sf, li, Math.max(0, lj - 1), lk) - sfg(sf, li, Math.min(this.nY - 1, lj + 1), lk) const n0z = sfg(sf, li, lj, Math.max(0, lk - 1)) - sfg(sf, li, lj, Math.min(this.nZ, lk + 1)) diff --git a/src/mol-gl/compute/histogram-pyramid/reduction.ts b/src/mol-gl/compute/histogram-pyramid/reduction.ts index 2705e28666ac875b94aeba1b4fa002428d2bea8c..0a33038ec3db9b9c4386e5a679865559158ca72b 100644 --- a/src/mol-gl/compute/histogram-pyramid/reduction.ts +++ b/src/mol-gl/compute/histogram-pyramid/reduction.ts @@ -14,6 +14,7 @@ import { ValueCell } from 'mol-util'; import { QuadSchema, QuadValues } from '../util'; import { Vec2 } from 'mol-math/linear-algebra'; import { getHistopyramidSum } from './sum'; +import { Framebuffer, createFramebuffer } from 'mol-gl/webgl/framebuffer'; const HistopyramidReductionSchema = { ...QuadSchema, @@ -61,12 +62,31 @@ function getLevelTexture(ctx: WebGLContext, level: number) { return tex } +type TextureFramebuffer = { texture: Texture, framebuffer: Framebuffer } +const LevelTexturesFramebuffers: TextureFramebuffer[] = [] +function getLevelTextureFramebuffer(ctx: WebGLContext, level: number) { + let textureFramebuffer = LevelTexturesFramebuffers[level] + const size = Math.pow(2, level) + if (textureFramebuffer === undefined) { + const texture = createTexture(ctx, 'image-float32', 'rgba', 'float', 'nearest') + const framebuffer = createFramebuffer(ctx.gl, ctx.stats) + texture.attachFramebuffer(framebuffer, 0) + textureFramebuffer = { texture, framebuffer } + textureFramebuffer.texture.define(size, size) + LevelTexturesFramebuffers[level] = textureFramebuffer + } + return textureFramebuffer +} + function setRenderingDefaults(ctx: WebGLContext) { const { gl, state } = ctx state.disable(gl.CULL_FACE) state.disable(gl.BLEND) state.disable(gl.DEPTH_TEST) + state.disable(gl.SCISSOR_TEST) state.depthMask(false) + state.colorMask(true, true, true, true) + state.clearColor(0, 0, 0, 0) } export interface HistogramPyramid { @@ -98,16 +118,19 @@ export function createHistogramPyramid(ctx: WebGLContext, inputTexture: Texture) const pyramidTexture = createTexture(ctx, 'image-float32', 'rgba', 'float', 'nearest') pyramidTexture.define(maxSize, maxSize) - const levelTextures: Texture[] = [] - for (let i = 0; i < levels; ++i) levelTextures.push(getLevelTexture(ctx, i)) + const levelTexturesFramebuffers: TextureFramebuffer[] = [] + for (let i = 0; i < levels; ++i) levelTexturesFramebuffers.push(getLevelTextureFramebuffer(ctx, i)) const renderable = getHistopyramidReductionRenderable(ctx, initialTexture) + ctx.state.currentRenderItemId = -1 setRenderingDefaults(ctx) let offset = 0; for (let i = 0; i < levels; i++) { const currLevel = levels - 1 - i - levelTextures[currLevel].attachFramebuffer(framebuffer, 0) + const tf = levelTexturesFramebuffers[currLevel] + tf.framebuffer.bind() + // levelTextures[currLevel].attachFramebuffer(framebuffer, 0) const size = Math.pow(2, currLevel) // console.log('size', size, 'draw-level', currLevel, 'read-level', levels - i) @@ -116,9 +139,10 @@ export function createHistogramPyramid(ctx: WebGLContext, inputTexture: Texture) ValueCell.update(renderable.values.uSize, Math.pow(2, i + 1) / maxSize) if (i > 0) { - ValueCell.update(renderable.values.tPreviousLevel, levelTextures[levels - i]) + ValueCell.update(renderable.values.tPreviousLevel, levelTexturesFramebuffers[levels - i].texture) renderable.update() } + ctx.state.currentRenderItemId = -1 renderable.render() pyramidTexture.bind(0) @@ -140,15 +164,18 @@ export function createHistogramPyramid(ctx: WebGLContext, inputTexture: Texture) offset += size; } + gl.finish() + // printTexture(ctx, pyramidTexture, 2) // - const finalCount = getHistopyramidSum(ctx, levelTextures[0]) + const finalCount = getHistopyramidSum(ctx, levelTexturesFramebuffers[0].texture) const height = Math.ceil(finalCount / Math.pow(2, levels)) const scale = Vec2.create(maxSize / inputTexture.width, maxSize / inputTexture.height) // console.log('height', height, 'finalCount', finalCount, 'scale', scale) + return { pyramidTex: pyramidTexture, count: finalCount, diff --git a/src/mol-gl/compute/histogram-pyramid/sum.ts b/src/mol-gl/compute/histogram-pyramid/sum.ts index 2880d4f8939e78650f9b65a2dd89fe09c84c31d2..cc360e859463268776a95bde4d95e128f5024099 100644 --- a/src/mol-gl/compute/histogram-pyramid/sum.ts +++ b/src/mol-gl/compute/histogram-pyramid/sum.ts @@ -54,17 +54,33 @@ function getSumTexture(ctx: WebGLContext) { /** name for shared framebuffer used for histogram-pyramid operations */ const FramebufferName = 'histogram-pyramid-sum' +function setRenderingDefaults(ctx: WebGLContext) { + const { gl, state } = ctx + state.disable(gl.CULL_FACE) + state.disable(gl.BLEND) + state.disable(gl.DEPTH_TEST) + state.disable(gl.SCISSOR_TEST) + state.depthMask(false) + state.colorMask(true, true, true, true) + state.clearColor(0, 0, 0, 0) +} + const sumArray = new Uint8Array(4) export function getHistopyramidSum(ctx: WebGLContext, pyramidTopTexture: Texture) { const { gl, framebufferCache } = ctx const renderable = getHistopyramidSumRenderable(ctx, pyramidTopTexture) + ctx.state.currentRenderItemId = -1 + const framebuffer = framebufferCache.get(FramebufferName).value const sumTexture = getSumTexture(ctx) sumTexture.attachFramebuffer(framebuffer, 0) + setRenderingDefaults(ctx) + gl.viewport(0, 0, 1, 1) renderable.render() + gl.finish() ctx.readPixels(0, 0, 1, 1, sumArray) ctx.unbindFramebuffer() diff --git a/src/mol-gl/compute/marching-cubes/active-voxels.ts b/src/mol-gl/compute/marching-cubes/active-voxels.ts index cf1367a8b867a03c1ea64eb318afc9fa16db9fcb..a3d5ab5ab14286b798894e78811d527a9ae6d3ac 100644 --- a/src/mol-gl/compute/marching-cubes/active-voxels.ts +++ b/src/mol-gl/compute/marching-cubes/active-voxels.ts @@ -56,7 +56,10 @@ function setRenderingDefaults(ctx: WebGLContext) { state.disable(gl.CULL_FACE) state.disable(gl.BLEND) state.disable(gl.DEPTH_TEST) + state.disable(gl.SCISSOR_TEST) state.depthMask(false) + state.colorMask(true, true, true, true) + state.clearColor(0, 0, 0, 0) } export function calcActiveVoxels(ctx: WebGLContext, cornerTex: Texture, gridDimensions: Vec3, isoValue: number) { @@ -70,6 +73,7 @@ export function calcActiveVoxels(ctx: WebGLContext, cornerTex: Texture, gridDime activeVoxelsTex.define(width, height) const renderable = getActiveVoxelsRenderable(ctx, cornerTex, gridDimensions, isoValue) + ctx.state.currentRenderItemId = -1 activeVoxelsTex.attachFramebuffer(framebuffer, 0) setRenderingDefaults(ctx) @@ -78,5 +82,7 @@ export function calcActiveVoxels(ctx: WebGLContext, cornerTex: Texture, gridDime // console.log('at', readTexture(ctx, activeVoxelsTex)) + gl.finish() + return activeVoxelsTex } \ No newline at end of file diff --git a/src/mol-gl/compute/marching-cubes/isosurface.ts b/src/mol-gl/compute/marching-cubes/isosurface.ts index 24a4cb508a6c7dc073d1cb0a526d7b9b66652383..1cb19527512dfe93b30352c18343beb7a0e2ce25 100644 --- a/src/mol-gl/compute/marching-cubes/isosurface.ts +++ b/src/mol-gl/compute/marching-cubes/isosurface.ts @@ -77,8 +77,10 @@ function setRenderingDefaults(ctx: WebGLContext) { state.disable(gl.CULL_FACE) state.disable(gl.BLEND) state.disable(gl.DEPTH_TEST) - state.depthMask(false) state.enable(gl.SCISSOR_TEST) + state.depthMask(false) + state.colorMask(true, true, true, true) + state.clearColor(0, 0, 0, 0) } export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Texture, volumeData: Texture, histogramPyramid: HistogramPyramid, gridDimensions: Vec3, transform: Mat4, isoValue: number, vertexGroupTexture?: Texture, normalTexture?: Texture) { @@ -87,11 +89,25 @@ export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Tex const framebuffer = framebufferCache.get(FramebufferName).value - if (!vertexGroupTexture) vertexGroupTexture = createTexture(ctx, 'image-float32', 'rgba', 'float', 'nearest') - vertexGroupTexture.define(pyramidTex.width, pyramidTex.height) + let needsClear = false + + if (!vertexGroupTexture) { + vertexGroupTexture = createTexture(ctx, 'image-float32', 'rgba', 'float', 'nearest') + vertexGroupTexture.define(pyramidTex.width, pyramidTex.height) + } else if (vertexGroupTexture.width !== pyramidTex.width || vertexGroupTexture.height !== pyramidTex.height) { + vertexGroupTexture.define(pyramidTex.width, pyramidTex.height) + } else { + needsClear = true + } - if (!normalTexture) normalTexture = createTexture(ctx, 'image-float32', 'rgba', 'float', 'nearest') - normalTexture.define(pyramidTex.width, pyramidTex.height) + if (!normalTexture) { + normalTexture = createTexture(ctx, 'image-float32', 'rgba', 'float', 'nearest') + normalTexture.define(pyramidTex.width, pyramidTex.height) + } else if (normalTexture.width !== pyramidTex.width || normalTexture.height !== pyramidTex.height) { + normalTexture.define(pyramidTex.width, pyramidTex.height) + } else { + needsClear = true + } // const infoTex = createTexture(ctx, 'image-float32', 'rgba', 'float', 'nearest') // infoTex.define(pyramidTex.width, pyramidTex.height) @@ -109,6 +125,7 @@ export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Tex // indexTex.define(pyramidTex.width, pyramidTex.height) const renderable = getIsosurfaceRenderable(ctx, pyramidTex, activeVoxelsBase, volumeData, gridDimensions, transform, isoValue, levels, scale, count) + ctx.state.currentRenderItemId = -1 vertexGroupTexture.attachFramebuffer(framebuffer, 0) normalTexture.attachFramebuffer(framebuffer, 1) @@ -133,9 +150,12 @@ export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Tex setRenderingDefaults(ctx) gl.viewport(0, 0, pyramidTex.width, pyramidTex.height) gl.scissor(0, 0, pyramidTex.width, height) + if (needsClear) gl.clear(gl.COLOR_BUFFER_BIT) renderable.render() state.disable(gl.SCISSOR_TEST) + gl.finish() + // const vgt = readTexture(ctx, vertexGroupTexture, pyramidTex.width, height) // console.log('vertexGroupTexture', vgt.array.subarray(0, 4 * count)) diff --git a/src/mol-gl/renderer.ts b/src/mol-gl/renderer.ts index 5813109172599f1f08c791d5f7348a152ab14021..bf14f95b6d6fa1b5f9c7aefa4e9463f78f9b4719 100644 --- a/src/mol-gl/renderer.ts +++ b/src/mol-gl/renderer.ts @@ -64,6 +64,7 @@ namespace Renderer { const p = deepClone({ ...PD.getDefaultValues(RendererParams), ...props }) const viewport = Viewport() + const bgColor = Color.toVec3Normalized(Vec3(), p.backgroundColor) const view = Mat4.clone(camera.view) const invView = Mat4.invert(Mat4.identity(), view) @@ -98,23 +99,14 @@ namespace Renderer { uCameraPosition: ValueCell.create(Vec3.clone(camera.state.position)), uFogNear: ValueCell.create(camera.state.fogNear), uFogFar: ValueCell.create(camera.state.fogFar), - uFogColor: ValueCell.create(Color.toVec3Normalized(Vec3(), p.backgroundColor)), + uFogColor: ValueCell.create(bgColor), uPickingAlphaThreshold: ValueCell.create(p.pickingAlphaThreshold), } const globalUniformList = Object.entries(globalUniforms) - const [ bgRed, bgGreen, bgBlue ] = Color.toRgbNormalized(p.backgroundColor) - gl.clearColor(bgRed, bgGreen, bgBlue, 1.0) - - if (props.backgroundColor !== undefined && props.backgroundColor !== p.backgroundColor) { - p.backgroundColor = props.backgroundColor - const [ r, g, b ] = Color.toRgbNormalized(p.backgroundColor) - gl.clearColor(r, g, b, 1.0) - ValueCell.update(globalUniforms.uFogColor, Vec3.set(globalUniforms.uFogColor.ref.value, r, g, b)) - } - let globalUniformsNeedUpdate = true + const renderObject = (r: Renderable<RenderableValues & BaseValues>, variant: GraphicsRenderVariant) => { const program = r.getProgram(variant) if (r.state.visible) { @@ -175,13 +167,19 @@ namespace Renderer { ValueCell.update(globalUniforms.uFogNear, camera.state.fogNear) globalUniformsNeedUpdate = true + state.currentRenderItemId = -1 const { renderables } = scene + state.disable(gl.SCISSOR_TEST) + state.disable(gl.BLEND) + state.depthMask(true) + state.colorMask(true, true, true, true) + state.enable(gl.DEPTH_TEST) + state.clearColor(bgColor[0], bgColor[1], bgColor[2], 1.0) + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) + if (variant === 'draw') { - state.disable(gl.BLEND) - state.enable(gl.DEPTH_TEST) - state.depthMask(true) for (let i = 0, il = renderables.length; i < il; ++i) { const r = renderables[i] if (r.state.opaque) renderObject(r, variant) @@ -196,9 +194,6 @@ namespace Renderer { } } else { // picking - state.disable(gl.BLEND) - state.enable(gl.DEPTH_TEST) - state.depthMask(true) for (let i = 0, il = renderables.length; i < il; ++i) { renderObject(renderables[i], variant) } @@ -210,6 +205,7 @@ namespace Renderer { return { clear: () => { state.depthMask(true) + state.clearColor(bgColor[0], bgColor[1], bgColor[2], 1.0) gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) }, render, @@ -221,9 +217,8 @@ namespace Renderer { } if (props.backgroundColor !== undefined && props.backgroundColor !== p.backgroundColor) { p.backgroundColor = props.backgroundColor - const [ r, g, b ] = Color.toRgbNormalized(p.backgroundColor) - gl.clearColor(r, g, b, 1.0) - ValueCell.update(globalUniforms.uFogColor, Vec3.set(globalUniforms.uFogColor.ref.value, r, g, b)) + Color.toVec3Normalized(bgColor, p.backgroundColor) + ValueCell.update(globalUniforms.uFogColor, Vec3.copy(globalUniforms.uFogColor.ref.value, bgColor)) } if (props.lightIntensity !== undefined && props.lightIntensity !== p.lightIntensity) { p.lightIntensity = props.lightIntensity diff --git a/src/mol-gl/shader/gaussian-density.frag b/src/mol-gl/shader/gaussian-density.frag index a78f893d0925baa6a2b91c122cdc2dd65c8fbc9c..2e7c82d3ae7deda046c7ff072e04d423c8de8a64 100644 --- a/src/mol-gl/shader/gaussian-density.frag +++ b/src/mol-gl/shader/gaussian-density.frag @@ -28,8 +28,6 @@ varying float vRadius; #pragma glslify: texture3dFrom2dNearest = require(./utils/texture3d-from-2d-nearest.glsl, intMod=intMod, intDiv=intDiv, foo=foo) // foo=foo is a workaround for a bug in glslify uniform vec3 uBboxSize; -uniform vec3 uBboxMin; -uniform vec3 uBboxMax; uniform vec3 uGridDim; uniform float uCurrentSlice; uniform float uCurrentX; @@ -56,7 +54,7 @@ void main() { #if defined(dCalcType_density) float radiusSq = vRadius * vRadius; float density = exp(-uAlpha * ((dist * dist) / radiusSq)); - gl_FragColor = vec4(density); + gl_FragColor.a = density; #elif defined(dCalcType_minDistance) gl_FragColor.a = 10000.0 - dist; // gl_FragColor.a = 1.0 - encodeFloatLog(dist); diff --git a/src/mol-gl/shader/gaussian-density.vert b/src/mol-gl/shader/gaussian-density.vert index f7557182942ce69b7861146dd3da32ffc3b5c52d..6db1ff7c8dc08e800402351964eeeb32210e2b41 100644 --- a/src/mol-gl/shader/gaussian-density.vert +++ b/src/mol-gl/shader/gaussian-density.vert @@ -20,7 +20,6 @@ varying float vRadius; uniform vec3 uBboxSize; uniform vec3 uBboxMin; -uniform vec3 uBboxMax; uniform vec3 uGridDim; uniform float uCurrentSlice; @@ -29,7 +28,7 @@ void main() { #if defined(dCalcType_groupId) vGroup = aGroup; #endif - float scale = max(uBboxSize.z, max(uBboxSize.x, uBboxSize.y)); + float scale = max(uBboxSize.x, uBboxSize.y); gl_PointSize = (vRadius / scale) * max(uGridDim.x, uGridDim.y) * 6.0; vPosition = (aPosition - uBboxMin) / uBboxSize; gl_Position = vec4(vPosition * 2.0 - 1.0, 1.0); diff --git a/src/mol-gl/webgl/context.ts b/src/mol-gl/webgl/context.ts index 09f567e2551d59c8e3f013f2f75de38680173928..52e957e04d8cbbafcd1f3d32e77aa6f7c8d0d7bb 100644 --- a/src/mol-gl/webgl/context.ts +++ b/src/mol-gl/webgl/context.ts @@ -245,6 +245,7 @@ function createStats(): WebGLStats { export type WebGLState = { currentProgramId: number currentMaterialId: number + currentRenderItemId: number enable: (cap: number) => void disable: (cap: number) => void @@ -252,6 +253,8 @@ export type WebGLState = { frontFace: (mode: number) => void cullFace: (mode: number) => void depthMask: (flag: boolean) => void + colorMask: (red: boolean, green: boolean, blue: boolean, alpha: boolean) => void + clearColor: (red: number, green: number, blue: number, alpha: number) => void blendFunc: (src: number, dst: number) => void blendFuncSeparate: (srcRGB: number, dstRGB: number, srcAlpha: number, dstAlpha: number) => void @@ -266,6 +269,8 @@ function createState(gl: GLRenderingContext): WebGLState { let currentFrontFace = gl.getParameter(gl.FRONT_FACE) let currentCullFace = gl.getParameter(gl.CULL_FACE_MODE) let currentDepthMask = gl.getParameter(gl.DEPTH_WRITEMASK) + let currentColorMask = gl.getParameter(gl.COLOR_WRITEMASK) + let currentClearColor = gl.getParameter(gl.COLOR_CLEAR_VALUE) let currentBlendSrcRGB = gl.getParameter(gl.BLEND_SRC_RGB) let currentBlendDstRGB = gl.getParameter(gl.BLEND_DST_RGB) @@ -278,6 +283,7 @@ function createState(gl: GLRenderingContext): WebGLState { return { currentProgramId: -1, currentMaterialId: -1, + currentRenderItemId: -1, enable: (cap: number) => { if (enabledCapabilities[cap] !== true ) { @@ -310,6 +316,22 @@ function createState(gl: GLRenderingContext): WebGLState { currentDepthMask = flag } }, + colorMask: (red: boolean, green: boolean, blue: boolean, alpha: boolean) => { + if (red !== currentColorMask[0] || green !== currentColorMask[1] || blue !== currentColorMask[2] || alpha !== currentColorMask[3]) + gl.colorMask(red, green, blue, alpha) + currentColorMask[0] = red + currentColorMask[1] = green + currentColorMask[2] = blue + currentColorMask[3] = alpha + }, + clearColor: (red: number, green: number, blue: number, alpha: number) => { + if (red !== currentClearColor[0] || green !== currentClearColor[1] || blue !== currentClearColor[2] || alpha !== currentClearColor[3]) + gl.clearColor(red, green, blue, alpha) + currentClearColor[0] = red + currentClearColor[1] = green + currentClearColor[2] = blue + currentClearColor[3] = alpha + }, blendFunc: (src: number, dst: number) => { if (src !== currentBlendSrcRGB || dst !== currentBlendDstRGB || src !== currentBlendSrcAlpha || dst !== currentBlendDstAlpha) { diff --git a/src/mol-gl/webgl/render-item.ts b/src/mol-gl/webgl/render-item.ts index e196b6ee08935a2975a435a47cb4bdce311a48bd..b516fb8099172ed50c21646934ab016174f4a947 100644 --- a/src/mol-gl/webgl/render-item.ts +++ b/src/mol-gl/webgl/render-item.ts @@ -96,8 +96,8 @@ export function createGraphicsRenderItem(ctx: WebGLContext, drawMode: DrawMode, } export type ComputeRenderItem = RenderItem<keyof typeof ComputeRenderVariantDefines & string> -export function createComputeRenderItem(ctx: WebGLContext, drawMode: DrawMode, shaderCode: ShaderCode, schema: RenderableSchema, values: RenderableValues) { - return createRenderItem(ctx, drawMode, shaderCode, schema, values, -1, ComputeRenderVariantDefines) +export function createComputeRenderItem(ctx: WebGLContext, drawMode: DrawMode, shaderCode: ShaderCode, schema: RenderableSchema, values: RenderableValues, materialId = -1) { + return createRenderItem(ctx, drawMode, shaderCode, schema, values, materialId, ComputeRenderVariantDefines) } /** @@ -164,25 +164,31 @@ export function createRenderItem<T extends RenderVariantDefines, S extends keyof render: (variant: S) => { if (drawCount === 0 || instanceCount === 0) return const program = programs[variant].value - const vertexArray = vertexArrays[variant] - if (program.id !== state.currentProgramId || program.id !== currentProgramId || - materialId === -1 || materialId !== state.currentMaterialId - ) { - // console.log('program.id changed or materialId changed/-1', materialId) - if (program.id !== state.currentProgramId) program.use() - program.setUniforms(materialUniformValueEntries) - state.currentMaterialId = materialId - currentProgramId = program.id - } - program.setUniforms(uniformValueEntries) - program.bindTextures(textures) - if (vertexArrayObject && vertexArray) { - vertexArrayObject.bindVertexArray(vertexArray) - // need to bind elements buffer explicitly since it is not always recorded in the VAO - if (elementsBuffer) elementsBuffer.bind() + if (program.id === currentProgramId && state.currentRenderItemId === id) { + program.setUniforms(uniformValueEntries) + program.bindTextures(textures) } else { - if (elementsBuffer) elementsBuffer.bind() - program.bindAttributes(attributeBuffers) + const vertexArray = vertexArrays[variant] + if (program.id !== state.currentProgramId || program.id !== currentProgramId || + materialId === -1 || materialId !== state.currentMaterialId + ) { + // console.log('program.id changed or materialId changed/-1', materialId) + if (program.id !== state.currentProgramId) program.use() + program.setUniforms(materialUniformValueEntries) + state.currentMaterialId = materialId + currentProgramId = program.id + } + program.setUniforms(uniformValueEntries) + program.bindTextures(textures) + if (vertexArrayObject && vertexArray) { + vertexArrayObject.bindVertexArray(vertexArray) + // need to bind elements buffer explicitly since it is not always recorded in the VAO + if (elementsBuffer) elementsBuffer.bind() + } else { + if (elementsBuffer) elementsBuffer.bind() + program.bindAttributes(attributeBuffers) + } + state.currentRenderItemId = id } if (isDebugMode) { checkFramebufferStatus(ctx.gl) diff --git a/src/mol-math/geometry/gaussian-density/gpu.ts b/src/mol-math/geometry/gaussian-density/gpu.ts index 8036d65c3ecf2df76bd4837711e96a30ad360554..448f6dfa2938776873400bf14f7c5c688a92e1b6 100644 --- a/src/mol-math/geometry/gaussian-density/gpu.ts +++ b/src/mol-math/geometry/gaussian-density/gpu.ts @@ -30,12 +30,11 @@ export const GaussianDensitySchema = { uCurrentSlice: UniformSpec('f'), uCurrentX: UniformSpec('f'), uCurrentY: UniformSpec('f'), - uBboxMin: UniformSpec('v3'), - uBboxMax: UniformSpec('v3'), - uBboxSize: UniformSpec('v3'), - uGridDim: UniformSpec('v3'), - uGridTexDim: UniformSpec('v3'), - uAlpha: UniformSpec('f'), + uBboxMin: UniformSpec('v3', true), + uBboxSize: UniformSpec('v3', true), + uGridDim: UniformSpec('v3', true), + uGridTexDim: UniformSpec('v3', true), + uAlpha: UniformSpec('f', true), tMinDistanceTex: TextureSpec('texture', 'rgba', 'float', 'nearest'), dGridTexType: DefineSpec('string', ['2d', '3d']), @@ -106,7 +105,7 @@ function calcGaussianDensityTexture2d(webgl: WebGLContext, position: PositionDat // - const { gl, framebufferCache } = webgl + const { gl, framebufferCache, state } = webgl const { uCurrentSlice, uCurrentX, uCurrentY } = renderable.values const framebuffer = framebufferCache.get(FramebufferName).value @@ -116,8 +115,12 @@ function calcGaussianDensityTexture2d(webgl: WebGLContext, position: PositionDat if (!texture) texture = createTexture(webgl, 'image-float32', 'rgba', 'float', 'nearest') texture.define(texDimX, texDimY) - function render(fbTex: Texture) { + // console.log(renderable) + + function render(fbTex: Texture, clear: boolean) { + state.currentRenderItemId = -1 fbTex.attachFramebuffer(framebuffer, 0) + if (clear) gl.clear(gl.COLOR_BUFFER_BIT) let currCol = 0 let currY = 0 let currX = 0 @@ -126,25 +129,31 @@ function calcGaussianDensityTexture2d(webgl: WebGLContext, position: PositionDat currCol -= texCols currY += dy currX = 0 + ValueCell.update(uCurrentY, currY) } - gl.viewport(currX, currY, dx, dy) - ValueCell.update(uCurrentSlice, i) + // console.log({ i, currX, currY }) ValueCell.update(uCurrentX, currX) - ValueCell.update(uCurrentY, currY) + ValueCell.update(uCurrentSlice, i) + gl.viewport(currX, currY, dx, dy) renderable.render() ++currCol currX += dx } } - setupMinDistanceRendering(webgl, renderable) - render(minDistanceTexture) - setupDensityRendering(webgl, renderable) - render(texture) + render(texture, true) + + setupMinDistanceRendering(webgl, renderable) + render(minDistanceTexture, true) + gl.finish() setupGroupIdRendering(webgl, renderable) - render(texture) + render(texture, false) + + // printTexture(webgl, texture, 1) + + gl.finish() return { texture, scale: Vec3.inverse(Vec3.zero(), delta), bbox: expandedBox, dim } } @@ -246,7 +255,6 @@ function getGaussianDensityRenderable(webgl: WebGLContext, drawCount: number, po uCurrentX: ValueCell.create(0), uCurrentY: ValueCell.create(0), uBboxMin: ValueCell.create(box.min), - uBboxMax: ValueCell.create(box.max), uBboxSize: ValueCell.create(extent), uGridDim: ValueCell.create(dimensions), uGridTexDim: ValueCell.create(Vec3.create(texDimX, texDimY, 0)), @@ -267,15 +275,18 @@ function getGaussianDensityRenderable(webgl: WebGLContext, drawCount: number, po function setRenderingDefaults(ctx: WebGLContext) { const { gl, state } = ctx state.disable(gl.CULL_FACE) - state.frontFace(gl.CCW) - state.cullFace(gl.BACK) state.enable(gl.BLEND) + state.disable(gl.DEPTH_TEST) + state.disable(gl.SCISSOR_TEST) + state.depthMask(false) + state.clearColor(0, 0, 0, 0) } function setupMinDistanceRendering(webgl: WebGLContext, renderable: ComputeRenderable<any>) { const { gl, state } = webgl ValueCell.update(renderable.values.dCalcType, 'minDistance') renderable.update() + state.colorMask(false, false, false, true) state.blendFunc(gl.ONE, gl.ONE) // the shader writes 1 - dist so we set blending to MAX state.blendEquation(webgl.extensions.blendMinMax.MAX) @@ -285,6 +296,7 @@ function setupDensityRendering(webgl: WebGLContext, renderable: ComputeRenderabl const { gl, state } = webgl ValueCell.update(renderable.values.dCalcType, 'density') renderable.update() + state.colorMask(false, false, false, true) state.blendFunc(gl.ONE, gl.ONE) state.blendEquation(gl.FUNC_ADD) } @@ -294,7 +306,8 @@ function setupGroupIdRendering(webgl: WebGLContext, renderable: ComputeRenderabl ValueCell.update(renderable.values.dCalcType, 'groupId') renderable.update() // overwrite color, don't change alpha - state.blendFuncSeparate(gl.ONE, gl.ZERO, gl.ZERO, gl.ONE) + state.colorMask(true, true, true, false) + state.blendFunc(gl.ONE, gl.ZERO) state.blendEquation(gl.FUNC_ADD) } diff --git a/src/tests/browser/marching-cubes.ts b/src/tests/browser/marching-cubes.ts index a0ee2f5389f74bdaddb8dbaa8dbf44883c57ba8c..783fd9dc474b17cb0dc7b9c7f7d0d632a63d921e 100644 --- a/src/tests/browser/marching-cubes.ts +++ b/src/tests/browser/marching-cubes.ts @@ -56,7 +56,7 @@ async function init() { } const isoValue = Math.exp(-props.smoothness) - if (false) { + if (true) { console.time('gpu gaussian2') const densityTextureData2 = await computeGaussianDensityTexture2d(position, box, radius, props, webgl).run() webgl.waitForGpuCommandsCompleteSync() @@ -119,7 +119,7 @@ async function init() { // console.time('cpu gaussian') - const densityData = await computeGaussianDensity(position, box, radius, { ...props, useGpu: false }, webgl).run() + const densityData = await computeGaussianDensity(position, box, radius, { ...props, useGpu: true }, webgl).run() console.timeEnd('cpu gaussian') // console.log({ densityData }) @@ -134,7 +134,6 @@ async function init() { console.timeEnd('cpu mc') // console.log('surface', surface) Mesh.transformImmediate(surface, densityData.transform) - Mesh.computeNormalsImmediate(surface) const meshProps = { doubleSided: true, flatShaded: false, alpha: 1.0 } const meshValues = Mesh.Utils.createValuesSimple(surface, meshProps, Color(0x995511), 1) const meshState = Mesh.Utils.createRenderableState(meshProps)