基于 2D 纹理的体绘制

Posted

技术标签:

【中文标题】基于 2D 纹理的体绘制【英文标题】:2D-texture based volume rendering 【发布时间】:2014-04-13 19:24:47 【问题描述】:

我在网上找到了一个很棒的体积渲染教程: volume rendering tutorial .示例代码是用 Windows 编写的,由于我在 Mac 上工作,因此我尝试根据自己的理解编写自己的代码。现在,我的程序只是在 Z 轴上从 -1 到 1 排列 2D 帧,而不应用 alpha 和混合。所以如果一切顺利,我应该可以看到第一片。但是,当我运行程序时,我得到了一些奇怪的东西。

我的代码:

//
//  VolumeRendering.cpp
//  Volume_Rendering
//
//  Created by HOBBY on 4/5/14.
//  Copyright (c) 2014 Yihao Jiang. All rights reserved.
//
#include <GLTools.h>
#include <GL/glew.h>
#include <Opengl/gl.h>
#include <glut/glut.h>
#include <fstream>
#include "VolumeRendering.h"
#include <GLMatrixStack.h>
#include <GLFrustum.h>
#include <GLGeometryTransform.h>

int m_uImageCount;
int m_uImageWidth;
int m_uImageHeight;
GLuint* m_puTextureIDs;

GLMatrixStack modelViewMatrix;
GLMatrixStack projectionMatrix;
GLFrame       cameraFrame;
GLFrustum     viewFrustum;
GLBatch       myBatch;
GLGeometryTransform    transformPipeline;
GLShaderManager        shaderManager;

void ChangeSize(int w, int h)

   glViewport(0, 0, w, h);
   GLdouble aspectRatio = (GLdouble)(w)/(GLdouble)(h);
   if (w <= h)
   
       viewFrustum.SetOrthographic(-1.0f, 1.0f, -(1.0f/aspectRatio), 1.0f/aspectRatio, -1.0f, 1.0f);
   
   else
   
       viewFrustum.SetOrthographic(-1.0f, 1.0f, -(1.0f * aspectRatio), 1.0f * aspectRatio, -1.0f, 1.0f);
   
   projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
   transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);



void SetupRC()

   glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
   shaderManager.InitializeStockShaders();

   glEnable(GL_DEPTH_TEST);

   const char* filePath = "/Users/WensarHobby/Documents/Codes/workspace/Volume_Rendering/Volume_Rendering/head256x256x109";
   if(!InitTextures2D(filePath))
   
       printf("InitTexture error");
   



bool InitTextures2D(const char* filePath)

    std::fstream myFile;
    myFile.open(filePath, std::ios::in | std::ios::binary);

    m_uImageCount = 109;
    m_uImageWidth = 256;
    m_uImageHeight = 256;

    // Holds the texuture IDs
    m_puTextureIDs = new GLuint[m_uImageCount];

    // Holds the luminance buffer
    char* chBuffer = new char[m_uImageWidth * m_uImageHeight];
    char* chRGBABuffer = new char[m_uImageWidth * m_uImageHeight * 4];
    glGenTextures(m_uImageCount, (GLuint*)m_puTextureIDs);

    // Read each frames and construct the texture
    for( int nIndx = 0; nIndx < m_uImageCount; ++nIndx )
    
        // Read the frame
        myFile.read(chBuffer, m_uImageWidth*m_uImageHeight);

        // Set the properties of the texture.
        glBindTexture( GL_TEXTURE_2D, m_puTextureIDs[nIndx] );
        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

        glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, m_uImageWidth, m_uImageHeight , 0,
                 GL_LUMINANCE, GL_UNSIGNED_BYTE,(GLvoid *) chBuffer);
        glBindTexture( GL_TEXTURE_2D, 0 );
    

    delete[] chBuffer;
    delete[] chRGBABuffer;
    return true;


void SpecialKeys(int key, int x, int y)

    if(key == GLUT_KEY_UP)
    

    if (key == GLUT_KEY_DOWN)
    

    

    if (key == GLUT_KEY_LEFT)
    

    

    if (key == GLUT_KEY_RIGHT)
    

    

    glutPostRedisplay();


void RenderScene(void)

    static GLfloat vLightPos [] =  1.0f, 1.0f, 0.0f ;
    static GLfloat vWhite [] =  1.0f, 1.0f, 1.0f, 1.0f ;

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);


    modelViewMatrix.PushMatrix();
    M3DMatrix44f mCamera;
    cameraFrame.GetCameraMatrix(mCamera);
    modelViewMatrix.MultMatrix(mCamera);

    for(int nIndx=0; nIndx <m_uImageCount;++nIndx)
    
        glBindTexture(GL_TEXTURE_2D, m_puTextureIDs[nIndx]);
        MakeQuads(nIndx);
        glBindTexture(GL_TEXTURE_2D, m_puTextureIDs[nIndx]);

    


    shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
                             transformPipeline.GetModelViewMatrix(),
                             transformPipeline.GetProjectionMatrix(),
                             vLightPos, vWhite, 0);
    myBatch.Draw();


    modelViewMatrix.PopMatrix();

    glutSwapBuffers();



