我试图在绘制单个球体的openGl片段着色器中实现简单的光线跟踪算法。

有时它绘制了一个扭曲的球体,但是大多数时候它什么也没有画。
使用实际的球体原点和半径,我在右上角得到了一个略微还原的球体。

#version 430 core

uniform ivec2 viewportDimensions;
uniform mat4 gl_ProjectionMatrix;
uniform ivec4 viewport;

out vec3 color;

struct Ray {
    vec3 origin;
    vec3 direction;
};

struct Sphere {
    vec3 origin;
    float radius;
};

float zNear = -0.1f;
float zFar = -100.0f;
float fieldOfViewX = 3.1415926535897932384626433832795 / 2.0f;

float sampleRay(Ray ray,Sphere s, float distance);
Ray computeEyeRay(float, float, int, int);
bool intersect(Ray r, Sphere s);
bool solveQuadratic(float a, float b, float c);
Ray calcEyeFromWindow(vec3 windowSpace);

void main() {
//  Ray r = computeEyeRay(gl_FragCoord.x + 0.5f, gl_FragCoord.y + 0.5f, viewportDimensions.x, viewportDimensions.y);
    Ray r = calcEyeFromWindow(vec3(gl_FragCoord.x + 0.5f, gl_FragCoord.y + 0.5f, 1f));
    Sphere s;
    s.origin = vec3(0.5f,-0.5f,-0.7f);
    s.radius = 0.8f;

    if (intersect(r,s))
        color = vec3(1,1,1);
    else
        color = vec3(0,0,0);
    }

Ray calcEyeFromWindow(vec3 windowSpace)
{
    vec4 ndcPos;
    ndcPos.xy = ((2.0 * gl_FragCoord.xy) - (2.0 * viewport.xy)) / (viewport.zw) - 1;
    ndcPos.z = (2.0 * gl_FragCoord.z - gl_DepthRange.near - gl_DepthRange.far) /
    (gl_DepthRange.far - gl_DepthRange.near);
    ndcPos.w = 1.0;

    vec4 clipPos = ndcPos / gl_FragCoord.w;
    vec4 eyePos = inverse(gl_ProjectionMatrix) * clipPos;

    Ray r;
    r.origin = eyePos.xyz;
    r.direction =normalize(eyePos.xyz);

    return r;
}

Ray computeEyeRay(float x, float y, int width, int height) {
    const float aspect = float(height) / float(width);
    const float s = -2.0f * tan(fieldOfViewX * 0.5f);

    const vec3 start = vec3( (float(x) / float(width) - 0.5) * s,
                        -(float(y) / float(height) - 0.5f) * s * aspect,
                        1.0f) * zNear;
    float startLength = sqrt( (start.x * start.x) + (start.y * start.y) + (start.z * start.z) );

    Ray e;
    e.origin = start;
    e.direction = normalize(start);
    return e;
}

bool intersect(Ray r, Sphere s) {
    float a = dot(r.direction,r.direction);
    float b = dot(r.direction, 2.0 * (r.origin-s.origin));
    float c = dot(s.origin, s.origin) + dot(r.origin,r.origin) +-2.0*dot(r.origin,s.origin) - (s.radius*s.radius);

    float disc = b*b + (-4.0)*a*c;

    if (disc < 0)
        return false;

    return true;

}


bool solveQuadratic(float a, float b, float c) {
    float t, t_1;

    float disc = a * b - 4 * a * c;
    if (disc < 0)
        return false;
    else {
        if (disc == 0)
            t = -0.5 * b / a;
        else {
            float q = (b > 0) ? -0.5 * (b+sqrt(disc)) : -0.5 * (b-sqrt(disc));
            t = q / a;
            t_1 = c / q;
        }
    }
    return true;

}

如果有人要编译和测试它,这里是程序的其余部分。
#include <stdio.h>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
#include <glm\glm.hpp>

// include opengl headers
#include <GL/glew.h>
#include <GL/freeglut.h>

