CSharpGL(25)一个用raycast实现体渲染VolumeRender的例子
2016-05-31 01:42
866 查看
[b]CSharpGL(25)一个用raycast实现体渲染VolumeRender的例子 [/b]
本文涉及的VolumeRendering相关的C#代码是从(https://github.com/toolchainX/Volume_Rendering_Using_GLSL)的C++代码转换来的。
Initialize
raycast做volume rendering的这个例子中,最耗空间的是3D纹理。但是这是无法避免的。其他空间和时间耗费都是极少的。
欢迎对OpenGL有兴趣的同学关注(https://github.com/bitzhuwei/CSharpGL)
本文涉及的VolumeRendering相关的C#代码是从(https://github.com/toolchainX/Volume_Rendering_Using_GLSL)的C++代码转换来的。
效果图
protected override void DoInitialize() { InitBackfaceRenderer(); InitRaycastRenderer(); initTFF1DTex(@"10RaycastVolumeRender\tff.dat"); int[] viewport = OpenGL.GetViewport(); initFace2DTex(viewport[2], viewport[3]); initVol3DTex(@"10RaycastVolumeRender\head256.raw", 256, 256, 225); initFrameBuffer(viewport[2], viewport[3]); //this.depthTest = new DepthTestSwitch(); RaycastingSetupUniforms(); } private void RaycastingSetupUniforms() { // setting uniforms such as // ScreenSize // StepSize // TransferFunc // ExitPoints i.e. the backface, the backface hold the ExitPoints of ray casting // VolumeTex the texture that hold the volume data i.e. head256.raw int[] viewport = OpenGL.GetViewport(); this.raycastRenderer.SetUniform("ScreenSize", new vec2(viewport[2], viewport[3])); this.raycastRenderer.SetUniform("StepSize", g_stepSize); this.raycastRenderer.SetUniform("TransferFunc", new samplerValue(BindTextureTarget.Texture1D, transferFunc1DTexObj[0], OpenGL.GL_TEXTURE0)); this.raycastRenderer.SetUniform("ExitPoints", new samplerValue(BindTextureTarget.Texture2D, backface2DTexObj[0], OpenGL.GL_TEXTURE1)); this.raycastRenderer.SetUniform("VolumeTex", new samplerValue(BindTextureTarget.Texture3D, vol3DTexObj[0], OpenGL.GL_TEXTURE2)); var clearColor = new float[4]; OpenGL.GetFloat(GetTarget.ColorClearValue, clearColor); this.raycastRenderer.SetUniform("backgroundColor", clearColor.ToVec4()); } private void initFrameBuffer(int texWidth, int texHeight) { // create a depth buffer for our framebuffer var depthBuffer = new uint[1]; OpenGL.GetDelegateFor<OpenGL.glGenRenderbuffersEXT>()(1, depthBuffer); OpenGL.GetDelegateFor<OpenGL.glBindRenderbufferEXT>()(OpenGL.GL_RENDERBUFFER, depthBuffer[0]); OpenGL.GetDelegateFor<OpenGL.glRenderbufferStorageEXT>()(OpenGL.GL_RENDERBUFFER, OpenGL.GL_DEPTH_COMPONENT, texWidth, texHeight); // attach the texture and the depth buffer to the framebuffer OpenGL.GetDelegateFor<OpenGL.glGenFramebuffersEXT>()(1, frameBuffer); OpenGL.GetDelegateFor<OpenGL.glBindFramebufferEXT>()(OpenGL.GL_FRAMEBUFFER_EXT, frameBuffer[0]); OpenGL.GetDelegateFor<OpenGL.glFramebufferTexture2DEXT>()(OpenGL.GL_FRAMEBUFFER_EXT, OpenGL.GL_COLOR_ATTACHMENT0_EXT, OpenGL.GL_TEXTURE_2D, backface2DTexObj[0], 0); OpenGL.GetDelegateFor<OpenGL.glFramebufferRenderbufferEXT>()(OpenGL.GL_FRAMEBUFFER_EXT, OpenGL.GL_DEPTH_ATTACHMENT_EXT, OpenGL.GL_RENDERBUFFER, depthBuffer[0]); checkFramebufferStatus(); //OpenGL.Enable(GL_DEPTH_TEST); } private void checkFramebufferStatus() { uint complete = OpenGL.GetDelegateFor<OpenGL.glCheckFramebufferStatusEXT>()(OpenGL.GL_FRAMEBUFFER_EXT); if (complete != OpenGL.GL_FRAMEBUFFER_COMPLETE_EXT) { throw new Exception("framebuffer is not complete"); } } private void initVol3DTex(string filename, int width, int height, int depth) { var data = new UnmanagedArray<byte>(width * height * depth); unsafe { int index = 0; int readCount = 0; byte* array = (byte*)data.Header.ToPointer(); using (var fs = new FileStream(filename, FileMode.Open, FileAccess.Read)) using (var br = new BinaryReader(fs)) { int unReadCount = (int)fs.Length; const int cacheSize = 1024 * 1024; do { int min = Math.Min(cacheSize, unReadCount); var cache = new byte[min]; readCount = br.Read(cache, 0, min); if (readCount != min) { throw new Exception(); } for (int i = 0; i < readCount; i++) { array[index++] = cache[i]; } unReadCount -= readCount; } while (readCount > 0); } } OpenGL.GenTextures(1, vol3DTexObj); // bind 3D texture target OpenGL.BindTexture(OpenGL.GL_TEXTURE_3D, vol3DTexObj[0]); OpenGL.TexParameteri(OpenGL.GL_TEXTURE_3D, OpenGL.GL_TEXTURE_MAG_FILTER, (int)OpenGL.GL_LINEAR); OpenGL.TexParameteri(OpenGL.GL_TEXTURE_3D, OpenGL.GL_TEXTURE_MIN_FILTER, (int)OpenGL.GL_LINEAR); OpenGL.TexParameteri(OpenGL.GL_TEXTURE_3D, OpenGL.GL_TEXTURE_WRAP_S, (int)OpenGL.GL_REPEAT); OpenGL.TexParameteri(OpenGL.GL_TEXTURE_3D, OpenGL.GL_TEXTURE_WRAP_T, (int)OpenGL.GL_REPEAT); OpenGL.TexParameteri(OpenGL.GL_TEXTURE_3D, OpenGL.GL_TEXTURE_WRAP_R, (int)OpenGL.GL_REPEAT); // pixel transfer happens here from client to OpenGL server OpenGL.PixelStorei(OpenGL.GL_UNPACK_ALIGNMENT, 1); OpenGL.TexImage3D(OpenGL.GL_TEXTURE_3D, 0, (int)OpenGL.GL_INTENSITY, width, height, depth, 0, OpenGL.GL_LUMINANCE, OpenGL.GL_UNSIGNED_BYTE, data.Header); data.Dispose(); } private void initFace2DTex(int width, int height) { OpenGL.GenTextures(1, backface2DTexObj); OpenGL.BindTexture(OpenGL.GL_TEXTURE_2D, backface2DTexObj[0]); OpenGL.TexParameteri(OpenGL.GL_TEXTURE_2D, OpenGL.GL_TEXTURE_WRAP_S, (int)OpenGL.GL_REPEAT); OpenGL.TexParameteri(OpenGL.GL_TEXTURE_2D, OpenGL.GL_TEXTURE_WRAP_T, (int)OpenGL.GL_REPEAT); OpenGL.TexParameteri(OpenGL.GL_TEXTURE_2D, OpenGL.GL_TEXTURE_MIN_FILTER, (int)OpenGL.GL_NEAREST); OpenGL.TexParameteri(OpenGL.GL_TEXTURE_2D, OpenGL.GL_TEXTURE_MAG_FILTER, (int)OpenGL.GL_NEAREST); OpenGL.TexImage2D(OpenGL.GL_TEXTURE_2D, 0, OpenGL.GL_RGBA16F, width, height, 0, OpenGL.GL_RGBA, OpenGL.GL_FLOAT, IntPtr.Zero); } private void initTFF1DTex(string filename) { // read in the user defined data of transfer function byte[] tff; using (var fs = new FileStream(filename, FileMode.Open, FileAccess.Read)) using (var br = new BinaryReader(fs)) { tff = br.ReadBytes((int)fs.Length); } OpenGL.GenTextures(1, transferFunc1DTexObj); OpenGL.BindTexture(OpenGL.GL_TEXTURE_1D, transferFunc1DTexObj[0]); OpenGL.TexParameteri(OpenGL.GL_TEXTURE_1D, OpenGL.GL_TEXTURE_WRAP_S, (int)OpenGL.GL_REPEAT); OpenGL.TexParameteri(OpenGL.GL_TEXTURE_1D, OpenGL.GL_TEXTURE_MIN_FILTER, (int)OpenGL.GL_NEAREST); OpenGL.TexParameteri(OpenGL.GL_TEXTURE_1D, OpenGL.GL_TEXTURE_MAG_FILTER, (int)OpenGL.GL_NEAREST); OpenGL.PixelStorei(OpenGL.GL_UNPACK_ALIGNMENT, 1); OpenGL.TexImage1D(OpenGL.GL_TEXTURE_1D, 0, OpenGL.GL_RGBA8, 256, 0, OpenGL.GL_RGBA, OpenGL.GL_UNSIGNED_BYTE, tff); } private void InitRaycastRenderer() { var shaderCodes = new ShaderCode[2]; shaderCodes[0] = new ShaderCode(File.ReadAllText(@"10RaycastVolumeRender\raycasting.vert"), ShaderType.VertexShader); shaderCodes[1] = new ShaderCode(File.ReadAllText(@"10RaycastVolumeRender\raycasting.frag"), ShaderType.FragmentShader); var map = new PropertyNameMap(); map.Add("position", "position"); map.Add("color", "color"); this.raycastRenderer = new Renderer(model, shaderCodes, map); this.raycastRenderer.Initialize(); this.raycastRenderer.SwitchList.Add(new CullFaceSwitch(CullFaceMode.Back, true)); } private void InitBackfaceRenderer() { var shaderCodes = new ShaderCode[2]; shaderCodes[0] = new ShaderCode(File.ReadAllText(@"10RaycastVolumeRender\backface.vert"), ShaderType.VertexShader); shaderCodes[1] = new ShaderCode(File.ReadAllText(@"10RaycastVolumeRender\backface.frag"), ShaderType.FragmentShader); var map = new PropertyNameMap(); map.Add("position", "position"); map.Add("color", "color"); this.backfaceRenderer = new Renderer(model, shaderCodes, map); this.backfaceRenderer.Initialize(); this.backfaceRenderer.SwitchList.Add(new CullFaceSwitch(CullFaceMode.Front, true)); }
Initialize
总结
当然,也可以先渲染出起始点,然后再找到终点的时候计算各个像素点的颜色值。raycast做volume rendering的这个例子中,最耗空间的是3D纹理。但是这是无法避免的。其他空间和时间耗费都是极少的。
欢迎对OpenGL有兴趣的同学关注(https://github.com/bitzhuwei/CSharpGL)
相关文章推荐
- LINQ用法学习
- c#遍历一个文件夹下的所有文件包括子文件夹
- C#中问号的使用
- C#基础之内存分配
- C# 插入排序算法
- C#用链式方法
- C#中Math类的计算整数的三种方法
- C#通用类型转换方法
- C#用DataTable实现Group by数据统计
- c# MD5的加密和解密
- (C#基础) byte[] 之初始化, 赋值,转换。
- c#获取当前应用程序所在路径
- C# 字符串加密解密方法
- c# EF基础记录
- .NET C# Tostring() format 格式化字符串大全
- C# 控制台输出
- C#基础之内存分配
- C# 窗体应用程序制作虚拟键盘按键功能
- C#截取字符串(String.Substring方法)
- C#委托与代理