GPU 单通道光线投射空体积 [关闭]

问题描述 投票:0回答:0

你好,下面的代码是我的一个简单体积单通道光线投射算法的渲染管道。它使用 OpenGL (glew,freeglut) 和 GLSL。当我渲染体积时,我得到的只是体积本身的外部,但如果我滚动到它内部则不是。我会提供截图。 Shaderloader 非常简单,所以我不会在这里发布。我使用带有 vcpkg 的 Visual Studio 2022 来处理我的库。这是我的代码(代码已缩短):

//includes and variables

//transfer function (lookup table) colour values

//function that load a volume from the given raw data file and 
//generates an OpenGL 3D texture from it
bool LoadVolume() {
        glTexImage3D(GL_TEXTURE_3D, 0, GL_RED, XDIM, YDIM, ZDIM, 0, GL_RED, GL_UNSIGNED_BYTE, pData);}
    

//function to generate interpolated colours from the set of colour values (jet_values)
//this function first calculates the amount of increments for each component and the
//index difference. Then it linearly interpolates the adjacent values to get the 
//interpolated result.
void LoadTransferFunction() {
    glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, 256, 0, GL_RGBA, GL_FLOAT, pData);}

//mouse down event handler
void OnMouseDown(int button, int s, int x, int y)

//mouse move event handler
void OnMouseMove(int x, int y)

//scroll callback function
void OnMouseScroll(int wheel, int direction, int x, int y)

//OpenGL initialization
void OnInit() {

    auto start = std::chrono::steady_clock::now();

    GL_CHECK_ERRORS

    //Load the raycasting shader
    shader.LoadFromFile(GL_VERTEX_SHADER, "raycaster.vert");
    shader.LoadFromFile(GL_FRAGMENT_SHADER, "raycaster.frag");


    //compile and link the shader
    shader.CreateAndLinkProgram();
    shader.Use();
    //add attributes and uniforms
    shader.AddAttribute("vVertex");
    shader.AddUniform("MVP");
    shader.AddUniform("volume");
    shader.AddUniform("camPos");
    shader.AddUniform("step_size");
    shader.AddUniform("lut");
    

    //pass constant uniforms at initialization
    glUniform3f(shader("step_size"), 1.0f / XDIM, 1.0f / YDIM, 1.0f / ZDIM);
    glUniform1i(shader("volume"), 0);
    glUniform1i(shader("lut"), 1);
    shader.UnUse();

    //GL_CHECK_ERRORS

        //load volume data
        if (LoadVolume()) {
            std::cout << "Volume data loaded successfully." << std::endl;
        }
        else {
            std::cout << "Cannot load volume data." << std::endl;
            exit(EXIT_FAILURE);
        }

//load the transfer function data and generate the trasnfer function (lookup table) texture
    LoadTransferFunction();

    //set background colour
    glClearColor(bg.r, bg.g, bg.b, bg.a);

    //setup unit cube vertex array and vertex buffer objects
    glGenVertexArrays(1, &cubeVAOID);
    glGenBuffers(1, &cubeVBOID);
    glGenBuffers(1, &cubeIndicesID);

    //unit cube vertices 
    glm::vec3 vertices[8] = {};

    //unit cube indices
    GLushort cubeIndices[36] = { };
    glBindVertexArray(cubeVAOID);
    glBindBuffer(GL_ARRAY_BUFFER, cubeVBOID);
    //pass cube vertices to buffer object memory
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), &(vertices[0].x), GL_STATIC_DRAW);

    GL_CHECK_ERRORS
    //enable vertex attributre array for position
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

    //pass indices to element array  buffer
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cubeIndicesID);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(cubeIndices), &cubeIndices[0], GL_STATIC_DRAW);

    glBindVertexArray(0);

    //enable depth test
    glEnable(GL_DEPTH_TEST);

    //set the over blending function
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    cout << "Initialization successfull" << endl;
    auto end = std::chrono::steady_clock::now();
    chrono::duration<double> elapsed_seconds = end - start;
    cout << "elapsed time: " << elapsed_seconds.count() << "s\n";
}

//release all allocated resources
void OnShutdown() {

//resize event handler
void OnResize(int w, int h) {

//display callback function
void OnRender() {
    GL_CHECK_ERRORS

    //set the camera transform
    glm::mat4 Tr = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, dist));
    glm::mat4 Rx = glm::rotate(Tr, rX, glm::vec3(1.0f, 0.0f, 0.0f));
    glm::mat4 MV = glm::rotate(Rx, rY, glm::vec3(0.0f, 1.0f, 0.0f));

    //get the camera position
    glm::vec3 camPos = glm::vec3(glm::inverse(MV) * glm::vec4(0, 0, 0, 1));

    //clear colour and depth buffer
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    //get the combined modelview projection matrix
    glm::mat4 MVP = P * MV;

    //enable blending and bind the cube vertex array object
    glEnable(GL_BLEND);
    glBindVertexArray(cubeVAOID);
    //bind the raycasting shader
    shader.Use();
    //pass shader uniforms
    glUniformMatrix4fv(shader("MVP"), 1, GL_FALSE, glm::value_ptr(MVP));
    glUniform3fv(shader("camPos"), 1, &(camPos.x));
    //render the cube
    glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, 0);
    //unbind the raycasting shader
    shader.UnUse();
    //disable blending
    glDisable(GL_BLEND);

    //swap front and back buffers to show the rendered result
    glutSwapBuffers();
}

