WFiberStipples-fragment.glsl 13.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------

#version 120

#include "WGEUtils.glsl" // for distancePointLineSegment(...)
28
#include "WGETextureTools.glsl"
29
#include "WFiberStipples-varyings.glsl"
30
#include "WFiberStipples-uniforms.glsl"
31

32 33 34 35 36 37 38
/**
 * Pseudo random number generator: http://stackoverflow.com/questions/12964279/whats-the-origin-of-this-glsl-rand-one-liner
 */
float rand(vec2 co){
  return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}

39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
// /**
//  * Converts HSL colors to RGB colors. This is used in this shader later to draw from a single random, a whole color (hue).
//  */
// vec4 hsv_to_rgb(float h, float s, float v, float a)
// {
//     float c = v * s;
//     h = mod((h * 6.0), 6.0);
//     float x = c * (1.0 - abs(mod(h, 2.0) - 1.0));
//     vec4 color;
//
//     if (0.0 <= h && h < 1.0) {
//         color = vec4(c, x, 0.0, a);
//     } else if (1.0 <= h && h < 2.0) {
//         color = vec4(x, c, 0.0, a);
//     } else if (2.0 <= h && h < 3.0) {
//         color = vec4(0.0, c, x, a);
//     } else if (3.0 <= h && h < 4.0) {
//         color = vec4(0.0, x, c, a);
//     } else if (4.0 <= h && h < 5.0) {
//         color = vec4(x, 0.0, c, a);
//     } else if (5.0 <= h && h < 6.0) {
//         color = vec4(c, 0.0, x, a);
//     } else {
//         color = vec4(0.0, 0.0, 0.0, a);
//     }
//
//     color.rgb += v - c;
//
//     return color;
// }
//
// vec4 hotIron( in float value )
// {
//     // // BLUE <-> RED
//     // vec4 color8  = vec4( 255.0 / 255.0, 255.0 / 255.0, 204.0 / 255.0, 1.0 );
//     // vec4 color7  = vec4( 255.0 / 255.0, 237.0 / 255.0, 160.0 / 255.0, 1.0 );
//     // vec4 color6  = vec4( 254.0 / 255.0, 217.0 / 255.0, 118.0 / 255.0, 1.0 );
//     // vec4 color5  = vec4( 254.0 / 255.0, 178.0 / 255.0,  76.0 / 255.0, 1.0 );
//     // vec4 color4  = vec4( 253.0 / 255.0, 141.0 / 255.0,  60.0 / 255.0, 1.0 );
//     // vec4 color3  = vec4( 252.0 / 255.0,  78.0 / 255.0,  42.0 / 255.0, 1.0 );
//     // vec4 color2  = vec4( 205.0 / 255.0, 000.0 / 255.0, 000.0 / 255.0, 1.0 );
//     // vec4 color1  = vec4( 180.0 / 255.0,  85.0 / 255.0, 255.0 / 255.0, 1.0 );
//     // vec4 color0  = vec4( 000.0 / 255.0, 150.0 / 255.0, 255.0 / 255.0, 1.0 );
//
//     // HOT IRON
//     vec4 color8  = vec4( 255.0 / 255.0, 255.0 / 255.0, 204.0 / 255.0, 1.0 );
//     vec4 color7  = vec4( 255.0 / 255.0, 237.0 / 255.0, 160.0 / 255.0, 1.0 );
//     vec4 color6  = vec4( 254.0 / 255.0, 217.0 / 255.0, 118.0 / 255.0, 1.0 );
//     vec4 color5  = vec4( 254.0 / 255.0, 178.0 / 255.0,  76.0 / 255.0, 1.0 );
//     vec4 color4  = vec4( 253.0 / 255.0, 141.0 / 255.0,  60.0 / 255.0, 1.0 );
//     vec4 color3  = vec4( 252.0 / 255.0,  78.0 / 255.0,  42.0 / 255.0, 1.0 );
//     vec4 color2  = vec4( 227.0 / 255.0,  26.0 / 255.0,  28.0 / 255.0, 1.0 );
//     vec4 color1  = vec4( 189.0 / 255.0,   0.0 / 255.0,  38.0 / 255.0, 1.0 );
//     vec4 color0  = vec4( 128.0 / 255.0,   0.0 / 255.0,  38.0 / 255.0, 1.0 );
//
//     // In order to use a different color map use the colors in the BLUE <-> RED section above from color0 to colorN.
//     // Depending on how much colors you need, set then the colorNum to e.g. 2 when using only two colors.
//     //
//     // // HOT IRON
//     int colorNum = 8;
//     // // BLUE <-> RED
//     // int colorNum = 3;
//
//     float colorValue = value * float( colorNum );
//     int sel = int( floor( colorValue ) );
//
//     if( sel >= colorNum )
//     {
//         return color0;
//     }
//     else if( sel < 0 )
//     {
//         return color0;
//     }
//     else
//     {
//         colorValue -= float( sel );
//
//         if( sel < 1 )
//         {
//             return ( color1 * colorValue + color0 * ( 1.0 - colorValue ) );
//         }
//         else if( sel < 2 )
//         {
//             return ( color2 * colorValue + color1 * ( 1.0 - colorValue ) );
//         }
//         else if( sel < 3 )
//         {
//             return ( color3 * colorValue + color2 * ( 1.0 - colorValue ) );
//         }
//         else if( sel < 4 )
//         {
//             return ( color4 * colorValue + color3 * ( 1.0 - colorValue ) );
//         }
//         else if( sel < 5 )
//         {
//             return ( color5 * colorValue + color4 * ( 1.0 - colorValue ) );
//         }
//         else if( sel < 6 )
//         {
//             return ( color6 * colorValue + color5 * ( 1.0 - colorValue ) );
//         }
//         else if( sel < 7 )
//         {
//             return ( color7 * colorValue + color6 * ( 1.0 - colorValue ) );
//         }
//         else if( sel < 8 )
//         {
//             return ( color8 * colorValue + color7 * ( 1.0 - colorValue ) );
//         }
//         else
//         {
//             return color0;
//         }
//     }
// }
//
156

