Browse Source

Merge pull request #863 from molstar/approx-spheres

add approximate option for spheres rendering
Alexander Rose 1 year ago
parent
commit
1afea8a86a

+ 1 - 0
CHANGELOG.md

@@ -10,6 +10,7 @@ Note that since we don't clearly distinguish between a public and private interf
 - Add 'NH2', 'FOR', 'FMT' to `CommonProteinCaps`
 - Add `opened` event to `PluginStateSnapshotManager`
 - Properly switch-off fog
+- Add `approximate` option for spheres rendering
 - Reduce `Spheres` memory usage
     - Derive mapping from VertexID
     - Pull position and group from texture

+ 3 - 0
src/mol-geo/geometry/spheres/spheres.ts

@@ -129,6 +129,7 @@ export namespace Spheres {
         xrayShaded: PD.Select<boolean | 'inverted'>(false, [[false, 'Off'], [true, 'On'], ['inverted', 'Inverted']], BaseGeometry.ShadingCategory),
         transparentBackfaces: PD.Select('off', PD.arrayToOptions(['off', 'on', 'opaque']), BaseGeometry.ShadingCategory),
         solidInterior: PD.Boolean(true, BaseGeometry.ShadingCategory),
+        approximate: PD.Boolean(false, { ...BaseGeometry.ShadingCategory, description: 'Faster rendering, but has artifacts.' }),
         bumpFrequency: PD.Numeric(0, { min: 0, max: 10, step: 0.1 }, BaseGeometry.ShadingCategory),
         bumpAmplitude: PD.Numeric(1, { min: 0, max: 5, step: 0.1 }, BaseGeometry.ShadingCategory),
     };