void MakeQuads(int quads_index)

    myBatch.Begin(GL_QUADS, 4, 1);
    myBatch.Normal3f(0.0f, 0.0f, -1.0f);
    myBatch.MultiTexCoord2f(quads_index, 0.0f, 0.0f);
    myBatch.Vertex3f(-1.0f, -1.0f, 1.0f - (GLfloat)(quads_index/m_uImageCount));

    myBatch.Normal3f(0.0f, 0.0f, -1.0f);
    myBatch.MultiTexCoord2f(quads_index, 1.0f, 0.0f);
    myBatch.Vertex3f(1.0f, -1.0f, 1.0f - (GLfloat)(quads_index/m_uImageCount));

    myBatch.Normal3f(0.0f, 0.0f, -1.0f);
    myBatch.MultiTexCoord2f(quads_index, 0.0f, 1.0f);
    myBatch.Vertex3f(-1.0f, 1.0f, 1.0f - (GLfloat)(quads_index/m_uImageCount));

    myBatch.Normal3f(0.0f, 0.0f, -1.0f);
    myBatch.MultiTexCoord2f(quads_index, 1.0f, 1.0f);
    myBatch.Vertex3f(1.0f, 1.0f, 1.0f - (GLfloat)(quads_index/m_uImageCount));
    myBatch.End();


void ShutdownRC(void)

    glDeleteTextures(m_uImageCount, (GLuint*)m_puTextureIDs);



int main(int argc, char* argv[])

    gltSetWorkingDirectory(argv[0]);
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
    glutInitWindowSize(400, 400);
    glutCreateWindow("Volume_Rendering");
    glutReshapeFunc(ChangeSize);
    glutSpecialFunc(SpecialKeys);
    glutDisplayFunc(RenderScene);

    GLenum err = glewInit();
    if (GLEW_OK != err) 
        fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
        return 1;
    

    SetupRC();

    glutMainLoop();
    ShutdownRC();
    return 0;


这是我奇怪的结果:

我是 OpenGL 和体渲染的新手,在我看来,我对着色器管理器的使用应该有问题。但我不太确定。谁能告诉我问题出在哪里?非常感谢。

【问题讨论】:

在我看来,这对于任何 opengl 或 directx 来说都是非常典型的第一步调试哈哈。你应该看看摆弄你的四边形坐标你没有得到更好的东西。这看起来像是启用了面剔除的一些错误的顶点旋转顺序。可能是任何东西。它已经很好你看到蓝色了! 我建议也发布着色器代码(我没有发现任何明显的东西。)正如@v.oddou 所说,这对于使用新代码的首次渲染来说并不罕见。我还建议暂时取消所有纹理代码,并首先专注于正确设置几何图形(使用固定颜色)。 @v.oddou 我做了一些测试,我将正交投影更改为透视投影,似乎可行。那么在我的代码中使用 setOrthographic 函数有什么问题呢? @holtavolt 我做了很多测试,现在我几乎可以肯定问题出在函数 MakeQuads() 上,更具体地说是 MultiTexCoord2f() 函数。如果我只在屏幕上绘制一帧并将所有 quads_​​index 替换为 0,它就可以工作。现在我正在考虑如何用一个着色器绘制多个纹理...... 【参考方案1】:

终于,我想通了!我是对的,问题在于函数 MultiTexCoord2f()。这里这个函数的第一个参数应该总是0而不是quads_​​index。这里没有多重纹理!!新代码如下所示:

#include <GLTools.h>
#include <GL/glew.h>
#include <Opengl/gl.h>
#include <glut/glut.h>
#include <fstream>
#include "VolumeRendering.h"
#include <GLMatrixStack.h>
#include <GLFrustum.h>
#include <GLGeometryTransform.h>

int m_uImageCount;
int m_uImageWidth;
int m_uImageHeight;
GLuint* m_puTextureIDs;

GLMatrixStack modelViewMatrix;
GLMatrixStack projectionMatrix;
GLFrame       cameraFrame;
GLFrame       objectFrame;
GLFrustum     viewFrustum;
GLBatch       myBatch;
GLGeometryTransform    transformPipeline;
GLShaderManager        shaderManager;

void ChangeSize(int w, int h)

    glViewport(0, 0, w, h);
    viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 500.0f);
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
    

void SetupRC()

    glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
    shaderManager.InitializeStockShaders();

    glEnable(GL_DEPTH_TEST);

    const char* filePath =     "/Users/WensarHobby/Documents/Codes/workspace/Volume_Rendering/Volume_Rendering/head256x256x109";
    if(!InitTextures2D(filePath))
    
        printf("InitTexture error");
    

    cameraFrame.MoveForward(-7.0f);


