当前位置: 首页 > article >正文

7、基于osg引擎实现读取vtk数据通过着色器实现简单体渲染(1)

基于光线投射原理实现的体渲染

  • 一、什么是体绘制?
  • 二、为什么不直接用3D模型渲染
  • 三、原理及部分代码解析
    • 1、什么是光线?
    • 2、什么是光线投射?
    • 3、为什么需要光线投射3D纹理?
    • 4、为什么必须是3D纹理?
    • 5、为什么还需要1D纹理?
    • 6、什么是光线投射?
    • 7、为什么必须使用光线投射?
    • 8、光线投射的完整流程
    • 9、平衡细节锐度和整体柔和度
    • 10、代码中的关键设计
    • 11、性能优化策略
    • 12、改进点
  • 四、着色器代码
    • 1、顶点着色器代码
    • 2、片元着色器代码

一、什么是体绘制?

1、核心目标:将三维离散标量场(如医学CT、MRI数据)可视化为二维图像
2、技术难点:数据量大(百万级体素)、需表现内部结构(如半透明、遮挡关系)
3、常见应用:医疗影像、流体模拟、地质勘探

二、为什么不直接用3D模型渲染

数据本质差异:CT/MRI等数据是空间标量长,没有显式表面。
渲染结果:三角网格可视化结果,模型内部是空的,没内容;但是体渲染无论内部还是表面都是有内容的。
示例:肺部CT中,肺泡结构无法用三角网格描述。

三、原理及部分代码解析

1、什么是光线?

在体渲染中,光线是一个数学抽象概念,描述从相机出发穿过三维空间的虚拟视线。

2、什么是光线投射?

光线投射(Ray Casting)是一种体数据可视化算法,通过模拟光线在三维空间中的传播过程,将离散的体数据(如CT、MRI扫描的体素)渲染为二维图像。
其核心思想是:​从每个像素反向投射一条光线穿过三维体数据,沿光线路径累积颜色和透明度,最终合成像素颜色。

3、为什么需要光线投射3D纹理?

3D纹理的作用:
存储原始体数据:每个体素(voxel)保存一个标量值,表示该空间位置的物理属性。
·医学CT:亨利单位
·流体模拟:密度、速度等
空间映射:通过(pos-minBound)/(maxBound-minBound)将模型坐标转换为纹理坐标

4、为什么必须是3D纹理?

三维数据本质:体数据本身是三维的(宽×高×深),无法用2D纹理表达。
​硬件优化:GPU对3D纹理的插值(三线性插值)和缓存机制专门优化,采样效率远高于手动计算体素位置。
​空间连续性:3D纹理的自动插值能平滑相邻体素间的密度值,避免“马赛克”伪影。

5、为什么还需要1D纹理?

从3D纹理中读取某个空间位置的标量值,但是最终要将其转换为颜色,着色器怎么知道这个标量值应该对应什么颜色呢?1D纹理就起到了这个作用。
语义映射:将标量值转换为可视属性
·输入:密度值(0~1)
·输出:RGBA颜色
示例:

# 肺部CT的典型传输函数
if density < 0.2: return (0,0,0,0)    # 空气→全透明
elif 0.2<d<0.3: return (1,0.8,0.6,0.1) # 软组织→半透明肉色
else: return (1,1,1,0.8)              # 骨骼→不透明白色

6、什么是光线投射?

光线投射(Ray Casting)是一种体数据可视化算法,通过模拟光线在三维空间中的传播过程,将离散的体数据(如CT、MRI扫描的体素)渲染为二维图像。
其核心思想是:​从每个像素反向投射一条光线穿过三维体数据,沿光线路径累积颜色和透明度,最终合成像素颜色。

7、为什么必须使用光线投射?

无结构限制:不需要预先生成表面几何
全空间采样:能捕捉任意位置的细节

