gfx: generate brdf lut

main
Dominik Madarász 2024-03-27 19:02:07 +01:00
parent b94c56ec58
commit ff72ac6bc9
6 changed files with 271 additions and 48 deletions

View File

@ -0,0 +1,100 @@
#version 400
const float PI = 3.1415926536;
in vec2 uv;
out vec2 fragcolor;
float RadicalInverse_VdC(uint bits) {
bits = (bits << 16u) | (bits >> 16u);
bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
return float(bits) * 2.3283064365386963e-10; // / 0x100000000
}
vec2 Hammersley(uint i, uint N) {
return vec2(float(i)/float(N), RadicalInverse_VdC(i));
}
vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness) {
float a = roughness*roughness;
float phi = 2.0 * PI * Xi.x;
float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y));
float sinTheta = sqrt(1.0 - cosTheta*cosTheta);
// from spherical coordinates to cartesian coordinates
vec3 H;
H.x = cos(phi) * sinTheta;
H.y = sin(phi) * sinTheta;
H.z = cosTheta;
// from tangent-space vector to world-space sample vector
vec3 up = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
vec3 tangent = normalize(cross(up, N));
vec3 bitangent = cross(N, tangent);
vec3 sampleVec = tangent * H.x + bitangent * H.y + N * H.z;
return normalize(sampleVec);
}
float GeometrySchlickGGX(float NdotV, float roughness) {
float a = roughness;
float k = (a * a) / 2.0;
float nom = NdotV;
float denom = NdotV * (1.0 - k) + k;
return nom / denom;
}
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) {
float NdotV = max(dot(N, V), 0.0);
float NdotL = max(dot(N, L), 0.0);
float ggx2 = GeometrySchlickGGX(NdotV, roughness);
float ggx1 = GeometrySchlickGGX(NdotL, roughness);
return ggx1 * ggx2;
}
vec2 GenerateBRDF(float NdotV, float roughness) {
vec3 V;
V.x = sqrt(1.0 - NdotV*NdotV);
V.y = 0.0;
V.z = NdotV;
float A = 0.0;
float B = 0.0;
vec3 N = vec3(0.0, 0.0, 1.0);
const uint SAMPLE_COUNT = 1024u;
for(uint i = 0u; i < SAMPLE_COUNT; ++i)
{
vec2 Xi = Hammersley(i, SAMPLE_COUNT);
vec3 H = ImportanceSampleGGX(Xi, N, roughness);
vec3 L = normalize(2.0 * dot(V, H) * H - V);
float NdotL = max(L.z, 0.0);
float NdotH = max(H.z, 0.0);
float VdotH = max(dot(V, H), 0.0);
if(NdotL > 0.0)
{
float G = GeometrySmith(N, V, L, roughness);
float G_Vis = (G * VdotH) / (NdotH * NdotV);
float Fc = pow(1.0 - VdotH, 5.0);
A += (1.0 - Fc) * G_Vis;
B += Fc * G_Vis;
}
}
A /= float(SAMPLE_COUNT);
B /= float(SAMPLE_COUNT);
return vec2(A, B);
}
void main() {
fragcolor = GenerateBRDF(uv.x, uv.y);
}

View File

@ -227,7 +227,7 @@ float geometry_smith( vec3 N, vec3 V, vec3 L, float roughness )
vec2 sphere_to_polar( vec3 normal )
{
normal = normalize( normal );
return vec2( ( atan( normal.z, normal.x ) + skysphere_rotation ) / PI / 2.0 + 0.5, acos( normal.y ) / PI );
return vec2( ( atan( normal.z, normal.x ) - PI*0.5f ) / PI / 2.0 + 0.5, acos( normal.y ) / PI );
}
// Our vertically GL_CLAMPed textures seem to blend towards black when sampling the half-pixel edge.
@ -285,7 +285,7 @@ vec3 sample_irradiance_fast( vec3 normal, vec3 vertex_tangent )
// Sample the irradiance map if it exists, otherwise fall back to blurred reflection map.
if ( has_tex_skyenv )
{
vec2 polar = sphere_to_polar_clamp_y( normal, 180.0 );
vec2 polar = sphere_to_polar( normal );
return textureLod( tex_skyenv, polar, 0.0 ).rgb * exposure;
}
else
@ -473,7 +473,7 @@ void main(void)
}
else if( map_roughness.has_tex ) {
//< @r-lyeh, metalness B, roughness G, (@todo: self-shadowing occlusion R; for now, any of R/B are metallic)
metallic = sample_colormap( map_roughness, v_texcoord ).b + sample_colormap( map_roughness, v_texcoord ).r;
metallic = sample_colormap( map_roughness, v_texcoord ).b;// + sample_colormap( map_roughness, v_texcoord ).r;
roughness = sample_colormap( map_roughness, v_texcoord ).g;
}
@ -708,21 +708,6 @@ void main(void)
// Technically this alpha may be too transparent, if there is a lot of reflected light we wouldn't
// see the background, maybe we can approximate it well enough by adding a fresnel term
fragcolor = vec4( color * shadowing().xyz, alpha );
// rimlight
#ifdef RIM
{
vec3 n = normalize(mat3(M) * v_normal_ws); // convert normal to view space
vec3 p = (M * vec4(v_position,1.0)).xyz; // convert position to view space
vec3 v = vec3(0,-1,0);
if (!u_rimambient) {
v = normalize(u_rimpivot-p);
}
float rim = 1.0 - max(dot(v,n), 0.0);
vec3 col = u_rimcolor*(pow(smoothstep(1.0-u_rimrange.x,u_rimrange.y,rim), u_rimrange.z));
fragcolor += vec4(col, 0.0);
}
#endif
}
#endif