157 158 159 160 161 162 163 164 165 166 167 168 169 170
/**
 * Computes voxel corner positions in pos[8] and retrieve vectors from u_vectorsSampler. This way we access all 8 surrunding vectors and may perform
 * custom interpolation with directional swapping. However, this method does not work as expected:
 *
 * Currently, the nearest neightbour (NN) interpolation of the GPU produces different results as our NN interpolation. Reasons are unknown and might
 * be wrong pos[8], wrong vectors (v[8]), or small offsets as linear GPU interpolation has a texture coordinate shift compared to NN GPU interpolation.
 *
 * \param textPos position for interpolation result
 * \param interpolDiff difference betwee our custom interpolation and GPU interpolation.
 *
 * \note You need to comment out the line: "result = v[nearest];" in order to enable trilinear custom interpol., and uncomment to enable custom NN interpol.
 *
 * @return interpolated vector at position textPos
 */
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
// vec3 customInterpolate( vec3 textPos, out vec3 interpolDiff )
// {
//   vec3 pos[8];
//   pos[0] = vec3( floor( textPos.x ), floor( textPos.y ), floor( textPos.z ) );
//   pos[1] = vec3(  ceil( textPos.x ), floor( textPos.y ), floor( textPos.z ) );
//   pos[2] = vec3( floor( textPos.x ),  ceil( textPos.y ), floor( textPos.z ) );
//   pos[3] = vec3(  ceil( textPos.x ),  ceil( textPos.y ), floor( textPos.z ) );
//   pos[4] = vec3( floor( textPos.x ), floor( textPos.y ),  ceil( textPos.z ) );
//   pos[5] = vec3(  ceil( textPos.x ), floor( textPos.y ),  ceil( textPos.z ) );
//   pos[6] = vec3( floor( textPos.x ),  ceil( textPos.y ),  ceil( textPos.z ) );
//   pos[7] = vec3(  ceil( textPos.x ),  ceil( textPos.y ),  ceil( textPos.z ) );
//
//   vec3 localPos = textPos - pos[0];
//   float lambdaX = localPos.x * u_pixelSizeX;
//   float lambdaY = localPos.y * u_pixelSizeY;
//   float lambdaZ = localPos.z * u_pixelSizeZ;
//
//   float h[8];
//   h[0] = ( 1 - lambdaX ) * ( 1 - lambdaY ) * ( 1 - lambdaZ );
//   h[1] = (     lambdaX ) * ( 1 - lambdaY ) * ( 1 - lambdaZ );
//   h[2] = ( 1 - lambdaX ) * (     lambdaY ) * ( 1 - lambdaZ );
//   h[3] = (     lambdaX ) * (     lambdaY ) * ( 1 - lambdaZ );
//   h[4] = ( 1 - lambdaX ) * ( 1 - lambdaY ) * (     lambdaZ );
//   h[5] = (     lambdaX ) * ( 1 - lambdaY ) * (     lambdaZ );
//   h[6] = ( 1 - lambdaX ) * (     lambdaY ) * (     lambdaZ );
//   h[7] = (     lambdaX ) * (     lambdaY ) * (     lambdaZ );
//
//   vec3 result = vec3( 0, 0, 0 );
//   vec3 v[8];
//   float dist = 9999999;
//   int nearest = 9999999;
//   for( int i = 0; i < 8; ++i )
//   {
//     if( length( pos[i] - textPos ) < dist )
//     {
//       dist = length( pos[i] - textPos );
//       nearest = i;
//     }
//     pos[i].x /= u_pixelSizeX * ( u_probTractSizeX -1 );
//     pos[i].y /= u_pixelSizeY * ( u_probTractSizeY -1 );
//     pos[i].z /= u_pixelSizeZ * ( u_probTractSizeZ -1 );
//     v[i] = texture3DUnscaled( u_vectorsSampler, pos[i], u_vectorsMin, u_vectorsScale ).xyz;
//     // for orientation swaps use the step function below instead of 1.0
//     float sgn = 1.0; // step( 0, dot( v[0], v[i] ) )*2 - 1;
//     result += h[i] * sgn * v[i];
//   }
//
//   result = v[nearest];
//   textPos.x /= u_pixelSizeX * ( u_probTractSizeX);
//   textPos.y /= u_pixelSizeY * ( u_probTractSizeY);
//   textPos.z /= u_pixelSizeZ * ( u_probTractSizeZ);
//
//   interpolDiff = vec3( 1, 1, 1 ) -  abs( result - texture3DUnscaled( u_vectorsSampler, textPos, u_vectorsMin, u_vectorsScale ).xyz );
//
//   return normalize( result );
// }
227

