refactor shaders, implement depth buffer
This commit is contained in:
parent
c4b74458a8
commit
cdc4aea9d5
|
@ -1,2 +1,4 @@
|
|||
const float INF = 1000.0;
|
||||
const float INF = 17.0;
|
||||
const float PI = 3.14159;
|
||||
const int SAMPLES = 1;
|
||||
const int BOUNCES = 4;
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
vec2 pixelUv()
|
||||
vec2 pixelUv(ivec2 pixelCoords, ivec2 dims)
|
||||
{
|
||||
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);
|
||||
|
|
|
@ -12,7 +12,11 @@ mat3 getTangentSpace(vec3 normal)
|
|||
|
||||
vec3 sampleHemisphere(vec3 normal)
|
||||
{
|
||||
vec2 uv = pixelUv();
|
||||
// TODO: make independent of this image uniform
|
||||
ivec2 pixelCoords = ivec2(gl_GlobalInvocationID.xy);
|
||||
ivec2 dims = imageSize(img_output);
|
||||
|
||||
vec2 uv = pixelUv(pixelCoords, dims);
|
||||
uv += _seed.xy;
|
||||
|
||||
vec4 noise = sampleNoise(uv);;
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
layout(local_size_x = 1, local_size_y = 1) in; // size of local work group - 1 pixel
|
||||
|
||||
// gbuffer?
|
||||
layout(rgba32f, binding = 2) readonly uniform image2D _g0;
|
||||
|
||||
// final output
|
||||
layout(rgba32f, binding = 0) uniform image2D img_output; // rgba32f defines internal format, image2d for random write to output texture
|
||||
|
||||
|
@ -35,18 +38,18 @@ void main()
|
|||
// base pixel colour for the image
|
||||
vec4 pixel = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
|
||||
vec2 uv = pixelUv();
|
||||
ivec2 pixelCoords = ivec2(gl_GlobalInvocationID.xy);
|
||||
ivec2 dims = imageSize(img_output);
|
||||
|
||||
int samples = 1;
|
||||
int bounces = 4;
|
||||
vec2 uv = pixelUv(pixelCoords, dims);
|
||||
|
||||
for (int i = 0; i < samples; i++)
|
||||
for (int i = 0; i < SAMPLES; i++)
|
||||
{
|
||||
// create a ray from the uv
|
||||
Ray ray = createCameraRay(uv);
|
||||
|
||||
// trace the rays path around the scene
|
||||
for (int j = 0; j < bounces; j++)
|
||||
for (int j = 0; j < BOUNCES; j++)
|
||||
{
|
||||
RayHit hit = trace(ray);
|
||||
|
||||
|
@ -55,7 +58,16 @@ void main()
|
|||
if (length(ray.energy) < 0.001) break;
|
||||
}
|
||||
}
|
||||
pixel.xyz /= samples;
|
||||
pixel.xyz /= SAMPLES;
|
||||
|
||||
vec4 d = imageLoad(_g0, ivec2(gl_GlobalInvocationID.xy));
|
||||
float depth = d.x;
|
||||
|
||||
pixel.xyz = mix(pixel.xyz, vec3(0), depth);
|
||||
|
||||
//pixel.a = 1.0;
|
||||
|
||||
//pixel.xyz = texture(_g0, uv).xyz;
|
||||
|
||||
// output to a specific pixel in the image
|
||||
imageStore(img_output, ivec2(gl_GlobalInvocationID.xy), pixel);
|
||||
|
|
|
@ -1,3 +1,48 @@
|
|||
#version 430
|
||||
|
||||
// writes first hit information into buffers to accelerate later passes
|
||||
|
||||
// local work group
|
||||
layout(local_size_x = 1, local_size_y = 1) in;
|
||||
|
||||
layout (rgba32f, binding = 2) uniform image2D g0_output;
|
||||
|
||||
#include func.glsl
|
||||
#include constants.glsl
|
||||
#include time.glsl
|
||||
#include sphere.glsl
|
||||
#include ray.glsl
|
||||
#include intersect.glsl
|
||||
#include random.glsl
|
||||
#include camera.glsl
|
||||
#include image.glsl
|
||||
#include scene.glsl
|
||||
|
||||
void main()
|
||||
{
|
||||
// x normal.x
|
||||
// y normal.y
|
||||
// z normal.z
|
||||
// w depth
|
||||
|
||||
vec4 pixel= vec4(0);
|
||||
ivec2 pixelCoords = ivec2(gl_GlobalInvocationID.xy);
|
||||
ivec2 dims = imageSize(g0_output);
|
||||
vec2 uv = pixelUv(pixelCoords, dims);
|
||||
|
||||
Ray ray = createCameraRay(uv);
|
||||
RayHit hit = trace(ray);
|
||||
|
||||
//pixel.xyz = hit.normal;
|
||||
|
||||
// TODO: non-linear depth
|
||||
float n = 1;
|
||||
float f = INF;
|
||||
float z = hit.distance;
|
||||
|
||||
float depth = (1.0/z-1.0/n)/(1.0/n-1.0/f);
|
||||
|
||||
pixel.x = z/f;
|
||||
|
||||
imageStore(g0_output, pixelCoords, pixel);
|
||||
}
|
||||
|
|
77
src/gfx.c
77
src/gfx.c
|
@ -14,11 +14,8 @@ unsigned int indices[] = {
|
|||
1, 2, 3
|
||||
};
|
||||
|
||||
SDL_Window* sdlWindow;
|
||||
SDL_GLContext* sdlContext;
|
||||
|
||||
GLuint compileShader(const char* path, GLenum type);
|
||||
|
||||
SDL_Window* gfxInit(int width, int height)
|
||||
{
|
||||
// load sdl modules
|
||||
|
@ -33,7 +30,7 @@ SDL_Window* gfxInit(int width, int height)
|
|||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
|
||||
|
||||
sdlWindow = SDL_CreateWindow(
|
||||
SDL_Window *sdlWindow = SDL_CreateWindow(
|
||||
"oglc",
|
||||
SDL_WINDOWPOS_UNDEFINED,
|
||||
SDL_WINDOWPOS_UNDEFINED,
|
||||
|
@ -62,19 +59,36 @@ SDL_Window* gfxInit(int width, int height)
|
|||
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &imageUnits);
|
||||
printf("max texture image units %d\n", imageUnits);
|
||||
|
||||
printWorkGroupLimits();
|
||||
|
||||
return sdlWindow;
|
||||
}
|
||||
|
||||
unsigned int compileQuadShaderProgram(const char* vsPath, const char* fsPath)
|
||||
int compileShaders(struct Shaders *shaders)
|
||||
{
|
||||
// everything is renderered onto the surface of one quad
|
||||
shaders->quad = compileQuadShaderProgram("bin/shader.vert", "bin/shader.frag");
|
||||
|
||||
// preprass writes first-pass information into buffers for later acceleration
|
||||
shaders->prepass = compileComputeShaderProgram("bin/rtpre.compute");
|
||||
|
||||
// lighting traces multiple bounces of light around the scene
|
||||
shaders->lighting = compileComputeShaderProgram("bin/rt.compute");
|
||||
|
||||
// TODO: actually make sure all the shaders compile
|
||||
return 0;
|
||||
}
|
||||
|
||||
GLuint compileQuadShaderProgram(const char* vsPath, const char* fsPath)
|
||||
{
|
||||
GLuint vs = compileShader(vsPath, GL_VERTEX_SHADER);
|
||||
GLuint fs = compileShader(fsPath, GL_FRAGMENT_SHADER);
|
||||
|
||||
unsigned int shaderProgram = glCreateProgram();
|
||||
GLuint shaderProgram = glCreateProgram();
|
||||
glAttachShader(shaderProgram, vs);
|
||||
glAttachShader(shaderProgram, fs);
|
||||
|
||||
// TODO: check program linking success
|
||||
// TODO: check program linking success textur
|
||||
glLinkProgram(shaderProgram);
|
||||
|
||||
GLint result = GL_FALSE;
|
||||
|
@ -99,7 +113,7 @@ unsigned int compileQuadShaderProgram(const char* vsPath, const char* fsPath)
|
|||
return shaderProgram;
|
||||
}
|
||||
|
||||
unsigned int compileComputeShaderProgram(const char* computeShaderPath)
|
||||
GLuint compileComputeShaderProgram(const char* computeShaderPath)
|
||||
{
|
||||
GLuint cs = compileShader(computeShaderPath, GL_COMPUTE_SHADER);
|
||||
GLuint computeProgram = glCreateProgram();
|
||||
|
@ -160,15 +174,40 @@ void setVertexAttributes()
|
|||
// color
|
||||
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, stride, (void*)(3*sizeof(float)));
|
||||
glEnableVertexAttribArray(1);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// uv
|
||||
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, stride, (void*)(6*sizeof(float)));
|
||||
glEnableVertexAttribArray(2);
|
||||
}
|
||||
|
||||
int createTextures(int width, int height, struct Shaders shaders, struct Textures* textures)
|
||||
{
|
||||
// generate noise
|
||||
textures->noise = createNoiseTexture(width, height);
|
||||
glBindTexture(GL_TEXTURE_2D,textures->noise);
|
||||
int loc = glGetUniformLocation(shaders.lighting, "_noise");
|
||||
glUniform1i(loc, textures->noise);
|
||||
|
||||
// create a texture for the compute shader to write to
|
||||
textures->target = createWriteOnlyTexture(width, height);
|
||||
|
||||
textures->g0 = createTexture(width, height);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
@ -216,9 +255,27 @@ GLuint createWriteOnlyTexture(int width, int height)
|
|||
return texture;
|
||||
}
|
||||
|
||||
// creates an empty texture in GL_TEXTURE2 unit
|
||||
GLuint createTexture(int width, int height)
|
||||
{
|
||||
GLuint texture;
|
||||
glGenTextures(1, &texture);
|
||||
//glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
|
||||
// an empty image
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, height, 0, GL_RGBA, GL_FLOAT, NULL);
|
||||
glBindImageTexture(2, texture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
void initBuffers()
|
||||
{
|
||||
unsigned int VAO, VBO, EBO;
|
||||
GLuint VAO, VBO, EBO;
|
||||
glGenVertexArrays(1, &VAO); // vertex array object
|
||||
glGenBuffers(1, &VBO); // vertex buffer object
|
||||
glGenBuffers(1, &EBO); // element buffer object
|
||||
|
|
35
src/gfx.h
35
src/gfx.h
|
@ -9,15 +9,46 @@
|
|||
#include "io.h"
|
||||
#include "random.h"
|
||||
|
||||
struct Shaders
|
||||
{
|
||||
GLuint quad;
|
||||
GLuint prepass;
|
||||
GLuint lighting;
|
||||
};
|
||||
|
||||
struct Textures
|
||||
{
|
||||
// texture that ultimately gets drawn to the framebuffer
|
||||
GLuint target;
|
||||
|
||||
// TODO: blue noise, pink noise!
|
||||
// noise texture to help with randomness
|
||||
GLuint noise;
|
||||
|
||||
// additional view space information
|
||||
//
|
||||
// x depth
|
||||
// y -
|
||||
// z -
|
||||
// w -
|
||||
GLuint g0;
|
||||
};
|
||||
|
||||
SDL_Window* gfxInit(int width, int height);
|
||||
|
||||
unsigned int compileQuadShaderProgram(const char* vsPath, const char* fsPath);
|
||||
unsigned int compileComputeShaderProgram();
|
||||
int compileShaders(struct Shaders *shaders);
|
||||
GLuint compileQuadShaderProgram(const char* vsPath, const char* fsPath);
|
||||
GLuint compileComputeShaderProgram(const char* csPath);
|
||||
|
||||
int createTextures(int width, int height, struct Shaders shaders, struct Textures* textures);
|
||||
GLuint createNoiseTexture(int width, int height);
|
||||
GLuint createTexture(int width, int height);
|
||||
GLuint createWriteOnlyTexture(int width, int height);
|
||||
GLuint compileShader(const char* path, GLenum type);
|
||||
|
||||
void printWorkGroupLimits();
|
||||
|
||||
// quad initialisation
|
||||
void setVertexAttributes();
|
||||
void initBuffers();
|
||||
|
||||
|
|
81
src/main.c
81
src/main.c
|
@ -1,3 +1,4 @@
|
|||
|
||||
#include "main.h"
|
||||
#include "gfx.h"
|
||||
#include "clock.h"
|
||||
|
@ -5,72 +6,76 @@
|
|||
|
||||
#include "sphere.h"
|
||||
#include "cam.h"
|
||||
#include "input.h"
|
||||
|
||||
const int WIDTH = 420;
|
||||
const int HEIGHT = 420;
|
||||
|
||||
void updateUniforms(GLuint shaderProgram);
|
||||
|
||||
struct TextureIDs
|
||||
{
|
||||
GLuint output; // the texture that ultimately gets rendered
|
||||
GLuint noise;
|
||||
} textureIds;
|
||||
SDL_Window *window;
|
||||
|
||||
int main()
|
||||
struct Shaders shaders;
|
||||
struct Textures textures;
|
||||
|
||||
void initialise()
|
||||
{
|
||||
printf("GL_TEXTURE0: %d\n", GL_TEXTURE0);
|
||||
printf("GL_TEXTURE1: %d\n", GL_TEXTURE1);
|
||||
window = gfxInit(WIDTH, HEIGHT);
|
||||
|
||||
randomInit();
|
||||
|
||||
// create a window and opengl context
|
||||
SDL_Window* window = gfxInit(WIDTH, HEIGHT);
|
||||
|
||||
// compile shader programs
|
||||
unsigned int computeProgram = compileComputeShaderProgram(
|
||||
"bin/rt.compute");
|
||||
unsigned int quadProgram = compileQuadShaderProgram(
|
||||
"bin/shader.vert",
|
||||
"bin/shader.frag");
|
||||
|
||||
// generate noise
|
||||
textureIds.noise = createNoiseTexture(WIDTH, HEIGHT);
|
||||
glBindTexture(GL_TEXTURE_2D,textureIds.noise);
|
||||
int noiseLoc = glGetUniformLocation(computeProgram, "_noise");
|
||||
glUniform1i(noiseLoc, textureIds.noise);
|
||||
|
||||
// create a texture for the compute shader to write to
|
||||
textureIds.output = createWriteOnlyTexture(WIDTH, HEIGHT);
|
||||
printWorkGroupLimits();
|
||||
|
||||
// initialise quad
|
||||
initBuffers();
|
||||
setVertexAttributes();
|
||||
|
||||
int frames = 0;
|
||||
// render loop
|
||||
while (!checkQuit())
|
||||
// compile shader programs
|
||||
compileShaders(&shaders);
|
||||
createTextures(WIDTH, HEIGHT, shaders, &textures);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// dispatch compute shader
|
||||
glUseProgram(computeProgram);
|
||||
updateUniforms(computeProgram);
|
||||
initialise();
|
||||
|
||||
int frames;
|
||||
for (frames = 0; !checkQuit(); frames++)
|
||||
{
|
||||
GLuint shader;
|
||||
|
||||
// prepass
|
||||
// TODO: write output to different texture than main output
|
||||
shader = shaders.prepass;
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, textures.g0);
|
||||
glUseProgram(shader);
|
||||
updateUniforms(shader);
|
||||
glDispatchCompute((GLuint)WIDTH, (GLuint)HEIGHT, 1);
|
||||
|
||||
// make sure we're finished writing to the texture before trying to read it
|
||||
glMemoryBarrier(GL_ALL_BARRIER_BITS);
|
||||
|
||||
// dispatch compute shaders
|
||||
shader = shaders.lighting;
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, textures.target);
|
||||
glUseProgram(shader);
|
||||
updateUniforms(shader);
|
||||
//int loc = glGetUniformLocation(shader, "_g0");
|
||||
//glUniform1i(loc, textures.g0);
|
||||
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);
|
||||
|
||||
// normal drawing pass
|
||||
glUseProgram(quadProgram);
|
||||
shader = shaders.quad;
|
||||
glUseProgram(shader);
|
||||
|
||||
// bind texture written to by compute stage to 2d target
|
||||
glBindTexture(GL_TEXTURE_2D, textureIds.output);
|
||||
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
|
||||
|
||||
// swip swap
|
||||
SDL_GL_SwapWindow(window);
|
||||
|
||||
frames++;
|
||||
}
|
||||
|
||||
float elapsed = now();
|
||||
|
|
Loading…
Reference in New Issue