【译】Volume Rendering

Volume Rendering 101

原文链接 https://graphicsrunner.blogspot.com/2009/01/volume-rendering-101.html
12
Pictures above from: http://www.cs.utah.edu/~jmk/simian/

34
有相当多的文件和论文的体积渲染。但是(就我所见)关于这个主题并没有很多好的教程。因此,本教程将尝试教授体渲染的基础知识,更具体地说体射线投射(Volume ray-casting)(或体射线行进,Volume ray-marching)。

体绘制是一种直接显示3D标量场而无需首先将中间表示形式拟合到数据(例如三角形)的方法。 我们如何渲染没有几何体的体积? 有两种传统的渲染体积的方法:基于切片的渲染和体积光线投射。 本教程将重点介绍体积射线投射。 与光线投射提供的基于片段的渲染相比,有很多优点; 例如跳过空白空间,独立于投影,易于实现以及单次通过。

体积射线投射(也称为射线行进)就是它的发音。 [编辑:体积射线投射与ala Doom或Nick的教程中的射线投射不同]射线投射在体积中,并以相等的间隔采样。 当光线行进通过体积时,通过使用传递函数将标量值映射到光学属性,该传递函数将导致RGBA颜色值,该值包括当前采样点的相应发射和吸收系数。 然后使用从前到后或从后到前的alpha混合来合成此颜色。

本教程将特别着重于如何将射线与体积相交并将其行进穿过体积。 在另一个教程中,我将重点介绍传递函数和着色。 首先,我们需要知道如何读取数据。 数据只是存储为切片[x,y,z]的标量值(通常是整数或浮点数),其中x =宽度,y =高度,z =深度。 每个切片的宽度为x个单位,高度为y个单位,切片的总数等于z。 数据的通用格式将以8位或16位RAW格式存储。 有了数据后,我们需要将其加载到卷纹理中。 这是我们整个过程的方式:

//create the scalar volume texturem
Volume = new Texture3D(Game.GraphicsDevice, mWidth, mHeight, mDepth, 0,
                        TextureUsage.Linear, SurfaceFormat.Single);

private void loadRAWFile8(FileStream file)
{
    BinaryReader reader = new BinaryReader(file);

    byte[] buffer = new byte[mWidth * mHeight * mDepth];
    int size = sizeof(byte);

    reader.Read(buffer, 0, size * buffer.Length);

    reader.Close();

    //scale the scalar values to [0, 1]
    mScalars = new float[buffer.Length];
    for (int i = 0; i < buffer.Length; i++)
    {
        mScalars[i] = (float)buffer[i] / byte.MaxValue;
    }

    mVolume.SetData(mScalars);
    mEffect.Parameters["Volume"].SetValue(mVolume);
}

为了渲染该纹理,我们拟合了一个边界框或立方体,即从体积的[0,0,0]到[1,1,1]。 然后我们渲染立方体并采样体积纹理以渲染体积。 但是,我们还需要找到从眼睛/相机开始并与立方体相交的光线的方法。
5
通过在着色器中执行射线-立方体相交,我们可以计算出从眼睛到当前像素位置与立方体的光线的相交。 但是,执行此操作的更好、更快的方法是将立方体的正面和背面三角形的位置渲染为纹理。 这很容易为我们提供光线的开始和结束位置,并且在着色器中,我们仅对纹理进行采样即可找到采样光线。 这是纹理的外观(正面,背面,光线方向):
678
这是呈现前后位置的代码:

//draw front faces
//draw the pixel positions to the textureGame.GraphicsDevice.SetRenderTarget(0, mFront);
Game.GraphicsDevice.Clear(Color.Black);

base.DrawCustomEffect();

Game.GraphicsDevice.SetRenderTarget(0, null);
//draw back faces
//draw the pixel positions to the textureGame.GraphicsDevice.SetRenderTarget(0, mBack);
Game.GraphicsDevice.Clear(Color.Black);
Game.GraphicsDevice.RenderState.CullMode = CullMode.CullCounterClockwiseFace;

base.DrawCustomEffect();

Game.GraphicsDevice.SetRenderTarget(0, null);
Game.GraphicsDevice.RenderState.CullMode = CullMode.CullClockwiseFace;

现在,为了执行体积的实际光线投射,我们渲染了立方体的正面。 在着色器中,我们对前后位置纹理进行采样,以找到将对体积进行采样的射线的方向(后-前)和起始位置(前)。 然后,通过沿等距距离沿射线前进当前采样位置,对体积进行迭代采样。 并且我们使用从前到后的合成来累积像素颜色。

float4 RayCastSimplePS(VertexShaderOutput input) : COLOR0{
    //calculate projective texture coordinates
    //used to project the front and back position textures onto the cube
    float2 texC = input.pos.xy /= input.pos.w;
    texC.x =  0.5f*texC.x + 0.5f;
    texC.y = -0.5f*texC.y + 0.5f;
 
    float3 front = tex2D(FrontS, texC).xyz;
    float3 back = tex2D(BackS, texC).xyz;
 
    float3 dir = normalize(back - front);
    float4 pos = float4(front, 0);
 
    float4 dst = float4(0, 0, 0, 0);
    float4 src = 0;
 
    float value = 0;
 
    float3 Step = dir * StepSize;
 
    for(int i = 0; i < Iterations; i++)
    {
        pos.w = 0;
        value = tex3Dlod(VolumeS, pos).r;
             
        src = (float4)value;
        src.a *= .5f; //reduce the alpha to have a more transparent result 
         
        //Front to back blending
        // dst.rgb = dst.rgb + (1 - dst.a) * src.a * src.rgb
        // dst.a   = dst.a   + (1 - dst.a) * src.a     
        src.rgb *= src.a;
        dst = (1.0f - dst.a)*src + dst;     
     
        //break from the loop when alpha gets high enough
        if(dst.a >= .95f)
            break; 
     
        //advance the current position
        pos.xyz += Step;
     
        //break if the position is greater than <1, 1, 1>
        if(pos.x > 1.0f  pos.y > 1.0f  pos.z > 1.0f)
            break;
    }
 
    return dst;
}

下面是采样的结果:一只脚,一个里面有龙虾的茶壶,引擎,盆景树,动脉瘤的ct扫描,头骨和泰迪熊。
9
10
11
12
13
14
15
项目源码:https://onedrive.live.com/authkey=%21AJM7E5k%5FxeKVfss&id=B80A3031B5BFA52B%21123&cid=B80A3031B5BFA52B

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值