2014-10-27 15 views
6

Ho:Volume il rendering in WebGL

  1. una matrice 3D contenente un set di dati 3D da visualizzare
  2. una matrice 4x4 che definisce spaziatura/scalatura/orientamento del volume da visualizzare
  3. un'opacità funzione di trasferimento
  4. una funzione di trasferimento del colore

Vorrei utilizzare ThreeJS per fare volume rendering (MIP, raycasting, etc.) di questi dati. Sono disponibili shader/demo?

Devo lavorare direttamente al livello dello shader o in javascript?

Ogni campione suggerimento/code sarebbe molto apprezzato, Miglior

+1

C'è l'esempio cubetti di marcia: http://threejs.org/examples/#webgl_marchingcubes –

+1

mrdoob anche collegato un esempio che ha fatto nel 2012 in un numero gihub: https://github.com/mrdoob/three.js/issues/1821 – Atrahasis

risposta

1

Sono disponibili alcuni shader/demo?

Leandro R Barbagallo ha scritto an in-depth blog post sul rendering del volume in WebGL.

+0

Il link è rotto (anche Archive.org) – Kroltan

+0

@ Kroltan Hmm, il collegamento Archive.org funziona per me –

+1

@Kroltan Inoltre, ecco il suo repository GitHub: https://github.com/lebarba/WebGLVolumeRendering –

1

WAVE Client Renderer è una libreria basata su Three.js per il rendering del volume tramite Ray Casting.

Il volume Ray Casting con accelerazione GPU viene in genere implementato il rendering multi-pass.

