diff --git a/shader/include/sphere.glsl b/shader/include/sphere.glsl index e991daa..dfa7483 100644 --- a/shader/include/sphere.glsl +++ b/shader/include/sphere.glsl @@ -1,8 +1,6 @@ struct Sphere { - vec3 center; - float radius; + // (c.x,c.y,c.z,r) + vec4 cr; vec3 albedo; - vec3 specular; - vec3 emission; }; diff --git a/shader/root/rt.glsl b/shader/root/rt.glsl index 0d48e0b..10a3ff5 100644 --- a/shader/root/rt.glsl +++ b/shader/root/rt.glsl @@ -1,5 +1,7 @@ #version 430 +#include sphere.glsl + // TODO: do i actually need explicit location descriptors? layout (location = 1) uniform vec4 _t; @@ -14,12 +16,15 @@ layout (location = 8) uniform vec3 _camll; layout (location = 9) uniform vec3 _cpos; layout (location = 10) uniform vec3 _tpos; // target +const int SPHERES = 250; // 253 is the maximum?? TODO: use uniform buffer objects +layout (location = 12) uniform int _activeSpheres; +layout (location = 13) uniform Sphere _spheres[SPHERES]; + 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 = 30.0; - -#include sphere.glsl +const float INF = 20.0; +const float PI = 3.14159; struct Ray { @@ -37,9 +42,12 @@ struct RayHit void intersectSphere(Ray ray, inout RayHit bestHit, Sphere sphere) { - vec3 d = ray.origin-sphere.center; + vec3 c = sphere.cr.xyz; + float r = sphere.cr.w; + + vec3 d = ray.origin-c; float p1 = -dot(ray.direction,d); - float p2sqr = p1*p1-dot(d,d)+sphere.radius*sphere.radius; + float p2sqr = p1*p1-dot(d,d)+r*r; if (p2sqr < 0) return; @@ -49,7 +57,7 @@ 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.normal = normalize(bestHit.position-c); bestHit.albedo = sphere.albedo; } } @@ -62,19 +70,6 @@ Ray createCameraRay(vec2 uv) vec3 target = vec3(0,0,0); - // transform camera origin to world space - // TODO: c2w matrix!! for now we just assume the camera is at the origin - // float3 origin = mul(_CameraToWorld, float4(0.0,0.0,0.0,1.0)).xyz; - - // TODO: offset from centre of the lens for depth of field - // 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; @@ -111,30 +106,10 @@ void main() hit.normal = vec3(0.0,0.0,0.0); hit.albedo = vec3(0.0,0.0,0.0); - vec3 spheresCenter = vec3(0.0,0.0,0.0); - - float t = _t.x; - Sphere s1; - s1.center = spheresCenter+vec3(sin(t),0.0,cos(t))*2.5; - s1.radius = 2.0; - s1.albedo = vec3(1.0,0.0,0.0); - - t+=3.1415/1.5; - Sphere s2; - s2.center = spheresCenter+vec3(sin(t),0.0,cos(t))*2.5; - s2.radius = 2.0; - s2.albedo = vec3(0.0,1.0,0.0); - - t+=3.1415/1.5; - Sphere s3; - s3.center = spheresCenter+vec3(sin(t),0.0,cos(t))*2.5; - s3.radius = 2.0; - s3.albedo = vec3(0.0,0.0,1.0); - - // ray-sphere intersection - intersectSphere(ray, hit, s1); - intersectSphere(ray, hit, s2); - intersectSphere(ray, hit, s3); + for (int i = 0; i < _activeSpheres; i++) + { + intersectSphere(ray, hit, _spheres[i]); + } // TODO: write depth to texture float depth = hit.distance/INF; diff --git a/src/gfx.c b/src/gfx.c index d65cf05..2e8bb58 100644 --- a/src/gfx.c +++ b/src/gfx.c @@ -54,6 +54,10 @@ SDL_Window* gfxInit(int width, int height) glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &availableAttributes); printf("max vertex attributes %d\n", availableAttributes); + int uniformLocations; + glGetIntegerv(GL_MAX_UNIFORM_LOCATIONS, &uniformLocations); + printf("max uniform locations %d\n", uniformLocations); + return sdlWindow; } diff --git a/src/main.c b/src/main.c index 6f1d782..70622fb 100644 --- a/src/main.c +++ b/src/main.c @@ -1,6 +1,8 @@ #include "main.h" #include "gfx.h" +#include "sphere.h" + const int WIDTH = 420; const int HEIGHT = 420; @@ -15,6 +17,8 @@ float time(); void updateUniforms(GLuint shaderProgram); void updateCameraUniforms(GLuint shaderProgram); +void updateSphereUniform(GLuint shaderProgram, struct Sphere sphere); + int main() { // create a window and opengl context @@ -62,6 +66,48 @@ int main() return 0; } +void makeSpheres(struct Sphere *spheres, int count) +{ + float t = time(); + + vec3 albedos[] = + { + {0.0,0.0,1.0}, + {0.0,1.0,0.0}, + {0.0,1.0,1.0}, + {1.0,0.0,0.0}, + {1.0,0.0,1.0}, + {1.0,1.0,0.0}, + {1.0,1.0,1.0} + }; + + // distance from center + float d = 6.0; + float radius = 0.5; + float x; + vec3 sc = {0.0,0.0,1.0}; + + for (int i = 0; i < count; i++) + { + x = t*0.1 + 2.0*CGLM_PI * i/(float)count; + sc[0] = sin(x)*d; + sc[2] = cos(x)*d; + + float ic = i/(float)count; + float r = sin(ic); + float g = sin(ic+1.0); + float b = sin(ic+2.0); + g = 1.0; + b = 1.0; + + vec3 col = {r,g,b}; + glm_vec3_scale(col, 0.5, col); + glm_vec3_adds(col, 0.5, col); + + spheres[i] = makeSphere(sc,radius,col); + } +} + void updateUniforms(GLuint shaderProgram) { float t = time(); // time @@ -70,13 +116,19 @@ void updateUniforms(GLuint shaderProgram) glUniform4f(tLocation, t, sin_t, (1.0 + sin_t)*0.5, 0.0f); updateCameraUniforms(shaderProgram); + + const int sphereCount = 42; + struct Sphere spheres[sphereCount]; + makeSpheres(spheres, sphereCount); + + updateSphereUniforms(shaderProgram, spheres, sphereCount); } 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 fovy = 90.0; // vertical field of view in deg float near = 0.1; float far = 1000.0; float aspect = (float)WIDTH/(float)HEIGHT; @@ -93,7 +145,8 @@ void updateCameraUniforms(GLuint shaderProgram) // lookat vector and view matrix float d = 10.0 + sin(t); - vec3 cpos = {sin(-t)*d,cos(0.5*t)*5.0,cos(-t)*d}; // camera pos + float pt = -t*0.1; + vec3 cpos = {sin(pt)*d,cos(0.5*t)*5.0,cos(pt)*d}; // camera pos vec3 tpos = {0.0,0.0,0.0}; // target pos glm_vec3_sub(cpos,tpos,cdir); // look dir (inverted cause opengl noises) glm_vec3_normalize(cdir); @@ -159,6 +212,7 @@ void updateCameraUniforms(GLuint shaderProgram) glUniform3f(camllLocation, camll[0], camll[1], camll[2]); } + float time() { // ms / 1000.0 = seconds since start diff --git a/src/sphere.c b/src/sphere.c new file mode 100644 index 0000000..35517d0 --- /dev/null +++ b/src/sphere.c @@ -0,0 +1,47 @@ +#include "sphere.h" + +struct Sphere makeSphere(vec3 center, float radius, vec3 albedo) +{ + struct Sphere s; + + s.cr[0] = center[0]; + s.cr[1] = center[1]; + s.cr[2] = center[2]; + s.cr[3] = radius; + + glm_vec3_copy(albedo, s.albedo); + + return s; +} + +void updateSphereUniform(GLuint shaderProgram, struct Sphere sphere) +{ + int scrloc, saloc; + scrloc = glGetUniformLocation(shaderProgram, "_sphere.cr"); + saloc = glGetUniformLocation(shaderProgram, "_sphere.albedo"); + + glUniform4fv(scrloc, 1, sphere.cr); + glUniform3fv(saloc, 1, sphere.albedo); + + updateSphereUniforms(shaderProgram, &sphere, 0); +} + +void updateSphereUniforms(GLuint shaderProgram, struct Sphere *spheres, int count) +{ + // set sphere count + int loc = glGetUniformLocation(shaderProgram, "_activeSpheres"); + glUniform1i(loc, count); + + // each sphere takes up two uniform locations + const int stride = 2; + + // first location in the array + loc = glGetUniformLocation(shaderProgram, "_spheres[0].cr"); + + for (int i = 0; i < count; i++) + { + struct Sphere s = spheres[i]; + glUniform4fv(loc+i*stride, 1, s.cr); + glUniform3fv(loc+i*stride+1, 1, s.albedo); + } +} diff --git a/src/sphere.h b/src/sphere.h new file mode 100644 index 0000000..5f416e4 --- /dev/null +++ b/src/sphere.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +#define GLEW_STATIC +#include + +#include + +struct Sphere +{ + vec4 cr; + vec3 albedo; +}; + +struct Sphere makeSphere(vec3 center, float radius, vec3 albedo); +void updateSphereUniform(GLuint shaderProgram, struct Sphere sphere); +void updateSphereUniforms(GLuint shaderProgram, struct Sphere *spheres, int count); diff --git a/todo.md b/todo.md index 048504d..0952e9c 100644 --- a/todo.md +++ b/todo.md @@ -7,10 +7,14 @@ * [x] compile processed shaders * [-] render image with compute shader * [x] render a texture to a full-screen quad - * [x] pass uniforms to texture to animate it + * [x] pass uniforms to shader to animate it + * [x] pass structed uniform buffers * [-] ray tracing time * [x] perspective * [x] camera lookat + * [ ] do a bounce + * [ ] do a 'flect + * [ ] do a 'fract * [-] depth * [x] acquire value * [ ] depth texture