2016-04-05 3 views
0

Je travaille sur mon application de rendu de volume (C# + OpenTK). Le volume est rendu en utilisant raycasting, j'ai trouvé beaucoup d'inspiration sur ce site: http://graphicsrunner.blogspot.sk/2009/01/volume-rendering-101.html, et même si mes applications fonctionnent avec OpenGL, l'idée principale d'utiliser la texture 3D et d'autres choses est la même. L'application fonctionne bien, mais après que je "coule dans le volume" (signifie à l'intérieur de la boîte englobante), tout disparaît, et je veux empêcher cela. Alors, y a-t-il un moyen facile de le faire? -> Je serai capable de circuler dans le volume ou de bouger dans le volume.Rendu de volume à l'aide de la projection de rayons à travers le volume

Voici le code du fragment shader:

#version 330 

in vec3 EntryPoint; 
in vec4 ExitPointCoord; 

uniform sampler2D ExitPoints; 
uniform sampler3D VolumeTex; 
uniform sampler1D TransferFunc; 
uniform float  StepSize; 
uniform float  AlphaReduce; 
uniform vec2  ScreenSize; 
layout (location = 0) out vec4 FragColor; 

void main() 
{ 
//gl_FragCoord --> http://www.txutxi.com/?p=182 
vec3 exitPoint = texture(ExitPoints, gl_FragCoord.st/ScreenSize).xyz; 

//background need no raycasting 
if (EntryPoint == exitPoint) 
    discard; 

vec3 rayDirection = normalize(exitPoint - EntryPoint); 
vec4 currentPosition = vec4(EntryPoint, 0.0f); 
vec4 colorSum = vec4(.0f,.0f,.0f,.0f); 
vec4 color = vec4(0.0f,0.0f,0.0f,0.0f); 
vec4 value = vec4(0.0f); 

vec3 Step = rayDirection * StepSize; 
float stepLength= length(Step); 
float LengthSum = 0.0f; 
float Length = length(exitPoint - EntryPoint); 

for(int i=0; i < 16000; i++) 
{ 
    currentPosition.w = 0.0f; 
    value = texture(VolumeTex, currentPosition.xyz); 
    color = texture(TransferFunc, value.a); 

    //reduce the alpha to have a more transparent result 
    color.a *= AlphaReduce; 

    //Front to back blending 
    color.rgb *= color.a; 
    colorSum = (1.0f - colorSum.a) * color + colorSum; 

    //accumulate length 
    LengthSum += stepLength; 

    //break from the loop when alpha gets high enough 
    if(colorSum.a >= .95f) 
     break; 

    //advance the current position 
    currentPosition.xyz += Step; 

    //break if the ray is outside of the bounding box 
    if(LengthSum >= Length) 
     break; 
} 
FragColor = colorSum; 
} 

Le code ci-dessous est basé sur https://github.com/toolchainX/Volume_Rendering_Using_GLSL

fonction Affichage():

public void Display() 
    { 
     // the color of the vertex in the back face is also the location 
     // of the vertex 
     // save the back face to the user defined framebuffer bound 
     // with a 2D texture named `g_bfTexObj` 
     // draw the front face of the box 
     // in the rendering process, i.e. the ray marching process 
     // loading the volume `g_volTexObj` as well as the `g_bfTexObj` 
     // after vertex shader processing we got the color as well as the location of 
     // the vertex (in the object coordinates, before transformation). 
     // and the vertex assemblied into primitives before entering 
     // fragment shader processing stage. 
     // in fragment shader processing stage. we got `g_bfTexObj` 
     // (correspond to 'VolumeTex' in glsl)and `g_volTexObj`(correspond to 'ExitPoints') 
     // as well as the location of primitives. 

     // draw the back face of the box 
     GL.Enable(EnableCap.DepthTest); 

     //"vykreslim" front || back face objemu do framebuffru --> teda do 2D textury s ID bfTexID 
     //(pomocou backface.frag &.vert) 
     GL.BindFramebuffer(FramebufferTarget.Framebuffer, frameBufferID); 
     GL.Viewport(0, 0, width, height); 
     LinkShader(spMain.GetProgramHandle(), bfVertShader.GetShaderHandle(), bfFragShader.GetShaderHandle()); 
     spMain.UseProgram(); 
     //cull front face 
     Render(CullFaceMode.Front); 
     spMain.UseProgram(0); 
     //klasicky framebuffer --> "obrazovka" 
     GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0); 

     GL.Viewport(0, 0, width, height); 
     LinkShader(spMain.GetProgramHandle(), rcVertShader.GetShaderHandle(), rcFragShader.GetShaderHandle()); 
     spMain.UseProgram(); 
     SetUniforms(); 
     Render(CullFaceMode.Back); 
     spMain.UseProgram(0); 

     GL.Disable(EnableCap.DepthTest); 
    } 

    private void DrawBox(CullFaceMode mode) 
    { 
     // --> Face culling allows non-visible triangles of closed surfaces to be culled before expensive Rasterization and Fragment Shader operations. 
     GL.Enable(EnableCap.CullFace); 
     GL.CullFace(mode); 
     GL.BindVertexArray(VAO); 
     GL.DrawElements(PrimitiveType.Triangles, 36, DrawElementsType.UnsignedInt, 0); 
     GL.BindVertexArray(0); 
     GL.Disable(EnableCap.CullFace); 
     spMain.UseProgram(0);//zapnuty bol v Render() ktora DrawBox zavolala 
    } 

    private void Render(CullFaceMode mode) 
    { 
     GL.ClearColor(0.0f, 0.0f, 0.0f, 1.0f); 
     GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); 
     spMain.UseProgram(); 
     spMain.SetUniform("modelViewMatrix", Current); 
     spMain.SetUniform("projectionMatrix", projectionMatrix); 
     DrawBox(mode); 
    } 