const int VIEWPORT_DIMENSION_X = 1280;
const int VIEWPORT_DIMENSION_Y = 1280;

void glutInitialization(int argc, char **argv);
void glewInitialization();
void display();
void resize(int w, int h);
void idle();
void drawSphere(float x, float y, float z);
GLuint LoadShaders(const char * vertex_file_path,const char * fragment_file_path);

GLuint VertexArrayID;
GLuint vertexbuffer; // This will identify our vertex buffer
GLuint programID;

static const GLfloat quadvertices[] = {
    -1.0f, 1.0f, .0f,
    -1.0f, -1.0f, .0f,
    1.0f, -1.0f, .0f,
    1.0f, -1.0f, .0f,
    1.0f, 1.0f, .0f,
    -1.0f, 1.0f, .0f
    };

static const GLfloat g_vertex_buffer_data[] = {
    -1.0f, -1.0f, 0.0f,
    1.0f, -1.0f, 0.0f,
    0.0f,  1.0f, 0.0f,
};

int main(int argc, char **argv)
{

    glutInitialization(argc, argv);
    glewInitialization();

    // create VAO
    glGenVertexArrays(1, &VertexArrayID);
    glBindVertexArray(VertexArrayID);

    // Generate 1 buffer
    glGenBuffers(1, &vertexbuffer);

    // Give our vertices to OpenGL.
    glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(quadvertices), quadvertices, GL_STATIC_DRAW);
    glVertexAttribPointer(
        0,                  //
        3,                  // size
        GL_FLOAT,           // type
        GL_FALSE,           // normalized?
        0,                  // stride
        (void*)0            // array buffer offset
        );
    glEnableVertexAttribArray(0);

    glClearColor(0.0,0.0,0.0,0.0);

    // Create and compile our GLSL program from the shaders
    programID = LoadShaders( "vertex.glsl", "fragment.glsl" );

    glViewport(0,0,1280,1280);
    // create uniform variables
    GLint viewportDimensionsHandle = glGetUniformLocation(programID, "viewportDimensions");
    glProgramUniform2i(programID, viewportDimensionsHandle, VIEWPORT_DIMENSION_X, VIEWPORT_DIMENSION_Y);

    GLint viewportHandle =glGetUniformLocation(programID, "viewport");
    glProgramUniform4i(programID, viewportHandle, 0,0,1280,1280);


    // start mainloop
    glutMainLoop();

    return 0;
}

void glutInitialization(int argc, char **argv) {
    // GLUT initializing
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
    glutInitWindowPosition(100,100);
    glutInitWindowSize(1280,1280);
    glutCreateWindow("raycasting");

    // register GLUT callbacks
    glutDisplayFunc(display);
    glutReshapeFunc(resize);
}

void glewInitialization() {
    // GLEW initializing
    glewInit();
    if (glewIsSupported("GL_VERSION_4_3"))
        printf("Ready for OpenGL 4.3\n");
    else {
        printf("OpenGL 4.3 not supported\n");
        exit(1);
    }
}

void display() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // Use our shader
    glUseProgram(programID);

    // Bind VAO
    glBindVertexArray(VertexArrayID);

    // Draw the triangle
    glDrawArrays(GL_TRIANGLES, 0, 6); // Starting from vertex 0; 3 vertices total -> 1 triangle

    // Unbind VAO
    glBindVertexArray(0);

    glutSwapBuffers();
}

void resize(int w, int h) {

}

void idle() {

}

void drawSphere(float x, float y, float z) {
    glPushMatrix();
}