228 229
void main()
{
230 231
    // vec3 diffusionDirection = customInterpolate( v_textPos, interpolDiff );
    vec3 diffusionDirection = texture3D( u_vectorsSampler, v_vecTexturePos ).xyz;
232 233 234 235 236 237

    // project into plane (given by two vectors aVec and bVec)
    vec3 aVecNorm = normalize( u_aVec );
    vec3 bVecNorm = normalize( u_bVec );
    vec3 projectedDirectionTextCoords = 0.5 * vec3( dot( aVecNorm, diffusionDirection ), dot( bVecNorm, diffusionDirection ), 0.0 );

238 239 240 241 242 243
    /**
     * Middle point of the quad in texture coordinates, needed for scaling the
     * projection of the principal diffusion direction to fit inside quad.
     */
    vec3 middlePoint_tex = vec3( 0.5, 0.5, 0.0 );

244 245
    vec3 scaledFocalPoint1 = middlePoint_tex + u_scale * projectedDirectionTextCoords;
    vec3 scaledFocalPoint2 = middlePoint_tex - u_scale * projectedDirectionTextCoords;
246

247
    float col = texture3D( u_colSampler, v_colorTexturePos ).r;
248

249 250 251 252 253 254 255
    // generally the area of a line stipple is a circle with radius R (each half for the endings of the line stipple) plus
    // a quad with height 2R and width length of the focalPoints v and w. hence we have this equation in R to solve:
    //
    //    R^2*PI + 2R*length(v, w) - A = 0
    //
    // where A is the area to fill.

256
    float area =  0.1 * u_glyphThickness; // this is arbitrarily set
257 258 259 260 261
    float l = distance( scaledFocalPoint1, scaledFocalPoint2 );
    float p2 = -l / 3.14159265;
    float q = area / 3.14159265;
    float r1 = p2 + sqrt( p2 * p2 + q );
    float r2 = p2 - sqrt( p2 * p2 + q );
262 263
    float radius = max( r1, r2 );// - 0.05;

264 265 266
    vec4 white = vec4( 1, 1, 1, 1 );
    vec4 black = vec4( 0, 0, 0, 1 );

267 268
    vec4 color = u_color;

269
    // opacity filtered color (default)
270
    vec4 c = color * pow( v_probability, 1.0 / (10.0 * u_colorThreshold) );
271 272

    if( u_colorThreshold >= 1.0 ) { // pure color
273
      c = color;
274
    }
275

276 277 278 279 280 281 282 283 284 285 286 287 288
    float dist = distancePointLineSegment( gl_TexCoord[1].xyz, scaledFocalPoint1, scaledFocalPoint2 );

    if( u_outlineInOut ) {
      if( dist < ( radius + u_outlineWidth ) ) {
        // // Debug: Show the direction of the stipple by using the first focal point
        // c = vec4( normalize( gl_TexCoord[1].xyz - scaledFocalPoint1 ).xyz, 1.0 );
        // // Debug: Shows the dfference between two interpolation results as color in RGB
        // gl_FragColor = vec4( interpolDiff, 1.0 );
        // // Debug: colored outline only
        // c.a=0;

        if( dist < radius ) {
          gl_FragColor = c;
289 290
        }
        else {
291 292 293
          if( u_outline ) {
            dist = dist - radius;
            for( int i = u_outlineSteps; i > 0; --i ) {
294
              float f = ( i / float( u_outlineSteps) );
295 296 297 298 299 300 301 302 303 304 305 306 307
              if( u_outlineDark ) {
                if( dist < f * u_outlineWidth ) {
                  gl_FragColor =vec4( (c * (1-f) ).rgb, c.a );
                }
              }
              else {
                if( dist <  f * u_outlineWidth ) {
                  gl_FragColor = vec4( ( c + vec4(f,f,f,0) ).rgb, c.a );
                }
              }
            }
          }
          else {
308
            discard;
309
          }
310
        }
311 312 313 314
      }
      else {
        discard;
      }
315

316
    }
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
    else {
      if( dist < radius ) {
        // // Debug: Show the direction of the stipple by using the first focal point
        // c = vec4( normalize( gl_TexCoord[1].xyz - scaledFocalPoint1 ).xyz, 1.0 );
        // // Debug: Shows the dfference between two interpolation results as color in RGB
        // gl_FragColor = vec4( interpolDiff, 1.0 );
        // // Debug: colored outline only
        // c.a=0;

        if( dist < ( radius - u_outlineWidth ) ) {
          gl_FragColor = c;
        }
        else {
          if( u_outline ) {
            for( int i = 0; i < u_outlineSteps; ++i ) {
              float f = ( i / float(u_outlineSteps) );
              if( u_outlineDark ) {
                if( dist < ( radius - f * u_outlineWidth ) ) {
                  gl_FragColor =vec4( (c * f ).rgb, c.a );
                }
              }
              else {
                if( dist < ( radius - f * u_outlineWidth ) ) {
                  gl_FragColor = vec4( c + vec4(1-f,1-f,1-f,0) );
                }
              }
            }
          }
          else {
            gl_FragColor = c;
          }
        }
      }
      else {
        discard;
      }
    }
354
}
355