diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c92d6aa847ea0c626ca7e49a0ce603c1ca7fee3..f68cac2f00e2a0b32a0afeeb5e9f3316d6a5d9a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ Note that since we don't clearly distinguish between a public and private interf - Fix sphere near-clipping with orthographic projection - Fix cylinder near-clipping - Add interior cylinder caps + - Add per-pixel object clipping ## [v3.26.0] - 2022-12-04 diff --git a/src/mol-gl/shader/chunks/clip-instance.glsl.ts b/src/mol-gl/shader/chunks/clip-instance.glsl.ts index 8ea189e67d496c48338d12a6e61096c87ad38be5..644a5f6cc4118b35165bbf444ef14c5e1431da2f 100644 --- a/src/mol-gl/shader/chunks/clip-instance.glsl.ts +++ b/src/mol-gl/shader/chunks/clip-instance.glsl.ts @@ -1,12 +1,7 @@ export const clip_instance = ` #if defined(dClipVariant_instance) && dClipObjectCount != 0 - int flag = 0; - #if defined(dClipping) - flag = int(floor(vClipping * 255.0 + 0.5)); - #endif - vec4 mCenter = uModel * aTransform * vec4(uInvariantBoundingSphere.xyz, 1.0); - if (clipTest(vec4(mCenter.xyz, uInvariantBoundingSphere.w), flag)) + if (clipTest(vec4(mCenter.xyz, uInvariantBoundingSphere.w))) // move out of [ -w, +w ] to 'discard' in vert shader gl_Position.z = 2.0 * gl_Position.w; #endif diff --git a/src/mol-gl/shader/chunks/clip-pixel.glsl.ts b/src/mol-gl/shader/chunks/clip-pixel.glsl.ts index dbec0f552ff752b95f7cb66f487cace69f104c22..84d90332819318dffe0dc74576459a6c2da57db4 100644 --- a/src/mol-gl/shader/chunks/clip-pixel.glsl.ts +++ b/src/mol-gl/shader/chunks/clip-pixel.glsl.ts @@ -1,12 +1,6 @@ export const clip_pixel = ` #if defined(dClipVariant_pixel) && dClipObjectCount != 0 - #if defined(dClipping) - int clippingFlag = int(floor(vClipping * 255.0 + 0.5)); - #else - int clippingFlag = 0; - #endif - - if (clipTest(vec4(vModelPosition, 0.0), clippingFlag)) + if (clipTest(vec4(vModelPosition, 0.0))) discard; #endif `; \ No newline at end of file diff --git a/src/mol-gl/shader/chunks/common-clip.glsl.ts b/src/mol-gl/shader/chunks/common-clip.glsl.ts index 5bca9dec16e2dd3069af86b7316f00813fda279e..31e759128efcf77973899e89319e80658540f614 100644 --- a/src/mol-gl/shader/chunks/common-clip.glsl.ts +++ b/src/mol-gl/shader/chunks/common-clip.glsl.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2020-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Ludovic Autin <autin@scripps.edu> * @author Alexander Rose <alexander.rose@weirdbyte.de> @@ -7,45 +7,45 @@ export const common_clip = ` #if dClipObjectCount != 0 - vec3 quaternionTransform(vec4 q, vec3 v) { + vec3 quaternionTransform(const in vec4 q, const in vec3 v) { vec3 t = 2.0 * cross(q.xyz, v); return v + q.w * t + cross(q.xyz, t); } - vec4 computePlane(vec3 normal, vec3 inPoint) { + vec4 computePlane(const in vec3 normal, const in vec3 inPoint) { return vec4(normalize(normal), -dot(normal, inPoint)); } - float planeSD(vec4 plane, vec3 center) { + float planeSD(const in vec4 plane, const in vec3 center) { return -dot(plane.xyz, center - plane.xyz * -plane.w); } - float sphereSD(vec3 position, vec4 rotation, vec3 size, vec3 center) { + float sphereSD(const in vec3 position, const in vec4 rotation, const in vec3 size, const in vec3 center) { return ( length(quaternionTransform(vec4(-rotation.x, -rotation.y, -rotation.z, rotation.w), center - position) / size) - 1.0 ) * min(min(size.x, size.y), size.z); } - float cubeSD(vec3 position, vec4 rotation, vec3 size, vec3 center) { + float cubeSD(const in vec3 position, const in vec4 rotation, const in vec3 size, const in vec3 center) { vec3 d = abs(quaternionTransform(vec4(-rotation.x, -rotation.y, -rotation.z, rotation.w), center - position)) - size; return min(max(d.x, max(d.y, d.z)), 0.0) + length(max(d, 0.0)); } - float cylinderSD(vec3 position, vec4 rotation, vec3 size, vec3 center) { + float cylinderSD(const in vec3 position, const in vec4 rotation, const in vec3 size, const in vec3 center) { vec3 t = quaternionTransform(vec4(-rotation.x, -rotation.y, -rotation.z, rotation.w), center - position); vec2 d = abs(vec2(length(t.xz), t.y)) - size.xy; return min(max(d.x, d.y), 0.0) + length(max(d, 0.0)); } - float infiniteConeSD(vec3 position, vec4 rotation, vec3 size, vec3 center) { + float infiniteConeSD(const in vec3 position, const in vec4 rotation, const in vec3 size, const in vec3 center) { vec3 t = quaternionTransform(vec4(-rotation.x, -rotation.y, -rotation.z, rotation.w), center - position); float q = length(t.xy); return dot(size.xy, vec2(q, t.z)); } - float getSignedDistance(vec3 center, int type, vec3 position, vec4 rotation, vec3 scale) { + float getSignedDistance(const in vec3 center, const in int type, const in vec3 position, const in vec4 rotation, const in vec3 scale) { if (type == 1) { vec3 normal = quaternionTransform(rotation, vec3(0.0, 1.0, 0.0)); vec4 plane = computePlane(normal, position); @@ -65,7 +65,7 @@ export const common_clip = ` #if __VERSION__ == 100 // 8-bit - int bitwiseAnd(int a, int b) { + int bitwiseAnd(const in int a, const in int b) { int d = 128; int result = 0; for (int i = 0; i < 8; ++i) { @@ -78,17 +78,23 @@ export const common_clip = ` return result; } - bool hasBit(int mask, int bit) { + bool hasBit(const in int mask, const in int bit) { return bitwiseAnd(mask, bit) == 0; } #else - bool hasBit(int mask, int bit) { + bool hasBit(const in int mask, const in int bit) { return (mask & bit) == 0; } #endif - // flag is a bit-flag for clip-objects to ignore (note, object ids start at 1 not 0) - bool clipTest(vec4 sphere, int flag) { + bool clipTest(const in vec4 sphere) { + // flag is a bit-flag for clip-objects to ignore (note, object ids start at 1 not 0) + #if defined(dClipping) + int flag = int(floor(vClipping * 255.0 + 0.5)); + #else + int flag = 0; + #endif + #pragma unroll_loop_start for (int i = 0; i < dClipObjectCount; ++i) { if (flag == 0 || hasBit(flag, UNROLLED_LOOP_INDEX + 1)) { diff --git a/src/mol-gl/shader/cylinders.frag.ts b/src/mol-gl/shader/cylinders.frag.ts index 7752742553bde109926043e12a996247a6dde2e1..f41e64f80059d986c5c7312076d5c8d62ee24f9c 100644 --- a/src/mol-gl/shader/cylinders.frag.ts +++ b/src/mol-gl/shader/cylinders.frag.ts @@ -34,7 +34,7 @@ bool CylinderImpostor( in vec3 rayOrigin, in vec3 rayDir, in vec3 start, in vec3 end, in float radius, out vec3 cameraNormal, out bool interior, - out vec3 viewPosition, out float fragmentDepth + out vec3 modelPosition, out vec3 viewPosition, out float fragmentDepth ){ vec3 ba = end - start; vec3 oc = rayOrigin - start; @@ -60,8 +60,12 @@ bool CylinderImpostor( if (y > 0.0 && y < baba) { interior = false; cameraNormal = (oc + t * rayDir - ba * y / baba) / radius; - viewPosition = (uView * vec4(rayOrigin + t * rayDir, 1.0)).xyz; + 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))) fragmentDepth = -1.0; + #endif if (fragmentDepth > 0.0) return true; } @@ -71,7 +75,8 @@ bool CylinderImpostor( if (abs(k1 + k2 * t) < h) { interior = false; cameraNormal = -ba / baba; - viewPosition = (uView * vec4(rayOrigin + t * rayDir, 1.0)).xyz; + modelPosition = rayOrigin + t * rayDir; + viewPosition = (uView * vec4(modelPosition, 1.0)).xyz; fragmentDepth = calcDepth(viewPosition); if (fragmentDepth > 0.0) return true; } @@ -81,7 +86,8 @@ bool CylinderImpostor( if (abs(k1 + k2 * t) < h) { interior = false; cameraNormal = ba / baba; - viewPosition = (uView * vec4(rayOrigin + t * rayDir, 1.0)).xyz; + modelPosition = rayOrigin + t * rayDir; + viewPosition = (uView * vec4(modelPosition, 1.0)).xyz; fragmentDepth = calcDepth(viewPosition); if (fragmentDepth > 0.0) return true; } @@ -95,7 +101,8 @@ bool CylinderImpostor( if (y > 0.0 && y < baba) { interior = true; cameraNormal = -(oc + t * rayDir - ba * y / baba) / radius; - viewPosition = (uView * vec4(rayOrigin + t * rayDir, 1.0)).xyz; + modelPosition = rayOrigin + t * rayDir; + viewPosition = (uView * vec4(modelPosition, 1.0)).xyz; fragmentDepth = calcDepth(viewPosition); return true; } @@ -106,7 +113,8 @@ bool CylinderImpostor( if (abs(k1 + k2 * t) < -h) { interior = true; cameraNormal = ba / baba; - viewPosition = (uView * vec4(rayOrigin + t * rayDir, 1.0)).xyz; + modelPosition = rayOrigin + t * rayDir; + viewPosition = (uView * vec4(modelPosition, 1.0)).xyz; fragmentDepth = calcDepth(viewPosition); if (fragmentDepth > 0.0) return true; } @@ -116,7 +124,8 @@ bool CylinderImpostor( if (abs(k1 + k2 * t) < -h) { interior = true; cameraNormal = -ba / baba; - viewPosition = (uView * vec4(rayOrigin + t * rayDir, 1.0)).xyz; + modelPosition = rayOrigin + t * rayDir; + viewPosition = (uView * vec4(modelPosition, 1.0)).xyz; fragmentDepth = calcDepth(viewPosition); if (fragmentDepth > 0.0) return true; } @@ -127,15 +136,14 @@ bool CylinderImpostor( } void main() { - #include clip_pixel - vec3 rayOrigin = vModelPosition; vec3 rayDir = mix(normalize(vModelPosition - uCameraPosition), uCameraDir, uIsOrtho); vec3 cameraNormal; + vec3 modelPosition; vec3 viewPosition; float fragmentDepth; - bool hit = CylinderImpostor(rayOrigin, rayDir, vStart, vEnd, vSize, cameraNormal, interior, viewPosition, fragmentDepth); + bool hit = CylinderImpostor(rayOrigin, rayDir, vStart, vEnd, vSize, cameraNormal, interior, modelPosition, viewPosition, fragmentDepth); if (!hit) discard; if (fragmentDepth < 0.0) discard; @@ -143,7 +151,10 @@ void main() { gl_FragDepthEXT = fragmentDepth; - vec3 vModelPosition = (uInvView * vec4(viewPosition, 1.0)).xyz; + vec3 vViewPosition = viewPosition; + vec3 vModelPosition = modelPosition; + + #include clip_pixel #include assign_material_color #if defined(dRenderVariant_pick) diff --git a/src/mol-gl/shader/direct-volume.frag.ts b/src/mol-gl/shader/direct-volume.frag.ts index f64cf9b3c7fa93f1604f9fa53ed6c24284465c34..ce61ae895fe13f54582e7b13008e026348e67392 100644 --- a/src/mol-gl/shader/direct-volume.frag.ts +++ b/src/mol-gl/shader/direct-volume.frag.ts @@ -229,7 +229,7 @@ vec4 raymarch(vec3 startLoc, vec3 step, vec3 rayDir) { #if defined(dClipVariant_pixel) && dClipObjectCount != 0 vec3 vModelPosition = v3m4(unitPos * uGridDim, modelTransform); - if (clipTest(vec4(vModelPosition, 0.0), 0)) { + if (clipTest(vec4(vModelPosition, 0.0))) { prevValue = value; pos += step; continue; diff --git a/src/mol-gl/shader/spheres.frag.ts b/src/mol-gl/shader/spheres.frag.ts index 55888215adb0bf946126f01777df352f04be21a0..7d5348d9563856df561e9ea7a965939e6302132b 100644 --- a/src/mol-gl/shader/spheres.frag.ts +++ b/src/mol-gl/shader/spheres.frag.ts @@ -23,7 +23,7 @@ varying float vRadiusSq; varying vec3 vPoint; varying vec3 vPointViewPosition; -bool SphereImpostor(out vec3 cameraPos, out vec3 cameraNormal, out bool interior, out float fragmentDepth){ +bool SphereImpostor(out vec3 modelPos, out vec3 cameraPos, out vec3 cameraNormal, out bool interior, out float fragmentDepth, out bool clipped){ vec3 cameraSpherePos = -vPointViewPosition; vec3 rayOrigin = mix(vec3(0.0, 0.0, 0.0), vPoint, uIsOrtho); @@ -40,14 +40,23 @@ bool SphereImpostor(out vec3 cameraPos, out vec3 cameraNormal, out bool interior float negT = mix(B - sqrtDet, B + sqrtDet, uIsOrtho); cameraPos = rayDirection * negT + rayOrigin; + modelPos = (uInvView * vec4(cameraPos, 1.0)).xyz; fragmentDepth = calcDepth(cameraPos); + #if defined(dClipVariant_pixel) && dClipObjectCount != 0 + if (clipTest(vec4(modelPos, 0.0))) { + clipped = true; + fragmentDepth = -1.0; + } + #endif + if (fragmentDepth > 0.0) { cameraNormal = normalize(cameraPos - cameraSpherePos); interior = false; return true; } else if (uDoubleSided) { cameraPos = rayDirection * posT + rayOrigin; + modelPos = (uInvView * vec4(cameraPos, 1.0)).xyz; fragmentDepth = calcDepth(cameraPos); cameraNormal = -normalize(cameraPos - cameraSpherePos); interior = true; @@ -58,25 +67,27 @@ bool SphereImpostor(out vec3 cameraPos, out vec3 cameraNormal, out bool interior } void main(void){ - #include clip_pixel - + vec3 modelPos; vec3 cameraPos; vec3 cameraNormal; float fragmentDepth; - bool hit = SphereImpostor(cameraPos, cameraNormal, interior, fragmentDepth); + bool clipped = false; + bool hit = SphereImpostor(modelPos, cameraPos, cameraNormal, interior, fragmentDepth, clipped); if (!hit) discard; if (fragmentDepth < 0.0) discard; if (fragmentDepth > 1.0) discard; - if (interior) { + vec3 vViewPosition = cameraPos; + vec3 vModelPosition = modelPos; + + if (interior && !clipped) { fragmentDepth = 0.0 + (0.0000001 / vRadius); } gl_FragDepthEXT = fragmentDepth; - vec3 vViewPosition = cameraPos; - vec3 vModelPosition = (uInvView * vec4(vViewPosition, 1.0)).xyz; + #include clip_pixel #include assign_material_color #if defined(dRenderVariant_pick)