From 089458476f2b1bad381b3b6cb919280ffdcb596c Mon Sep 17 00:00:00 2001 From: ktyl Date: Wed, 1 Mar 2023 00:12:15 +0000 Subject: [PATCH] generate blue noise points --- src/gfx.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++++++++- src/gfx.h | 2 + 2 files changed, 127 insertions(+), 1 deletion(-) diff --git a/src/gfx.c b/src/gfx.c index 461185b..039cbdc 100644 --- a/src/gfx.c +++ b/src/gfx.c @@ -197,7 +197,7 @@ int createTextures(int width, int height, struct Shaders shaders, struct Texture } // creates a noise texture in active texture 1 -GLuint createNoiseTexture(int width, int height) +GLuint createWhiteNoiseTexture(int width, int height) { // same init steps as with a regular texture GLuint texture; @@ -230,6 +230,130 @@ GLuint createNoiseTexture(int width, int height) return texture; } +void generateBlueNoisePoints(vec2* points, int m, int n) +{ + vec2 firstSample = {randomFloat(), randomFloat()}; + struct Candidate + { + vec2 pos; + // distance to closest point already in pattern + float distance; + }; + + for (int i = 0; i < n; i++) + { + // generate a bunch of candidates + int count = m * i; + struct Candidate candidates[count]; + //int closest = -1; + + for (int j = 0; j < count; j++) + { + struct Candidate* c = &candidates[j]; + + c->pos[0] = randomFloat(); + c->pos[1] = randomFloat(); + // the largest distance we should expect is sqrt(2), + // so pick a maximum larger than that + c->distance = 1.5; + + // get the distance of the closest point already in the pattern + for (int k = 0; k < i; k++) + { + float distance = glm_vec2_distance(c->pos, points[k]); + if (distance < c->distance) + { + c->distance = distance; + //closest = k; + } + } + } + + // of our candidates, now determine which of them has the furthest + // closest-distance + int furthest = -1; + float furthestDistance = 0.0; + for (int j = 0; j < count; j++) + { + if (candidates[j].distance > furthestDistance) + { + furthest = j; + furthestDistance = candidates[j].distance; + } + } + + glm_vec2_copy(candidates[furthest].pos, points[i]); + } +} + +GLuint createBlueNoiseTexture(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); + printf("generating blue noise\n"); + + float* data = (float*)malloc(length*sizeof(float)); + + // generate a bunch of points + int m = 100; + int n = 100; + vec2 points[n]; + generateBlueNoisePoints(points, m, n); + + // use those points to generate a texture + + //for (int i = 0; i < length; i++) + //{ + // data[i] = randomFloat(); + //} + + for (int i = 0; i < width*height; i++) + { + int pixelIdx = i; + int x = pixelIdx % width; + int y = pixelIdx / width; + float u = x / (float)width; + float v = y / (float)height; + vec2 pixel = {u,v}; + + for (int j = 0; j < n; j++) + { + float d = glm_vec2_distance(points[j], pixel); + float r = 0.01; + if (d < r) + { + data[i * channels + 2] = 1.0; + } + } + } + + 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); + + free(data); + + return texture; +} + +GLuint createNoiseTexture(int width, int height) +{ + //return createWhiteNoiseTexture(width, height); + return createBlueNoiseTexture(width, height); +} + GLuint createWriteOnlyTexture(int width, int height) { GLuint texture; diff --git a/src/gfx.h b/src/gfx.h index db364e7..1c30422 100644 --- a/src/gfx.h +++ b/src/gfx.h @@ -6,6 +6,8 @@ #include #include +#include + #include "io.h" #include "random.h"