View File

@ -371199,6 +371199,9 @@ texture_t texture_compressed_from_mem(const void *data, int len, unsigned flags)
if( dimensions > 0 ) glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_REPEAT);
if( dimensions > 1 ) glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_REPEAT);
if( dimensions > 2 ) glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_REPEAT);
if( flags&TEXTURE_CLAMP && dimensions > 0 ) glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
if( flags&TEXTURE_CLAMP && dimensions > 1 ) glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if( flags&TEXTURE_CLAMP && dimensions > 2 ) glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
if( target == GL_TEXTURE_CUBE_MAP ) target = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
@ -372620,15 +372623,55 @@ int ui_fxs() {
static texture_t brdf = {0};
static void brdf_load() {
const char *filename;
filename = "Skyboxes/brdf_lut1k_256x256_32F.ktx";
filename = "Skyboxes/brdf_lut2k_512x512_32F.ktx";
// generate texture
unsigned tex;
glGenTextures(1, &tex);
brdf = texture_compressed( filename,
TEXTURE_CLAMP | TEXTURE_NEAREST | TEXTURE_RG | TEXTURE_FLOAT
);
unsigned texchecker = texture_checker().id;
ASSERT(brdf.id != texchecker, "!Couldn't load BRDF lookup table '%s'!", filename );
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RG16F, 512, 512, 0, GL_RG, GL_FLOAT, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
brdf.id = tex;
brdf.w = 512;
brdf.h = 512;
// create program and generate BRDF LUT
unsigned lut_fbo = fbo(tex, 0, 0), rbo=0;
fbo_bind(lut_fbo);
static int program = -1, vao = -1;
if( program < 0 ) {
const char* vs = vfs_read("shaders/vs_0_2_fullscreen_quad_B_flipped.glsl");
const char* fs = vfs_read("shaders/brdf.glsl");
program = shader(vs, fs, "", "fragcolor", NULL);
glGenVertexArrays( 1, (GLuint*)&vao );
}
glDisable(GL_BLEND);
handle old_shader = last_shader;
glUseProgram( program );
glViewport(0, 0, 512, 512);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glBindVertexArray( vao );
glDrawArrays( GL_TRIANGLES, 0, 6 );
profile_incstat("Render.num_drawcalls", +1);
profile_incstat("Render.num_triangles", +2);
glBindVertexArray( 0 );
glUseProgram( last_shader );
fbo_unbind();
fbo_destroy(lut_fbo);
}
texture_t brdf_lut() {
@ -372649,7 +372692,7 @@ bool colormap( colormap_t *cm, const char *texture_name, bool load_as_srgb ) {
int srgb = load_as_srgb ? TEXTURE_SRGB : 0;
int hdr = strendi(texture_name, ".hdr") ? TEXTURE_FLOAT|TEXTURE_RGBA : 0;
texture_t t = texture_compressed(texture_name, TEXTURE_LINEAR | TEXTURE_MIPMAPS | TEXTURE_REPEAT | hdr | srgb);
texture_t t = texture_compressed(texture_name, TEXTURE_LINEAR | TEXTURE_ANISOTROPY | TEXTURE_MIPMAPS | TEXTURE_REPEAT | hdr | srgb);
if( t.id == texture_checker().id ) {
cm->texture = NULL;
@ -373028,7 +373071,7 @@ void model_set_uniforms(model_t m, int shader, mat44 mv, mat44 proj, mat44 view,
shader_bool( "has_tex_skysphere", has_tex_skysphere );
shader_bool( "has_tex_skyenv", has_tex_skyenv );
if( has_tex_skysphere ) {
float mipCount = floor( log2( m.sky_refl.h ) );
float mipCount = floor( log2( max(m.sky_refl.w, m.sky_refl.h) ) );
shader_texture("tex_skysphere", m.sky_refl);
shader_float( "skysphere_mip_count", mipCount );
}
@ -382654,6 +382697,9 @@ static void v4k_post_init(float refresh_rate) {
hz = refresh_rate;
// t = glfwGetTime();
// preload brdf LUT early
(void)brdf_lut();
}
// ----------------------------------------------------------------------------

View File

@ -48,6 +48,9 @@ static void v4k_post_init(float refresh_rate) {
hz = refresh_rate;
// t = glfwGetTime();
// preload brdf LUT early
(void)brdf_lut();
}
// ----------------------------------------------------------------------------

View File

@ -1180,6 +1180,9 @@ texture_t texture_compressed_from_mem(const void *data, int len, unsigned flags)
if( dimensions > 0 ) glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_REPEAT);
if( dimensions > 1 ) glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_REPEAT);
if( dimensions > 2 ) glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_REPEAT);
if( flags&TEXTURE_CLAMP && dimensions > 0 ) glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
if( flags&TEXTURE_CLAMP && dimensions > 1 ) glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if( flags&TEXTURE_CLAMP && dimensions > 2 ) glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
if( target == GL_TEXTURE_CUBE_MAP ) target = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
@ -2601,15 +2604,55 @@ int ui_fxs() {
static texture_t brdf = {0};
static void brdf_load() {
const char *filename;
filename = "Skyboxes/brdf_lut1k_256x256_32F.ktx";
filename = "Skyboxes/brdf_lut2k_512x512_32F.ktx";
// generate texture
unsigned tex;
glGenTextures(1, &tex);
brdf = texture_compressed( filename,
TEXTURE_CLAMP | TEXTURE_NEAREST | TEXTURE_RG | TEXTURE_FLOAT
);
unsigned texchecker = texture_checker().id;
ASSERT(brdf.id != texchecker, "!Couldn't load BRDF lookup table '%s'!", filename );
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RG16F, 512, 512, 0, GL_RG, GL_FLOAT, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
brdf.id = tex;
brdf.w = 512;
brdf.h = 512;
// create program and generate BRDF LUT
unsigned lut_fbo = fbo(tex, 0, 0), rbo=0;
fbo_bind(lut_fbo);
static int program = -1, vao = -1;
if( program < 0 ) {
const char* vs = vfs_read("shaders/vs_0_2_fullscreen_quad_B_flipped.glsl");
const char* fs = vfs_read("shaders/brdf.glsl");
program = shader(vs, fs, "", "fragcolor", NULL);
glGenVertexArrays( 1, (GLuint*)&vao );
}
glDisable(GL_BLEND);
handle old_shader = last_shader;
glUseProgram( program );
glViewport(0, 0, 512, 512);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glBindVertexArray( vao );
glDrawArrays( GL_TRIANGLES, 0, 6 );
profile_incstat("Render.num_drawcalls", +1);
profile_incstat("Render.num_triangles", +2);
glBindVertexArray( 0 );
glUseProgram( last_shader );
fbo_unbind();
fbo_destroy(lut_fbo);
}
texture_t brdf_lut() {
@ -2630,7 +2673,7 @@ bool colormap( colormap_t *cm, const char *texture_name, bool load_as_srgb ) {
int srgb = load_as_srgb ? TEXTURE_SRGB : 0;
int hdr = strendi(texture_name, ".hdr") ? TEXTURE_FLOAT|TEXTURE_RGBA : 0;
texture_t t = texture_compressed(texture_name, TEXTURE_LINEAR | TEXTURE_MIPMAPS | TEXTURE_REPEAT | hdr | srgb);
texture_t t = texture_compressed(texture_name, TEXTURE_LINEAR | TEXTURE_ANISOTROPY | TEXTURE_MIPMAPS | TEXTURE_REPEAT | hdr | srgb);
if( t.id == texture_checker().id ) {
cm->texture = NULL;
@ -3009,7 +3052,7 @@ void model_set_uniforms(model_t m, int shader, mat44 mv, mat44 proj, mat44 view,
shader_bool( "has_tex_skysphere", has_tex_skysphere );
shader_bool( "has_tex_skyenv", has_tex_skyenv );
if( has_tex_skysphere ) {
float mipCount = floor( log2( m.sky_refl.h ) );
float mipCount = floor( log2( max(m.sky_refl.w, m.sky_refl.h) ) );
shader_texture("tex_skysphere", m.sky_refl);
shader_float( "skysphere_mip_count", mipCount );
}

View File

@ -18352,6 +18352,9 @@ texture_t texture_compressed_from_mem(const void *data, int len, unsigned flags)
if( dimensions > 0 ) glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_REPEAT);
if( dimensions > 1 ) glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_REPEAT);
if( dimensions > 2 ) glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_REPEAT);
if( flags&TEXTURE_CLAMP && dimensions > 0 ) glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
if( flags&TEXTURE_CLAMP && dimensions > 1 ) glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if( flags&TEXTURE_CLAMP && dimensions > 2 ) glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
if( target == GL_TEXTURE_CUBE_MAP ) target = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
@ -19773,15 +19776,55 @@ int ui_fxs() {
static texture_t brdf = {0};
static void brdf_load() {
const char *filename;
filename = "Skyboxes/brdf_lut1k_256x256_32F.ktx";
filename = "Skyboxes/brdf_lut2k_512x512_32F.ktx";
// generate texture
unsigned tex;
glGenTextures(1, &tex);
brdf = texture_compressed( filename,
TEXTURE_CLAMP | TEXTURE_NEAREST | TEXTURE_RG | TEXTURE_FLOAT
);
unsigned texchecker = texture_checker().id;
ASSERT(brdf.id != texchecker, "!Couldn't load BRDF lookup table '%s'!", filename );
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RG16F, 512, 512, 0, GL_RG, GL_FLOAT, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
brdf.id = tex;
brdf.w = 512;
brdf.h = 512;
// create program and generate BRDF LUT
unsigned lut_fbo = fbo(tex, 0, 0), rbo=0;
fbo_bind(lut_fbo);
static int program = -1, vao = -1;
if( program < 0 ) {
const char* vs = vfs_read("shaders/vs_0_2_fullscreen_quad_B_flipped.glsl");
const char* fs = vfs_read("shaders/brdf.glsl");
program = shader(vs, fs, "", "fragcolor", NULL);
glGenVertexArrays( 1, (GLuint*)&vao );
}
glDisable(GL_BLEND);
handle old_shader = last_shader;
glUseProgram( program );
glViewport(0, 0, 512, 512);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glBindVertexArray( vao );
glDrawArrays( GL_TRIANGLES, 0, 6 );
profile_incstat("Render.num_drawcalls", +1);
profile_incstat("Render.num_triangles", +2);
glBindVertexArray( 0 );
glUseProgram( last_shader );
fbo_unbind();
fbo_destroy(lut_fbo);
}
texture_t brdf_lut() {
@ -19802,7 +19845,7 @@ bool colormap( colormap_t *cm, const char *texture_name, bool load_as_srgb ) {
int srgb = load_as_srgb ? TEXTURE_SRGB : 0;
int hdr = strendi(texture_name, ".hdr") ? TEXTURE_FLOAT|TEXTURE_RGBA : 0;
texture_t t = texture_compressed(texture_name, TEXTURE_LINEAR | TEXTURE_MIPMAPS | TEXTURE_REPEAT | hdr | srgb);
texture_t t = texture_compressed(texture_name, TEXTURE_LINEAR | TEXTURE_ANISOTROPY | TEXTURE_MIPMAPS | TEXTURE_REPEAT | hdr | srgb);
if( t.id == texture_checker().id ) {
cm->texture = NULL;
@ -20181,7 +20224,7 @@ void model_set_uniforms(model_t m, int shader, mat44 mv, mat44 proj, mat44 view,
shader_bool( "has_tex_skysphere", has_tex_skysphere );
shader_bool( "has_tex_skyenv", has_tex_skyenv );
if( has_tex_skysphere ) {
float mipCount = floor( log2( m.sky_refl.h ) );
float mipCount = floor( log2( max(m.sky_refl.w, m.sky_refl.h) ) );
shader_texture("tex_skysphere", m.sky_refl);
shader_float( "skysphere_mip_count", mipCount );
}
@ -29807,6 +29850,9 @@ static void v4k_post_init(float refresh_rate) {
hz = refresh_rate;
// t = glfwGetTime();
// preload brdf LUT early
(void)brdf_lut();
}
// ----------------------------------------------------------------------------