int main(int argc, char** argv) {
    //freeglut initialization
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
    glutInitContextVersion(3, 3);
    glutInitContextFlags(GLUT_CORE_PROFILE | GLUT_DEBUG);

    //main window
    glutInitWindowSize(WIDTH, HEIGHT);
    glutCreateWindow("Volume Rendering using GPU Ray Casting - OpenGL 3.3");


    //glew initialization
    glewExperimental = GL_TRUE;
    GLenum err = glewInit();
    if (GLEW_OK != err) {
        cerr << "Error: " << glewGetErrorString(err) << endl;
    }
    else {
        if (GLEW_VERSION_3_3)
        {
            cout << "Driver supports OpenGL 3.3\nDetails:" << endl;
        }
    }
    err = glGetError(); //this is to ignore INVALID ENUM error 1282
    GL_CHECK_ERRORS

    //output hardware information

    GL_CHECK_ERRORS

    //OpenGL initialization
    OnInit();

    //callback hooks

    //main loop call
    glutMainLoop();

    return 0;
}

顶点着色器:

#version 330 core
  
layout(location = 0) in vec3 vVertex; //object space vertex position

//uniform
uniform mat4 MVP;   //combined modelview projection matrix

smooth out vec3 vUV; //3D texture coordinates for texture lookup in the fragment shader

void main()
{  
//get the clipspace position 
gl_Position = MVP*vec4(vVertex.xyz,1);

//get the 3D texture coordinates by adding (0.5,0.5,0.5) to the object space 
//vertex position. Since the unit cube is at origin (min: (-0.5,-0.5,-0.5) and max: (0.5,0.5,0.5))
//adding (0.5,0.5,0.5) to the unit cube object space position gives us values from (0,0,0) to 
//(1,1,1)
    vUV = vVertex + vec3(0.5);
}

片段着色器:

version 330 core

layout(location = 0) out vec4 vFragColor;   //fragment shader output

smooth in vec3 vUV;             //3D texture coordinates form vertex shader 
                        //interpolated by rasterizer

//uniforms
uniform sampler3D   volume;     //volume dataset
uniform sampler1D   lut;        //look-up-table for transferfunction
uniform vec3        camPos;     //camera position
uniform vec3        step_size;  //ray step size 

//constants
const int MAX_SAMPLES = 300;    //total samples for each ray march step
const vec3 texMin = vec3(0);    //minimum texture access coordinate
const vec3 texMax = vec3(1);    //maximum texture access coordinate

void main()
{ 
    //transferfunction
    vFragColor = texture(lut, texture(volume, vUV).r);

    //get the 3D texture coordinates for lookup into the volume dataset
    vec3 dataPos = vUV;

    //Getting the ray marching direction:
    //get the object space position by subracting 0.5 from the
    //3D texture coordinates. Then subtraact it from camera position
    //and normalize to get the ray marching direction
    vec3 geomDir = normalize((vUV-vec3(0.5)) - camPos); 

    //multiply the raymarching direction with the step size to get the
    //sub-step size we need to take at each raymarching step
    vec3 dirStep = geomDir * step_size; 
     
    //flag to indicate if the raymarch loop should terminate
    bool stop = false; 

    //for all samples along the ray
    for (int i = 0; i < MAX_SAMPLES; i++) {
        // advance ray by dirstep
        dataPos = dataPos + dirStep;
        
        
        //The two constants texMin and texMax have a value of vec3(-1,-1,-1)
        //and vec3(1,1,1) respectively. To determine if the data value is 
        //outside the volume data, we use the sign function. The sign function 
        //return -1 if the value is less than 0, 0 if the value is equal to 0 
        //and 1 if value is greater than 0. Hence, the sign function for the 
        //calculation (sign(dataPos-texMin) and sign (texMax-dataPos)) will 
        //give us vec3(1,1,1) at the possible minimum and maximum position. 
        //When we do a dot product between two vec3(1,1,1) we get the answer 3. 
        //So to be within the dataset limits, the dot product will return a 
        //value less than 3. If it is greater than 3, we are already out of 
        //the volume dataset
        stop = dot(sign(dataPos-texMin),sign(texMax-dataPos)) < 3.0;

        //if the stopping condition is true we brek out of the ray marching loop
        if (stop) 
            break;

        // data fetching from the red channel of volume texture
        float sample = texture(volume, dataPos).r;  
        
        //Opacity calculation using compositing:
        //here we use front to back compositing scheme whereby the current sample
        //value is multiplied to the currently accumulated alpha and then this product
        //is subtracted from the sample value to get the alpha from the previous steps.
        //Next, this alpha is multiplied with the current sample colour and accumulated
        //to the composited colour. The alpha value from the previous steps is then 
        //accumulated to the composited colour alpha.
        float prev_alpha = sample - (sample * vFragColor.a);
        vFragColor.rgb = prev_alpha * vec3(sample) + vFragColor.rgb; 
        vFragColor.a += prev_alpha; 
            
        //early ray termination
        //if the currently composited colour alpha is already fully saturated
        //we terminated the loop
        if( vFragColor.a>0.99)
            break;
    } 
}
距离体积小 放大音量
https://i.stack.imgur.com/TFm9S.png https://i.stack.imgur.com/kOD3f.png
c++ opengl glsl volume raycasting
© www.soinside.com 2019 - 2024. All rights reserved.