sooon
sooon

Reputation: 4888

glsl - ray marching not working in fragment shader

I am learning GLSL and ray-marching now. I tried to convert this shader-toy into my c++ OpenGL project but failed.

Below are my codes:

Main.cpp:

GLuint screenWidth = 1280, screenHeight = 720;

int main ()
{
    GLFWwindow* window = NULL;
    const GLubyte* renderer;
    const GLubyte* version;

    if (!glfwInit ()) {
        fprintf (stderr, "ERROR: could not start GLFW3\n");
        return 1;
    }

    glfwWindowHint (GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint (GLFW_CONTEXT_VERSION_MINOR, 1);
    glfwWindowHint (GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    glfwWindowHint (GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    window = glfwCreateWindow (screenWidth, screenHeight, "OpenGL", NULL, NULL);
    if (!window) {
        fprintf (stderr, "ERROR: could not open window with GLFW3\n");
        glfwTerminate ();
        return 1;
    }
    glfwMakeContextCurrent (window);

    glewExperimental = GL_TRUE;
    glewInit ();
    glViewport(0, 0, screenWidth*2, screenHeight*2);

    glEnable (GL_DEPTH_TEST);
    glDepthFunc (GL_LESS);

    Shader ourShader("vertex_shader.glsl", "fragment_shader.glsl");

    GLint positionLocation = glGetAttribLocation(ourShader.Program, "a_position");

     glUniform2f(glGetUniformLocation(ourShader.Program, "resolution"), (GLfloat)screenWidth, (GLfloat)screenHeight);

    GLint mouseLocation = glGetUniformLocation(ourShader.Program, "mouse");
    glUniform4f(mouseLocation, 0.0, 0.0, 0.0, 0.0);

    GLfloat mx = glm::max(screenWidth, screenHeight);
    GLfloat xdivmx = screenWidth/mx; //Coordinates range from [-1,1].
    GLfloat ydivmx = screenHeight/mx;
    GLint screenRatioLocation = glGetUniformLocation(ourShader.Program, "screenRatio");
    glUniform2f(screenRatioLocation, xdivmx, ydivmx);

    GLfloat timeLocation = glGetUniformLocation(ourShader.Program, "time");
    glUniform1f(timeLocation, deltaTime);


    GLfloat vertices[] = {
        -1.0f, -1.0f,
        1.0f, -1.0f,
        -1.0f,  1.0f,
        -1.0f,  1.0f,
        1.0f, -1.0f,
        1.0f,  1.0f   // Top Left
    };

    GLuint VBO, VAO, EBO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);
    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    while (!glfwWindowShouldClose(window))
    {
        glfwPollEvents();

        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);

        ourShader.Use();

        glBindVertexArray(VAO);
        glDrawArrays(GL_TRIANGLES, 0, 6);=
        glBindVertexArray(0);

        glfwSwapBuffers(window);
    }
    // Properly de-allocate all resources once they've outlived their purpose
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteBuffers(1, &EBO);
    // Terminate GLFW, clearing any resources allocated by GLFW.
    glfwTerminate();
    return 0;
}

vertex code:

vertex_shader.glsl:
#version 410 core
layout (location = 0) in vec2 a_position;

out vec2 surfacePosition;
uniform vec2 screenRatio;
uniform vec2 resolution;

void main() {
    surfacePosition = a_position * screenRatio;
    gl_Position = vec4(a_position, 0, 1);
}

fragment code:

#version 410 core

in vec2 surfacePosition;

out vec4 color;
vec4 gl_FragCoord;

uniform float time;
uniform vec2 resolution;
uniform vec4 mouse;


const int MAX_MARCHING_STEPS = 255;
const float MIN_DIST = 0.0;
const float MAX_DIST = 100.0;
const float EPSILON = 0.0001;

#define PI 3.1415926535898 // That was from memory, so if things start flying off the screen...

float sphereSDF(vec3 samplePoint) {
    return length(samplePoint) - 1.0;
}
float sceneSDF(vec3 samplePoint) {
    return sphereSDF(samplePoint);
}

float shortestDistanceToSurface(vec3 eye, vec3 marchingDirection, float start, float end) {
    float depth = start;
    for (int i = 0; i < MAX_MARCHING_STEPS; i++) {
        float dist = sceneSDF(eye + depth * marchingDirection);
        if (dist < EPSILON) {
            return depth;
        }
        depth += dist;
        if (depth >= end) {
            return end;
        }
    }
    return end;
}

vec3 rayDirection(float fieldOfView, vec2 size, vec2 fragCoord) {
    vec2 xy = fragCoord - size / 2.0;
    float z = size.y / tan(radians(fieldOfView) / 2.0);
    return normalize(vec3(xy, -z));
}



void main() {

    vec3 dir = rayDirection(45.0, resolution.xy, surfacePosition.xy);
    vec3 eye = vec3(0.0f, 0.0f, 5.0f);
    float dist = shortestDistanceToSurface(eye, dir, MIN_DIST, MAX_DIST);

    if (dist > MAX_DIST - EPSILON) {
        // Didn't hit anything
        color = vec4(0.0, 0.0, 0.0, 0.0);
        return;
    }

    color = vec4(1.0, 0.0, 0.0, 1.0);
}

with this, all I see is black screen. But if i change to vec3 eye = vec3(0.0f, 0.0f, 1.0f);, I will get the whole screen red. I suspect is something to do with the surfacePosition.xy but I am not sure how to resolve this. I did tried gl_FragCoord.xy too but still black screen.

Update 01

It seems like all of my uniform data did not get through the shaders.

I just do a quite test:

glUniform2f(glGetUniformLocation(ourShader.Program, "resolution"), 0.5, (GLfloat)screenHeight);

And I still get black screen. While I go to fragment Shader and change this line:

vec3 dir = rayDirection(45.0, vec2(1280,720), surfacePosition.xy);//<-- explicitly my screen resolution, just to test.

Then I got the red circle as expected.

Upvotes: 1

Views: 792

Answers (1)

vallentin
vallentin

Reputation: 26245

Link Failure: Fragment info
-------------
0(6) : error C5109: variable "gl_FragCoord" domain conflicts with semantics "WPOS"

Always remember to check the compile, validation and link status. The problem is that you've defined gl_FragCoord and this is conflicting with the built-in gl_FragCoord.

Assuming that your Shader class doesn't by default call glUseProgram(). Then you need to explicitly call it before calling any glUniform*(). Note that any glGetUniformLocation(), glGetAttribLocation(), glGetActiveUniform() and glGetActiveAttrib() call does not have that need (for obvious reasons).

You're also enabling depth testing but never clearing the depth buffer. So either disable depth testing or clear the depth buffer.

Lastly ShaderToy's fragCoord is the equivalent to gl_FragCoord. Your surfacePosition however is not. So just use gl_FragCoord it's here to stay.

Thus using gl_FragCoord instead of surfacePosition you should see (like on ShaderToy):

Additionally glGenBuffers(1, &EBO) is redundant and I have no idea why you want to set the viewport to double its size. The call to glGetAttribLocation() is also redundant, not just because you aren't using it. But because you're using the layout qualifier anyways.

Note that you also have time and mouse and equally need to specify those, if you end up using them.

Also like I mentioned before since you instead could use gl_FragCoord. This still means that there's no need for surfacePosition and screenRatio.

Upvotes: 2

Related Questions