From bea7cb58025d08b85272f83ea0574b05ce60c8dd Mon Sep 17 00:00:00 2001 From: ktyl Date: Mon, 2 Aug 2021 09:35:39 +0100 Subject: [PATCH] implement perspective rays --- res/shader/root/rt.glsl | 56 +++++++++++++++----- src/main.c | 113 +++++++++++++++++++++++++++++++--------- src/main.h | 3 ++ todo.md | 2 +- 4 files changed, 135 insertions(+), 39 deletions(-) diff --git a/res/shader/root/rt.glsl b/res/shader/root/rt.glsl index 4cd406d..7445cc1 100644 --- a/res/shader/root/rt.glsl +++ b/res/shader/root/rt.glsl @@ -2,14 +2,19 @@ layout (location = 1) uniform vec4 t; -layout (location = 2) uniform vec3 w; // view space axes -layout (location = 3) uniform vec3 u; -layout (location = 4) uniform vec3 v; +layout (location = 2) uniform vec3 _w; // view space axes +layout (location = 3) uniform vec3 _u; +layout (location = 4) uniform vec3 _v; + +layout (location = 5) uniform mat4 _cameraInverseProjection; +layout (location = 6) uniform vec3 _camh; +layout (location = 7) uniform vec3 _camv; +layout (location = 8) uniform vec3 _camll; layout(local_size_x = 1, local_size_y = 1) in; // size of local work group - 1 pixel layout(rgba32f, binding = 0) uniform image2D img_output; // rgba32f defines internal format, image2d for random write to output texture -const float INF = 1000.0f; +const float INF = 20.0; #include sphere.glsl @@ -24,6 +29,7 @@ struct RayHit vec3 position; float distance; vec3 normal; + vec3 albedo; }; void intersectSphere(Ray ray, inout RayHit bestHit, Sphere sphere) @@ -41,13 +47,14 @@ void intersectSphere(Ray ray, inout RayHit bestHit, Sphere sphere) bestHit.distance = t; bestHit.position = ray.origin + t*ray.direction; bestHit.normal = normalize(bestHit.position-sphere.center); + bestHit.albedo = sphere.albedo; } } Ray createCameraRay(vec2 uv) { // transform -1..1 -> 0..1 - //uv = uv*0.5+0.5; + uv = uv*0.5+0.5; //uv.x=1-uv.x; // transform camera origin to world space @@ -58,12 +65,22 @@ Ray createCameraRay(vec2 uv) // float2 rd = _CameraLensRadius * randomInUnitDisk(); // float3 offset = _CameraU * rd.x + _CameraV * rd.y; + // invert perspective projection of view space position + //vec3 dir = mul(_cameraInverseProjection, float4(uv, 0.0, 1.0)).xyz; + + // TODO: transform direction from camera to world space (move camera around!) + + vec3 dir; + dir = uv.x*_camh + uv.y*_camv; + dir = _camll + uv.x*_camh + uv.y*_camv; + dir = normalize(dir); + float max_x = 5.0; float max_y = 5.0; Ray ray; - ray.origin = vec3(uv.x * max_x, uv.y * max_y, 0.0); - ray.direction = vec3(0.0,0.0,1.0); // ortho forwards + ray.origin = vec3(0.0,0.0,0.0); + ray.direction = dir; return ray; } @@ -87,18 +104,33 @@ void main() hit.position = vec3(0.0,0.0,0.0); hit.distance = INF; hit.normal = vec3(0.0,0.0,0.0); + hit.albedo = vec3(0.0,0.0,0.0); + + vec3 spheresCenter = _w*-10.0; + + Sphere s1; + s1.center = spheresCenter+vec3(sin(t.x),0.0,cos(t.x))*2.5; + s1.radius = 2.0; + s1.albedo = vec3(1.0,0.0,0.0); + + Sphere s2; + s2.center = spheresCenter-vec3(sin(t.x),0.0,cos(t.x))*2.5; + s2.radius = 2.0; + s2.albedo = vec3(0.0,0.0,1.0); Sphere sphere; - //sphere.center = vec3(0.0,0.0,10.0+0.5*t.y); - sphere.center = w*-10.0; + sphere.center = _w*-10.0; + sphere.center += vec3(0.0,0.0,t.y); sphere.radius = 4.0; // ray-sphere intersection - intersectSphere(ray, hit, sphere); + intersectSphere(ray, hit, s1); + intersectSphere(ray, hit, s2); - float depth = (hit.distance-6.0)/4.0; + // TODO: write depth to texture + float depth = hit.distance/INF; - pixel = vec4(t.z,1.0-t.z,depth,1.0); + pixel = vec4(hit.albedo,1.0); pixel *= (1.0-depth); // output to a specific pixel in the image diff --git a/src/main.c b/src/main.c index 552e3f2..f98bb17 100644 --- a/src/main.c +++ b/src/main.c @@ -1,6 +1,9 @@ #include "main.h" #include "gfx.h" +const int WIDTH = 420; +const int HEIGHT = 420; + // forward declarations // input @@ -9,16 +12,16 @@ int checkQuit(); // time float time(); +void updateUniforms(GLuint shaderProgram); +void updateCameraUniforms(GLuint shaderProgram); + int main() { - int width = 420; - int height = 420; - // create a window and opengl context - SDL_Window* window = gfxInit(width, height); + SDL_Window* window = gfxInit(WIDTH, HEIGHT); // create a texture for the compute shader to write to - GLuint textureOutput = createWriteOnlyTexture(width, height); + GLuint textureOutput = createWriteOnlyTexture(WIDTH, HEIGHT); printWorkGroupLimits(); // compile shader programs @@ -32,33 +35,15 @@ int main() initBuffers(); setVertexAttributes(); - // render loop while (!checkQuit()) { glUseProgram(computeProgram); - // update uniforms - float t = time(); // time - float sin_t = sin(t); - int tLocation = glGetUniformLocation(computeProgram, "t"); - glUniform4f(tLocation, t, sin_t, (1.0 + sin_t)*0.5, 0.0f); - - // form view space axes - vec3 u,v; - vec3 up = {0,1.0,0}; - vec3 w = {0,sin_t*0.1,-1.0}; - glm_vec3_norm(w); - glm_vec3_cross(up,w,u); - glm_vec3_norm(u); - glm_vec3_cross(w, u, v); - int wLocation = glGetUniformLocation(computeProgram, "w"); - glUniform3f(wLocation+0, w[0], w[1], w[2]); // w - glUniform3f(wLocation+1, u[0], u[1], u[2]); // u - glUniform3f(wLocation+2, v[0], v[1], v[2]); // v + updateUniforms(computeProgram); // dispatch compute shader - glDispatchCompute((GLuint)width, (GLuint)height, 1); + glDispatchCompute((GLuint)WIDTH, (GLuint)HEIGHT, 1); // make sure we're finished writing to the texture before trying to read it glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); @@ -77,9 +62,85 @@ int main() return 0; } +void updateUniforms(GLuint shaderProgram) +{ + float t = time(); // time + float sin_t = sin(t); + int tLocation = glGetUniformLocation(shaderProgram, "t"); + glUniform4f(tLocation, t, sin_t, (1.0 + sin_t)*0.5, 0.0f); + + updateCameraUniforms(shaderProgram); +} + +void updateCameraUniforms(GLuint shaderProgram) +{ + // set up perspective projection matrix and its inverse + mat4 proj, proji; + float fovy = 60.0; // vertical field of view in deg + float near = 0.1; + float far = 1000.0; + float aspect = (float)WIDTH/(float)HEIGHT; + glm_perspective(fovy,aspect,near,far,proj); // TODO: radians or degrees?? + glm_mat4_inv(proj, proji); + int inverseProjLocation = glGetUniformLocation(shaderProgram, "_cameraInverseProjection"); + glUniformMatrix4fv(inverseProjLocation, 1, GL_FALSE, proji[0]); + + // form view space axes + vec3 u,v; + vec3 up = {0.0,1.0,0.0}; + vec3 w = {0.0,0.0,-1.0}; + glm_vec3_norm(w); + glm_vec3_cross(up,w,u); + glm_vec3_norm(u); + glm_vec3_cross(w, u, v); + int wLocation = glGetUniformLocation(shaderProgram, "_w"); + glUniform3f(wLocation+0, w[0], w[1], w[2]); // w + glUniform3f(wLocation+1, u[0], u[1], u[2]); // u + glUniform3f(wLocation+2, v[0], v[1], v[2]); // v + + // get camera properties + float theta = glm_rad(fovy); // convert fovy to radians + float h = tan(theta*0.5); + float vph = 2.0*h; // viewport height + float vpw = aspect*vph; // viewport width + + // TODO: actual focal length lmao + float f = 1.0; + + // camera axes + // + // use vec3_scale instead of vec3_multiply to get scalar multiplication + // https://cglm.readthedocs.io/en/latest/vec3.html#c.glm_vec3_scale + vec3 camh={0}, + camv={0}, + camll={0}, + camhh={0}, + camvh={0}, + fw={0}; + + glm_vec3_scale(u,f*vpw,camh); + int camhLocation = glGetUniformLocation(shaderProgram, "_camh"); + glUniform3f(camhLocation, camh[0], camh[1], camh[2]); + glm_vec3_scale(v,f*vph,camv); + int camvLocation = camhLocation+1; + glUniform3f(camvLocation, camv[0], camv[1], camv[2]); + + // camera lower left corner + // calculate half-axes and w*f to establish 3d position of ll corner in camera space + glm_vec3_scale(u,f*vpw*0.5,camhh); + glm_vec3_scale(v,f*vph*0.5,camvh); + glm_vec3_scale(w,f,fw); + glm_vec3_sub(camll,camhh,camll); + glm_vec3_sub(camll,camvh,camll); + glm_vec3_sub(camll,fw,camll); + int camllLocation = glGetUniformLocation(shaderProgram, "_camll"); + glUniform3f(camllLocation, camll[0], camll[1], camll[2]); +} + float time() { - return (float)SDL_GetTicks() / 1000.0f; // ms / 1000.0 = seconds since start + // ms / 1000.0 = seconds since start + return (float)SDL_GetTicks() / 1000.0f; } int checkQuit() diff --git a/src/main.h b/src/main.h index 9fd7431..95e9ef9 100644 --- a/src/main.h +++ b/src/main.h @@ -2,3 +2,6 @@ #include #include +#include + +#include diff --git a/todo.md b/todo.md index dc4ab3f..3d59c31 100644 --- a/todo.md +++ b/todo.md @@ -9,7 +9,7 @@ * [x] render a texture to a full-screen quad * [x] pass uniforms to texture to animate it * [-] ray tracing time - * [-] perspective + * [x] perspective * [-] depth * [x] acquire value * [ ] depth texture