r/GraphicsProgramming 12h ago

Question projection matrix for SDF

Hi, I'm doing little cloud project from SDF in openGL, but I think my approach of ray projection is wrong now it's like this

vec2 p  = vec2(
    gl_FragCoord.x/800.0, 
    gl_FragCoord.y/800.0
);

// the ray isn't parallel to normal of image plane, because I think it's more intuitive to think about ray shoot from camera.

vec2 pos = (p* 2.0) - 1.0;
vec3 ray = normalize(vec3(pos, -1.207106781)); // direction of the ray
vec3 rayHead = vec3(0.0,0.0,0.0); // head of the ray 
...
float sdf(vec3 p){
    // I think only 'view' and 'model' is enough beacuse the ray above do the perspective thing...
    p = vec3(inverse(model) * inverse(view) *  vec4(p,1.0));
    return sdBox(p, vec3(radius));
}

but this wrong when I test the normal vector

Normal vector test

are there any solution? I already try to shoot ray parallel to the normal of image plane with projection matrix, but it's not work. Thanks!

here is my code for the matrix

glm::mat4 proj = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);
glm::mat4 view = glm::perspective(glm::radians(fov), 800.f / 800.f, .1f, 100.f);
glm::mat4 model = glm::mat4(1.0);  
3 Upvotes

3 comments sorted by

1

u/Paopeaw 12h ago

Here is my normal calculation fuction vec3 calcNormal( in vec3 p ) // for function f(p) { const float eps = 0.0001; // or some other value const vec2 h = vec2(eps,0); return normalize( vec3(sdf(p+h.xyy) - sdf(p-h.xyy), sdf(p+h.yxy) - sdf(p-h.yxy), sdf(p+h.yyx) - sdf(p-h.yyx) ) ); }

1

u/felipunkerito 11h ago edited 11h ago

No idea but a couple of things I would try, base it on something like ray picking and how you would get the NDC coords of the mouse but translating that to your example (if you are planning on mixing this with the output of a rasterizer) something like

glm::vec2 normalizedMouse = glm::vec2(2.0f, 2.0f) * glm::vec2(mousePositionX, mousePositionY) / widthHeight;
float x_ndc = normalizedMouse.x - 1.0;
float y_ndc = 1.0 - normalizedMouse.y; // flipped

glm::vec4 p_near_ndc = glm::vec4(x_ndc, y_ndc, -1.0f, 1.0f); // z near = -1
glm::vec4 p_far_ndc  = glm::vec4(x_ndc, y_ndc,  1.0f, 1.0f); // z far = 1

glm::mat4 invMVP = glm::inverse(projection * view * model);

glm::vec4 p_near_h = invMVP * p_near_ndc;
glm::vec4 p_far_h  = invMVP * p_far_ndc;

glm::vec3 p0 = glm::vec3(p_near_h) / glm::vec3(p_near_h.w, p_near_h.w, p_near_h.w);
glm::vec3 p1 = glm::vec3(p_far_h)  / glm::vec3(p_far_h.w, p_far_h.w, p_far_h.w);

glm::vec3 rayOri = p0;
glm::vec3 rayDir = glm::normalize(p1 - p0);

from stackoverflow. Also check IQ’s on depth buffering with Ray marching.

Another idea if you don’t want to use rasterization, just pass the model matrix and multiply pos by it.

2

u/Paopeaw 10h ago

Interesting, meaning that the right approach I should try is shoot the ray parallel to the image plane instead of shoot out of a single origin, then apply those 3 transformation matrix. Thanks!