implement perspective rays

This commit is contained in:
ktyl 2021-08-02 09:35:39 +01:00
parent 4b8f28f70e
commit bea7cb5802
4 changed files with 135 additions and 39 deletions

View File

@ -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

View File

@ -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()

View File

@ -2,3 +2,6 @@
#include <cglm/vec3.h>
#include <cglm/cam.h>
#include <cglm/util.h>
#include <math.h>

View File

@ -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