8、光线投射的完整流程

    A[相机像素] --> B(发射光线)B --> C{与体数据包围盒相交?}C -->|| D[丢弃/背景色]C -->|| E[沿光线步进采样]E --> F[获取体素密度]F --> G[传输函数映射颜色]G --> H[累积颜色与透明度]H --> I{透明度饱和?}I -->|| J[提前终止]I -->|| EJ --> K[输出最终颜色]

关键步骤
1)光线生成
原理:从相机每个像素发射一条视线方向的光线

vec3 rayDir = normalize(vDirection); // 视线方向
vec3 rayStart = vCameraModelPosition; // 相机位置

2)包围盒求交
目的:快速确定光线与体数据的有效交集区域
算法:
·计算光线与包围盒各面的交点tmin、tmax
·取最大tmin作为入口点,最小tmax作为出口点

vec2 hitBox(vec3 orig, vec3 dir) { /* 返回 near 和 far 值 */ }

3)光线步进(Ray Marching)
采样间隔: △ t = 3 s t e p s ( 保证覆盖最大体素对角线 ) △t=\frac{\sqrt3}{steps}(保证覆盖最大体素对角线) t=steps3 (保证覆盖最大体素对角线)

for (float t = near; t < far; t += delta) {vec3 pos = rayStart + t * rayDir; // 当前采样点// 获取密度和颜色...
}

9、平衡细节锐度和整体柔和度

    for (float t = bounds.x; t < bounds.y; t += delta) {sampleStart = vCameraModelPosition + t * rayDir;vec3 texCoord = (sampleStart - minBound) * voxelSizeInv;float density = texture3D(baseTexture, texCoord).r;vec4 color = texture1D(tfTexture, density);color.rbg = pow(color.rbg, vec3(2.2));//从gamma空间转换到线性空间color *= densityFactor * delta;finalColor += T*color;T*=1.0-color.a;if (T<0.01) break;}

densityFactor 是体渲染中平衡细节锐度与整体柔和度的关键参数:

​锐化模式​(大值):突出高密度结构,适合硬表面检测,光线被快速吸收(如浓雾),短距离内不透明。
​柔和模式​(小值):增强半透明效果,适合生物组织或流体可视化,光线缓慢衰减(如薄雾),长距离混合。
通过调整此参数,用户可以在不修改传输函数或数据的前提下,快速优化渲染结果的视觉风格。
与 steps 的协同:
当 densityFactor 较小时,需增加 steps 以保证采样足够深度,避免漏掉细节。
当 densityFactor 较大时,可减少 steps 以优化性能(因光线提前终止)。

10、代码中的关键设计

1)模型空间 → 纹理空间:
t e x C o o r d = 模型坐标 − m i n B o u n d m a x B o u n d − m i n B o u n d ( 确保采样位置与体数据纹理对齐 ) texCoord=模型坐标-minBound\over maxBound-minBound(确保采样位置与体数据纹理对齐) maxBoundminBound(确保采样位置与体数据纹理对齐)texCoord=模型坐标minBound
2)伽马校正

// 采样后转线性空间
color.rgb = pow(color.rgb, vec3(2.2)); 
// 输出前转回sRGB空间
gl_FragColor.rgb = pow(finalColor.rgb, vec3(1.0/2.2));

11、性能优化策略

包围盒剪裁:减少无效采样次数
​自适应步长:在低密度区域增大步长
​提前终止:当透明度接近完全不透明时停止采样

12、改进点

1)增加参数以实现剖切(裁剪)功能;
2)性能优化:自适应步长

float currentStep = delta; // 基础步长
if (density < 0.01) {      // 空区域加速currentStep *= 4.0;    // 增大步长t += currentStep;      // 直接跳过空区域continue;
} else if (density < 0.1) { currentStep *= 2.0;    // 半空区域中等加速
}
// 正常采样...

3)使用八叉树优化体渲染性能,显著较少光线投射中的无效采样次数。

四、着色器代码

1、顶点着色器代码