@@ -214,6 +215,7 @@ export namespace Spheres {
             dXrayShaded: ValueCell.create(props.xrayShaded === 'inverted' ? 'inverted' : props.xrayShaded === true ? 'on' : 'off'),
             dTransparentBackfaces: ValueCell.create(props.transparentBackfaces),
             dSolidInterior: ValueCell.create(props.solidInterior),
+            dApproximate: ValueCell.create(props.approximate),
             uBumpFrequency: ValueCell.create(props.bumpFrequency),
             uBumpAmplitude: ValueCell.create(props.bumpAmplitude),
 
@@ -236,6 +238,7 @@ export namespace Spheres {
         ValueCell.updateIfChanged(values.dXrayShaded, props.xrayShaded === 'inverted' ? 'inverted' : props.xrayShaded === true ? 'on' : 'off');
         ValueCell.updateIfChanged(values.dTransparentBackfaces, props.transparentBackfaces);
         ValueCell.updateIfChanged(values.dSolidInterior, props.solidInterior);
+        ValueCell.updateIfChanged(values.dApproximate, props.approximate);
         ValueCell.updateIfChanged(values.uBumpFrequency, props.bumpFrequency);
         ValueCell.updateIfChanged(values.uBumpAmplitude, props.bumpAmplitude);
     }

+ 1 - 0
src/mol-gl/renderable/spheres.ts

@@ -24,6 +24,7 @@ export const SpheresSchema = {
     dXrayShaded: DefineSpec('string', ['off', 'on', 'inverted']),
     dTransparentBackfaces: DefineSpec('string', ['off', 'on', 'opaque']),
     dSolidInterior: DefineSpec('boolean'),
+    dApproximate: DefineSpec('boolean'),
     uBumpFrequency: UniformSpec('f', 'material'),
     uBumpAmplitude: UniformSpec('f', 'material'),
 

+ 1 - 1
src/mol-gl/shader/chunks/common-clip.glsl.ts

@@ -65,7 +65,7 @@ export const common_clip = `
 
     #if __VERSION__ == 100
         // 8-bit
-        int bitwiseAnd(const in int a, const in int b) {
+        int bitwiseAnd(in int a, in int b) {
             int d = 128;
             int result = 0;
             for (int i = 0; i < 8; ++i) {

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

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2019-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ * Copyright (c) 2019-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
@@ -19,7 +19,6 @@ precision highp int;
 uniform mat4 uInvView;
 
 varying float vRadius;
-varying float vRadiusSq;
 varying vec3 vPoint;
 varying vec3 vPointViewPosition;
 
@@ -37,7 +36,7 @@ bool SphereImpostor(out vec3 modelPos, out vec3 cameraPos, out vec3 cameraNormal
     vec3 cameraSphereDir = mix(cameraSpherePos, rayOrigin - cameraSpherePos, uIsOrtho);
 
     float B = dot(rayDirection, cameraSphereDir);
-    float det = B * B + vRadiusSq - dot(cameraSphereDir, cameraSphereDir);
+    float det = B * B + vRadius * vRadius - dot(cameraSphereDir, cameraSphereDir);
 
     if (det < 0.0) return false;
 
@@ -83,21 +82,34 @@ bool SphereImpostor(out vec3 modelPos, out vec3 cameraPos, out vec3 cameraNormal
 }
 
 void main(void){
-    vec3 modelPos;
-    vec3 cameraPos;
     vec3 cameraNormal;
     float fragmentDepth;
     bool clipped = false;
-    bool hit = SphereImpostor(modelPos, cameraPos, cameraNormal, interior, fragmentDepth);
-    if (!hit) discard;
 
-    if (fragmentDepth < 0.0) discard;
-    if (fragmentDepth > 1.0) discard;
+    #ifdef dApproximate
+        vec3 pointDir = -vPointViewPosition - vPoint;
+        if (dot(pointDir, pointDir) > vRadius * vRadius) discard;
+        vec3 vViewPosition = -vPointViewPosition;
+        fragmentDepth = gl_FragCoord.z;
+        #ifndef dIgnoreLight
+            pointDir.z -= cos(length(pointDir) / vRadius);
+            cameraNormal = -normalize(pointDir / vRadius);
+        #endif
+        interior = false;
+    #else
+        vec3 modelPos;
+        vec3 cameraPos;
+        bool hit = SphereImpostor(modelPos, cameraPos, cameraNormal, interior, fragmentDepth);
+        if (!hit) discard;
 
-    vec3 vViewPosition = cameraPos;
-    vec3 vModelPosition = modelPos;
+        if (fragmentDepth < 0.0) discard;
+        if (fragmentDepth > 1.0) discard;
 
-    gl_FragDepthEXT = fragmentDepth;
+        gl_FragDepthEXT = fragmentDepth;
+
+        vec3 vModelPosition = modelPos;
+        vec3 vViewPosition = cameraPos;
+    #endif
 
     #include clip_pixel
     #include assign_material_color

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

@@ -25,7 +25,6 @@ attribute mat4 aTransform;
 attribute float aInstance;
 
 varying float vRadius;
-varying float vRadiusSq;
 varying vec3 vPoint;
 varying vec3 vPointViewPosition;
 
@@ -102,10 +101,15 @@ void main(void){
     vec4 position4 = vec4(position, 1.0);
     vec4 mvPosition = uModelView * aTransform * position4;
 
-    gl_Position = uProjection * vec4(mvPosition.xyz, 1.0);
-    quadraticProjection(size, position, mapping);
+    #ifdef dApproximate
+        vec4 mvCorner = vec4(mvPosition.xyz, 1.0);
+        mvCorner.xy += mapping * vRadius;
+        gl_Position = uProjection * mvCorner;
+    #else
+        gl_Position = uProjection * vec4(mvPosition.xyz, 1.0);
+        quadraticProjection(vRadius, position, mapping);
+    #endif
 
-    vRadiusSq = vRadius * vRadius;
     vec4 vPoint4 = uInvProjection * gl_Position;
     vPoint = vPoint4.xyz / vPoint4.w;
     vPointViewPosition = -mvPosition.xyz / mvPosition.w;