瀏覽代碼

improve impostor shaders

- fix sphere near-clipping with orthographic projection
- fix cylinder near-clipping
- add interior cylinder caps
Alexander Rose 2 年之前
父節點
當前提交
601bd5ba7a

+ 4 - 0
CHANGELOG.md

@@ -8,6 +8,10 @@ Note that since we don't clearly distinguish between a public and private interf
 
 
 - Fix 'once' for animations of systems with many frames
 - Fix 'once' for animations of systems with many frames
 - Better guard against issue (black fringes) with bumpiness in impostors
 - Better guard against issue (black fringes) with bumpiness in impostors
+- Improve impostor shaders
+    - Fix sphere near-clipping with orthographic projection
+    - Fix cylinder near-clipping
+    - Add interior cylinder caps
 
 
 ## [v3.26.0] - 2022-12-04
 ## [v3.26.0] - 2022-12-04
 
 

+ 46 - 19
src/mol-gl/shader/cylinders.frag.ts

@@ -33,7 +33,8 @@ uniform mat4 uInvView;
 bool CylinderImpostor(
 bool CylinderImpostor(
     in vec3 rayOrigin, in vec3 rayDir,
     in vec3 rayOrigin, in vec3 rayDir,
     in vec3 start, in vec3 end, in float radius,
     in vec3 start, in vec3 end, in float radius,
-    out vec4 intersection, out bool interior
+    out vec3 cameraNormal, out bool interior,
+    out vec3 viewPosition, out float fragmentDepth
 ){
 ){
     vec3 ba = end - start;
     vec3 ba = end - start;
     vec3 oc = rayOrigin - start;
     vec3 oc = rayOrigin - start;
@@ -42,7 +43,7 @@ bool CylinderImpostor(
     float bard = dot(ba, rayDir);
     float bard = dot(ba, rayDir);
     float baoc = dot(ba, oc);
     float baoc = dot(ba, oc);
 
 
-    float k2 = baba - bard*bard;
+    float k2 = baba - bard * bard;
     float k1 = baba * dot(oc, rayDir) - baoc * bard;
     float k1 = baba * dot(oc, rayDir) - baoc * bard;
     float k0 = baba * dot(oc, oc) - baoc * baoc - radius * radius * baba;
     float k0 = baba * dot(oc, oc) - baoc * baoc - radius * radius * baba;
 
 
@@ -58,8 +59,10 @@ bool CylinderImpostor(
     float y = baoc + t * bard;
     float y = baoc + t * bard;
     if (y > 0.0 && y < baba) {
     if (y > 0.0 && y < baba) {
         interior = false;
         interior = false;
-        intersection = vec4(t, (oc + t * rayDir - ba * y / baba) / radius);
-        return true;
+        cameraNormal = (oc + t * rayDir - ba * y / baba) / radius;
+        viewPosition = (uView * vec4(rayOrigin + t * rayDir, 1.0)).xyz;
+        fragmentDepth = calcDepth(viewPosition);
+        if (fragmentDepth > 0.0) return true;
     }
     }
 
 
     if (topCap && y < 0.0) {
     if (topCap && y < 0.0) {
@@ -67,16 +70,20 @@ bool CylinderImpostor(
         t = -baoc / bard;
         t = -baoc / bard;
         if (abs(k1 + k2 * t) < h) {
         if (abs(k1 + k2 * t) < h) {
             interior = false;
             interior = false;
-            intersection = vec4(t, ba * sign(y) / baba);
-            return true;
+            cameraNormal = -ba / baba;
+            viewPosition = (uView * vec4(rayOrigin + t * rayDir, 1.0)).xyz;
+            fragmentDepth = calcDepth(viewPosition);
+            if (fragmentDepth > 0.0) return true;
         }
         }
     } else if(bottomCap && y >= 0.0) {
     } else if(bottomCap && y >= 0.0) {
         // bottom cap
         // bottom cap
         t = (baba - baoc) / bard;
         t = (baba - baoc) / bard;
         if (abs(k1 + k2 * t) < h) {
         if (abs(k1 + k2 * t) < h) {
             interior = false;
             interior = false;
-            intersection = vec4(t, ba * sign(y) / baba);
-            return true;
+            cameraNormal = ba / baba;
+            viewPosition = (uView * vec4(rayOrigin + t * rayDir, 1.0)).xyz;
+            fragmentDepth = calcDepth(viewPosition);
+            if (fragmentDepth > 0.0) return true;
         }
         }
     }
     }
 
 
@@ -87,11 +94,33 @@ bool CylinderImpostor(
         y = baoc + t * bard;
         y = baoc + t * bard;
         if (y > 0.0 && y < baba) {
         if (y > 0.0 && y < baba) {
             interior = true;
             interior = true;
-            intersection = vec4(t, (oc + t * rayDir - ba * y / baba) / radius);
+            cameraNormal = -(oc + t * rayDir - ba * y / baba) / radius;
+            viewPosition = (uView * vec4(rayOrigin + t * rayDir, 1.0)).xyz;
+            fragmentDepth = calcDepth(viewPosition);
             return true;
             return true;
         }
         }
 
 
-        // TODO: handle inside caps???
+        if (topCap && y < 0.0) {
+            // top cap
+            t = -baoc / bard;
+            if (abs(k1 + k2 * t) < -h) {
+                interior = true;
+                cameraNormal = ba / baba;
+                viewPosition = (uView * vec4(rayOrigin + t * rayDir, 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 = true;
+                cameraNormal = -ba / baba;
+                viewPosition = (uView * vec4(rayOrigin + t * rayDir, 1.0)).xyz;
+                fragmentDepth = calcDepth(viewPosition);
+                if (fragmentDepth > 0.0) return true;
+            }
+        }
     }
     }
 
 
     return false;
     return false;
@@ -100,23 +129,21 @@ bool CylinderImpostor(
 void main() {
 void main() {
     #include clip_pixel
     #include clip_pixel
 
 
+    vec3 rayOrigin = vModelPosition;
     vec3 rayDir = mix(normalize(vModelPosition - uCameraPosition), uCameraDir, uIsOrtho);
     vec3 rayDir = mix(normalize(vModelPosition - uCameraPosition), uCameraDir, uIsOrtho);
 
 
-    vec4 intersection;
-    bool interior;
-    bool hit = CylinderImpostor(vModelPosition, rayDir, vStart, vEnd, vSize, intersection, interior);
+    vec3 cameraNormal;
+    vec3 viewPosition;
+    float fragmentDepth;
+    bool hit = CylinderImpostor(rayOrigin, rayDir, vStart, vEnd, vSize, cameraNormal, interior, viewPosition, fragmentDepth);
     if (!hit) discard;
     if (!hit) discard;
 
 
-    vec3 vViewPosition = vModelPosition + intersection.x * rayDir;
-    vViewPosition = (uView * vec4(vViewPosition, 1.0)).xyz;
-    float fragmentDepth = calcDepth(vViewPosition);
-
     if (fragmentDepth < 0.0) discard;
     if (fragmentDepth < 0.0) discard;
     if (fragmentDepth > 1.0) discard;
     if (fragmentDepth > 1.0) discard;
 
 
     gl_FragDepthEXT = fragmentDepth;
     gl_FragDepthEXT = fragmentDepth;
 
 
-    vec3 vModelPosition = (uInvView * vec4(vViewPosition, 1.0)).xyz;
+    vec3 vModelPosition = (uInvView * vec4(viewPosition, 1.0)).xyz;
     #include assign_material_color
     #include assign_material_color
 
 
     #if defined(dRenderVariant_pick)
     #if defined(dRenderVariant_pick)
@@ -135,7 +162,7 @@ void main() {
         gl_FragColor = material;
         gl_FragColor = material;
     #elif defined(dRenderVariant_color)
     #elif defined(dRenderVariant_color)
         mat3 normalMatrix = transpose3(inverse3(mat3(uView)));
         mat3 normalMatrix = transpose3(inverse3(mat3(uView)));
-        vec3 normal = normalize(normalMatrix * -normalize(intersection.yzw));
+        vec3 normal = normalize(normalMatrix * -normalize(cameraNormal));
         #include apply_light_color
         #include apply_light_color
 
 
         #include apply_interior_color
         #include apply_interior_color

+ 4 - 1
src/mol-gl/shader/cylinders.vert.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 Alexander Rose <alexander.rose@weirdbyte.de>
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
  */
@@ -69,6 +69,9 @@ void main() {
     vViewPosition = mvPosition.xyz;
     vViewPosition = mvPosition.xyz;
     gl_Position = uProjection * mvPosition;
     gl_Position = uProjection * mvPosition;
 
 
+    mvPosition.z -= 2.0 * (length(vEnd - vStart) + vSize); // avoid clipping
+    gl_Position.z = (uProjection * mvPosition).z;
+
     #include clip_instance
     #include clip_instance
 }
 }
 `;
 `;

+ 24 - 28
src/mol-gl/shader/spheres.frag.ts

@@ -23,12 +23,8 @@ varying float vRadiusSq;
 varying vec3 vPoint;
 varying vec3 vPoint;
 varying vec3 vPointViewPosition;
 varying vec3 vPointViewPosition;
 
 
-vec3 cameraPos;
-vec3 cameraNormal;
-
-bool Impostor(out vec3 cameraPos, out vec3 cameraNormal){
+bool SphereImpostor(out vec3 cameraPos, out vec3 cameraNormal, out bool interior, out float fragmentDepth){
     vec3 cameraSpherePos = -vPointViewPosition;
     vec3 cameraSpherePos = -vPointViewPosition;
-    cameraSpherePos.z += vRadius;
 
 
     vec3 rayOrigin = mix(vec3(0.0, 0.0, 0.0), vPoint, uIsOrtho);
     vec3 rayOrigin = mix(vec3(0.0, 0.0, 0.0), vPoint, uIsOrtho);
     vec3 rayDirection = mix(normalize(vPoint), vec3(0.0, 0.0, 1.0), uIsOrtho);
     vec3 rayDirection = mix(normalize(vPoint), vec3(0.0, 0.0, 1.0), uIsOrtho);
@@ -37,49 +33,49 @@ bool Impostor(out vec3 cameraPos, out vec3 cameraNormal){
     float B = dot(rayDirection, cameraSphereDir);
     float B = dot(rayDirection, cameraSphereDir);
     float det = B * B + vRadiusSq - dot(cameraSphereDir, cameraSphereDir);
     float det = B * B + vRadiusSq - dot(cameraSphereDir, cameraSphereDir);
 
 
-    if (det < 0.0){
-        discard;
-        return false;
-    }
+    if (det < 0.0) return false;
 
 
     float sqrtDet = sqrt(det);
     float sqrtDet = sqrt(det);
-    float posT = mix(B + sqrtDet, B + sqrtDet, uIsOrtho);
-    float negT = mix(B - sqrtDet, sqrtDet - B, uIsOrtho);
+    float posT = mix(B + sqrtDet, B - sqrtDet, uIsOrtho);
+    float negT = mix(B - sqrtDet, B + sqrtDet, uIsOrtho);
 
 
     cameraPos = rayDirection * negT + rayOrigin;
     cameraPos = rayDirection * negT + rayOrigin;
+    fragmentDepth = calcDepth(cameraPos);
 
 
-    if (calcDepth(cameraPos) <= 0.0) {
+    if (fragmentDepth > 0.0) {
+        cameraNormal = normalize(cameraPos - cameraSpherePos);
+        interior = false;
+        return true;
+    } else if (uDoubleSided) {
         cameraPos = rayDirection * posT + rayOrigin;
         cameraPos = rayDirection * posT + rayOrigin;
+        fragmentDepth = calcDepth(cameraPos);
+        cameraNormal = -normalize(cameraPos - cameraSpherePos);
         interior = true;
         interior = true;
-    } else {
-        interior = false;
+        return true;
     }
     }
 
 
-    cameraNormal = normalize(cameraPos - cameraSpherePos);
-    cameraNormal *= float(!interior) * 2.0 - 1.0;
-
-    return !interior;
+    return false;
 }
 }
 
 
 void main(void){
 void main(void){
     #include clip_pixel
     #include clip_pixel
 
 
-    bool flag = Impostor(cameraPos, cameraNormal);
-    if (!uDoubleSided) {
-        if (interior) discard;
-    }
-
-    vec3 vViewPosition = cameraPos;
-    float fragmentDepth = calcDepth(vViewPosition);
-    if (!flag && fragmentDepth >= 0.0) {
-        fragmentDepth = 0.0 + (0.0000001 / vRadius);
-    }
+    vec3 cameraPos;
+    vec3 cameraNormal;
+    float fragmentDepth;
+    bool hit = SphereImpostor(cameraPos, cameraNormal, interior, fragmentDepth);
+    if (!hit) discard;
 
 
     if (fragmentDepth < 0.0) discard;
     if (fragmentDepth < 0.0) discard;
     if (fragmentDepth > 1.0) discard;
     if (fragmentDepth > 1.0) discard;
 
 
+    if (interior && fragmentDepth >= 0.0) {
+        fragmentDepth = 0.0 + (0.0000001 / vRadius);
+    }
+
     gl_FragDepthEXT = fragmentDepth;
     gl_FragDepthEXT = fragmentDepth;
 
 
+    vec3 vViewPosition = cameraPos;
     vec3 vModelPosition = (uInvView * vec4(vViewPosition, 1.0)).xyz;
     vec3 vModelPosition = (uInvView * vec4(vViewPosition, 1.0)).xyz;
     #include assign_material_color
     #include assign_material_color
 
 

+ 4 - 2
src/mol-gl/shader/spheres.vert.ts

@@ -1,5 +1,5 @@
 /**
 /**
- * Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
  */
@@ -85,7 +85,6 @@ void main(void){
 
 
     vec4 position4 = vec4(aPosition, 1.0);
     vec4 position4 = vec4(aPosition, 1.0);
     vec4 mvPosition = uModelView * aTransform * position4;
     vec4 mvPosition = uModelView * aTransform * position4;
-    mvPosition.z -= vRadius; // avoid clipping, added again in fragment shader
 
 
     gl_Position = uProjection * vec4(mvPosition.xyz, 1.0);
     gl_Position = uProjection * vec4(mvPosition.xyz, 1.0);
     quadraticProjection(size, aPosition);
     quadraticProjection(size, aPosition);
@@ -97,6 +96,9 @@ void main(void){
 
 
     vModelPosition = (uModel * aTransform * position4).xyz; // for clipping in frag shader
     vModelPosition = (uModel * aTransform * position4).xyz; // for clipping in frag shader
 
 
+    mvPosition.z -= 2.0 * vRadius; // avoid clipping
+    gl_Position.z = (uProjection * vec4(mvPosition.xyz, 1.0)).z;
+
     #include clip_instance
     #include clip_instance
 }
 }
 `;
 `;