#version 110
/* GLSL 1.10需要显式声明精度 (OpenGL ES要求) */
#ifdef GL_ES
precision highp  float;
#endif
// 体数据采样步长
uniform float xStepSize,yStepSize,zStepSize;
// 体数据纹理和颜色纹理
uniform sampler3D baseTexture;
uniform sampler1D tfTexture;
// 体数据包围盒边界
uniform vec3 minBound,maxBound;
varying vec3 vDirection;//模型空间下的光线方向
varying vec3 vCameraModelPosition;//模型空间下的相机位置
void main(void)
{// 计算裁剪空间的位置gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;vec4 cameraPos = (gl_ModelViewMatrixInverse * vec4(0, 0, 0, 1));vCameraModelPosition = cameraPos.xyz/cameraPos.w;vDirection = gl_Vertex.xyz/gl_Vertex.w- vCameraModelPosition;}

2、片元着色器代码

#version 110
/* GLSL 1.10需要显式声明精度 (OpenGL ES要求) */
#ifdef GL_ES
precision highp  float;
precision highp sampler3D;
precision highp sampler1D;
#endif
#define EPSILON 1e-3// 体数据纹理和颜色纹理
uniform sampler3D baseTexture;
uniform sampler1D tfTexture;uniform int steps;//采样步长,值越大,采样次数越多,效果越小,但性能越差
uniform float densityFactor;//值越大,颜色变化剧烈,细节边界变得锐利,可能出现不平滑的锯齿状过渡;值越小,颜色变化缓慢,叠加的颜色较多,导致整体视觉上更加柔和、模糊,增强了雾气感
// 体数据包围盒边界
uniform vec3 minBound,maxBound;varying vec3 vDirection;//模型空间下的光线方向
varying vec3 vCameraModelPosition;//模型空间下的相机位置const int maxSamples = 256;
vec2 hitBox(vec3 orig, vec3 dir) {vec3 inv_dir = 1.0 / dir;// 光线方向倒数(处理正负方向)vec3 tmin_tmp = (minBound - orig) * inv_dir;// 沿光线方向到达包围盒各轴最小边界的距离vec3 tmax_tmp = (maxBound - orig) * inv_dir; // 沿光线方向到达包围盒各轴最大边界的距离vec3 tmin = min(tmin_tmp, tmax_tmp);// 各轴向的最近交点vec3 tmax = max(tmin_tmp, tmax_tmp);// 各轴向的最远交点float near = max(max(tmin.x, max(tmin.y, tmin.z)),0.0);// 光线最终进入包围盒的距离float far = min(tmax.x, min( tmax.y, tmax.z)); // 光线最终离开包围盒的距离return vec2( near, far );
}void main(void)
{vec3 rayDir = normalize(vDirection);vec2 bounds = hitBox( vCameraModelPosition, rayDir );bounds.x -= 0.000001;if ( bounds.x >= bounds.y) discard;//光线与包围盒无交点。vec3 sampleStart = vCameraModelPosition + bounds.x * rayDir;// 初始化颜色累积vec4 finalColor = vec4(0.0);const float opacityThreshold = 0.99;   // 不透明度阈值float T = 1.0;// 光线步进采样float delta = sqrt(3.0) / float(steps);             // 均匀步长vec3 voxelSizeInv = 1.0 / (maxBound - minBound); for (float t = bounds.x; t < bounds.y; t += delta) {sampleStart = vCameraModelPosition + t * rayDir;vec3 texCoord = (sampleStart - minBound) * voxelSizeInv;float density = texture3D(baseTexture, texCoord).r;vec4 color = texture1D(tfTexture, density);color.rbg = pow(color.rbg, vec3(2.2));//从gamma空间转换到线性空间color *= densityFactor * delta;finalColor += T*color;T*=1.0-color.a;if (T<0.01) break;}// 丢弃完全透明的片元if (finalColor.a < EPSILON) discard;finalColor.rgb = pow(finalColor.rgb, vec3(1.0/2.2));gl_FragColor = finalColor;}

体渲染结果

相关文章:

7、基于osg引擎实现读取vtk数据通过着色器实现简单体渲染(1)

基于光线投射原理实现的体渲染 一、什么是体绘制&#xff1f;二、为什么不直接用3D模型渲染三、原理及部分代码解析1、什么是光线&#xff1f;2、什么是光线投射&#xff1f;3、为什么需要光线投射3D纹理&#xff1f;4、为什么必须是3D纹理&#xff1f;5、为什么还需要1D纹理&a…...

二、vtkCommand的使用

一、概述 vtkCommand是VTK中的一个重要的类&#xff0c;用于处理事件和回调机制。它允许用户在特定事件发生时执行自定义的操作&#xff0c;例如在交互操作、数据更新或渲染过程中触发某些功能。 二、主要功能 1、事件处理&#xff1a;vtkCommand用于监听和处理VTK管线中的各…...

Git的详细使用方法

Git 是一个分布式版本控制系统&#xff0c;用于跟踪和管理代码的变更。以下是 Git 的详细使用方法&#xff1a; 1. 安装 Git Windows&#xff1a;从 Git 官网 下载安装包。 Linux&#xff08;Ubuntu/Debian&#xff09; sudo apt install git macOS&#xff1a; 使用 Homebr…...

在 Windows 上使用 choco 安装 mkcert 并配置 Vue 运行HTTPS

解决在Windows上使用Vue本地运行HTTPS的问题,vue-cli或vite都可以使用 步骤 1&#xff1a;确认 Chocolatey 是否已安装 1. 检查 choco 命令是否可用 打开 PowerShell&#xff08;管理员权限&#xff09;&#xff0c;输入&#xff1a; choco -v如果显示版本号&#xff08;如…...

spring声明式事务原理01-调用第1层@Transactional方法(事务访问入口)

文章目录 【README】【步骤1】UserAppService调用userSupport.saveNewUser()【步骤2】获取到TransactionInterceptor【步骤3】chain不为空&#xff0c;接着执行CglibMethodInvocation#proceed方法【补充】AopContext作用 【步骤4】CglibMethodInvocation#proceed方法【步骤5】调…...

Qt-D指针与Q指针的设计哲学

文章目录 前言PIMLP与二进制兼容性D指针Q指针优化d指针继承Q_D和Q_Q 前言 在探索Qt源码的过程中会看到类的成员有一个d指针&#xff0c;d指针类型是一个private的类&#xff0c;这种设计模式称为PIMPL&#xff08;pointer to implementation&#xff09;&#xff0c;本文根据Q…...

数据结构——单链表list

前言&#xff1a;大家好&#x1f60d;&#xff0c;本文主要介绍数据结构——单链表 目录 一、单链表 二、使用步骤 1.结构体定义 2.初始化 3.插入 3.1 头插 3.2 尾插 3.3 按位置插 四.删除 4.1头删 4.2 尾删 4.3 按位置删 4.4按值删 五 统计有效值个数 六 销毁…...

java 的标记接口RandomAccess使用方法

在 Java 中&#xff0c;RandomAccess 是一个标记接口&#xff08;marker interface&#xff09;&#xff0c;用于标识实现该接口的 List 实现类支持快速&#xff08;通常是常数时间复杂度 O(1)&#xff09;的随机访问。常见的实现类包括 ArrayList&#xff0c;而不包括 LinkedL…...

基于PHP的网店进销存管理系统(源码+lw+部署文档+讲解),源码可白嫖!

摘要 相比于以前的传统进销存管理方式&#xff0c;智能化的管理方式可以大幅降低进销存管理的运营人员成本&#xff0c;实现了进销存管理的标准化、制度化、程序化的管理&#xff0c;有效地防止了商品信息及仓库信息的随意管理&#xff0c;提高了信息的处理速度和精确度&#…...

Vue3 Pinia $subscribe localStorage的用法 Store的组合式写法

Vue3 Pinia $subscribe 可以用来监视Stroe数据的变化 localStorage的用法 localStorage中只能存字符串&#xff0c;所有对象要选转成json字符串 定义store时&#xff0c;从localStorage中读取数据talkList可能是字符串也可能是空数组 Store的组合式写法 直接使用reactiv…...

【PHP】获取PHP-FPM的状态信息

文章目录 一、前言二、环境三、过程1&#xff09;修改PHP-FPM配置文件2&#xff09;修改Nginx配置文件3&#xff09;访问页面4&#xff09;修改状态页面端口 一、前言 PHP-FPM内置有一个状态页面&#xff0c;通过这个页面可以获取到FPM的一些状态信息&#xff08;见下图&#…...

(性能测试)性能测试工具 2.jmeter的环境搭建 3jmeter元件和4使用实例 5jmeter元件和参数化

目录 性能测试工具 性能测试工具 jemeter环境搭建 jmeter的常用目录介绍 jmeter修改语言和主题--jmeter界面的汉化 jmeter元件 jmeter元件和组件的介绍 jmeter的作用域原则 jmeter的执行顺序 案例&#xff1a;执行顺序 jmeter使用案例 jmeter线程组的介绍 jmeter…...

Java 大视界 -- 基于 Java 的大数据实时流处理中的窗口操作与时间语义详解(135)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…...

数据库的基本知识

目录 一、创建数据库和数据表1.1 创建数据库相关代码1.2 创建数据表1.3 约束条件1.3.1 主键约束1.3.2 非空约束1.3.3 唯一性约束1.3.4 默认约束1.3.5 自增字段 1.4 手工建表 二、数据查询功能2.1 sql 查询的7个关键词2.1.1 select2.1.2 from2.1.3 where2.1.4 group by2.1.5 hav…...

失败的面试经历(ʘ̥∧ʘ̥)

一.面向对象的三大特性 1.封装&#xff1a;将对象内部的属性私有化&#xff0c;外部对象不能够直接访问&#xff0c;但是可以提供一些可以使外部对象操作内部属性的方法。 2.继承&#xff1a;类与类之间会有一些相似之处&#xff0c;但也会有一些异处&#xff0c;使得他们与众…...

【Jmeter】使用教程

下载及安装 参考链接: JMeter下载及安装&#xff08;附插件及中文包超详细&#xff09; 参考链接: 【Jmeter】win 10 / win 11&#xff1a;Jmeter 下载、安装、汉化、新机迁移、版本更新&#xff08;Jmeter 4 以上版本均适用&#xff09; 分辨率的调整 参考链接: Jmeter5.3字…...

Android 7 及以上夜神模拟器,Fiddler 抓 https 包

文章目录 问题描述解决方案环境准备操作步骤1、导出 Fiddler 证书并修改成 .pem 和 .0 文件2、修改夜神模拟器配置3、打开夜神模拟器设备的 USB 调试选项4、将0725b47c.0证书放入夜神模拟器系统证书目录5、夜神模拟器 cmd 环境配置6、给 0725b47c.0 证书赋予权限7、打开 fiddle…...

全国医院数据可视化分析系统

【大数据】全国医院数据可视化分析系统 &#xff08;完整系统源码开发笔记详细部署教程&#xff09;✅ 目录 一、项目简介二、项目界面展示三、项目视频展示 一、项目简介 &#x1f3e5; 项目名&#xff1a;医疗导航神器&#xff01;——《基于大数据的微医挂号网医院数据可视…...

音视频入门基础:RTCP专题(1)——RTCP官方文档下载

一、引言 实时传输控制协议&#xff08;Real-time Transport Control Protocol或RTP Control Protocol或简写RTCP&#xff09;是实时传输协议&#xff08;RTP&#xff09;的一个姐妹协议。RTCP由《RFC 3550》定义&#xff08;取代废弃的《RFC 1889》&#xff09;。RTP使用一个…...

蓝桥杯专项复习——结构体、输入输出

目录 结构体&#xff1a;排序 输入输出 结构体&#xff1a;排序 [NOIP2007]奖学金 #include<iostream> #include<cstring> #include<algorithm>using namespace std;const int N310; int n;struct Student {int chinese,math,eng,sum;int idx; }Stu[N];//定…...

工作记录 2017-01-06

工作记录 2017-01-06 序号 工作 相关人员 1 协助BPO进行Billing的工作。 修改CSV、EDI837的导入。 修改邮件上的问题。 更新RD服务器。 郝 修改的问题&#xff1a; 1、 In “Full Job Summary” (patient info.), sometime, the Visit->Facility is missed, then …...

探索 Rust 高效 Web 开发:Hyperlane 框架深度解析

探索 Rust 高效 Web 开发&#xff1a;Hyperlane 框架深度解析 在当今的 Web 开发领域&#xff0c;追求高性能、轻量级的框架一直是开发者们的不懈追求。对于 Rust 语言开发者而言&#xff0c;Hyperlane 框架正以其独特的魅力崭露头角&#xff0c;为构建现代 Web 服务提供了一种…...

LLM(2):准备构建 LLM

在了解大语言模型一文中&#xff0c;对 LLM 做了初步介绍&#xff0c;本文接续前一篇文章的内容&#xff0c;简要介绍 LLM 的应用和构建过程。 1.2 LLM 的应用 由于大型语言模型&#xff08;LLMs&#xff09;在解析和理解非结构化文本数据方面具备先进能力&#xff0c;它们在…...

pytest+allure+jenkins

本地运行参考&#xff1a;pytestallure 入门-CSDN博客 jenkins运行如下&#xff1a; 安装插件&#xff1a;allure 配置allure安装目录 配置pytest、allure 环境变量 配置流水线 进行build,结果如下 ,点击allure report 查看结果...

[蓝桥杯]花束搭配【算法赛】

题目链接 题意 n朵花 每朵花有两个属性a,b 如果两朵花满足 a i a j > b i b j a_ia_j>b_ib_j ai​aj​>bi​bj​ 就称为完美方案 求一共有多少种完美方案 ( i , j ) 与 ( j , i ) (i,j)与(j,i) (i,j)与(j,i)视为不同组合 思路 数据范围 1 ≤ n ≤ 2 1 0 5 1\…...

大模型架构全景解析:从Transformer到未来计算范式

1. Transformer 架构 核心模型 GPT-4、BERT、T5、LLaMA、通义千问、文心ERNIE 关键技术 多头注意力&#xff1a;GPT-4 使用 96 头注意力位置编码创新&#xff1a;LLaMA 采用 RoPE&#xff08;旋转位置编码&#xff09;&#xff0c;Claude 3 引入 ALiBi归一化优化&#xff1…...

【linux篇】--linux常见指令

文章目录 一、Linux基本概念 二、Linux入门 1.目录结构 2.Linux命令 *Linux基础命令 ls命令的选项&#xff1a; 3.目录切换相关命令&#xff08;cd & pwd) 4.相对&绝对路径和特殊路径符 4.1相对路径 4.2绝对路径 4.3 你特殊路径符 5.创建目录命令&#xff08;mkdir) 6.…...

Kubernetes的组成和架构

Kubernetes&#xff08;K8s&#xff09;是一个开源的容器编排平台&#xff0c;用于自动化部署、扩展和管理容器化应用程序。它由多个组件组成&#xff0c;这些组件可以分为两类&#xff1a;控制平面&#xff08;Control Plane&#xff09;组件和节点&#xff08;Node&#xff0…...

ElementUI 表格中插入图片缩略图,鼠标悬停显示大图

如何在 ElementUI 的表格组件 Table 中插入图片缩略图&#xff0c;通过鼠标悬停显示大图&#xff1f;介绍以下2种方式&#xff1a; 方法1&#xff1a;直接在模板元素中插入 <template><el-table :data"tableData"><el-table-column label"图片…...

【实战ES】实战 Elasticsearch:快速上手与深度实践-附录-1-常用命令速查表-集群健康检查、索引生命周期管理、故障诊断命令

&#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 附录-常用命令速查表 1-Elasticsearch 运维命令速查表&#xff08;集群健康检查、ILM管理、故障诊断&#xff09;一、集群健康检查与监控1.1 集群健康状态核心命令1.2 节点级健康诊断…...