From 6ecfd41cdb7a1c619b56ab6bcf4cb61e85d59667 Mon Sep 17 00:00:00 2001
From: Alexander Rose <alex.rose@rcsb.org>
Date: Mon, 13 May 2019 13:54:30 -0700
Subject: [PATCH] fix sphere impostors with orthographic camera

---
 src/mol-canvas3d/camera.ts             |  6 ++---
 src/mol-canvas3d/canvas3d.ts           |  6 ++---
 src/mol-gl/renderable/schema.ts        |  3 +++
 src/mol-gl/renderer.ts                 |  7 ++++++
 src/mol-gl/shader/spheres.frag         | 35 +++++++++++---------------
 src/mol-gl/shader/spheres.vert         | 17 +------------
 src/mol-math/linear-algebra/3d/mat4.ts |  2 +-
 7 files changed, 33 insertions(+), 43 deletions(-)

diff --git a/src/mol-canvas3d/camera.ts b/src/mol-canvas3d/camera.ts
index 6dbc0f8d9..bde9504bc 100644
--- a/src/mol-canvas3d/camera.ts
+++ b/src/mol-canvas3d/camera.ts
@@ -152,7 +152,7 @@ namespace Camera {
     /**
      * Sets an offseted view in a larger frustum. This is useful for
      * - multi-window or multi-monitor/multi-machine setups
-     * - jittering the camera position for 
+     * - jittering the camera position for
      */
     export interface ViewOffset {
         enabled: boolean,
@@ -183,9 +183,9 @@ namespace Camera {
 
             target: Vec3.create(0, 0, 0),
 
-            near: 0.1,
+            near: 1,
             far: 10000,
-            fogNear: 0.1,
+            fogNear: 1,
             fogFar: 10000,
 
             fov: Math.PI / 4,
diff --git a/src/mol-canvas3d/canvas3d.ts b/src/mol-canvas3d/canvas3d.ts
index e380a6142..06bab863c 100644
--- a/src/mol-canvas3d/canvas3d.ts
+++ b/src/mol-canvas3d/canvas3d.ts
@@ -130,7 +130,7 @@ namespace Canvas3D {
         const depthTexture = createTexture(webgl, 'image-depth', 'depth', 'ushort', 'nearest')
         depthTexture.define(canvas.width, canvas.height)
         depthTexture.attachFramebuffer(drawTarget.framebuffer, 'depth')
-        
+
         const postprocessingTarget = createRenderTarget(webgl, canvas.width, canvas.height)
         const postprocessing = getPostprocessingRenderable(webgl, drawTarget.texture, depthTexture, p.postprocessing)
 
@@ -272,7 +272,7 @@ namespace Canvas3D {
                     renderPostprocessing()
                 }
 
-                // compose draw with hold target
+                // compose rendered scene with hold target
                 composeTarget.bind()
                 gl.viewport(0, 0, canvas.width, canvas.height)
                 state.enable(gl.BLEND)
@@ -291,7 +291,7 @@ namespace Canvas3D {
             ValueCell.update(compose.values.uWeight, 1.0)
             ValueCell.update(compose.values.tColor, composeTarget.texture)
             compose.update()
-            
+
             webgl.unbindFramebuffer()
             gl.viewport(0, 0, canvas.width, canvas.height)
             state.disable(gl.BLEND)
diff --git a/src/mol-gl/renderable/schema.ts b/src/mol-gl/renderable/schema.ts
index cdc083cdb..492b5a513 100644
--- a/src/mol-gl/renderable/schema.ts
+++ b/src/mol-gl/renderable/schema.ts
@@ -155,11 +155,14 @@ export const GlobalUniformSchema = {
     uRoughness: UniformSpec('f'),
     uReflectivity: UniformSpec('f'),
 
+    uIsOrtho: UniformSpec('f'),
     uPixelRatio: UniformSpec('f'),
     uViewportHeight: UniformSpec('f'),
     uViewport: UniformSpec('v4'),
 
     uCameraPosition: UniformSpec('v3'),
+    uNear: UniformSpec('f'),
+    uFar: UniformSpec('f'),
     uFogNear: UniformSpec('f'),
     uFogFar: UniformSpec('f'),
     uFogColor: UniformSpec('v3'),
diff --git a/src/mol-gl/renderer.ts b/src/mol-gl/renderer.ts
index 2c427b728..1561924f4 100644
--- a/src/mol-gl/renderer.ts
+++ b/src/mol-gl/renderer.ts
@@ -85,6 +85,7 @@ namespace Renderer {
             uModelViewProjection: ValueCell.create(modelViewProjection),
             uInvModelViewProjection: ValueCell.create(invModelViewProjection),
 
+            uIsOrtho: ValueCell.create(camera.state.mode === 'orthographic' ? 1 : 0),
             uPixelRatio: ValueCell.create(ctx.pixelRatio),
             uViewportHeight: ValueCell.create(viewport.height),
             uViewport: ValueCell.create(Viewport.toVec4(Vec4(), viewport)),
@@ -97,6 +98,8 @@ namespace Renderer {
             uReflectivity: ValueCell.create(p.reflectivity),
 
             uCameraPosition: ValueCell.create(Vec3.clone(camera.state.position)),
+            uNear: ValueCell.create(camera.state.near),
+            uFar: ValueCell.create(camera.state.far),
             uFogNear: ValueCell.create(camera.state.fogNear),
             uFogFar: ValueCell.create(camera.state.fogFar),
             uFogColor: ValueCell.create(bgColor),
@@ -162,7 +165,11 @@ namespace Renderer {
             ValueCell.update(globalUniforms.uModelViewProjection, Mat4.mul(modelViewProjection, modelView, camera.projection))
             ValueCell.update(globalUniforms.uInvModelViewProjection, Mat4.invert(invModelViewProjection, modelViewProjection))
 
+            ValueCell.update(globalUniforms.uIsOrtho, camera.state.mode === 'orthographic' ? 1 : 0)
+
             ValueCell.update(globalUniforms.uCameraPosition, camera.state.position)
+            ValueCell.update(globalUniforms.uFar, camera.state.far)
+            ValueCell.update(globalUniforms.uNear, camera.state.near)
             ValueCell.update(globalUniforms.uFogFar, camera.state.fogFar)
             ValueCell.update(globalUniforms.uFogNear, camera.state.fogNear)
 
diff --git a/src/mol-gl/shader/spheres.frag b/src/mol-gl/shader/spheres.frag
index 0f0488b4f..f436e493e 100644
--- a/src/mol-gl/shader/spheres.frag
+++ b/src/mol-gl/shader/spheres.frag
@@ -12,14 +12,13 @@ precision highp int;
 #pragma glslify: import('./chunks/light-frag-params.glsl')
 
 uniform mat4 uProjection;
-// uniform vec3 interiorColor;
-// uniform float interiorDarkening;
-vec3 interiorColor = vec3(1.0, 0.5, 0.5);
-float interiorDarkening = 0.0;
+// uniform vec3 uInteriorColor;
+// uniform float uInteriorDarkening;
+vec3 uInteriorColor = vec3(0.5, 0.5, 0.5);
+float uInteriorDarkening = 0.0;
 
-uniform float clipNear;
-// uniform float ortho;
-float ortho = 0.0;
+uniform float uClipNear;
+uniform float uIsOrtho;
 
 varying float vRadius;
 varying float vRadiusSq;
@@ -38,16 +37,16 @@ float calcDepth(const in vec3 cameraPos){
 }
 
 float calcClip(const in vec3 cameraPos) {
-    return dot(vec4(cameraPos, 1.0), vec4(0.0, 0.0, 1.0, clipNear - 0.5));
+    return dot(vec4(cameraPos, 1.0), vec4(0.0, 0.0, 1.0, uClipNear - 0.5));
 }
 
 bool Impostor(out vec3 cameraPos, out vec3 cameraNormal){
     vec3 cameraSpherePos = -vPointViewPosition;
     cameraSpherePos.z += vRadius;
 
-    vec3 rayOrigin = mix(vec3(0.0, 0.0, 0.0), vPoint, ortho);
-    vec3 rayDirection = mix(normalize(vPoint), vec3(0.0, 0.0, 1.0), ortho);
-    vec3 cameraSphereDir = mix(cameraSpherePos, rayOrigin - cameraSpherePos, ortho);
+    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 cameraSphereDir = mix(cameraSpherePos, rayOrigin - cameraSpherePos, uIsOrtho);
 
     float B = dot(rayDirection, cameraSphereDir);
     float det = B * B + vRadiusSq - dot(cameraSphereDir, cameraSphereDir);
@@ -58,8 +57,8 @@ bool Impostor(out vec3 cameraPos, out vec3 cameraNormal){
     }
 
     float sqrtDet = sqrt(det);
-    float posT = mix(B + sqrtDet, B + sqrtDet, ortho);
-    float negT = mix(B - sqrtDet, sqrtDet - B, ortho);
+    float posT = mix(B + sqrtDet, B + sqrtDet, uIsOrtho);
+    float negT = mix(B - sqrtDet, sqrtDet - B, uIsOrtho);
 
     cameraPos = rayDirection * negT + rayOrigin;
 
@@ -85,10 +84,6 @@ bool Impostor(out vec3 cameraPos, out vec3 cameraNormal){
     return !interior;
 }
 
-void main2(void){
-    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
-}
-
 void main(void){
     bool flag = Impostor(cameraPos, cameraNormal);
 
@@ -105,7 +100,7 @@ void main(void){
         // make spheres with a greater radius occlude smaller ones
         #ifdef NEAR_CLIP
             if( flag2 ){
-                gl_FragDepthEXT = max(0.0, calcDepth(vec3(-(clipNear - 0.5))) + (0.0000001 / vRadius));
+                gl_FragDepthEXT = max(0.0, calcDepth(vec3(-(uClipNear - 0.5))) + (0.0000001 / vRadius));
             }else if(gl_FragDepthEXT >= 0.0){
                 gl_FragDepthEXT = 0.0 + (0.0000001 / vRadius);
             }
@@ -136,9 +131,9 @@ void main(void){
 
         if(interior){
             #ifdef USE_INTERIOR_COLOR
-                gl_FragColor.rgb = interiorColor;
+                gl_FragColor.rgb = uInteriorColor;
             #endif
-            gl_FragColor.rgb *= 1.0 - interiorDarkening;
+            gl_FragColor.rgb *= 1.0 - uInteriorDarkening;
         }
 
         #pragma glslify: import('./chunks/apply-marker-color.glsl')
diff --git a/src/mol-gl/shader/spheres.vert b/src/mol-gl/shader/spheres.vert
index 656563543..0fc4e2c05 100644
--- a/src/mol-gl/shader/spheres.vert
+++ b/src/mol-gl/shader/spheres.vert
@@ -34,21 +34,6 @@ const mat4 D = mat4(
     0.0, 0.0, 0.0, -1.0
 );
 
-mat4 transpose2(in mat4 inMatrix) {
-    vec4 i0 = inMatrix[0];
-    vec4 i1 = inMatrix[1];
-    vec4 i2 = inMatrix[2];
-    vec4 i3 = inMatrix[3];
-
-    mat4 outMatrix = mat4(
-        vec4(i0.x, i1.x, i2.x, i3.x),
-        vec4(i0.y, i1.y, i2.y, i3.y),
-        vec4(i0.z, i1.z, i2.z, i3.z),
-        vec4(i0.w, i1.w, i2.w, i3.w)
-    );
-    return outMatrix;
-}
-
 /**
  * Compute point size and center using the technique described in:
  * "GPU-Based Ray-Casting of Quadratic Surfaces" http://dl.acm.org/citation.cfm?id=2386396
@@ -64,7 +49,7 @@ void quadraticProjection(const in float radius, const in vec3 position){
         position.x, position.y, position.z, 1.0
     );
 
-    mat4 R = transpose2(uProjection * uModelView * aTransform * T);
+    mat4 R = transpose(uProjection * uModelView * aTransform * T);
     float A = dot(R[3], D * R[3]);
     float B = -2.0 * dot(R[0], D * R[3]);
     float C = dot(R[0], D * R[0]);
diff --git a/src/mol-math/linear-algebra/3d/mat4.ts b/src/mol-math/linear-algebra/3d/mat4.ts
index ed77c0c6c..ff0167e3f 100644
--- a/src/mol-math/linear-algebra/3d/mat4.ts
+++ b/src/mol-math/linear-algebra/3d/mat4.ts
@@ -833,7 +833,7 @@ namespace Mat4 {
         out[ 15 ] = 0;
         return out;
     }
-    
+
     /**
      * Generates a orthogonal projection matrix with the given bounds
      */
-- 
GitLab