Il primo passaggio di shader è molto semplice. Traccia le coordinate della trama (a coordinate dell'oggetto) della posizione in cui i raggi colpiscono il lato posteriore del cubo.

È possibile trovare esempi di shader GLSL, con il seguente modello di ejs.

firstPass.frag

precision mediump int; 

precision mediump float; 



varying vec4 backColor; 



void main(void) 

{ 

    gl_FragColor = backColor; 

} 

firstPass.vert

precision mediump int; 

precision mediump float; 



attribute vec4 vertColor; 



varying vec4 backColor; 

varying vec4 pos; 



void main(void) 

{ 

    backColor = vertColor; 



    pos = projectionMatrix * modelViewMatrix * vec4(position, 1.0); 

    gl_Position = pos; 

} 

Il secondo passaggio esegue un campionamento effettiva dei dati e la visualizzazione dell'immagine finale.

secondPass.vert

precision mediump int; 

precision mediump float; 



attribute vec4 vertColor; 



varying vec4 backColor; 

varying vec4 pos; 



void main(void) 

{ 

    backColor = vertColor; 



    pos = projectionMatrix * modelViewMatrix * vec4(position, 1.0); 

    gl_Position = pos; 

} 

secondPass.frag

#ifdef GL_FRAGMENT_PRECISION_HIGH 

// highp is supported 

precision highp int; 

precision highp float; 

#else 

// high is not supported 

precision mediump int; 

precision mediump float; 

#endif 



varying vec4 frontColor; 

varying vec4 pos; 



uniform sampler2D uBackCoord; 

uniform sampler2D uTransferFunction; 

uniform sampler2D uSliceMaps[<%= maxTexturesNumber %>]; 



uniform float uNumberOfSlices; 

uniform float uMinGrayVal; 

uniform float uMaxGrayVal; 

uniform float uOpacityVal; 

uniform float uColorVal; 

uniform float uAbsorptionModeIndex; 

uniform float uSlicesOverX; 

uniform float uSlicesOverY; 

uniform float uSteps; 

// uniform int uAvailable_textures_number; 



//Acts like a texture3D using Z slices and trilinear filtering. 

float getVolumeValue(vec3 volpos) 

{ 

    float s1Original, s2Original, s1, s2; 

    float dx1, dy1; 

    // float dx2, dy2; 

    // float value; 



    vec2 texpos1,texpos2; 



    float slicesPerSprite = uSlicesOverX * uSlicesOverY; 



    s1Original = floor(volpos.z*uNumberOfSlices); 

    // s2Original = min(s1Original + 1.0, uNumberOfSlices); 



    int tex1Index = int(floor(s1Original/slicesPerSprite)); 

    // int tex2Index = int(floor(s2Original/slicesPerSprite)); 



    s1 = mod(s1Original, slicesPerSprite); 

    // s2 = mod(s2Original, slicesPerSprite); 



    dx1 = fract(s1/uSlicesOverX); 

    dy1 = floor(s1/uSlicesOverY)/uSlicesOverY; 



    // dx2 = fract(s2/uSlicesOverX); 

    // dy2 = floor(s2/uSlicesOverY)/uSlicesOverY; 



    texpos1.x = dx1+(volpos.x/uSlicesOverX); 

    texpos1.y = dy1+(volpos.y/uSlicesOverY); 



    // texpos2.x = dx2+(volpos.x/uSlicesOverX); 

    // texpos2.y = dy2+(volpos.y/uSlicesOverY); 



    float value1 = 0.0, value2 = 0.0; 

    // bool value1Set = false, value2Set = false; 



    // int numberOfSlicemaps = int(ceil(uNumberOfSlices/(uSlicesOverX * uSlicesOverY))); 



    <% for(var i=0; i < maxTexturesNumber; i++) { %> 

     if(tex1Index == <%=i%>) 

     { 

      value1 = texture2D(uSliceMaps[<%=i%>],texpos1).x; 

     } 



     <% if(i < maxTexturesNumber-1) { %> 

      else 

     <% } %> 

    <% } %> 



    return value1; 



    // for (int x = 0; x < gl_MaxTextureImageUnits-2; x++) 

    // { 

    //  if(x == numberOfSlicemaps) 

    //  { 

    //   break; 

    //  } 



    //  if(x == tex1Index) { 

    //   value1 = texture2D(uSliceMaps[x],texpos1).x; 

    //   value1Set = true; 

    //  } 



    //  if(x == tex2Index) { 

    //   value2 = texture2D(uSliceMaps[x],texpos2).x; 

    //   value2Set = true; 

    //  } 



    //  if(value1Set && value2Set) { 

    //   break; 

    //  } 



    // } 



    // return mix(value1, value2, fract(volpos.z*uNumberOfSlices)); 



} 



void main(void) 

{ 

vec2 texC = ((pos.xy/pos.w) + 1.0)/2.0; 



vec4 backColor = texture2D(uBackCoord,texC); 



vec3 dir = backColor.rgb - frontColor.rgb; 

//dir /= length(dir); 



vec4 vpos = frontColor; 



//  vec3 Step = dir/uSteps; 

vec3 Step = dir/uSteps; 



vec4 accum = vec4(0, 0, 0, 0); 

vec4 sample = vec4(0.0, 0.0, 0.0, 0.0); 

vec4 colorValue = vec4(0, 0, 0, 0); 

float biggest_gray_value = 0.0; 



float opacityFactor = uOpacityVal; 

float lightFactor = uColorVal; 



// const 4095 - just example of big number 

// It because expression i > uSteps impossible 

for(float i = 0.0; i < 4095.0; i+=1.0) 

{ 

// It because expression i > uSteps impossible 

    if(i == uSteps) { 

     break; 

    } 



    float gray_val = getVolumeValue(vpos.xyz); 



    if(gray_val < uMinGrayVal || gray_val > uMaxGrayVal) { 

     colorValue = vec4(0.0); 

    } else { 

     if(biggest_gray_value < gray_val) { 

      biggest_gray_value = gray_val; 

     } 



     if(uAbsorptionModeIndex == 0.0) 

     { 

      vec2 tf_pos; 

      tf_pos.x = (gray_val - uMinGrayVal)/(uMaxGrayVal - uMinGrayVal); 

      tf_pos.y = 0.5; 



      colorValue = texture2D(uTransferFunction,tf_pos); 

      //colorValue = vec4(tf_pos.x, tf_pos.x, tf_pos.x, 1.0); 



      sample.a = colorValue.a * opacityFactor; 

      sample.rgb = colorValue.rgb * uColorVal; 

      accum += sample; 



      if(accum.a>=1.0) 

       break; 



     } 



     if(uAbsorptionModeIndex == 1.0) 

     { 

      vec2 tf_pos; 

      tf_pos.x = (gray_val - uMinGrayVal)/(uMaxGrayVal - uMinGrayVal); 

      tf_pos.y = 0.5; 



      colorValue = texture2D(uTransferFunction,tf_pos); 

      //colorValue = vec4(tf_pos.x, tf_pos.x, tf_pos.x, 1.0); 



      sample.a = colorValue.a * opacityFactor * (1.0/uSteps); 

      sample.rgb = (1.0 - accum.a) * colorValue.rgb * sample.a * lightFactor; 

      accum += sample; 



      if(accum.a>=1.0) 

       break; 



     } 



     if(uAbsorptionModeIndex == 2.0) 

     { 

      vec2 tf_pos; 

      tf_pos.x = (biggest_gray_value - uMinGrayVal)/(uMaxGrayVal - uMinGrayVal); 

      tf_pos.y = 0.5; 



      colorValue = texture2D(uTransferFunction,tf_pos); 

      //colorValue = vec4(tf_pos.x, tf_pos.x, tf_pos.x, 1.0); 

      sample.a = colorValue.a * opacityFactor; 

      sample.rgb = colorValue.rgb * uColorVal; 



      accum = sample; 



     } 



    } 



    //advance the current position 

    vpos.xyz += Step; 



    //break if the position is greater than <1, 1, 1> 

    if(vpos.x > 1.0 || vpos.y > 1.0 || vpos.z > 1.0 || vpos.x < 0.0 || vpos.y < 0.0 || vpos.z < 0.0) 

    { 

     break; 

    } 



} 



gl_FragColor = accum; 



} 
+0

è meglio ora? –