bool InitTextures2D(const char* filePath)

    std::fstream myFile;
    myFile.open(filePath, std::ios::in | std::ios::binary);

    m_uImageCount = 109;
    m_uImageWidth = 256;
    m_uImageHeight = 256;

    // Holds the texuture IDs
    m_puTextureIDs = new GLuint[m_uImageCount];

    // Holds the luminance buffer
    char* chBuffer = new char[m_uImageWidth * m_uImageHeight];
    //char* chRGBABuffer = new char[m_uImageWidth * m_uImageHeight * 4];
    glGenTextures(m_uImageCount, m_puTextureIDs);

    // Read each frames and construct the texture
    for( int nIndx = 0; nIndx < m_uImageCount; ++nIndx )
    
        // Read the frame
        myFile.read(chBuffer, m_uImageWidth*m_uImageHeight);

        // Set the properties of the texture.
        glBindTexture( GL_TEXTURE_2D, m_puTextureIDs[nIndx] );
        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

        glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, m_uImageWidth, m_uImageHeight , 0,
                 GL_LUMINANCE, GL_UNSIGNED_BYTE,(GLvoid *) chBuffer);
        glBindTexture( GL_TEXTURE_2D, 0 );
    

    delete[] chBuffer;
   // delete[] chRGBABuffer;
    return true;


void SpecialKeys(int key, int x, int y)

glutPostRedisplay();


void RenderScene(void)

    static GLfloat vLightPos [] =  1.0f, 1.0f, 0.0f ;
    static GLfloat vWhite [] =  1.0f, 1.0f, 1.0f, 1.0f ;

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);


    modelViewMatrix.PushMatrix();
    M3DMatrix44f mCamera;
    cameraFrame.GetCameraMatrix(mCamera);
    modelViewMatrix.MultMatrix(mCamera);

    M3DMatrix44f mObjectFrame;
    objectFrame.GetMatrix(mObjectFrame);
    modelViewMatrix.MultMatrix(mObjectFrame);

    for(int nIndx=0; nIndx <m_uImageCount;++nIndx)
    
        glBindTexture(GL_TEXTURE_2D, m_puTextureIDs[nIndx]);
        MakeQuads(nIndx);
        glBindTexture(GL_TEXTURE_2D, m_puTextureIDs[nIndx]);
        shaderManager.UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
                                 transformPipeline.GetModelViewMatrix(),
                                 transformPipeline.GetProjectionMatrix(),
                                 vLightPos, vWhite, 0);
        myBatch.Draw();
    

    modelViewMatrix.PopMatrix();

    glutSwapBuffers();



void MakeQuads(int quads_index)

    myBatch.Begin(GL_QUADS, 4, 1);

    myBatch.Normal3f(0.0f, 0.0f, -1.0f);
    myBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
    myBatch.Vertex3f(-1.0f, -1.0f, 1.0f - (GLfloat)(quads_index/m_uImageCount));
    //myBatch.Vertex3f(-1.0f, -1.0f, 1.0f);

    myBatch.Normal3f(0.0f, 0.0f, -1.0f);
    myBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
    myBatch.Vertex3f(1.0f, -1.0f, 1.0f - (GLfloat)(quads_index/m_uImageCount));
    //myBatch.Vertex3f(1.0f, -1.0f, 1.0f);

    myBatch.Normal3f(0.0f, 0.0f, -1.0f);
    myBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
    myBatch.Vertex3f(1.0f, 1.0f, 1.0f - (GLfloat)(quads_index/m_uImageCount));
    //myBatch.Vertex3f(1.0f, 1.0f, 1.0f);

    myBatch.Normal3f(0.0f, 0.0f, -1.0f);
    myBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
    myBatch.Vertex3f(-1.0f, 1.0f, 1.0f - (GLfloat)(quads_index/m_uImageCount));
    //myBatch.Vertex3f(-1.0f, 1.0f, 1.0f);

    myBatch.End();


void ShutdownRC(void)

    glDeleteTextures(m_uImageCount, (GLuint*)m_puTextureIDs);



int main(int argc, char* argv[])
    
    gltSetWorkingDirectory(argv[0]);
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
    glutInitWindowSize(400, 400);
    glutCreateWindow("Volume_Rendering");
    glutReshapeFunc(ChangeSize);
    glutSpecialFunc(SpecialKeys);
    glutDisplayFunc(RenderScene);

    GLenum err = glewInit();
    if (GLEW_OK != err) 
        fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
        return 1;
    

    SetupRC();

    glutMainLoop();

    ShutdownRC();
    return 0;


【讨论】:

以上是关于基于 2D 纹理的体绘制的主要内容,如果未能解决你的问题,请参考以下文章

在 OpenGL 中绘制多个 2D 纹理

LWJGL OpenGL 不会绘制 2D 纹理

vtk等值面体绘制|纹理映射体绘制 附:不透明传输函数,颜色传输函数光照与阴影

获取使用 gl.texImage2D 绘制的纹理的“红色”像素值

如何使用 glDrawTexOES 绘制纹理?

使用 OpenGL ES 2.0 绘制 2D 图像