Le problème est (je pense) que comme je me déplace vers le volume (je ne bouge pas la caméra, juste en augmentant le volume), si le facteur d'échelle> 2.7quelque chose, je suis dans le volume, cela signifie "après l'avion sur lequel est le image finale étant rendue ", donc on ne peut rien voir. La solution (peut-être) que je peux penser, est quelque chose comme ça: Si je tends le facteur d'échelle = 2.7something:

1.) -> n'échelle pas le volume

2.) -> d'une façon ou d'une autre dit de fragmenter le shader pour déplacer EntryPoint vers le RayDirection pour une certaine longueur (probablement basé sur le facteur d'échelle).

Maintenant, j'ai essayé cette "méthode" et il semble que cela peut fonctionner: (ou [0,1])

vec3 entryPoint = EntryPoint + some_value * rayDirection; 

Le some_value doivent être serrées entre [0,1 [intervalle , mais peut-être qu'il n'a pas affaire merci de que:

if (EntryPoint == exitPoint) 
discard; 

alors maintenant, peut-être (si ma solution est pas si mal), je peux changer ma réponse à cette question: Comment calculer la some_value (base sur le facteur d'échelle que j'envoie au fragment shader)?

if(scale_factor < 2.7something) 
    work like before; 
else 
{ 
    compute some_value; //(I need help with this part) 
    change entry point; 
    work like before; 
} 

(Je ne suis pas speeker natif anglais, donc s'il y a quelques grosses erreurs dans le texte et vous ne comprenez pas quelque chose, laissez-moi savoir et je vais essayer de corriger ces bugs)

Merci.

+0

Afin de vous aider efficacement, nous avons besoin de voir du code. –

Répondre

0

J'ai résolu mon problème. Cela ne fait pas illusion "d'être entouré par le volume", mais maintenant, je peux circuler à travers le volume et rien ne disparaît. Voici le code de ma solution a été ajoutée au fragment shader:

vec3 entryPoint = vec3(0.0f); 

if(scaleCoeff >= 2.7f) 
{ 
    float tmp = min((scaleCoeff - 2.7f) * 0.1f, 1.0f); 
    entryPoint = EntryPoint + tmp * (exitPoint - EntryPoint); 
} 
else 
{ 
    entryPoint = EntryPoint; 
} 
// 

Mais si vous savez ou pouvez penser à une meilleure solution qui rend l'effet « être entouré par le volume », je serai heureux si vous laissez moi sais.

Merci.