https://i.stack.imgur.com/R3Er2.jpg
I have a raymarching shader written in GLSL ES, in it is a capsule sdf that I am trying to render. I am currently using this as a post effect, so I'm setting the shader and the uniforms, then drawing a rectangle to the screen in the draw gui event. ( I'm not worried about occlusion at this time, I just want to make this part work first ).
The capsule is showing up on the screen, however no matter what I do, i can't seem to get it to display in the right place at the right angle. The distance between the camera and the shape are accurate, however when the camera rotates, the shape rotates about the screen wildly, and seems to be stretched by my screen's aspect ratio ( I have an ultrawide monitor ). I have tried to account for the aspect ratio in the shader but I honestly can't tell if it's working because everything else is behaving so strangely. It's been a long time since I've written a raymarching shader, so I'm out of practice, on top of that I've been staring at this code so long I have basically become blind to whatever it is that's being problematic.
The Shader:
precision mediump float;
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
uniform vec3 camRot;
uniform vec3 camPos;
uniform vec3 camFwd;
uniform float fov;
uniform vec3 startPoint;
uniform vec3 endPoint;
uniform vec2 resolution;
#define MAX_STEPS 100
#define MAX_DIST 1000.
#define SURF_DIST .001
#define TAU 6.283185
#define PI 3.141592
#define S smoothstep
float sdCapsule(vec3 p, vec3 a, vec3 b, float r) {
vec3 pa = p - a;
vec3 ba = b - a;
float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);
return length(pa - ba * h) - r;
}
float GetDist(vec3 p) {
float d = sdCapsule(p, startPoint, endPoint, 1.0);
return d;
}
float RayMarch(vec3 ro, vec3 rd) {
float dO=0.;
for(int i=0; i<MAX_STEPS; i++) {
vec3 p = ro + rd*dO;
float dS = GetDist(p);
dO += dS;
if(dO>MAX_DIST || abs(dS)<SURF_DIST) break;
}
return dO;
}
vec3 GetRayDir(vec3 ro, vec3 lookAt, vec2 uv) {
vec3 forward = normalize(lookAt - ro);
vec3 right = normalize(cross(vec3(0.0, 1.0, 0.0), forward));
vec3 up = cross(forward, right);
return normalize(forward + right * uv.x + up * uv.y);
}
void main() {
float aspectRatio = resolution.x / resolution.y;
vec2 screenUV = (gl_FragCoord.xy - 0.5 * resolution.xy) / resolution.y;
vec2 uv = vec2(screenUV.x / aspectRatio, screenUV.y);
vec3 ro = camPos;
vec3 fwd = camFwd;
vec3 rd = GetRayDir(ro, fwd, uv);
vec4 col = vec4(0.0);
float d = RayMarch(ro, rd);
if(d < MAX_DIST) {
col = vec4(1.0);
}
gl_FragColor = col;
}
The Uniforms:
shader_set(shd_sdf_electricity);
u_camRot = shader_get_uniform(shd_sdf_electricity,"camRot");
u_camFwd = shader_get_uniform(shd_sdf_electricity,"camFwd");
u_fov = shader_get_uniform(shd_sdf_electricity,"fov");
u_camPos = shader_get_uniform(shd_sdf_electricity,"camPos");
u_startPoint = shader_get_uniform(shd_sdf_electricity,"startPoint");
u_endPoint = shader_get_uniform(shd_sdf_electricity,"endPoint");
u_resolution = shader_get_uniform(shd_sdf_electricity,"resolution");
shader_set_uniform_f(u_camRot,degtorad(QuakeMgr.pawn.cam_yaw),degtorad(QuakeMgr.pawn.cam_pitch),degtorad(QuakeMgr.pawn.cam_roll));
shader_set_uniform_f(u_camFwd,QuakeMgr.pawn.xto,QuakeMgr.pawn.yto,QuakeMgr.pawn.zto);
shader_set_uniform_f(u_camPos,QuakeMgr.pawn.x,QuakeMgr.pawn.y,QuakeMgr.pawn.z);
shader_set_uniform_f(u_fov,80);
shader_set_uniform_f(u_resolution,global.gameResX,global.gameResY);
shader_set_uniform_f(u_startPoint,x-128,y,z);
shader_set_uniform_f(u_endPoint,x+128,y,z);
//draw_cube(x,y,z,256,c_white);
draw_rectangle(0,0,global.gameResX,global.gameResY,false);
shader_reset();
I've tried too many things to count. I've been slapping keys on my keyboard for the past 5 hours trying to get this to behave, so far, the imgur video I shared is the closest I've come to success.