diff --git a/CHANGELOG.md b/CHANGELOG.md index ae05abb51ae48b596525bbb267797a132c186c40..bca9400de92c552b79720ba8f223ec3520dde185 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ Note that since we don't clearly distinguish between a public and private interf - Fix cylinder near-clipping - Add interior cylinder caps - Add per-pixel object clipping + - Add `solidInterior` parameter - Fix `QualityAssessment` assignment bug for structures with different auth vs label sequence numbering - Refresh `ApplyActionControl`'s param definition when toggling expanded state diff --git a/src/mol-gl/shader/cylinders.frag.ts b/src/mol-gl/shader/cylinders.frag.ts index c1169f27a6d3c08ba47fbc71dba835b24d0cf1b3..b820b770948e38fe5af005bf613e57172ccc3dd1 100644 --- a/src/mol-gl/shader/cylinders.frag.ts +++ b/src/mol-gl/shader/cylinders.frag.ts @@ -28,6 +28,12 @@ uniform mat4 uInvView; #include light_frag_params #include common_clip +#ifdef dSolidInterior + const bool solidInterior = true; +#else + const bool solidInterior = false; +#endif + // adapted from https://www.shadertoy.com/view/4lcSRn // The MIT License, Copyright 2016 Inigo Quilez bool CylinderImpostor( @@ -63,6 +69,9 @@ bool CylinderImpostor( bool bottomInterior = false; #endif + bool clipped = false; + bool objectClipped = false; + // body outside h = sqrt(h); float t = (-k1 - h) / k2; @@ -74,36 +83,76 @@ bool CylinderImpostor( viewPosition = (uView * vec4(modelPosition, 1.0)).xyz; fragmentDepth = calcDepth(viewPosition); #if defined(dClipVariant_pixel) && dClipObjectCount != 0 - if (clipTest(vec4(modelPosition, 0.0))) fragmentDepth = -1.0; + if (clipTest(vec4(modelPosition, 0.0))) { + objectClipped = true; + fragmentDepth = -1.0; + #ifdef dSolidInterior + topCap = !topInterior; + bottomCap = !bottomInterior; + #endif + } #endif if (fragmentDepth > 0.0) return true; + clipped = true; } - if (topCap && y < 0.0) { - // top cap - t = -baoc / bard; - if (abs(k1 + k2 * t) < h) { - interior = topInterior; - cameraNormal = -ba / baba; - modelPosition = rayOrigin + t * rayDir; - viewPosition = (uView * vec4(modelPosition, 1.0)).xyz; - fragmentDepth = calcDepth(viewPosition); - if (fragmentDepth > 0.0) return true; - } - } else if (bottomCap && y >= 0.0) { - // bottom cap - t = (baba - baoc) / bard; - if (abs(k1 + k2 * t) < h) { - interior = bottomInterior; - cameraNormal = ba / baba; - modelPosition = rayOrigin + t * rayDir; - viewPosition = (uView * vec4(modelPosition, 1.0)).xyz; - fragmentDepth = calcDepth(viewPosition); - if (fragmentDepth > 0.0) return true; + if (!clipped) { + if (topCap && y < 0.0) { + // top cap + t = -baoc / bard; + if (abs(k1 + k2 * t) < h) { + interior = topInterior; + cameraNormal = -ba / baba; + modelPosition = rayOrigin + t * rayDir; + viewPosition = (uView * vec4(modelPosition, 1.0)).xyz; + fragmentDepth = calcDepth(viewPosition); + #if defined(dClipVariant_pixel) && dClipObjectCount != 0 + if (clipTest(vec4(modelPosition, 0.0))) { + objectClipped = true; + fragmentDepth = -1.0; + #ifdef dSolidInterior + topCap = !topInterior; + bottomCap = !bottomInterior; + #endif + } + #endif + if (fragmentDepth > 0.0) { + #ifdef dSolidInterior + if (interior) cameraNormal = -rayDir; + #endif + return true; + } + } + } else if (bottomCap && y >= 0.0) { + // bottom cap + t = (baba - baoc) / bard; + if (abs(k1 + k2 * t) < h) { + interior = bottomInterior; + cameraNormal = ba / baba; + modelPosition = rayOrigin + t * rayDir; + viewPosition = (uView * vec4(modelPosition, 1.0)).xyz; + fragmentDepth = calcDepth(viewPosition); + #if defined(dClipVariant_pixel) && dClipObjectCount != 0 + if (clipTest(vec4(modelPosition, 0.0))) { + objectClipped = true; + fragmentDepth = -1.0; + #ifdef dSolidInterior + topCap = !topInterior; + bottomCap = !bottomInterior; + #endif + } + #endif + if (fragmentDepth > 0.0) { + #ifdef dSolidInterior + if (interior) cameraNormal = -rayDir; + #endif + return true; + } + } } } - if (uDoubleSided) { + if (uDoubleSided || solidInterior) { // body inside h = -h; t = (-k1 - h) / k2; @@ -116,8 +165,10 @@ bool CylinderImpostor( fragmentDepth = calcDepth(viewPosition); if (fragmentDepth > 0.0) { #ifdef dSolidInterior - fragmentDepth = 0.0 + (0.0000001 / vSize); - cameraNormal = -rayDir; + if (!objectClipped) { + fragmentDepth = 0.0 + (0.0000002 / vSize); + cameraNormal = -rayDir; + } #endif return true; } @@ -134,8 +185,10 @@ bool CylinderImpostor( fragmentDepth = calcDepth(viewPosition); if (fragmentDepth > 0.0) { #ifdef dSolidInterior - fragmentDepth = 0.0 + (0.0000001 / vSize); - cameraNormal = -rayDir; + if (!objectClipped) { + fragmentDepth = 0.0 + (0.0000002 / vSize); + cameraNormal = -rayDir; + } #endif return true; } @@ -151,8 +204,10 @@ bool CylinderImpostor( fragmentDepth = calcDepth(viewPosition); if (fragmentDepth > 0.0) { #ifdef dSolidInterior - fragmentDepth = 0.0 + (0.0000001 / vSize); - cameraNormal = -rayDir; + if (!objectClipped) { + fragmentDepth = 0.0 + (0.0000002 / vSize); + cameraNormal = -rayDir; + } #endif return true; } diff --git a/src/mol-gl/shader/cylinders.vert.ts b/src/mol-gl/shader/cylinders.vert.ts index f9d1a0694409d57700e7624388b495217b119538..60b3f19328854456f0fdfccfbd6b985d29f0b8c6 100644 --- a/src/mol-gl/shader/cylinders.vert.ts +++ b/src/mol-gl/shader/cylinders.vert.ts @@ -57,10 +57,6 @@ void main() { // ensure cylinder 'dir' is pointing towards the camera if(dot(camDir, dir) < 0.0) { dir = -dir; - // TODO: revisit - // vec3 tmp = vStart; - // vStart = vEnd; - // vEnd = tmp; } vec3 left = cross(camDir, dir); diff --git a/src/mol-gl/shader/spheres.frag.ts b/src/mol-gl/shader/spheres.frag.ts index 9af2d9d39b2f81ce8fc3e20e0b653d19f282d6f3..9eaf356c7fd1ec4ecc0d0bddbab6d99059150e8c 100644 --- a/src/mol-gl/shader/spheres.frag.ts +++ b/src/mol-gl/shader/spheres.frag.ts @@ -23,7 +23,13 @@ varying float vRadiusSq; varying vec3 vPoint; varying vec3 vPointViewPosition; -bool SphereImpostor(out vec3 modelPos, out vec3 cameraPos, out vec3 cameraNormal, out bool interior, out float fragmentDepth, out bool clipped){ +#ifdef dSolidInterior + const bool solidInterior = true; +#else + const bool solidInterior = false; +#endif + +bool SphereImpostor(out vec3 modelPos, out vec3 cameraPos, out vec3 cameraNormal, out bool interior, out float fragmentDepth){ vec3 cameraSpherePos = -vPointViewPosition; vec3 rayOrigin = mix(vec3(0.0, 0.0, 0.0), vPoint, uIsOrtho); @@ -43,9 +49,11 @@ bool SphereImpostor(out vec3 modelPos, out vec3 cameraPos, out vec3 cameraNormal modelPos = (uInvView * vec4(cameraPos, 1.0)).xyz; fragmentDepth = calcDepth(cameraPos); + bool objectClipped = false; + #if defined(dClipVariant_pixel) && dClipObjectCount != 0 if (clipTest(vec4(modelPos, 0.0))) { - clipped = true; + objectClipped = true; fragmentDepth = -1.0; } #endif @@ -54,12 +62,18 @@ bool SphereImpostor(out vec3 modelPos, out vec3 cameraPos, out vec3 cameraNormal cameraNormal = normalize(cameraPos - cameraSpherePos); interior = false; return true; - } else if (uDoubleSided) { + } else if (uDoubleSided || solidInterior) { cameraPos = rayDirection * posT + rayOrigin; modelPos = (uInvView * vec4(cameraPos, 1.0)).xyz; fragmentDepth = calcDepth(cameraPos); cameraNormal = -normalize(cameraPos - cameraSpherePos); interior = true; + #ifdef dSolidInterior + if (!objectClipped) { + fragmentDepth = 0.0 + (0.0000001 / vRadius); + cameraNormal = -mix(normalize(vPoint), vec3(0.0, 0.0, 1.0), uIsOrtho); + } + #endif return true; } @@ -72,7 +86,7 @@ void main(void){ vec3 cameraNormal; float fragmentDepth; bool clipped = false; - bool hit = SphereImpostor(modelPos, cameraPos, cameraNormal, interior, fragmentDepth, clipped); + bool hit = SphereImpostor(modelPos, cameraPos, cameraNormal, interior, fragmentDepth); if (!hit) discard; if (fragmentDepth < 0.0) discard; @@ -81,13 +95,6 @@ void main(void){ vec3 vViewPosition = cameraPos; vec3 vModelPosition = modelPos; - #ifdef dSolidInterior - if (interior && !clipped) { - fragmentDepth = 0.0 + (0.0000001 / vRadius); - cameraNormal = -mix(normalize(vPoint), vec3(0.0, 0.0, 1.0), uIsOrtho); - } - #endif - gl_FragDepthEXT = fragmentDepth; #include clip_pixel