volume rendering 坐标分析-2

本文详细解释了如何将uv坐标转换为世界坐标系中的浮点数,并在此基础上实现光线与物体的交互。包括uv坐标的定义、视线变换原理、求交过程以及如何从3D纹理中获取颜色信息。

坐标关键代码如下:

//将uv转换为-1到1之间的浮点数
    float u = (x / (float) imageW)*2.0f-1.0f;
    float v = (y / (float) imageH)*2.0f-1.0f;

    // calculate eye ray in world space
    Ray eyeRay;
    eyeRay.o = make_float3(mul(c_invViewMatrix, make_float4(0.0f, 0.0f, 0.0f, 1.0f)));
    eyeRay.d = normalize(make_float3(u, v, -2.0f));//
    eyeRay.d = mul(c_invViewMatrix, eyeRay.d);//
    // find intersection with box
	float tnear, tfar;
	int hit = intersectBox(eyeRay, boxMin, boxMax, &tnear, &tfar);
    if (!hit) return;
	if (tnear < 0.0f) tnear = 0.0f;     // clamp to near plane

    // march along ray from front to back, accumulating color
    float4 sum = make_float4(0.0f);
    float t = tnear;
    float3 pos = eyeRay.o + eyeRay.d*tnear;
    float3 step = eyeRay.d*tstep;

    for(int i=0; i<maxSteps; i++) {
        // read from 3D texture
        // remap position to [0, 1] coordinates
        float sample = tex3D(tex, pos.x*0.5f+0.5f, pos.y*0.5f+0.5f, pos.z*0.5f+0.5f);//?


1、先声明,世界坐标系为x [-1, 1]; y [-1, 1]; z[-1, 1]。(自己随便说是世界坐标系)

2、u,v可以肯定是在[-1, 1]之间变化的,因为x和y 的变化范围分别在[0,imageW]和[0,imageH]变化(x / (float) imageW)在[0,1]变化乘以2在[0,2]变化,再减1,在[-1, 1]变化。

3、说明视线的变化。首先规定眼睛的位置:make_float4(0.0f, 0.0f, 0.0f, 1.0f);然后对眼睛的位置进行仿射变换:mul(c_invViewMatrix, make_float4(0.0f, 0.0f, 0.0f, 1.0f)),这里变换矩阵是变换视点的矩阵,所以是模型变换的逆矩阵。最后,mul(c_invViewMatrix, eyeRay.d); 对视线进行变换。

4、求交,求交也是在世界坐标系下。

5、求纹理坐标。由于纹理生成时,使用了:tex.normalized = true;  所以会对坐标进行标准化范围[0, 1],所以又需要将坐标变换到[0, 1]之间,tex3D(tex, pos.x*0.5f+0.5f, pos.y*0.5f+0.5f, pos.z*0.5f+0.5f); 意思是:[-1, 1]*0.5 + 0.5 = [0, 1]

 

至此坐标变换完成。

体绘制(Volume Rendering)是一种用于可视化三维标量场数据的图形技术,广泛应用于医学成像、科学计算和工程仿真等领域。在OpenGL中实现体绘制通常涉及纹理映射、光线投射(ray casting)或光线步进(ray marching)算法,并结合着色器语言(如GLSL)进行高效的GPU处理。 ### 体绘制的基本原理 体绘制的核心思想是将三维体积数据(volume data)以某种方式投影到二维屏幕上,保留其内部结构信息。常见的方法包括: - **最大强度投影(MIP, Maximum Intensity Projection)**:沿视线方向选取最大值作为像素颜色。 - **合成投影(Compositing)**:通过累积每个采样点的颜色和透明度来模拟光线穿过体积的效果。 - **传输函数(Transfer Function)**:将标量值映射为颜色和不透明度,控制不同组织或材料的显示效果。 ### OpenGL 实现步骤 以下是一个简化的实现流程,适用于基于纹理的体绘制: 1. **加载体积数据** - 使用诸如RAW、VTK等格式读取三维数据集。 - 将数据上传为3D纹理(`GL_TEXTURE_3D`),设置合适的滤波参数。 ```cpp GLuint volumeTexture; glGenTextures(1, &volumeTexture); glBindTexture(GL_TEXTURE_3D, volumeTexture); glTexImage3D(GL_TEXTURE_3D, 0, GL_RED, width, height, depth, 0, GL_RED, GL_UNSIGNED_BYTE, data); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); ``` 2. **构建包围盒(Bounding Box)几何体** - 创建一个包围整个体积的立方体,用于在片段着色器中执行光线步进。 - 可使用两个三角形构成的全屏四边形替代立方体,简化深度计算。 3. **编写GLSL着色器** - **顶点着色器**:传递纹理坐标或世界坐标。 ```glsl #version 450 core layout(location = 0) in vec3 position; out vec3 texCoord; uniform mat4 modelViewProjection; void main() { texCoord = position * 0.5 + 0.5; // 转换到[0,1]范围 gl_Position = modelViewProjection * vec4(position, 1.0); } ``` - **片段着色器**:执行光线步进逻辑,采样3D纹理并应用传输函数。 ```glsl #version 450 core in vec3 texCoord; out vec4 fragColor; uniform sampler3D volumeTex; uniform int numSteps = 100; float transferFunc(float val) { return smoothstep(0.4, 0.6, val); // 简单线性映射示例 } void main() { vec3 rayDir = normalize(texCoord - 0.5); vec3 pos = texCoord; float accumulatedAlpha = 0.0; vec3 color = vec3(0.0); for (int i = 0; i < numSteps; ++i) { float val = texture(volumeTex, pos).r; float alpha = transferFunc(val); color += (1.0 - accumulatedAlpha) * alpha * vec3(val); accumulatedAlpha += alpha; pos += rayDir / float(numSteps); } fragColor = vec4(color, accumulatedAlpha); } ``` 4. **渲染与交互** - 利用变换反馈或Uniform Buffer Object(UBO)更新视角矩阵。 - 添加滑块或颜色编辑器调整传输函数参数。 ### 性能优化建议 - 使用**空域跳跃(Empty Space Skipping)**:跳过没有有效数据的区域,减少不必要的采样。 - 启用**早期退出(Early Ray Termination)**:当累积透明度接近1时停止采样。 - 应用**降采样(Downsampling)**或**自适应步长(Adaptive Step Size)**平衡质量和性能。 - 对大规模数据使用**多分辨率LOD(Level of Detail)**策略。 ### 教程与资源推荐 - [LearnOpenGL Volume Rendering Tutorial](https://learnopengl.com/In-Practice/Volume-Rendering) 提供了详细的分步指导[^1]。 - [GPU Gems 3: Real-Time Volume Rendering](https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch39.html) 深入探讨了高级技巧和优化方案。 - [OpenVR/Volume Rendering Example](https://github.com/OSVR/OSVR-Core/tree/master/src/vrpn) 展示了一个完整的开源实现案例[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值