GLuint LoadShaders(const char * vertex_file_path,const char * fragment_file_path){

    // Create the shaders
    GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
    GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);

    // Read the Vertex Shader code from the file
    std::string VertexShaderCode;
    std::ifstream VertexShaderStream(vertex_file_path, std::ios::in);
    if(VertexShaderStream.is_open())
    {
        std::string Line = "";
        while(getline(VertexShaderStream, Line))
            VertexShaderCode += "\n" + Line;
        VertexShaderStream.close();
    }

    // Read the Fragment Shader code from the file
    std::string FragmentShaderCode;
    std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in);
    if(FragmentShaderStream.is_open()){
        std::string Line = "";
        while(getline(FragmentShaderStream, Line))
            FragmentShaderCode += "\n" + Line;
        FragmentShaderStream.close();
    }

    GLint Result = GL_FALSE;
    int InfoLogLength;

    // Compile Vertex Shader
    printf("Compiling shader : %s\n", vertex_file_path);
    char const * VertexSourcePointer = VertexShaderCode.c_str();
    glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL);
    glCompileShader(VertexShaderID);

    // Check Vertex Shader
    glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
    glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
    std::vector<char> VertexShaderErrorMessage(InfoLogLength);
    glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
    fprintf(stdout, "%s\n", &VertexShaderErrorMessage[0]);

    // Compile Fragment Shader
    printf("Compiling shader : %s\n", fragment_file_path);
    char const * FragmentSourcePointer = FragmentShaderCode.c_str();
    glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL);
    glCompileShader(FragmentShaderID);

    // Check Fragment Shader
    glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
    glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
    std::vector<char> FragmentShaderErrorMessage(InfoLogLength);
    glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
    fprintf(stdout, "%s\n", &FragmentShaderErrorMessage[0]);

    // Link the program
    fprintf(stdout, "Linking program\n");
    GLuint ProgramID = glCreateProgram();
    glAttachShader(ProgramID, VertexShaderID);
    glAttachShader(ProgramID, FragmentShaderID);
    glLinkProgram(ProgramID);

    // Check the program
    glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
    glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
    std::vector<char> ProgramErrorMessage( std::max(InfoLogLength, int(1)) );
    glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
    fprintf(stdout, "%s\n", &ProgramErrorMessage[0]);

    glDeleteShader(VertexShaderID);
    glDeleteShader(FragmentShaderID);

    return ProgramID;
}

最佳答案

我敢肯定这不是一个完整的解决方案,但它最终吸引了一个 Realm :

 #version 430 core

    uniform ivec2 viewportDimensions;
    uniform mat4 gl_ProjectionMatrix;
    uniform ivec4 viewport;
    uniform float imageAspectRatio;
    uniform float angle;

    out vec3 color;

    struct Ray {
        vec3 origin;
        vec3 direction;
    };

    struct Sphere {
        vec3 origin;
        float radius;
    };

    bool intersect(Ray r, Sphere s);


    void main() {

        focal = 60;
        angle = tan(focal * 0.5 * 3.1415926535897932384626433832795 / 180); // convert from degree to radian
        float xx = (2 * (gl_FragCoord.x + 0.5) / viewportDimensions.x - 1) * angle * imageAspectRatio;
        float yy = (1 - 2 * (gl_FragCoord.y + 0.5) / viewportDimensions.y) * angle;

        vec3 rayOrigin = vec3(0,0,0);
        vec3 rayDirection = normalize(vec3(xx, yy, -1) - rayOrigin);

        Ray r;
        r.origin = rayOrigin;
        r.direction = rayDirection;

        Sphere s;
        s.origin = vec3(0.0f,0.0f,-1.1f);
        s.radius =0.55f;


        if (intersect(r,s))
            color = vec3(1,0,1);
        else
            color = vec3(0,0,0);
        }

    bool intersect(Ray r, Sphere s) {
        float a = dot(r.direction,r.direction);
        float b = dot(r.direction, 2.0 * (r.origin-s.origin));
        float c = dot(s.origin, s.origin) + dot(r.origin,r.origin) +-2.0*dot(r.origin,s.origin) - (s.radius*s.radius);

        float disc = b*b + (-4.0)*a*c;

        if (disc < 0)
            return false;

        return true;

    }

关于c++ - GLSL的光线追踪,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24702767/

10-11 19:30