I have some problems regarding sphere tracing/ray marching in GLSL using SDF functions:
My main program (C++, using Vulkan) generates a screen quad and supplies the vertex shader with a per-vertex inPosition
. The vertex shader has access to the window resolution, projection matrix and view matrix. The projection matrix is generated with glm::perspective(45.0, 1920/1080, 0.1, 100.0);
.
In the vertex shader, I try to calculate a ray (position and direction using homogeneous coordinates) coming from the origin at vec4(0.0, 0.0, 0.0, 1.0)
through the image plane. I am confused where to place the image plane and chose vec4(inPosition.xy, -5.0, 1.0)
for now to look along the negative z-axis.
The following code represents my vertex shader:
#version 450
#extension GL_ARB_separate_shader_objects : enable
struct Ray
{
vec4 pos;
vec4 dir;
};
layout(binding = 0) uniform UniformBufferObject {
vec3 res;
mat4 projection;
mat4 view;
} ubo;
layout(location = 0) in vec3 inPosition;
layout(location = 0) out vec3 iResolution;
layout(location = 1) out Ray iRay;
out gl_PerVertex {
vec4 gl_Position;
};
void main() {
fragCoord = vec2(
((inPosition.x+1)/2) * (ubo.res.x-1),
((inPosition.y+1)/2) * (ubo.res.y-1)
);
iResolution = ubo.res;
gl_Position = vec4(inPosition, 1.0);
vec4 direction = inverse(ubo.projection) * vec4(inPosition.xy, -5.0, 1.0);
iRay.dir = direction;
iRay.pos = vec4(direction.xy, 0.0, 1.0);
}
I used the projection matrix to transform the directions to world space and distort the unit cube to the window resolution. However, in my fragment shader the SDF functions and intersections do not work properly. I can only see a sphere if I set the same values for the distance and the radius. See the fragment shader:
#version 450
#extension GL_ARB_separate_shader_objects : enable
struct Ray
{
vec4 pos;
vec4 dir;
};
layout(location = 0) in vec3 iResolution;
layout(location = 1) in Ray iRay;
layout(location = 0) out vec4 outColor;
float sdfSphere(vec3 p, float r)
{
return length(p) - r;
}
bool intersect(Ray ray)
{
for(int i = 0; i < 100; i++) {
float hit = sdfSphere((ray.pos.xyz + vec3(0.0, 0.0, -11.0)), 11.0);
ray.pos += hit * ray.dir;
if (hit < 0.001) {
return true;
}
}
return false;
}
void main()
{
bool result = intersect(iRay);
if(result == false) {
outColor = vec4(0.0, 0.0, 0.0, 1.0);
} else {
outColor = vec4(1.0, 0.0, 0.0, 1.0);
}
}
My question is: How to I have to apply the projection matrix properly? And if it is already applied properly, why am I not able to set a different position/radius for the SDF sphere?