我试图实现基于光线投射的体绘制,因此我需要将float数组作为纹理(Sampler3D)传递给片段着色器。 我有一个包含所有体素的体数据结构。每个体素包含密度值。因此,对于处理,我将值存储到浮点数组中。
//initialize glew, initialize glfw, create window, etc.
float* density;
density = new float[volume->size()];
for (int i = 0; i < volume->size(); i++){
density[i] = volume->voxel(i).getValue();
}
然后我尝试创建和绑定纹理。
glGenTextures(1, &textureHandle);
glBindTexture(GL_TEXTURE_3D, textureHandle);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_REPEAT);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage3D(GL_TEXTURE_3D, 0, GL_LUMINANCE, volume->width(),
volume->height(), volume->depth(), 0, GL_LUMINANCE, GL_FLOAT, density);
在我的渲染循环中,我尝试将纹理加载到统一的Sampler3D。
glClearColor(0.4f, 0.2f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
GLint gSampler = glGetUniformLocation(shader->shaderProgram, "volume");
glUniform1i(gSampler, 0);
cube->draw();
因此,基本思路是在顶点着色器中计算光线投射的当前位置和方向。
in vec3 position;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform vec4 cameraPos;
out vec3 pos;
out vec3 dir;
void main(){
gl_Position = projection * view * model * vec4(position, 1.0);
pos = position;
dir = pos - (inverse(model) * cameraPos).xyz;
}
这似乎运作良好,到目前为止一切顺利。片段着色器看起来像这样。我沿着光线拍摄一些样本,密度值最大的样本将被视为红色,绿色和蓝色的颜色。
#version 330 core
in vec3 pos;
in vec3 dir;
uniform sampler3D volume;
out vec4 color;
const float stepSize = 0.008;
const float iterations = 1000;
void main(){
vec3 rayDir = normalize(dir);
vec3 rayPos = pos;
float src;
float dst = 0;
float density = 0;
for(int i = 0; i < iterations; i++){
src = texture(volume, rayPos).r;
if(src > density){
density = src;
}
rayPos += rayDir * stepSize;
//check whether rays are within bounds. if not -> break.
}
color = vec4(density, density, density, 1.0f);
}
现在我尝试插入一些小的调试断言。
if(src != 0){
rayPos = vec3(1.0f);
break;
}
但是在每个像素的每次迭代中src似乎都是0。这让我得出结果,即采样器没有正确设置。调试C ++代码我在将密码数组传递给着色器之前就得到了密度数组的正确值,所以我猜必须缺少一些opengl函数。提前谢谢!
答案 0 :(得分:1)
glTexImage3D(GL_TEXTURE_3D, 0, GL_LUMINANCE, volume->width(), volume->height(), volume->depth(), 0, GL_LUMINANCE, GL_FLOAT, density);
除非这个密度在[0,1]的范围内,否则这几乎肯定不会达到你想要的目的。
GL_LUMINANCE
,当用作internal format(glTexImage3D
的第三个参数)时,意味着OpenGL纹理数据中的每个像素都将包含一个 {{ 3}} value 。所以如果你想要一个浮点值,那你就不幸了。
执行此操作的正确方法是明确声明数据的类型和像素大小。从3.1中的核心OpenGL配置文件中删除了亮度,因此今天的方法是使用GL_R32F
作为内部格式。这声明每个像素包含一个值,该值是32位浮点数。
如果您确实需要在RGB通道上广播值,可以使用normal integer来完成此操作。您可以设置一个混合模板,将红色组件广播到您喜欢的任何其他频道。
glActiveTexture(GL_TEXTURE0);
GLint gSampler = glGetUniformLocation(shader->shaderProgram, "volume");
glUniform1i(gSampler, 0);
我听说绑定纹理也是一个好主意。你知道,如果你真的想读它;)