diff --git a/src/mol-gl/_spec/renderer.spec.ts b/src/mol-gl/_spec/renderer.spec.ts index 67d7ac11c0dd1b49c0a5fc9af2d666fc579189a2..c2b5b3925a412b23955760131c5ee07c9c0dcac2 100644 --- a/src/mol-gl/_spec/renderer.spec.ts +++ b/src/mol-gl/_spec/renderer.spec.ts @@ -138,7 +138,7 @@ describe('renderer', () => { scene.add(points) expect(ctx.bufferCount).toBe(4); - expect(ctx.textureCount).toBe(4); + expect(ctx.textureCount).toBe(5); expect(ctx.vaoCount).toBe(4); expect(ctx.programCache.count).toBe(4); expect(ctx.shaderCache.count).toBe(8); diff --git a/src/mol-gl/renderer.ts b/src/mol-gl/renderer.ts index 7c6831489246a6aebe4c38633518c05a211fe5f4..a05756c6392b7fc26cc37d3f4c7aa408f33ef6a0 100644 --- a/src/mol-gl/renderer.ts +++ b/src/mol-gl/renderer.ts @@ -177,7 +177,7 @@ namespace Renderer { gl.depthMask(true) for (let i = 0, il = renderables.length; i < il; ++i) { const r = renderables[i] - if (r.state.opaque) renderObject(r, variant) + if (r.state.opaque && !r.values.dTransparency.ref.value) renderObject(r, variant) } gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) @@ -185,7 +185,7 @@ namespace Renderer { for (let i = 0, il = renderables.length; i < il; ++i) { const r = renderables[i] gl.depthMask(r.values.uAlpha.ref.value === 1.0) - if (!r.state.opaque) renderObject(r, variant) + if (!r.state.opaque || r.values.dTransparency.ref.value) renderObject(r, variant) } } else { // picking diff --git a/src/mol-gl/shader/chunks/assign-color-varying.glsl b/src/mol-gl/shader/chunks/assign-color-varying.glsl index e820a5849227b98f5c074bdadd7df819376fafa5..3aff425ffe42230481d5b75bdf3da9d0577a6802 100644 --- a/src/mol-gl/shader/chunks/assign-color-varying.glsl +++ b/src/mol-gl/shader/chunks/assign-color-varying.glsl @@ -19,5 +19,5 @@ #endif #ifdef dTransparency - vTransparency = readFromTexture(tTransparency, aInstance * float(uGroupCount) + aGroup, uTransparencyTexDim); + vTransparency = readFromTexture(tTransparency, aInstance * float(uGroupCount) + aGroup, uTransparencyTexDim).a; #endif \ No newline at end of file diff --git a/src/mol-gl/shader/chunks/assign-material-color.glsl b/src/mol-gl/shader/chunks/assign-material-color.glsl index bd35c1fcb6e4a3122b36c29c5991ede2326781a8..56e406dcedb22bc3b379ab39d045f9e925ad1255 100644 --- a/src/mol-gl/shader/chunks/assign-material-color.glsl +++ b/src/mol-gl/shader/chunks/assign-material-color.glsl @@ -13,5 +13,40 @@ // apply transparency #if defined(dTransparency) && (defined(dColorType_uniform) || defined(dColorType_attribute) || defined(dColorType_instance) || defined(dColorType_group) || defined(dColorType_groupInstance)) - material.a *= 1 - vTransparency; + float ma = material.a * (1.0 - vTransparency); + ivec2 pixelCoord = ivec2(gl_FragCoord.xy); + + // const mat4 thresholdMatrix = mat4( + // 1.0 / 17.0, 9.0 / 17.0, 3.0 / 17.0, 11.0 / 17.0, + // 13.0 / 17.0, 5.0 / 17.0, 15.0 / 17.0, 7.0 / 17.0, + // 4.0 / 17.0, 12.0 / 17.0, 2.0 / 17.0, 10.0 / 17.0, + // 16.0 / 17.0, 8.0 / 17.0, 14.0 / 17.0, 6.0 / 17.0 + // ); + // float at = thresholdMatrix[pixelCoord.x % 4][pixelCoord.y % 4]; + + // https://research.nvidia.com/publication/hashed-alpha-testing + // Find the discretized derivatives of our coordinates + float maxDeriv = max(length(dFdx(vViewPosition)), length(dFdy(vViewPosition))); + float pixScale = 1.0 / maxDeriv; + // Find two nearest log-discretized noise scales + vec2 pixScales = vec2(exp2(floor(log2(pixScale))), exp2(ceil(log2(pixScale)))); + // Compute alpha thresholds at our two noise scales + vec2 alpha = vec2(hash3d(floor(pixScales.x * vViewPosition)), hash3d(floor(pixScales.y * vViewPosition))); + // Factor to interpolate lerp with + float lerpFactor = fract(log2(pixScale)); + // Interpolate alpha threshold from noise at two scales + float x = (1.0 - lerpFactor) * alpha.x + lerpFactor * alpha.y; + // Pass into CDF to compute uniformly distrib threshold + float a = min(lerpFactor, 1.0 - lerpFactor); + vec3 cases = vec3( + x * x / (2.0 * a * (1.0 - a)), + (x - 0.5 * a) / (1.0 - a), + 1.0 - ((1.0 - x) * (1.0 - x) / (2.0 * a * (1.0 - a))) + ); + // Find our final, uniformly distributed alpha threshold + float at = (x < (1.0 - a)) ? ((x < a) ? cases.x : cases.y) : cases.z; + // Avoids ατ == 0. Could also do + at = clamp(at, 1.0e-6, 1.0); + + if (ma < 0.99 && (ma < 0.01 || ma < at)) discard; #endif \ No newline at end of file diff --git a/src/mol-gl/shader/chunks/common.glsl b/src/mol-gl/shader/chunks/common.glsl index c26150ec86632fe48034fa8e6265a42d375ed4eb..b10d6d621574588d3c2eb829217d5e69b20902e0 100644 --- a/src/mol-gl/shader/chunks/common.glsl +++ b/src/mol-gl/shader/chunks/common.glsl @@ -1,6 +1,14 @@ float intDiv(float a, float b) { return float(int(a) / int(b)); } float intMod(float a, float b) { return a - b * float(int(a) / int(b)); } +float hash2d(vec2 coord2d) { + return fract(1.0e4 * sin(17.0 * coord2d.x + 0.1 * coord2d.y) * (0.1 + abs(sin(13.0 * coord2d.y + coord2d.x)))); +} + +float hash3d(vec3 coord3d) { + return hash2d(vec2(hash2d(coord3d.xy), coord3d.z)); +} + #if __VERSION__ != 300 // transpose diff --git a/src/mol-repr/structure/complex-representation.ts b/src/mol-repr/structure/complex-representation.ts index da59074da1cf8f6c0b2c6978cf93581f1fbcb887..e8ed4daf473e96be54a04d54cd67e357f1c6a329 100644 --- a/src/mol-repr/structure/complex-representation.ts +++ b/src/mol-repr/structure/complex-representation.ts @@ -69,6 +69,7 @@ export function ComplexRepresentation<P extends StructureParams>(label: string, if (state.alphaFactor !== undefined && visual) visual.setAlphaFactor(state.alphaFactor) if (state.pickable !== undefined && visual) visual.setPickable(state.pickable) if (state.overpaint !== undefined && visual) visual.setOverpaint(state.overpaint) + if (state.transparency !== undefined && visual) visual.setTransparency(state.transparency) if (state.transform !== undefined && visual) visual.setTransform(state.transform) if (state.unitTransforms !== undefined && visual) { // Since ComplexVisuals always renders geometries between units the application of `unitTransforms` diff --git a/src/mol-repr/structure/complex-visual.ts b/src/mol-repr/structure/complex-visual.ts index aeb4752bd5415d26610e43f10cc3b77c779170c4..0cc0bf9274c6ba4484e871bcc87300770119b993 100644 --- a/src/mol-repr/structure/complex-visual.ts +++ b/src/mol-repr/structure/complex-visual.ts @@ -197,7 +197,7 @@ export function ComplexVisual<G extends Geometry, P extends ComplexParams & Geom setTransform(matrix?: Mat4, instanceMatrices?: Float32Array | null) { Visual.setTransform(renderObject, matrix, instanceMatrices) }, - setOverpaint(overpaint: Overpaint, clear = false) { + setOverpaint(overpaint: Overpaint) { return Visual.setOverpaint(renderObject, overpaint, lociApply, true) }, setTransparency(transparency: Transparency) { diff --git a/src/mol-repr/structure/units-representation.ts b/src/mol-repr/structure/units-representation.ts index 8985cb7750405864cae3d68ab9f7d158380c6c3c..b54a84c252131a13e1af0c16612e026a309a731b 100644 --- a/src/mol-repr/structure/units-representation.ts +++ b/src/mol-repr/structure/units-representation.ts @@ -172,11 +172,12 @@ export function UnitsRepresentation<P extends UnitsParams>(label: string, ctx: R } function setState(state: Partial<StructureRepresentationState>) { - const { visible, alphaFactor, pickable, overpaint, transform, unitTransforms } = state + const { visible, alphaFactor, pickable, overpaint, transparency, transform, unitTransforms } = state if (visible !== undefined) visuals.forEach(({ visual }) => visual.setVisibility(visible)) if (alphaFactor !== undefined) visuals.forEach(({ visual }) => visual.setAlphaFactor(alphaFactor)) if (pickable !== undefined) visuals.forEach(({ visual }) => visual.setPickable(pickable)) if (overpaint !== undefined) visuals.forEach(({ visual }) => visual.setOverpaint(overpaint)) + if (transparency !== undefined) visuals.forEach(({ visual }) => visual.setTransparency(transparency)) if (transform !== undefined) visuals.forEach(({ visual }) => visual.setTransform(transform)) if (unitTransforms !== undefined) { visuals.forEach(({ visual, group }) => { diff --git a/src/mol-repr/visual.ts b/src/mol-repr/visual.ts index 3675e810816ce7393075864f2d3b25004f93a3c6..0e120b6e6d887939043f1c319bb2272e201c90ae 100644 --- a/src/mol-repr/visual.ts +++ b/src/mol-repr/visual.ts @@ -97,6 +97,7 @@ namespace Visual { lociApply(loci, apply) } ValueCell.update(tOverpaint, tOverpaint.ref.value) + console.log(renderObject) } export function setTransparency(renderObject: GraphicsRenderObject | undefined, transparency: Transparency, lociApply: LociApply, clear: boolean) { diff --git a/src/mol-repr/volume/representation.ts b/src/mol-repr/volume/representation.ts index fffc5461d14d62489e3c876816c306d75157a44d..621c17ebcf8fb4e07924573f8b544e7e2fa28291 100644 --- a/src/mol-repr/volume/representation.ts +++ b/src/mol-repr/volume/representation.ts @@ -254,6 +254,7 @@ export function VolumeRepresentation<P extends VolumeParams>(label: string, ctx: if (state.alphaFactor !== undefined && visual) visual.setAlphaFactor(state.alphaFactor) if (state.pickable !== undefined && visual) visual.setPickable(state.pickable) if (state.overpaint !== undefined && visual) visual.setOverpaint(state.overpaint) + if (state.transparency !== undefined && visual) visual.setTransparency(state.transparency) if (state.transform !== undefined && visual) visual.setTransform(state.transform) Representation.updateState(_state, state)