0

I'm working on my volume rendering application (C# + OpenTK). The volume is being rendered using raycasting, i found a lot of inspiration on this site: http://graphicsrunner.blogspot.sk/2009/01/volume-rendering-101.html, and even though my applications works with OpenGL, the main idea of using 3D texture and other stuff is the same. Application works fine, but after I "flow into the volume" (means inside the bounding box), everything dissapears, and I want to prevent this. So is there some easy way to do this? --> I will be able to flow through the volume or move in the volume.

Here is the code of 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;
}

The code below is based on https://github.com/toolchainX/Volume_Rendering_Using_GLSL

Display() function:

    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);
    }

The problem is (I think) that as I'm moving towards the volume (I don't move the camera, just scaling the volume), if the scale factor > 2.7something, I'm in the volume, it means "after the plane on which is the final picture being rendered", so a can't see anything. The solution (maybe) that I can think of, is something like that: If I reach the scale factor = 2.7something:

1.) -> don't scale the volume

2.) -> somehow told to fragment shader to move EntryPoint towards the RayDirection for some length (probably based on the scale factor).

Now, I tried this "method" and it seems that it can work:

vec3 entryPoint = EntryPoint + some_value * rayDirection;

The some_value have to be clamped between [0,1[ interval (or [0,1]?) , but maybe it doesn't matter thank's to that:

if (EntryPoint == exitPoint)
discard;

So now, maybe (if my solution isn't so bad), I can change my answer to this: How to compute the some_value (based on scale factor which I send to 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;
}

(I'm not native english speeker, so If there are some big mistakes in the text and you don't understand something, just let me know and I'll try to fix these bugs)

Thank's.

imo
  • 11
  • 3

2 Answers2

1

I solved my problem. It doesn't make "being surrounded by the volume" illusion, but now, I can flow through the volume and nothing disappears. This is the code of my solution added to 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;
}
//

But if you know or can think about better solution that makes the "being surrounded by the volume" effect, I'll be glad if you let me know.

Thank you.

imo
  • 11
  • 3
0

If understand correctly, I think you should use Plane Clipping to go through the volume. (I could give you a simple example based on your code if you attach this solution. Translate the whole C++ project to C# is too time-consuming.)

J. Sue
  • 64
  • 6