diff --git a/shader/root/rt.glsl b/shader/root/rt.glsl index 67aa379..f67849b 100644 --- a/shader/root/rt.glsl +++ b/shader/root/rt.glsl @@ -2,6 +2,8 @@ #include sphere.glsl +layout(local_size_x = 1, local_size_y = 1) in; // size of local work group - 1 pixel + // TODO: do i actually need explicit location descriptors? layout (location = 1) uniform vec4 _t; @@ -16,14 +18,17 @@ 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 +// 253 is the maximum?? TODO: use uniform buffer objects +const int SPHERES = 250; + layout (location = 12) uniform int _activeSpheres; layout (location = 13) uniform Sphere _spheres[SPHERES]; uniform vec4 _seed; -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 +layout(binding=1) uniform sampler2D _noise; // noise texture const float INF = 1000.0; const float PI = 3.14159; @@ -144,14 +149,34 @@ RayHit trace(Ray ray) return hit; } +vec2 pixelUv() +{ + ivec2 pixelCoords = ivec2(gl_GlobalInvocationID.xy); + + ivec2 dims = imageSize(img_output); + + vec2 uv; + uv.x = (float(pixelCoords.x * 2 - dims.x) / dims.x) * dims.x/dims.y; // account for aspect ratio + uv.y = (float(pixelCoords.y * 2 - dims.y) / dims.y); + + return uv; +} + +vec4 sampleNoise() +{ + return texture(_noise, pixelUv()); +} + float random(vec2 st) { - st += gl_GlobalInvocationID.xy; - st += _seed.xy; - st += _seed.zw; - normalize(st); + //st += gl_GlobalInvocationID.xy; + //st += _seed.xy; + //st += _seed.zw; + //normalize(st); - return fract(sin(dot(st.xy,vec2(12.9898,78.233)))*43758.5453123); + vec2 nuv = texture(_noise, st.xy).xy; + + return fract(sin(dot(nuv,vec2(12.9898,78.233)))*43758.5453123); } float sdot(vec3 x, vec3 y, float f = 1.0) @@ -173,15 +198,17 @@ mat3 getTangentSpace(vec3 normal) vec3 sampleHemisphere(vec3 normal) { - float cosTheta = random(normal.xy); + vec4 noise = sampleNoise(); + + float cosTheta = random(normalize(normal.xy+noise.xy)); float sinTheta = sqrt(max(0.0,1.0-cosTheta*cosTheta)); - float phi = 2.0*PI*random(normal.yx); + float phi = 2.0*PI*random(normalize(normal.yz+noise.xw)); vec3 tangentSpaceDir = vec3(cos(phi)*sinTheta, sin(phi)*sinTheta, cosTheta); // convert direction from tangent space to world space mat3 ts = getTangentSpace(normal); - return ts* tangentSpaceDir; + return ts * tangentSpaceDir; } vec3 scatterLambert(inout Ray ray, RayHit hit) @@ -213,13 +240,10 @@ void main() // get index in global work group ie xy position ivec2 pixel_coords = ivec2(gl_GlobalInvocationID.xy); - ivec2 dims = imageSize(img_output); // fetch image dimensions - vec2 uv; - uv.x = (float(pixel_coords.x * 2 - dims.x) / dims.x) * dims.x/dims.y; // account for aspect ratio - uv.y = (float(pixel_coords.y * 2 - dims.y) / dims.y); + vec2 uv = pixelUv(); int samples = 2; - int bounces = 3; + int bounces = 2; for (int i = 0; i < samples; i++) { @@ -244,6 +268,8 @@ void main() //pixel = vec4(hit.albedo,1.0); //pixel *= (1.0-depth); + //pixel = texture(_noise, uv); + // output to a specific pixel in the image imageStore(img_output, pixel_coords, pixel); } diff --git a/src/gfx.c b/src/gfx.c index 2e8bb58..7f12c0e 100644 --- a/src/gfx.c +++ b/src/gfx.c @@ -1,4 +1,5 @@ #include "gfx.h" +#include "random.h" #include "stb_image.h" float vertices[] = { @@ -58,6 +59,10 @@ SDL_Window* gfxInit(int width, int height) glGetIntegerv(GL_MAX_UNIFORM_LOCATIONS, &uniformLocations); printf("max uniform locations %d\n", uniformLocations); + int imageUnits; + glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &imageUnits); + printf("max texture image units %d\n", imageUnits); + return sdlWindow; } @@ -191,6 +196,38 @@ void createTextureFromFile(const char* imagePath) stbi_image_free(data); } +// creates a noise texture in active texture 1 +GLuint createNoiseTexture(int width, int height) +{ + // same init steps as with a regular texture + GLuint texture; + glGenTextures(1, &texture); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, texture); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_REPEAT); + + int channels = 4; // rgba + int length = width*height*channels; + printf("generating %d random floats\n", length); + + float data[width*height*channels]; + + for (int i = 0; i < length; i++) + { + data[i] = randomFloat(); + } + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, height, 0, GL_RGBA, GL_FLOAT, data); + glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F); + glGenerateMipmap(GL_TEXTURE_2D); + + return texture; +} + GLuint createWriteOnlyTexture(int width, int height) { GLuint texture; diff --git a/src/gfx.h b/src/gfx.h index ef8b305..e594cbb 100644 --- a/src/gfx.h +++ b/src/gfx.h @@ -7,12 +7,14 @@ #include #include "io.h" +#include "random.h" SDL_Window* gfxInit(int width, int height); unsigned int compileQuadShaderProgram(const char* vsPath, const char* fsPath); unsigned int compileComputeShaderProgram(); +GLuint createNoiseTexture(int width, int height); void createTextureFromFile(const char* path); GLuint createWriteOnlyTexture(int width, int height); void printWorkGroupLimits(); diff --git a/src/main.c b/src/main.c index 9a415c9..6a18b9d 100644 --- a/src/main.c +++ b/src/main.c @@ -13,9 +13,14 @@ void updateUniforms(GLuint shaderProgram); int main() { + randomInit(); + // create a window and opengl context SDL_Window* window = gfxInit(WIDTH, HEIGHT); + // generate noise + GLuint noise = createNoiseTexture(WIDTH, HEIGHT); + // create a texture for the compute shader to write to GLuint textureOutput = createWriteOnlyTexture(WIDTH, HEIGHT); printWorkGroupLimits(); @@ -27,18 +32,21 @@ int main() "bin/shader.vert", "bin/shader.frag"); + glBindTexture(GL_TEXTURE_2D, noise); + int noiseLoc = glGetUniformLocation(computeProgram, "_noise"); + glUniform1i(noiseLoc, noise); + // initialise quad initBuffers(); setVertexAttributes(); + int frames = 0; // render loop while (!checkQuit()) { - glUseProgram(computeProgram); - - updateUniforms(computeProgram); - // dispatch compute shader + glUseProgram(computeProgram); + updateUniforms(computeProgram); glDispatchCompute((GLuint)WIDTH, (GLuint)HEIGHT, 1); // make sure we're finished writing to the texture before trying to read it @@ -46,15 +54,23 @@ int main() // normal drawing pass glUseProgram(quadProgram); - glActiveTexture(GL_TEXTURE0); // use computed texture - glBindTexture(GL_TEXTURE_2D, textureOutput); + // bind texture written to by compute stage to 2d target + glBindTexture(GL_TEXTURE_2D, textureOutput); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); // swip swap SDL_GL_SwapWindow(window); + + frames++; } + float elapsed = now(); + printf("%d frames in %f seconds (avg: %f fps)\n", + frames, + elapsed, + (float)frames/elapsed); + return 0; }