Browse Source

wip, direct volume rendering

Alexander Rose 6 years ago
parent
commit
5c93fe0713

+ 2 - 1
src/mol-geo/representation/volume/direct-volume.ts

@@ -134,8 +134,9 @@ function createVolumeTexture3d(volume: VolumeData) {
 
     let i = 0
     for (let z = 0; z < depth; ++z) {
+        for (let y = 0; y < height; ++y) {
         for (let x = 0; x < width; ++x) {
-            for (let y = 0; y < height; ++y) {
+
                 array[i + 3] = ((get(data, x, y, z) - stats.min) / (stats.max - stats.min)) * 255
                 i += 4
             }

+ 4 - 0
src/mol-gl/renderable/schema.ts

@@ -126,12 +126,16 @@ export const GlobalUniformSchema = {
     uModelView: UniformSpec('m4'),
     uInvModelView: UniformSpec('m4'),
     uProjection: UniformSpec('m4'),
+    uInvProjection: UniformSpec('m4'),
+    uModelViewProjection: UniformSpec('m4'),
+    uInvModelViewProjection: UniformSpec('m4'),
     // uLightPosition: Uniform('v3'),
     uLightColor: UniformSpec('v3'),
     uLightAmbient: UniformSpec('v3'),
 
     uPixelRatio: UniformSpec('f'),
     uViewportHeight: UniformSpec('f'),
+    uViewport: UniformSpec('v4'),
 
     uHighlightColor: UniformSpec('v3'),
     uSelectColor: UniformSpec('v3'),

+ 13 - 1
src/mol-gl/renderer.ts

@@ -10,7 +10,7 @@ import { Camera } from 'mol-view/camera/base';
 
 import Scene from './scene';
 import { Context, createImageData } from './webgl/context';
-import { Mat4, Vec3 } from 'mol-math/linear-algebra';
+import { Mat4, Vec3, Vec4 } from 'mol-math/linear-algebra';
 import { Renderable } from './renderable';
 import { Color } from 'mol-util/color';
 import { ValueCell } from 'mol-util';
@@ -54,6 +54,7 @@ namespace Renderer {
         let { clearColor, viewport: _viewport } = { ...DefaultRendererProps, ...props }
 
         const viewport = Viewport.clone(_viewport)
+        const viewportVec4 = Viewport.toVec4(Vec4.zero(), viewport)
 
         // const lightPosition = Vec3.create(0, 0, -100)
         const lightColor = Vec3.create(1.0, 1.0, 1.0)
@@ -72,6 +73,9 @@ namespace Renderer {
         const invView = Mat4.invert(Mat4.identity(), view)
         const modelView = Mat4.clone(camera.view)
         const invModelView = Mat4.invert(Mat4.identity(), modelView)
+        const invProjection = Mat4.invert(Mat4.identity(), camera.projection)
+        const modelViewProjection = Mat4.mul(Mat4.identity(), modelView, camera.projection)
+        const invModelViewProjection = Mat4.invert(Mat4.identity(), modelViewProjection)
 
         const globalUniforms: GlobalUniformValues = {
             uModel: ValueCell.create(Mat4.identity()),
@@ -79,10 +83,14 @@ namespace Renderer {
             uInvView: ValueCell.create(invView),
             uModelView: ValueCell.create(modelView),
             uInvModelView: ValueCell.create(invModelView),
+            uInvProjection: ValueCell.create(invProjection),
             uProjection: ValueCell.create(Mat4.clone(camera.projection)),
+            uModelViewProjection: ValueCell.create(modelViewProjection),
+            uInvModelViewProjection: ValueCell.create(invModelViewProjection),
 
             uPixelRatio: ValueCell.create(ctx.pixelRatio),
             uViewportHeight: ValueCell.create(viewport.height),
+            uViewport: ValueCell.create(viewportVec4),
 
             uLightColor: ValueCell.create(Vec3.clone(lightColor)),
             uLightAmbient: ValueCell.create(Vec3.clone(lightAmbient)),
@@ -143,6 +151,9 @@ namespace Renderer {
             ValueCell.update(globalUniforms.uModelView, Mat4.mul(modelView, scene.view, camera.view))
             ValueCell.update(globalUniforms.uInvModelView, Mat4.invert(invModelView, modelView))
             ValueCell.update(globalUniforms.uProjection, camera.projection)
+            ValueCell.update(globalUniforms.uInvProjection, Mat4.invert(invProjection, camera.projection))
+            ValueCell.update(globalUniforms.uModelViewProjection, Mat4.mul(modelViewProjection, modelView, camera.projection))
+            ValueCell.update(globalUniforms.uInvModelViewProjection, Mat4.invert(invModelViewProjection, modelViewProjection))
 
             ValueCell.update(globalUniforms.uFogFar, camera.fogFar)
             ValueCell.update(globalUniforms.uFogNear, camera.fogNear)
@@ -171,6 +182,7 @@ namespace Renderer {
                 Viewport.set(viewport, x, y, width, height)
                 gl.viewport(x, y, width, height)
                 ValueCell.update(globalUniforms.uViewportHeight, height)
+                ValueCell.update(globalUniforms.uViewport, Vec4.set(viewportVec4, x, y, width, height))
             },
             getImageData: () => {
                 const { width, height } = viewport

+ 22 - 136
src/mol-gl/shader/direct-volume.frag

@@ -17,12 +17,7 @@ varying vec3 origPos;
 
 uniform float uAlpha;
 uniform mat4 uInvView;
-uniform mat4 uModelView;
-uniform mat4 uInvModelView;
 uniform float uIsoValue;
-uniform vec3 uBboxMin;
-uniform vec3 uBboxMax;
-uniform vec3 uBboxSize;
 uniform vec3 uGridDim;
 uniform sampler2D tTransferTex;
 
@@ -33,56 +28,6 @@ uniform sampler2D tTransferTex;
     uniform sampler3D tGridTex;
 #endif
 
-// float uIsoValue = exp(-1.5);
-// float uIsoValue = 0.7;
-
-varying vec4 vNearPos;
-varying vec4 vFarPos;
-varying vec3 vPosition;
-
-#pragma glslify: transpose = require(./utils/transpose.glsl)
-
-vec3 extractCameraPos(const in mat4 modelView) {
-    // Get the 3 basis vector planes at the camera origin and transform them into model space.
-    //
-    // NOTE: Planes have to be transformed by the inverse transpose of a matrix
-    //       Nice reference here: http://www.opengl.org/discussion_boards/showthread.php/159564-Clever-way-to-transform-plane-by-matrix
-    //
-    //       So for a transform to model space we need to do:
-    //            inverse(transpose(inverse(MV)))
-    //       This equals : transpose(MV) - see Lemma 5 in http://mathrefresher.blogspot.com.au/2007/06/transpose-of-matrix.html
-    //
-    // As each plane is simply (1,0,0,0), (0,1,0,0), (0,0,1,0) we can pull the data directly from the transpose matrix.
-    //
-    mat4 modelViewT = transpose(modelView);
-
-    // Get plane normals
-    vec3 n1 = vec3(modelViewT[0]);
-    vec3 n2 = vec3(modelViewT[1]);
-    vec3 n3 = vec3(modelViewT[2]);
-
-    // Get plane distances
-    float d1 = modelViewT[0].w;
-    float d2 = modelViewT[1].w;
-    float d3 = modelViewT[2].w;
-
-    // Get the intersection of these 3 planes
-    // (uisng math from RealTime Collision Detection by Christer Ericson)
-    vec3 n2n3 = cross(n2, n3);
-    float denom = dot(n1, n2n3);
-
-    vec3 top = (n2n3 * d1) + cross(n1, (d3 * n2) - (d2 * n3));
-    return top / -denom;
-}
-
-vec3 palette(in float t, in vec3 a, in vec3 b, in vec3 c, in vec3 d) {
-    return a + b * cos(6.28318 * (c * t + d));
-}
-
-vec3 palette1(in float t) {
-    return palette(t, vec3(0.5,0.5,0.5),vec3(0.5,0.5,0.5),vec3(1.0,1.0,1.0),vec3(0.0,0.10,0.20));
-}
-
 #if defined(dGridTexType_2d)
     // TODO workaround due to some kind of GPU bug
     float myMod(float a, float b) {
@@ -121,48 +66,31 @@ vec4 transferFunction(float value) {
 const float gradOffset = 0.5;
 const vec3 color = vec3(0.45, 0.55, 0.8);
 
-vec4 raymarch(vec3 cameraPos) {
-    vec3 pos = unitCoord;
+vec4 raymarch(vec3 startLoc, vec3 step, vec3 viewDir) {
+    vec3 scaleVol = vec3(1.0) / uGridDim;
+    vec3 pos = startLoc + scaleVol * 0.5;
     float prevValue = -127.0;
     float value = 0.0;
-    // float MAX_STEPS_F = max(max(uGridDim.x, uGridDim.y), uGridDim.z);
-    // int MAX_STEPS = 2 * int(length(vec3(imgresx, imgresy, imgresz)));
-    float stepSize = 1.0 / float(dMaxSteps);
     vec4 src = vec4(0.0);
     vec4 dst = vec4(0.0);
 
-    vec3 rayDir = normalize(origPos - cameraPos);
-    // rayDir = normalize(vec3(1.0, 1.0, 0.0));
-    // return vec4(rayDir, 0.5);
-    vec3 isoPos;
-    float tmp;
-    vec3 gradient = vec3(1.0);
-    vec3 step = rayDir * (1.0 / uGridDim) * 0.5;
+    #if defined(dRenderMode_isosurface)
+        vec3 isoPos;
+        float tmp;
 
-    vec3 scaleVol = vec3(1.0) / uGridDim;
-    vec3 dx = vec3(gradOffset * scaleVol.x, 0.0, 0.0);
-    vec3 dy = vec3(0.0, gradOffset * scaleVol.y, 0.0);
-    vec3 dz = vec3(0.0, 0.0, gradOffset * scaleVol.z);
-
-    // dst = vec4(textureVal(vec3(pos.xy, 0.6)).xyz, 0.5);
-    // vec2 foo = (vec2(5.0 * uGridDim.x, 5.0 * uGridDim.y) + (pos.xy * uGridDim.xy)) / uGridTexDim;
-    // dst = texture2D(tGridTex, foo);
-    // dst = texture2D(tGridTex, unitCoord.xy);
-    // dst.xyz = pos;
-    // return mix(dst, vec4(1.0, 0.0, 0.0, 1.0), 0.5);
+        vec3 gradient = vec3(1.0);
+        vec3 dx = vec3(gradOffset * scaleVol.x, 0.0, 0.0);
+        vec3 dy = vec3(0.0, gradOffset * scaleVol.y, 0.0);
+        vec3 dz = vec3(0.0, 0.0, gradOffset * scaleVol.z);
+    #endif
 
     for(int i = 0; i < dMaxSteps; ++i){
-        if( pos.x <= 1.0 && pos.y <= 1.0 && pos.z <= 1.0 && pos.x >= 0.0 && pos.y >= 0.0 && pos.z >= 0.0) {
-            value = textureVal(pos).a; // current voxel value
-        } else {
+        value = textureVal(pos).a; // current voxel value
+        if(pos.x > 1.01 || pos.y > 1.01 || pos.z > 1.01 || pos.x < -0.01 || pos.y < -0.01 || pos.z < -0.01)
             break;
-        }
 
         #if defined(dRenderMode_volume)
-            // src = texture1D(transferRGBASampler, scalarData);
             src = transferFunction(value);
-            // src.rgb = palette1(value);
-            // src.a = 1.0 - pow(1.0 - src.a, 0.5);
             src.rgb *= src.a;
             dst = (1.0 - dst.a) * src + dst; // standard blending
         #endif
@@ -181,10 +109,10 @@ vec4 raymarch(vec3 cameraPos) {
                 gradient.z = textureVal(isoPos - dz).a - textureVal(isoPos + dz).a;
                 gradient = normalize(gradient);
 
-                float d = float(dot(gradient, normalize(cameraPos)) > 0.0);
+                float d = float(dot(gradient, viewDir) > 0.0);
                 gradient = (2.0 * d - 1.0) * gradient;
 
-                src.rgb = color.rgb * abs(dot(gradient, normalize(cameraPos)));
+                src.rgb = color.rgb * abs(dot(gradient, viewDir));
                 src.a = uAlpha;
 
                 // draw interior darker
@@ -208,56 +136,14 @@ vec4 raymarch(vec3 cameraPos) {
 
 void main () {
     vec3 cameraPos = uInvView[3].xyz / uInvView[3].w;
-    // vec3 cameraPos = extractCameraPos(uModelView);
-    // vec3 cameraPos = vec3(10.0, 0.0, 0.0);
-    gl_FragColor = raymarch(cameraPos);
+
+    vec3 rayDir = normalize(origPos - cameraPos);
+    vec3 startLoc = unitCoord;
+    vec3 step = rayDir * (1.0 / uGridDim) * 0.5;
+
+    gl_FragColor = raymarch(startLoc, step, normalize(cameraPos));
     if (length(gl_FragColor.rgb) < 0.00001) discard;
     #if defined(dRenderMode_volume)
         gl_FragColor.a = uAlpha;
     #endif
-    // gl_FragColor = vec4(unitCoord, 1.0);
-    // gl_FragColor = vec4(1.0, 0.0, 0.0, 0.5);
-}
-
-
-// const float relativeStepSize = 1.0;
-// vec3 u_size = uGridDim;
-
-// void main () {
-//     // Normalize clipping plane info
-//     vec3 farPos = vFarPos.xyz / vFarPos.w;
-//     vec3 nearPos = vNearPos.xyz / vNearPos.w;
-//     // Calculate unit vector pointing in the view direction through this fragment.
-//     vec3 viewRay = normalize(nearPos.xyz - farPos.xyz);
-
-//     // Compute the (negative) distance to the front surface or near clipping plane.
-//     // v_position is the back face of the cuboid, so the initial distance calculated in the dot
-//     // product below is the distance from near clip plane to the back of the cuboid
-//     float distance = dot(nearPos - vPosition, viewRay);
-//     distance = max(distance, min((-0.5 - vPosition.x) / viewRay.x, (u_size.x - 0.5 - vPosition.x) / viewRay.x));
-//     distance = max(distance, min((-0.5 - vPosition.y) / viewRay.y, (u_size.y - 0.5 - vPosition.y) / viewRay.y));
-//     distance = max(distance, min((-0.5 - vPosition.z) / viewRay.z, (u_size.z - 0.5 - vPosition.z) / viewRay.z));
-//     // Now we have the starting position on the front surface
-//     vec3 front = vPosition + viewRay * distance;
-//     // Decide how many steps to take
-//     int nsteps = int(-distance / relativeStepSize + 0.5);
-//     // if (nsteps < 1)
-//         // discard;
-//     // Get starting location and step vector in texture coordinates
-//     vec3 step = ((vPosition - front) / u_size) / float(nsteps);
-//     vec3 startLoc = front / u_size;
-//     // For testing: show the number of steps. This helps to establish
-//     // whether the rays are correctly oriented
-//     gl_FragColor = vec4(0.0, float(nsteps) / 1.0 / u_size.x, 1.0, 1.0);
-//     gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
-//     return;
-
-//     // if (u_renderstyle == 0)
-//         // cast_mip(startLoc, step, nsteps, viewRay);
-//     // else if (u_renderstyle == 1)
-//     //     cast_iso(start_loc, step, nsteps, view_ray);
-
-
-//     if (gl_FragColor.a < 0.05)
-//         discard;
-// }
+}

+ 3 - 31
src/mol-gl/shader/direct-volume.vert

@@ -15,41 +15,13 @@ varying vec3 origPos;
 uniform vec3 uBboxSize;
 uniform vec3 uBboxMin;
 uniform vec3 uBboxMax;
-uniform mat4 uTransform;
 
-uniform mat4 uInvView;
 uniform mat4 uModelView;
-uniform mat4 uInvModelView;
-uniform mat4 uProjection, uView, uModel;
-
-varying vec4 vNearPos;
-varying vec4 vFarPos;
-varying vec3 vPosition;
+uniform mat4 uProjection;
 
 void main() {
     unitCoord = aPosition + vec3(0.5);
-    vec4 mvPosition = uView * uModel * vec4(unitCoord * uBboxSize + uBboxMin, 1.0);
-    // vec4 mvPosition = vec4(unitCoord * uBboxSize + uBboxMin, 1.0);
-    // origPos = mvPosition.xyz;
+    vec4 mvPosition = uModelView * vec4(unitCoord * uBboxSize + uBboxMin, 1.0);
     origPos = unitCoord * uBboxSize + uBboxMin;
     gl_Position = uProjection * mvPosition;
-}
-
-// void main() {
-//     // Project local vertex coordinate to camera position. Then do a step
-//     // backward (in cam coords) to the near clipping plane, and project back. Do
-//     // the same for the far clipping plane. This gives us all the information we
-//     // need to calculate the ray and truncate it to the viewing cone.
-//     vec3 position = aPosition * uBboxSize + uBboxMin;
-//     vec4 position4 = vec4(position, 1.0);
-//     vec4 posInCam = uView * position4;
-//     // Intersection of ray and near clipping plane (z = -1 in clip coords)
-//     posInCam.z = -posInCam.w;
-//     vNearPos = uInvView * posInCam;
-//     // Intersection of ray and far clipping plane (z = +1 in clip coords)
-//     posInCam.z = posInCam.w;
-//     vFarPos = uInvView * posInCam;
-//     // Set varyings and output pos
-//     vPosition = position;
-//     gl_Position = uProjection * uModelView * position4;
-// }
+}

+ 8 - 0
src/mol-view/camera/util.ts

@@ -30,6 +30,14 @@ export namespace Viewport {
         viewport.height = height
         return viewport
     }
+
+    export function toVec4(v4: Vec4, viewport: Viewport): Vec4 {
+        v4[0] = viewport.x
+        v4[1] = viewport.y
+        v4[2] = viewport.width
+        v4[3] = viewport.height
+        return v4
+    }
 }
 
 const tmpVec3 = Vec3.zero()