WIP: light probes support
parent
3bf4a4d851
commit
0b8d85f81c
|
@ -0,0 +1,6 @@
|
|||
# Add directories or file patterns to ignore during indexing (e.g. foo/ or *.csv)
|
||||
*.*
|
||||
!*.c
|
||||
!*.cpp
|
||||
!*.inl
|
||||
!*.h
|
|
@ -1,5 +1,6 @@
|
|||
default
|
||||
.art*.zip
|
||||
*.rdi
|
||||
__pycache__
|
||||
.vs
|
||||
.vscode
|
||||
|
|
|
@ -3,5 +3,5 @@ call razzle amd64
|
|||
if exist .env.bat (
|
||||
call .env.bat
|
||||
)
|
||||
code .
|
||||
cursor .
|
||||
exit
|
19
bind/v4k.lua
19
bind/v4k.lua
|
@ -1110,11 +1110,24 @@ typedef struct colormap_t {
|
|||
typedef struct cubemap_t {
|
||||
unsigned id;
|
||||
vec3 sh[9];
|
||||
int framebuffers[6];
|
||||
int textures[6];
|
||||
int depth_buffers[6];
|
||||
unsigned width, height;
|
||||
float *pixels;
|
||||
int step;
|
||||
vec3 pos;
|
||||
} cubemap_t;
|
||||
cubemap_t cubemap( const image_t image, int flags );
|
||||
cubemap_t cubemap6( const image_t images[6], int flags );
|
||||
void cubemap_destroy(cubemap_t *c);
|
||||
cubemap_t* cubemap_get_active();
|
||||
void cubemap_bake_begin(cubemap_t *c, vec3 pos, unsigned width, unsigned height);
|
||||
bool cubemap_bake_step(cubemap_t *c, mat44 proj , mat44 view );
|
||||
void cubemap_bake_end(cubemap_t *c, float sky_intensity);
|
||||
void cubemap_sh_reset(cubemap_t *c);
|
||||
void cubemap_sh_shader(cubemap_t *c);
|
||||
void cubemap_sh_add_light(cubemap_t *c, vec3 light, vec3 dir, float strength);
|
||||
unsigned fbo( unsigned texture_color, unsigned texture_depth, int wr_flags );
|
||||
void fbo_bind(unsigned id);
|
||||
void fbo_unbind();
|
||||
|
@ -1235,13 +1248,11 @@ enum SKYBOX_FLAGS {
|
|||
SKYBOX_PBR,
|
||||
};
|
||||
typedef struct skybox_t {
|
||||
handle program;
|
||||
handle program, rayleigh_program;
|
||||
mesh_t geometry;
|
||||
cubemap_t cubemap;
|
||||
int flags;
|
||||
int framebuffers[6];
|
||||
int textures[6];
|
||||
float *pixels;
|
||||
bool rayleigh_immediate;
|
||||
texture_t sky, refl, env;
|
||||
} skybox_t;
|
||||
skybox_t skybox(const char *panorama_or_cubemap_folder, int flags);
|
||||
|
|
|
@ -38,6 +38,7 @@ int main(int argc, char** argv) {
|
|||
initialized = 1;
|
||||
sky = skybox(flag("--mie") ? 0 : SKY_DIRS[SKY_DIR], 0);
|
||||
mdl = model(OBJ_MDLS[OBJ_MDL], 0);
|
||||
// sky.rayleigh_immediate = 1;
|
||||
rotation44(mdl.pivot, 0, 1,0,0); // @fixme: -90,1,0,0 -> should we rotate SHMs as well? compensate rotation in shader?
|
||||
}
|
||||
|
||||
|
@ -54,12 +55,14 @@ int main(int argc, char** argv) {
|
|||
// render
|
||||
mat44 mvp; multiply44x2(mvp, cam.proj, cam.view);
|
||||
{
|
||||
if (flag("--mie")) {
|
||||
// skybox_sh_reset(&sky);
|
||||
skybox_mie_calc_sh(&sky, 4.0f);
|
||||
// float x = cosf((float)window_time())*4;
|
||||
// skybox_sh_add_light(&sky, vec3(0.3,0.3,0.3), vec3(0,1,0), 16*absf(cosf((float)window_time()*2))+2);
|
||||
// skybox_sh_add_light(&sky, vec3(0.6,0,0), vec3(x,1,0), 2);
|
||||
do_once {
|
||||
if (flag("--mie")) {
|
||||
// skybox_sh_reset(&sky);
|
||||
skybox_mie_calc_sh(&sky, 4.0f);
|
||||
// float x = cosf((float)window_time())*4;
|
||||
// skybox_sh_add_light(&sky, vec3(0.3,0.3,0.3), vec3(0,1,0), 16*absf(cosf((float)window_time()*2))+2);
|
||||
// skybox_sh_add_light(&sky, vec3(0.6,0,0), vec3(x,1,0), 2);
|
||||
}
|
||||
}
|
||||
|
||||
skybox_render(&sky, cam.proj, cam.view);
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
#include "v4k.h"
|
||||
|
||||
int SKY_DIR = 0;
|
||||
const char *SKY_DIRS[] = {
|
||||
"cubemaps/bridge3/",
|
||||
"cubemaps/colors/",
|
||||
"cubemaps/colors2/",
|
||||
"hdr/Tokyo_BigSight_1k.hdr",
|
||||
};
|
||||
|
||||
int OBJ_MDL = 0;
|
||||
const char *OBJ_MDLS[] = {
|
||||
"meshes/CornellBox-Original.obj",
|
||||
"meshes/sphere.obj",
|
||||
"meshes/suzanne.obj",
|
||||
"meshes/gazebo.obj",
|
||||
};
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
window_create(85, WINDOW_MSAA8);
|
||||
|
||||
camera_t cam = camera(); {
|
||||
cam.position = vec3(0, 7.5, 15);
|
||||
cam.pitch = -15;
|
||||
cam.yaw = -90;
|
||||
camera_fps(&cam, 0, 0);
|
||||
}
|
||||
skybox_t sky = {0};
|
||||
skybox_t env_probe = {0};
|
||||
model_t mdl = {0};
|
||||
|
||||
bool initialized = 0;
|
||||
bool must_reload = 0;
|
||||
|
||||
while( window_swap()) {
|
||||
if (input_down(KEY_ESC)) break;
|
||||
// reloading
|
||||
if( must_reload ) {
|
||||
must_reload = 0;
|
||||
skybox_destroy(&sky);
|
||||
model_destroy(mdl);
|
||||
initialized = 0;
|
||||
}
|
||||
if( !initialized ) {
|
||||
initialized = 1;
|
||||
sky = skybox(flag("--mie") ? 0 : SKY_DIRS[SKY_DIR], 0);
|
||||
env_probe = skybox(0, 0);
|
||||
mdl = model(OBJ_MDLS[OBJ_MDL], 0);
|
||||
// rotation44(mdl.pivot, 0, 1,0,0); // @fixme: -90,1,0,0 -> should we rotate SHMs as well? compensate rotation in shader?
|
||||
}
|
||||
|
||||
// fps camera
|
||||
bool active = ui_active() || ui_hover() || gizmo_active() ? false : input(MOUSE_L) || input(MOUSE_M) || input(MOUSE_R);
|
||||
window_cursor( !active );
|
||||
|
||||
if( active ) cam.speed = clampf(cam.speed + input_diff(MOUSE_W) / 10, 0.05f, 5.0f);
|
||||
vec2 mouse = scale2(vec2(input_diff(MOUSE_X), -input_diff(MOUSE_Y)), 0.2f * active);
|
||||
vec3 wasdec = scale3(vec3(input(KEY_D)-input(KEY_A),input(KEY_E)-input(KEY_C),input(KEY_W)-input(KEY_S)), cam.speed);
|
||||
camera_moveby(&cam, wasdec);
|
||||
camera_fps(&cam, mouse.x,mouse.y);
|
||||
|
||||
static bool first_time = true;
|
||||
static bool animate_probe_pos = false;
|
||||
static vec3 probe_pos;
|
||||
if (input_down(KEY_T)) {
|
||||
animate_probe_pos = !animate_probe_pos;
|
||||
}
|
||||
if (animate_probe_pos) {
|
||||
probe_pos = vec3(0, 5, 0);
|
||||
probe_pos.x = sinf(window_time()*2)*2.0f;
|
||||
}
|
||||
if (input_down(KEY_SPACE) || first_time || animate_probe_pos) {
|
||||
first_time = false;
|
||||
mat44 probe_proj, probe_view;
|
||||
if (!animate_probe_pos) {
|
||||
probe_pos = cam.position;
|
||||
}
|
||||
cubemap_bake_begin(&env_probe.cubemap, probe_pos, 1024, 1024);
|
||||
while (cubemap_bake_step(&env_probe.cubemap, probe_proj, probe_view)) {
|
||||
skybox_render(&sky, probe_proj, probe_view);
|
||||
shader_bind(mdl.program);
|
||||
shader_vec3v("u_coefficients_sh", 9, sky.cubemap.sh);
|
||||
|
||||
model_render(mdl, probe_proj, probe_view, mdl.pivot, 0);
|
||||
}
|
||||
cubemap_bake_end(&env_probe.cubemap, 1.2f);
|
||||
}
|
||||
|
||||
ddraw_sphere(probe_pos, 0.1f);
|
||||
|
||||
// render
|
||||
mat44 mvp; multiply44x2(mvp, cam.proj, cam.view);
|
||||
{
|
||||
// skybox_render(&env_probe, cam.proj, cam.view);
|
||||
skybox_render(&sky, cam.proj, cam.view);
|
||||
|
||||
shader_bind(mdl.program);
|
||||
shader_vec3v("u_coefficients_sh", 9, env_probe.cubemap.sh);
|
||||
shader_int("u_textured", false);
|
||||
|
||||
model_render(mdl, cam.proj, cam.view, mdl.pivot, 0);
|
||||
}
|
||||
|
||||
if( ui_panel("Scene", 0)) {
|
||||
if( ui_list("Skybox", SKY_DIRS, countof(SKY_DIRS), &SKY_DIR) ) {
|
||||
must_reload = 1;
|
||||
}
|
||||
if( ui_list("Model", OBJ_MDLS, countof(OBJ_MDLS), &OBJ_MDL) ) {
|
||||
must_reload = 1;
|
||||
}
|
||||
ui_separator();
|
||||
for (int i = 0; i < 9; i++) {
|
||||
ui_color3f(va("SH Coefficient [%d]", i), &sky.cubemap.sh[i].x);
|
||||
}
|
||||
ui_panel_end();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
# Blender 4.2.1 LTS MTL File: 'None'
|
||||
# www.blender.org
|
||||
|
||||
newmtl backWall
|
||||
Ns 10.000005
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.725000 0.710000 0.680000
|
||||
Ks 0.000000 0.000000 0.000000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 1
|
||||
|
||||
newmtl ceiling
|
||||
Ns 10.000005
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.725000 0.710000 0.680000
|
||||
Ks 0.000000 0.000000 0.000000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 1
|
||||
|
||||
newmtl floor
|
||||
Ns 10.000005
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.725000 0.710000 0.680000
|
||||
Ks 0.000000 0.000000 0.000000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 1
|
||||
|
||||
newmtl leftWall
|
||||
Ns 10.000005
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.630000 0.065000 0.050000
|
||||
Ks 0.000000 0.000000 0.000000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 1
|
||||
|
||||
newmtl light
|
||||
Ns 10.000005
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.780000 0.780000 0.780000
|
||||
Ks 0.000000 0.000000 0.000000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 1
|
||||
|
||||
newmtl rightWall
|
||||
Ns 10.000005
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.140000 0.450000 0.091000
|
||||
Ks 0.000000 0.000000 0.000000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 1
|
||||
|
||||
newmtl shortBox
|
||||
Ns 10.000005
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.725000 0.710000 0.680000
|
||||
Ks 0.000000 0.000000 0.000000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 1
|
||||
|
||||
newmtl tallBox
|
||||
Ns 10.000005
|
||||
Ka 1.000000 1.000000 1.000000
|
||||
Kd 0.725000 0.710000 0.680000
|
||||
Ks 0.000000 0.000000 0.000000
|
||||
Ke 0.000000 0.000000 0.000000
|
||||
Ni 1.000000
|
||||
d 1.000000
|
||||
illum 1
|
|
@ -0,0 +1,106 @@
|
|||
# Blender 4.2.1 LTS
|
||||
# www.blender.org
|
||||
mtllib CornellBox-Original.mtl
|
||||
o CornellBox-Original
|
||||
v -4.040000 3.960000 -0.000000
|
||||
v 4.000000 3.960000 -0.000000
|
||||
v 4.000000 -4.159999 0.000000
|
||||
v -3.960000 -4.160000 0.000000
|
||||
v -4.080000 3.959999 -7.960001
|
||||
v -4.079999 -4.160001 -7.960000
|
||||
v 4.000000 -4.160000 -7.960000
|
||||
v 4.000000 3.960000 -7.960001
|
||||
v -3.960000 -4.160000 0.000000
|
||||
v 4.000000 -4.159999 0.000000
|
||||
v 4.000000 -4.160000 -7.960000
|
||||
v -4.079999 -4.160001 -7.960000
|
||||
v 4.000000 -4.159999 0.000000
|
||||
v 4.000000 3.960000 -0.000000
|
||||
v 4.000000 3.960000 -7.960001
|
||||
v 4.000000 -4.160000 -7.960000
|
||||
v -4.040000 3.960000 -0.000000
|
||||
v -3.960000 -4.160000 0.000000
|
||||
v -4.079999 -4.160001 -7.960000
|
||||
v -4.080000 3.959999 -7.960001
|
||||
v 2.120000 3.000000 -2.400000
|
||||
v 2.800000 0.680000 -2.400000
|
||||
v 0.520000 -0.000000 -2.400000
|
||||
v -0.200000 2.280000 -2.400000
|
||||
v -0.200000 2.280000 -0.000000
|
||||
v -0.200000 2.280000 -2.400000
|
||||
v 0.520000 -0.000000 -2.400000
|
||||
v 0.520000 0.000000 0.000000
|
||||
v 2.120000 3.000000 -0.000000
|
||||
v 2.120000 3.000000 -2.400000
|
||||
v -0.200000 2.280000 -2.400000
|
||||
v -0.200000 2.280000 -0.000000
|
||||
v 2.800000 0.680000 -0.000000
|
||||
v 2.800000 0.680000 -2.400000
|
||||
v 2.120000 3.000000 -2.400000
|
||||
v 2.120000 3.000000 -0.000000
|
||||
v 0.520000 0.000000 0.000000
|
||||
v 0.520000 -0.000000 -2.400000
|
||||
v 2.800000 0.680000 -2.400000
|
||||
v 2.800000 0.680000 -0.000000
|
||||
v -2.120000 0.359999 -4.800000
|
||||
v 0.160000 -0.360000 -4.800000
|
||||
v -0.560000 -2.680001 -4.800000
|
||||
v -2.840000 -1.960001 -4.800000
|
||||
v -2.120000 0.360000 -0.000000
|
||||
v -2.120000 0.359999 -4.800000
|
||||
v -2.840000 -1.960001 -4.800000
|
||||
v -2.840000 -1.960000 0.000000
|
||||
v -2.840000 -1.960000 0.000000
|
||||
v -2.840000 -1.960001 -4.800000
|
||||
v -0.560000 -2.680001 -4.800000
|
||||
v -0.560000 -2.680000 0.000000
|
||||
v -0.560000 -2.680000 0.000000
|
||||
v -0.560000 -2.680001 -4.800000
|
||||
v 0.160000 -0.360000 -4.800000
|
||||
v 0.160000 -0.360000 0.000000
|
||||
v 0.160000 -0.360000 0.000000
|
||||
v 0.160000 -0.360000 -4.800000
|
||||
v -2.120000 0.359999 -4.800000
|
||||
v -2.120000 0.360000 -0.000000
|
||||
v -0.960000 0.639999 -7.920000
|
||||
v -0.960000 -0.880001 -7.920000
|
||||
v 0.920000 -0.880001 -7.920000
|
||||
v 0.920000 0.639999 -7.920000
|
||||
vn -0.0000 -0.0000 -1.0000
|
||||
vn -0.0000 -0.0000 1.0000
|
||||
vn -0.0000 1.0000 -0.0000
|
||||
vn -1.0000 -0.0000 -0.0000
|
||||
vn 0.9999 0.0049 -0.0100
|
||||
vn -0.9536 -0.3011 -0.0000
|
||||
vn -0.2964 0.9551 -0.0000
|
||||
vn 0.9596 0.2813 -0.0000
|
||||
vn 0.2858 -0.9583 -0.0000
|
||||
vn -0.9551 0.2964 -0.0000
|
||||
vn -0.3011 -0.9536 -0.0000
|
||||
vn 0.9551 -0.2964 -0.0000
|
||||
vn 0.3011 0.9536 -0.0000
|
||||
s 0
|
||||
usemtl floor
|
||||
f 1//1 2//1 3//1 4//1
|
||||
usemtl ceiling
|
||||
f 5//2 6//2 7//2 8//2
|
||||
usemtl backWall
|
||||
f 9//3 10//3 11//3 12//3
|
||||
usemtl rightWall
|
||||
f 13//4 14//4 15//4 16//4
|
||||
usemtl leftWall
|
||||
f 17//5 18//5 19//5 20//5
|
||||
usemtl shortBox
|
||||
f 21//1 22//1 23//1 24//1
|
||||
f 25//6 26//6 27//6 28//6
|
||||
f 29//7 30//7 31//7 32//7
|
||||
f 33//8 34//8 35//8 36//8
|
||||
f 37//9 38//9 39//9 40//9
|
||||
usemtl tallBox
|
||||
f 41//1 42//1 43//1 44//1
|
||||
f 45//10 46//10 47//10 48//10
|
||||
f 49//11 50//11 51//11 52//11
|
||||
f 53//12 54//12 55//12 56//12
|
||||
f 57//13 58//13 59//13 60//13
|
||||
usemtl light
|
||||
f 61//2 62//2 63//2 64//2
|
|
@ -44,6 +44,7 @@ vec4 shadowing() {
|
|||
}
|
||||
|
||||
uniform float u_global_alpha; /// set:1.0
|
||||
uniform float u_global_opacity; /// set:1.0
|
||||
uniform vec3 u_cam_pos;
|
||||
uniform vec3 u_cam_dir;
|
||||
uniform float frame_time;
|
||||
|
|
|
@ -200,6 +200,7 @@ surface_t surface() {
|
|||
s.fragcolor *= shadowing();
|
||||
s.fragcolor.rgb += get_rimlight();
|
||||
s.fragcolor.a *= u_global_alpha;
|
||||
s.fragcolor *= vec4(u_global_opacity);
|
||||
|
||||
#ifdef SHADING_PBR
|
||||
{
|
||||
|
|
|
@ -17209,12 +17209,27 @@ API void fullscreen_quad_ycbcr_flipped( texture_t texture_YCbCr[3] );
|
|||
typedef struct cubemap_t {
|
||||
unsigned id; // texture id
|
||||
vec3 sh[9]; // precomputed spherical harmonics coefficients
|
||||
|
||||
// bake data
|
||||
int framebuffers[6];
|
||||
int textures[6];
|
||||
int depth_buffers[6];
|
||||
unsigned width, height;
|
||||
float *pixels;
|
||||
int step;
|
||||
vec3 pos;
|
||||
} cubemap_t;
|
||||
|
||||
API cubemap_t cubemap( const image_t image, int flags ); // 1 equirectangular panorama
|
||||
API cubemap_t cubemap6( const image_t images[6], int flags ); // 6 cubemap faces
|
||||
API void cubemap_destroy(cubemap_t *c);
|
||||
API cubemap_t* cubemap_get_active();
|
||||
API void cubemap_bake_begin(cubemap_t *c, vec3 pos, unsigned width, unsigned height);
|
||||
API bool cubemap_bake_step(cubemap_t *c, mat44 proj /* out */, mat44 view /* out */);
|
||||
API void cubemap_bake_end(cubemap_t *c, float sky_intensity);
|
||||
API void cubemap_sh_reset(cubemap_t *c);
|
||||
API void cubemap_sh_shader(cubemap_t *c);
|
||||
API void cubemap_sh_add_light(cubemap_t *c, vec3 light, vec3 dir, float strength);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// fbos
|
||||
|
@ -17453,15 +17468,11 @@ enum SKYBOX_FLAGS {
|
|||
};
|
||||
|
||||
typedef struct skybox_t {
|
||||
handle program;
|
||||
handle program, rayleigh_program;
|
||||
mesh_t geometry;
|
||||
cubemap_t cubemap;
|
||||
int flags;
|
||||
|
||||
// mie
|
||||
int framebuffers[6];
|
||||
int textures[6];
|
||||
float *pixels;
|
||||
bool rayleigh_immediate;
|
||||
|
||||
// pbr
|
||||
texture_t sky, refl, env;
|
||||
|
@ -17472,9 +17483,9 @@ API skybox_t skybox_pbr(const char *sky_map, const char *refl_map, const char *e
|
|||
API int skybox_render(skybox_t *sky, mat44 proj, mat44 view);
|
||||
API void skybox_destroy(skybox_t *sky);
|
||||
API void skybox_mie_calc_sh(skybox_t *sky, float sky_intensity);
|
||||
API void skybox_sh_reset(skybox_t *sky);
|
||||
API void skybox_sh_shader(skybox_t *sky);
|
||||
API void skybox_sh_add_light(skybox_t *sky, vec3 light, vec3 dir, float strength);
|
||||
API void skybox_sh_reset(skybox_t *sky); /* @deprecated */
|
||||
API void skybox_sh_shader(skybox_t *sky); /* @deprecated */
|
||||
API void skybox_sh_add_light(skybox_t *sky, vec3 light, vec3 dir, float strength); /* @deprecated */
|
||||
|
||||
API int skybox_push_state(skybox_t *sky, mat44 proj, mat44 view); // @to deprecate
|
||||
API int skybox_pop_state(); // @to deprecate
|
||||
|
@ -383606,6 +383617,13 @@ cubemap_t cubemap( const image_t in, int flags ) {
|
|||
void cubemap_destroy(cubemap_t *c) {
|
||||
glDeleteTextures(1, &c->id);
|
||||
c->id = 0; // do not destroy SH coefficients still. they might be useful in the future.
|
||||
|
||||
if (c->pixels) {
|
||||
FREE(c->pixels);
|
||||
glDeleteFramebuffers(6, c->framebuffers);
|
||||
glDeleteTextures(6, c->textures);
|
||||
glDeleteRenderbuffers(6, c->depth_buffers);
|
||||
}
|
||||
}
|
||||
|
||||
static cubemap_t *last_cubemap;
|
||||
|
@ -383614,6 +383632,166 @@ cubemap_t* cubemap_get_active() {
|
|||
return last_cubemap;
|
||||
}
|
||||
|
||||
// cubemap baker
|
||||
|
||||
static int sky_last_fb;
|
||||
static int sky_last_vp[4];
|
||||
void cubemap_bake_begin(cubemap_t *c, vec3 pos, unsigned width, unsigned height) {
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &sky_last_fb);
|
||||
glGetIntegerv(GL_VIEWPORT, sky_last_vp);
|
||||
c->step = 0;
|
||||
c->pos = pos;
|
||||
|
||||
if (!c->pixels || (c->width != width || c->height != height)) {
|
||||
c->pixels = REALLOC(c->pixels, width*height*12);
|
||||
c->width = width;
|
||||
c->height = height;
|
||||
|
||||
if (!c->framebuffers[0]) {
|
||||
glDeleteFramebuffers(6, c->framebuffers);
|
||||
glDeleteTextures(6, c->textures);
|
||||
glDeleteRenderbuffers(6, c->depth_buffers);
|
||||
for(int i = 0; i < 6; ++i) {
|
||||
c->framebuffers[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!c->framebuffers[0]) {
|
||||
for(int i = 0; i < 6; ++i) {
|
||||
glGenFramebuffers(1, &c->framebuffers[i]);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, c->framebuffers[i]);
|
||||
|
||||
glGenTextures(1, &c->textures[i]);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, c->textures[i]);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_FLOAT, NULL);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, c->textures[i], 0);
|
||||
|
||||
// attach depth buffer
|
||||
glGenRenderbuffers(1, &c->depth_buffers[i]);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, c->depth_buffers[i]);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, c->depth_buffers[i]);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool cubemap_bake_step(cubemap_t *c, mat44 proj /* out */, mat44 view /* out */) {
|
||||
if (c->step >= 6) return false;
|
||||
|
||||
static vec3 directions[6] = {{ 1, 0, 0},{-1, 0, 0},{ 0, 1, 0},{ 0,-1, 0},{ 0, 0, 1},{ 0, 0,-1}};
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, c->framebuffers[c->step]);
|
||||
glViewport(0, 0, c->width, c->height);
|
||||
glClearColor(0, 0, 0, 1);
|
||||
glClearDepth(1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
perspective44(proj, 90.0f, c->width / (float)c->height, 0.1f, 1000.f);
|
||||
lookat44(view, c->pos, add3(c->pos, directions[c->step]), vec3(0,-1,0));
|
||||
++c->step;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void cubemap_bake_end(cubemap_t *c, float sky_intensity) {
|
||||
if (!sky_intensity) {
|
||||
sky_intensity = 1.0f;
|
||||
}
|
||||
|
||||
if (c->id) {
|
||||
glDeleteTextures(1, &c->id);
|
||||
c->id = 0;
|
||||
}
|
||||
|
||||
glGenTextures(1, &c->id);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, c->id);
|
||||
|
||||
int samples = 0;
|
||||
for (int i = 0; i < 6; i++) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, c->framebuffers[i]);
|
||||
glReadPixels(0, 0, c->width, c->height, GL_RGB, GL_FLOAT, c->pixels);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, c->width, c->height, 0, GL_RGB, GL_FLOAT, c->pixels);
|
||||
|
||||
// calculate SH coefficients (@ands)
|
||||
// copied from cubemap6 method
|
||||
const vec3 skyDir[] = {{ 1, 0, 0},{-1, 0, 0},{ 0, 1, 0},{ 0,-1, 0},{ 0, 0, 1},{ 0, 0,-1}};
|
||||
const vec3 skyX[] = {{ 0, 0,-1},{ 0, 0, 1},{ 1, 0, 0},{ 1, 0, 0},{ 1, 0, 0},{-1, 0, 0}};
|
||||
const vec3 skyY[] = {{ 0, 1, 0},{ 0, 1, 0},{ 0, 0,-1},{ 0, 0, 1},{ 0, 1, 0},{ 0, 1, 0}};
|
||||
int step = 16;
|
||||
for (int y = 0; y < c->height; y += step) {
|
||||
float *p = (float*)(c->pixels + y * c->width * 3);
|
||||
for (int x = 0; x < c->width; x += step) {
|
||||
vec3 n = add3(
|
||||
add3(
|
||||
scale3(skyX[i], 2.0f * (x / (c->width - 1.0f)) - 1.0f),
|
||||
scale3(skyY[i], -2.0f * (y / (c->height - 1.0f)) + 1.0f)),
|
||||
skyDir[i]); // texelDirection;
|
||||
float l = len3(n);
|
||||
vec3 light = scale3(vec3(p[0], p[1], p[2]), (1 / (l * l * l)) * sky_intensity); // texelSolidAngle * texel_radiance;
|
||||
n = norm3(n);
|
||||
c->sh[0] = add3(c->sh[0], scale3(light, 0.282095f));
|
||||
c->sh[1] = add3(c->sh[1], scale3(light, -0.488603f * n.y * 2.0 / 3.0));
|
||||
c->sh[2] = add3(c->sh[2], scale3(light, 0.488603f * n.z * 2.0 / 3.0));
|
||||
c->sh[3] = add3(c->sh[3], scale3(light, -0.488603f * n.x * 2.0 / 3.0));
|
||||
c->sh[4] = add3(c->sh[4], scale3(light, 1.092548f * n.x * n.y / 4.0));
|
||||
c->sh[5] = add3(c->sh[5], scale3(light, -1.092548f * n.y * n.z / 4.0));
|
||||
c->sh[6] = add3(c->sh[6], scale3(light, 0.315392f * (3.0f * n.z * n.z - 1.0f) / 4.0));
|
||||
c->sh[7] = add3(c->sh[7], scale3(light, -1.092548f * n.x * n.z / 4.0));
|
||||
c->sh[8] = add3(c->sh[8], scale3(light, 0.546274f * (n.x * n.x - n.y * n.y) / 4.0));
|
||||
p += 3 * step;
|
||||
samples++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int s = 0; s < 9; s++) {
|
||||
c->sh[s] = scale3(c->sh[s], 32.f / samples);
|
||||
}
|
||||
|
||||
glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, sky_last_fb);
|
||||
glViewport(sky_last_vp[0], sky_last_vp[1], sky_last_vp[2], sky_last_vp[3]);
|
||||
}
|
||||
|
||||
void cubemap_sh_reset(cubemap_t *c) {
|
||||
for (int s = 0; s < 9; s++) {
|
||||
c->sh[s] = vec3(0,0,0);
|
||||
}
|
||||
}
|
||||
|
||||
void cubemap_sh_shader(cubemap_t *c) {
|
||||
shader_vec3v("u_coefficients_sh", 9, c->sh);
|
||||
}
|
||||
|
||||
void cubemap_sh_add_light(cubemap_t *c, vec3 light, vec3 dir, float strength) {
|
||||
// Normalize the direction
|
||||
vec3 norm_dir = norm3(dir);
|
||||
|
||||
// Scale the light color and intensity
|
||||
vec3 scaled_light = scale3(light, strength);
|
||||
|
||||
// Add light to the SH coefficients
|
||||
c->sh[0] = add3(c->sh[0], scale3(scaled_light, 0.282095f));
|
||||
c->sh[1] = add3(c->sh[1], scale3(scaled_light, -0.488603f * norm_dir.y));
|
||||
c->sh[2] = add3(c->sh[2], scale3(scaled_light, 0.488603f * norm_dir.z));
|
||||
c->sh[3] = add3(c->sh[3], scale3(scaled_light, -0.488603f * norm_dir.x));
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// skyboxes
|
||||
|
||||
|
@ -383628,7 +383806,10 @@ skybox_t skybox(const char *asset, int flags) {
|
|||
// sky program
|
||||
sky.flags = flags && flags != SKYBOX_PBR ? flags : !!asset ? SKYBOX_CUBEMAP : SKYBOX_RAYLEIGH; // either cubemap or rayleigh
|
||||
sky.program = shader(vfs_read("shaders/vs_3_3_skybox.glsl"),
|
||||
sky.flags ? vfs_read("fs_3_4_skybox.glsl") : vfs_read("shaders/fs_3_4_skybox_rayleigh.glsl"),
|
||||
vfs_read("fs_3_4_skybox.glsl"),
|
||||
"att_position", "fragcolor", NULL);
|
||||
sky.rayleigh_program = shader(vfs_read("shaders/vs_3_3_skybox.glsl"),
|
||||
vfs_read("shaders/fs_3_4_skybox_rayleigh.glsl"),
|
||||
"att_position", "fragcolor", NULL);
|
||||
|
||||
// sky cubemap & SH
|
||||
|
@ -383652,7 +383833,7 @@ skybox_t skybox(const char *asset, int flags) {
|
|||
}
|
||||
} else {
|
||||
// set up mie defaults // @fixme: use shader params instead
|
||||
shader_bind(sky.program);
|
||||
shader_bind(sky.rayleigh_program);
|
||||
shader_vec3("uSunPos", vec3( 0, 0.1, -1 ));
|
||||
shader_vec3("uRayOrigin", vec3(0.0, 6372000.0, 0.0));
|
||||
shader_float("uSunIntensity", 22.0);
|
||||
|
@ -383723,120 +383904,58 @@ skybox_t skybox_pbr(const char *sky_map, const char *refl_map, const char *env_m
|
|||
return sky;
|
||||
}
|
||||
|
||||
static renderstate_t skybox_rs;
|
||||
API vec4 window_getcolor_(); // internal use, not public
|
||||
|
||||
static inline
|
||||
void skybox_render_rayleigh(skybox_t *sky, mat44 proj, mat44 view) {
|
||||
last_cubemap = &sky->cubemap;
|
||||
|
||||
do_once {
|
||||
skybox_rs = renderstate();
|
||||
skybox_rs.depth_test_enabled = 1;
|
||||
skybox_rs.cull_face_enabled = 0;
|
||||
skybox_rs.front_face = GL_CCW;
|
||||
}
|
||||
|
||||
// we have to reset clear color here, because of wrong alpha compositing issues on native transparent windows otherwise
|
||||
// vec4 bgcolor = window_getcolor_();
|
||||
// skybox_rs.clear_color[0] = bgcolor.r;
|
||||
// skybox_rs.clear_color[1] = bgcolor.g;
|
||||
// skybox_rs.clear_color[2] = bgcolor.b;
|
||||
// skybox_rs.clear_color[3] = 1; // @transparent
|
||||
|
||||
mat44 mvp; multiply44x2(mvp, proj, view);
|
||||
|
||||
//glDepthMask(GL_FALSE);
|
||||
shader_bind(sky->rayleigh_program);
|
||||
shader_mat44("u_mvp", mvp);
|
||||
|
||||
renderstate_apply(&skybox_rs);
|
||||
mesh_render(&sky->geometry);
|
||||
}
|
||||
|
||||
void skybox_mie_calc_sh(skybox_t *sky, float sky_intensity) {
|
||||
unsigned WIDTH = 1024, HEIGHT = 1024;
|
||||
int last_fb;
|
||||
int vp[4];
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &last_fb);
|
||||
glGetIntegerv(GL_VIEWPORT, vp);
|
||||
|
||||
if (!sky_intensity) {
|
||||
sky_intensity = 1.0f;
|
||||
cubemap_bake_begin(&sky->cubemap, vec3(0, 0, 0), 1024, 1024);
|
||||
mat44 proj, view;
|
||||
while (cubemap_bake_step(&sky->cubemap, proj, view)) {
|
||||
skybox_render_rayleigh(sky, proj, view);
|
||||
}
|
||||
|
||||
if (!sky->pixels)
|
||||
sky->pixels = MALLOC(WIDTH*HEIGHT*12);
|
||||
|
||||
if (!sky->framebuffers[0]) {
|
||||
for(int i = 0; i < 6; ++i) {
|
||||
glGenFramebuffers(1, &sky->framebuffers[i]);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, sky->framebuffers[i]);
|
||||
|
||||
glGenTextures(1, &sky->textures[i]);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, sky->textures[i]);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, WIDTH, HEIGHT, 0, GL_RGB, GL_FLOAT, NULL);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, sky->textures[i], 0);
|
||||
}
|
||||
}
|
||||
|
||||
static vec3 directions[6] = {{ 1, 0, 0},{-1, 0, 0},{ 0, 1, 0},{ 0,-1, 0},{ 0, 0, 1},{ 0, 0,-1}};
|
||||
|
||||
int samples = 0;
|
||||
for(int i = 0; i < 6; ++i) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, sky->framebuffers[i]);
|
||||
glViewport(0, 0, WIDTH, HEIGHT);
|
||||
glUseProgram(sky->program);
|
||||
|
||||
mat44 proj; perspective44(proj, 90.0f, WIDTH / (float)HEIGHT, 0.1f, 500.f);
|
||||
mat44 view; lookat44(view, vec3(0,0,0), directions[i], vec3(0,-1,0));
|
||||
|
||||
skybox_render(sky, proj, view);
|
||||
|
||||
glReadPixels(0, 0, WIDTH, HEIGHT, GL_RGB, GL_FLOAT, sky->pixels);
|
||||
|
||||
// calculate SH coefficients (@ands)
|
||||
// copied from cubemap6 method
|
||||
const vec3 skyDir[] = {{ 1, 0, 0},{-1, 0, 0},{ 0, 1, 0},{ 0,-1, 0},{ 0, 0, 1},{ 0, 0,-1}};
|
||||
const vec3 skyX[] = {{ 0, 0,-1},{ 0, 0, 1},{ 1, 0, 0},{ 1, 0, 0},{ 1, 0, 0},{-1, 0, 0}};
|
||||
const vec3 skyY[] = {{ 0, 1, 0},{ 0, 1, 0},{ 0, 0,-1},{ 0, 0, 1},{ 0, 1, 0},{ 0, 1, 0}};
|
||||
int step = 16;
|
||||
for (int y = 0; y < HEIGHT; y += step) {
|
||||
float *p = (float*)(sky->pixels + y * WIDTH * 3);
|
||||
for (int x = 0; x < WIDTH; x += step) {
|
||||
vec3 n = add3(
|
||||
add3(
|
||||
scale3(skyX[i], 2.0f * (x / (WIDTH - 1.0f)) - 1.0f),
|
||||
scale3(skyY[i], -2.0f * (y / (HEIGHT - 1.0f)) + 1.0f)),
|
||||
skyDir[i]); // texelDirection;
|
||||
float l = len3(n);
|
||||
vec3 light = scale3(vec3(p[0], p[1], p[2]), (1 / (l * l * l)) * sky_intensity); // texelSolidAngle * texel_radiance;
|
||||
n = norm3(n);
|
||||
sky->cubemap.sh[0] = add3(sky->cubemap.sh[0], scale3(light, 0.282095f));
|
||||
sky->cubemap.sh[1] = add3(sky->cubemap.sh[1], scale3(light, -0.488603f * n.y * 2.0 / 3.0));
|
||||
sky->cubemap.sh[2] = add3(sky->cubemap.sh[2], scale3(light, 0.488603f * n.z * 2.0 / 3.0));
|
||||
sky->cubemap.sh[3] = add3(sky->cubemap.sh[3], scale3(light, -0.488603f * n.x * 2.0 / 3.0));
|
||||
sky->cubemap.sh[4] = add3(sky->cubemap.sh[4], scale3(light, 1.092548f * n.x * n.y / 4.0));
|
||||
sky->cubemap.sh[5] = add3(sky->cubemap.sh[5], scale3(light, -1.092548f * n.y * n.z / 4.0));
|
||||
sky->cubemap.sh[6] = add3(sky->cubemap.sh[6], scale3(light, 0.315392f * (3.0f * n.z * n.z - 1.0f) / 4.0));
|
||||
sky->cubemap.sh[7] = add3(sky->cubemap.sh[7], scale3(light, -1.092548f * n.x * n.z / 4.0));
|
||||
sky->cubemap.sh[8] = add3(sky->cubemap.sh[8], scale3(light, 0.546274f * (n.x * n.x - n.y * n.y) / 4.0));
|
||||
p += 3 * step;
|
||||
samples++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int s = 0; s < 9; s++) {
|
||||
sky->cubemap.sh[s] = scale3(sky->cubemap.sh[s], 32.f / samples);
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, last_fb);
|
||||
glViewport(vp[0], vp[1], vp[2], vp[3]);
|
||||
cubemap_bake_end(&sky->cubemap, sky_intensity);
|
||||
}
|
||||
|
||||
void skybox_sh_reset(skybox_t *sky) {
|
||||
for (int s = 0; s < 9; s++) {
|
||||
sky->cubemap.sh[s] = vec3(0,0,0);
|
||||
}
|
||||
cubemap_sh_reset(&sky->cubemap);
|
||||
}
|
||||
|
||||
void skybox_sh_shader(skybox_t *sky) {
|
||||
shader_vec3v("u_coefficients_sh", 9, sky->cubemap.sh);
|
||||
cubemap_sh_shader(&sky->cubemap);
|
||||
}
|
||||
|
||||
void skybox_sh_add_light(skybox_t *sky, vec3 light, vec3 dir, float strength) {
|
||||
// Normalize the direction
|
||||
vec3 norm_dir = norm3(dir);
|
||||
|
||||
// Scale the light color and intensity
|
||||
vec3 scaled_light = scale3(light, strength);
|
||||
|
||||
// Add light to the SH coefficients
|
||||
sky->cubemap.sh[0] = add3(sky->cubemap.sh[0], scale3(scaled_light, 0.282095f));
|
||||
sky->cubemap.sh[1] = add3(sky->cubemap.sh[1], scale3(scaled_light, -0.488603f * norm_dir.y));
|
||||
sky->cubemap.sh[2] = add3(sky->cubemap.sh[2], scale3(scaled_light, 0.488603f * norm_dir.z));
|
||||
sky->cubemap.sh[3] = add3(sky->cubemap.sh[3], scale3(scaled_light, -0.488603f * norm_dir.x));
|
||||
cubemap_sh_add_light(&sky->cubemap, light, dir, strength);
|
||||
}
|
||||
|
||||
API vec4 window_getcolor_(); // internal use, not public
|
||||
|
||||
static renderstate_t skybox_rs;
|
||||
|
||||
int skybox_push_state(skybox_t *sky, mat44 proj, mat44 view) {
|
||||
last_cubemap = &sky->cubemap;
|
||||
|
||||
|
@ -383848,20 +383967,18 @@ int skybox_push_state(skybox_t *sky, mat44 proj, mat44 view) {
|
|||
}
|
||||
|
||||
// we have to reset clear color here, because of wrong alpha compositing issues on native transparent windows otherwise
|
||||
vec4 bgcolor = window_getcolor_();
|
||||
skybox_rs.clear_color[0] = bgcolor.r;
|
||||
skybox_rs.clear_color[1] = bgcolor.g;
|
||||
skybox_rs.clear_color[2] = bgcolor.b;
|
||||
skybox_rs.clear_color[3] = 1; // @transparent
|
||||
// vec4 bgcolor = window_getcolor_();
|
||||
// skybox_rs.clear_color[0] = bgcolor.r;
|
||||
// skybox_rs.clear_color[1] = bgcolor.g;
|
||||
// skybox_rs.clear_color[2] = bgcolor.b;
|
||||
// skybox_rs.clear_color[3] = 1; // @transparent
|
||||
|
||||
mat44 mvp; multiply44x2(mvp, proj, view);
|
||||
|
||||
//glDepthMask(GL_FALSE);
|
||||
shader_bind(sky->program);
|
||||
shader_mat44("u_mvp", mvp);
|
||||
if( sky->flags ) {
|
||||
shader_cubemap("u_cubemap", sky->cubemap.id);
|
||||
}
|
||||
shader_cubemap("u_cubemap", sky->cubemap.id);
|
||||
|
||||
renderstate_apply(&skybox_rs);
|
||||
return 0; // @fixme: return sortable hash here?
|
||||
|
@ -383873,6 +383990,10 @@ int skybox_pop_state() {
|
|||
return 0;
|
||||
}
|
||||
int skybox_render(skybox_t *sky, mat44 proj, mat44 view) {
|
||||
if (sky->rayleigh_immediate && !sky->flags) {
|
||||
skybox_render_rayleigh(sky, proj, view);
|
||||
return 0;
|
||||
}
|
||||
skybox_push_state(sky, proj, view);
|
||||
mesh_render(&sky->geometry);
|
||||
skybox_pop_state();
|
||||
|
@ -383882,12 +384003,6 @@ void skybox_destroy(skybox_t *sky) {
|
|||
glDeleteProgram(sky->program);
|
||||
cubemap_destroy(&sky->cubemap);
|
||||
mesh_destroy(&sky->geometry);
|
||||
|
||||
if (sky->pixels) {
|
||||
FREE(sky->pixels);
|
||||
glDeleteFramebuffers(6, sky->framebuffers);
|
||||
glDeleteTextures(6, sky->textures);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -1933,6 +1933,13 @@ cubemap_t cubemap( const image_t in, int flags ) {
|
|||
void cubemap_destroy(cubemap_t *c) {
|
||||
glDeleteTextures(1, &c->id);
|
||||
c->id = 0; // do not destroy SH coefficients still. they might be useful in the future.
|
||||
|
||||
if (c->pixels) {
|
||||
FREE(c->pixels);
|
||||
glDeleteFramebuffers(6, c->framebuffers);
|
||||
glDeleteTextures(6, c->textures);
|
||||
glDeleteRenderbuffers(6, c->depth_buffers);
|
||||
}
|
||||
}
|
||||
|
||||
static cubemap_t *last_cubemap;
|
||||
|
@ -1941,6 +1948,166 @@ cubemap_t* cubemap_get_active() {
|
|||
return last_cubemap;
|
||||
}
|
||||
|
||||
// cubemap baker
|
||||
|
||||
static int sky_last_fb;
|
||||
static int sky_last_vp[4];
|
||||
void cubemap_bake_begin(cubemap_t *c, vec3 pos, unsigned width, unsigned height) {
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &sky_last_fb);
|
||||
glGetIntegerv(GL_VIEWPORT, sky_last_vp);
|
||||
c->step = 0;
|
||||
c->pos = pos;
|
||||
|
||||
if (!c->pixels || (c->width != width || c->height != height)) {
|
||||
c->pixels = REALLOC(c->pixels, width*height*12);
|
||||
c->width = width;
|
||||
c->height = height;
|
||||
|
||||
if (!c->framebuffers[0]) {
|
||||
glDeleteFramebuffers(6, c->framebuffers);
|
||||
glDeleteTextures(6, c->textures);
|
||||
glDeleteRenderbuffers(6, c->depth_buffers);
|
||||
for(int i = 0; i < 6; ++i) {
|
||||
c->framebuffers[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!c->framebuffers[0]) {
|
||||
for(int i = 0; i < 6; ++i) {
|
||||
glGenFramebuffers(1, &c->framebuffers[i]);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, c->framebuffers[i]);
|
||||
|
||||
glGenTextures(1, &c->textures[i]);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, c->textures[i]);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_FLOAT, NULL);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, c->textures[i], 0);
|
||||
|
||||
// attach depth buffer
|
||||
glGenRenderbuffers(1, &c->depth_buffers[i]);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, c->depth_buffers[i]);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, c->depth_buffers[i]);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool cubemap_bake_step(cubemap_t *c, mat44 proj /* out */, mat44 view /* out */) {
|
||||
if (c->step >= 6) return false;
|
||||
|
||||
static vec3 directions[6] = {{ 1, 0, 0},{-1, 0, 0},{ 0, 1, 0},{ 0,-1, 0},{ 0, 0, 1},{ 0, 0,-1}};
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, c->framebuffers[c->step]);
|
||||
glViewport(0, 0, c->width, c->height);
|
||||
glClearColor(0, 0, 0, 1);
|
||||
glClearDepth(1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
perspective44(proj, 90.0f, c->width / (float)c->height, 0.1f, 1000.f);
|
||||
lookat44(view, c->pos, add3(c->pos, directions[c->step]), vec3(0,-1,0));
|
||||
++c->step;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void cubemap_bake_end(cubemap_t *c, float sky_intensity) {
|
||||
if (!sky_intensity) {
|
||||
sky_intensity = 1.0f;
|
||||
}
|
||||
|
||||
if (c->id) {
|
||||
glDeleteTextures(1, &c->id);
|
||||
c->id = 0;
|
||||
}
|
||||
|
||||
glGenTextures(1, &c->id);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, c->id);
|
||||
|
||||
int samples = 0;
|
||||
for (int i = 0; i < 6; i++) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, c->framebuffers[i]);
|
||||
glReadPixels(0, 0, c->width, c->height, GL_RGB, GL_FLOAT, c->pixels);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, c->width, c->height, 0, GL_RGB, GL_FLOAT, c->pixels);
|
||||
|
||||
// calculate SH coefficients (@ands)
|
||||
// copied from cubemap6 method
|
||||
const vec3 skyDir[] = {{ 1, 0, 0},{-1, 0, 0},{ 0, 1, 0},{ 0,-1, 0},{ 0, 0, 1},{ 0, 0,-1}};
|
||||
const vec3 skyX[] = {{ 0, 0,-1},{ 0, 0, 1},{ 1, 0, 0},{ 1, 0, 0},{ 1, 0, 0},{-1, 0, 0}};
|
||||
const vec3 skyY[] = {{ 0, 1, 0},{ 0, 1, 0},{ 0, 0,-1},{ 0, 0, 1},{ 0, 1, 0},{ 0, 1, 0}};
|
||||
int step = 16;
|
||||
for (int y = 0; y < c->height; y += step) {
|
||||
float *p = (float*)(c->pixels + y * c->width * 3);
|
||||
for (int x = 0; x < c->width; x += step) {
|
||||
vec3 n = add3(
|
||||
add3(
|
||||
scale3(skyX[i], 2.0f * (x / (c->width - 1.0f)) - 1.0f),
|
||||
scale3(skyY[i], -2.0f * (y / (c->height - 1.0f)) + 1.0f)),
|
||||
skyDir[i]); // texelDirection;
|
||||
float l = len3(n);
|
||||
vec3 light = scale3(vec3(p[0], p[1], p[2]), (1 / (l * l * l)) * sky_intensity); // texelSolidAngle * texel_radiance;
|
||||
n = norm3(n);
|
||||
c->sh[0] = add3(c->sh[0], scale3(light, 0.282095f));
|
||||
c->sh[1] = add3(c->sh[1], scale3(light, -0.488603f * n.y * 2.0 / 3.0));
|
||||
c->sh[2] = add3(c->sh[2], scale3(light, 0.488603f * n.z * 2.0 / 3.0));
|
||||
c->sh[3] = add3(c->sh[3], scale3(light, -0.488603f * n.x * 2.0 / 3.0));
|
||||
c->sh[4] = add3(c->sh[4], scale3(light, 1.092548f * n.x * n.y / 4.0));
|
||||
c->sh[5] = add3(c->sh[5], scale3(light, -1.092548f * n.y * n.z / 4.0));
|
||||
c->sh[6] = add3(c->sh[6], scale3(light, 0.315392f * (3.0f * n.z * n.z - 1.0f) / 4.0));
|
||||
c->sh[7] = add3(c->sh[7], scale3(light, -1.092548f * n.x * n.z / 4.0));
|
||||
c->sh[8] = add3(c->sh[8], scale3(light, 0.546274f * (n.x * n.x - n.y * n.y) / 4.0));
|
||||
p += 3 * step;
|
||||
samples++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int s = 0; s < 9; s++) {
|
||||
c->sh[s] = scale3(c->sh[s], 32.f / samples);
|
||||
}
|
||||
|
||||
glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, sky_last_fb);
|
||||
glViewport(sky_last_vp[0], sky_last_vp[1], sky_last_vp[2], sky_last_vp[3]);
|
||||
}
|
||||
|
||||
void cubemap_sh_reset(cubemap_t *c) {
|
||||
for (int s = 0; s < 9; s++) {
|
||||
c->sh[s] = vec3(0,0,0);
|
||||
}
|
||||
}
|
||||
|
||||
void cubemap_sh_shader(cubemap_t *c) {
|
||||
shader_vec3v("u_coefficients_sh", 9, c->sh);
|
||||
}
|
||||
|
||||
void cubemap_sh_add_light(cubemap_t *c, vec3 light, vec3 dir, float strength) {
|
||||
// Normalize the direction
|
||||
vec3 norm_dir = norm3(dir);
|
||||
|
||||
// Scale the light color and intensity
|
||||
vec3 scaled_light = scale3(light, strength);
|
||||
|
||||
// Add light to the SH coefficients
|
||||
c->sh[0] = add3(c->sh[0], scale3(scaled_light, 0.282095f));
|
||||
c->sh[1] = add3(c->sh[1], scale3(scaled_light, -0.488603f * norm_dir.y));
|
||||
c->sh[2] = add3(c->sh[2], scale3(scaled_light, 0.488603f * norm_dir.z));
|
||||
c->sh[3] = add3(c->sh[3], scale3(scaled_light, -0.488603f * norm_dir.x));
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// skyboxes
|
||||
|
||||
|
@ -1955,7 +2122,10 @@ skybox_t skybox(const char *asset, int flags) {
|
|||
// sky program
|
||||
sky.flags = flags && flags != SKYBOX_PBR ? flags : !!asset ? SKYBOX_CUBEMAP : SKYBOX_RAYLEIGH; // either cubemap or rayleigh
|
||||
sky.program = shader(vfs_read("shaders/vs_3_3_skybox.glsl"),
|
||||
sky.flags ? vfs_read("fs_3_4_skybox.glsl") : vfs_read("shaders/fs_3_4_skybox_rayleigh.glsl"),
|
||||
vfs_read("fs_3_4_skybox.glsl"),
|
||||
"att_position", "fragcolor", NULL);
|
||||
sky.rayleigh_program = shader(vfs_read("shaders/vs_3_3_skybox.glsl"),
|
||||
vfs_read("shaders/fs_3_4_skybox_rayleigh.glsl"),
|
||||
"att_position", "fragcolor", NULL);
|
||||
|
||||
// sky cubemap & SH
|
||||
|
@ -1979,7 +2149,7 @@ skybox_t skybox(const char *asset, int flags) {
|
|||
}
|
||||
} else {
|
||||
// set up mie defaults // @fixme: use shader params instead
|
||||
shader_bind(sky.program);
|
||||
shader_bind(sky.rayleigh_program);
|
||||
shader_vec3("uSunPos", vec3( 0, 0.1, -1 ));
|
||||
shader_vec3("uRayOrigin", vec3(0.0, 6372000.0, 0.0));
|
||||
shader_float("uSunIntensity", 22.0);
|
||||
|
@ -2050,120 +2220,58 @@ skybox_t skybox_pbr(const char *sky_map, const char *refl_map, const char *env_m
|
|||
return sky;
|
||||
}
|
||||
|
||||
static renderstate_t skybox_rs;
|
||||
API vec4 window_getcolor_(); // internal use, not public
|
||||
|
||||
static inline
|
||||
void skybox_render_rayleigh(skybox_t *sky, mat44 proj, mat44 view) {
|
||||
last_cubemap = &sky->cubemap;
|
||||
|
||||
do_once {
|
||||
skybox_rs = renderstate();
|
||||
skybox_rs.depth_test_enabled = 1;
|
||||
skybox_rs.cull_face_enabled = 0;
|
||||
skybox_rs.front_face = GL_CCW;
|
||||
}
|
||||
|
||||
// we have to reset clear color here, because of wrong alpha compositing issues on native transparent windows otherwise
|
||||
// vec4 bgcolor = window_getcolor_();
|
||||
// skybox_rs.clear_color[0] = bgcolor.r;
|
||||
// skybox_rs.clear_color[1] = bgcolor.g;
|
||||
// skybox_rs.clear_color[2] = bgcolor.b;
|
||||
// skybox_rs.clear_color[3] = 1; // @transparent
|
||||
|
||||
mat44 mvp; multiply44x2(mvp, proj, view);
|
||||
|
||||
//glDepthMask(GL_FALSE);
|
||||
shader_bind(sky->rayleigh_program);
|
||||
shader_mat44("u_mvp", mvp);
|
||||
|
||||
renderstate_apply(&skybox_rs);
|
||||
mesh_render(&sky->geometry);
|
||||
}
|
||||
|
||||
void skybox_mie_calc_sh(skybox_t *sky, float sky_intensity) {
|
||||
unsigned WIDTH = 1024, HEIGHT = 1024;
|
||||
int last_fb;
|
||||
int vp[4];
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &last_fb);
|
||||
glGetIntegerv(GL_VIEWPORT, vp);
|
||||
|
||||
if (!sky_intensity) {
|
||||
sky_intensity = 1.0f;
|
||||
cubemap_bake_begin(&sky->cubemap, vec3(0, 0, 0), 1024, 1024);
|
||||
mat44 proj, view;
|
||||
while (cubemap_bake_step(&sky->cubemap, proj, view)) {
|
||||
skybox_render_rayleigh(sky, proj, view);
|
||||
}
|
||||
|
||||
if (!sky->pixels)
|
||||
sky->pixels = MALLOC(WIDTH*HEIGHT*12);
|
||||
|
||||
if (!sky->framebuffers[0]) {
|
||||
for(int i = 0; i < 6; ++i) {
|
||||
glGenFramebuffers(1, &sky->framebuffers[i]);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, sky->framebuffers[i]);
|
||||
|
||||
glGenTextures(1, &sky->textures[i]);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, sky->textures[i]);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, WIDTH, HEIGHT, 0, GL_RGB, GL_FLOAT, NULL);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, sky->textures[i], 0);
|
||||
}
|
||||
}
|
||||
|
||||
static vec3 directions[6] = {{ 1, 0, 0},{-1, 0, 0},{ 0, 1, 0},{ 0,-1, 0},{ 0, 0, 1},{ 0, 0,-1}};
|
||||
|
||||
int samples = 0;
|
||||
for(int i = 0; i < 6; ++i) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, sky->framebuffers[i]);
|
||||
glViewport(0, 0, WIDTH, HEIGHT);
|
||||
glUseProgram(sky->program);
|
||||
|
||||
mat44 proj; perspective44(proj, 90.0f, WIDTH / (float)HEIGHT, 0.1f, 500.f);
|
||||
mat44 view; lookat44(view, vec3(0,0,0), directions[i], vec3(0,-1,0));
|
||||
|
||||
skybox_render(sky, proj, view);
|
||||
|
||||
glReadPixels(0, 0, WIDTH, HEIGHT, GL_RGB, GL_FLOAT, sky->pixels);
|
||||
|
||||
// calculate SH coefficients (@ands)
|
||||
// copied from cubemap6 method
|
||||
const vec3 skyDir[] = {{ 1, 0, 0},{-1, 0, 0},{ 0, 1, 0},{ 0,-1, 0},{ 0, 0, 1},{ 0, 0,-1}};
|
||||
const vec3 skyX[] = {{ 0, 0,-1},{ 0, 0, 1},{ 1, 0, 0},{ 1, 0, 0},{ 1, 0, 0},{-1, 0, 0}};
|
||||
const vec3 skyY[] = {{ 0, 1, 0},{ 0, 1, 0},{ 0, 0,-1},{ 0, 0, 1},{ 0, 1, 0},{ 0, 1, 0}};
|
||||
int step = 16;
|
||||
for (int y = 0; y < HEIGHT; y += step) {
|
||||
float *p = (float*)(sky->pixels + y * WIDTH * 3);
|
||||
for (int x = 0; x < WIDTH; x += step) {
|
||||
vec3 n = add3(
|
||||
add3(
|
||||
scale3(skyX[i], 2.0f * (x / (WIDTH - 1.0f)) - 1.0f),
|
||||
scale3(skyY[i], -2.0f * (y / (HEIGHT - 1.0f)) + 1.0f)),
|
||||
skyDir[i]); // texelDirection;
|
||||
float l = len3(n);
|
||||
vec3 light = scale3(vec3(p[0], p[1], p[2]), (1 / (l * l * l)) * sky_intensity); // texelSolidAngle * texel_radiance;
|
||||
n = norm3(n);
|
||||
sky->cubemap.sh[0] = add3(sky->cubemap.sh[0], scale3(light, 0.282095f));
|
||||
sky->cubemap.sh[1] = add3(sky->cubemap.sh[1], scale3(light, -0.488603f * n.y * 2.0 / 3.0));
|
||||
sky->cubemap.sh[2] = add3(sky->cubemap.sh[2], scale3(light, 0.488603f * n.z * 2.0 / 3.0));
|
||||
sky->cubemap.sh[3] = add3(sky->cubemap.sh[3], scale3(light, -0.488603f * n.x * 2.0 / 3.0));
|
||||
sky->cubemap.sh[4] = add3(sky->cubemap.sh[4], scale3(light, 1.092548f * n.x * n.y / 4.0));
|
||||
sky->cubemap.sh[5] = add3(sky->cubemap.sh[5], scale3(light, -1.092548f * n.y * n.z / 4.0));
|
||||
sky->cubemap.sh[6] = add3(sky->cubemap.sh[6], scale3(light, 0.315392f * (3.0f * n.z * n.z - 1.0f) / 4.0));
|
||||
sky->cubemap.sh[7] = add3(sky->cubemap.sh[7], scale3(light, -1.092548f * n.x * n.z / 4.0));
|
||||
sky->cubemap.sh[8] = add3(sky->cubemap.sh[8], scale3(light, 0.546274f * (n.x * n.x - n.y * n.y) / 4.0));
|
||||
p += 3 * step;
|
||||
samples++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int s = 0; s < 9; s++) {
|
||||
sky->cubemap.sh[s] = scale3(sky->cubemap.sh[s], 32.f / samples);
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, last_fb);
|
||||
glViewport(vp[0], vp[1], vp[2], vp[3]);
|
||||
cubemap_bake_end(&sky->cubemap, sky_intensity);
|
||||
}
|
||||
|
||||
void skybox_sh_reset(skybox_t *sky) {
|
||||
for (int s = 0; s < 9; s++) {
|
||||
sky->cubemap.sh[s] = vec3(0,0,0);
|
||||
}
|
||||
cubemap_sh_reset(&sky->cubemap);
|
||||
}
|
||||
|
||||
void skybox_sh_shader(skybox_t *sky) {
|
||||
shader_vec3v("u_coefficients_sh", 9, sky->cubemap.sh);
|
||||
cubemap_sh_shader(&sky->cubemap);
|
||||
}
|
||||
|
||||
void skybox_sh_add_light(skybox_t *sky, vec3 light, vec3 dir, float strength) {
|
||||
// Normalize the direction
|
||||
vec3 norm_dir = norm3(dir);
|
||||
|
||||
// Scale the light color and intensity
|
||||
vec3 scaled_light = scale3(light, strength);
|
||||
|
||||
// Add light to the SH coefficients
|
||||
sky->cubemap.sh[0] = add3(sky->cubemap.sh[0], scale3(scaled_light, 0.282095f));
|
||||
sky->cubemap.sh[1] = add3(sky->cubemap.sh[1], scale3(scaled_light, -0.488603f * norm_dir.y));
|
||||
sky->cubemap.sh[2] = add3(sky->cubemap.sh[2], scale3(scaled_light, 0.488603f * norm_dir.z));
|
||||
sky->cubemap.sh[3] = add3(sky->cubemap.sh[3], scale3(scaled_light, -0.488603f * norm_dir.x));
|
||||
cubemap_sh_add_light(&sky->cubemap, light, dir, strength);
|
||||
}
|
||||
|
||||
API vec4 window_getcolor_(); // internal use, not public
|
||||
|
||||
static renderstate_t skybox_rs;
|
||||
|
||||
int skybox_push_state(skybox_t *sky, mat44 proj, mat44 view) {
|
||||
last_cubemap = &sky->cubemap;
|
||||
|
||||
|
@ -2175,20 +2283,18 @@ int skybox_push_state(skybox_t *sky, mat44 proj, mat44 view) {
|
|||
}
|
||||
|
||||
// we have to reset clear color here, because of wrong alpha compositing issues on native transparent windows otherwise
|
||||
vec4 bgcolor = window_getcolor_();
|
||||
skybox_rs.clear_color[0] = bgcolor.r;
|
||||
skybox_rs.clear_color[1] = bgcolor.g;
|
||||
skybox_rs.clear_color[2] = bgcolor.b;
|
||||
skybox_rs.clear_color[3] = 1; // @transparent
|
||||
// vec4 bgcolor = window_getcolor_();
|
||||
// skybox_rs.clear_color[0] = bgcolor.r;
|
||||
// skybox_rs.clear_color[1] = bgcolor.g;
|
||||
// skybox_rs.clear_color[2] = bgcolor.b;
|
||||
// skybox_rs.clear_color[3] = 1; // @transparent
|
||||
|
||||
mat44 mvp; multiply44x2(mvp, proj, view);
|
||||
|
||||
//glDepthMask(GL_FALSE);
|
||||
shader_bind(sky->program);
|
||||
shader_mat44("u_mvp", mvp);
|
||||
if( sky->flags ) {
|
||||
shader_cubemap("u_cubemap", sky->cubemap.id);
|
||||
}
|
||||
shader_cubemap("u_cubemap", sky->cubemap.id);
|
||||
|
||||
renderstate_apply(&skybox_rs);
|
||||
return 0; // @fixme: return sortable hash here?
|
||||
|
@ -2200,6 +2306,10 @@ int skybox_pop_state() {
|
|||
return 0;
|
||||
}
|
||||
int skybox_render(skybox_t *sky, mat44 proj, mat44 view) {
|
||||
if (sky->rayleigh_immediate && !sky->flags) {
|
||||
skybox_render_rayleigh(sky, proj, view);
|
||||
return 0;
|
||||
}
|
||||
skybox_push_state(sky, proj, view);
|
||||
mesh_render(&sky->geometry);
|
||||
skybox_pop_state();
|
||||
|
@ -2209,12 +2319,6 @@ void skybox_destroy(skybox_t *sky) {
|
|||
glDeleteProgram(sky->program);
|
||||
cubemap_destroy(&sky->cubemap);
|
||||
mesh_destroy(&sky->geometry);
|
||||
|
||||
if (sky->pixels) {
|
||||
FREE(sky->pixels);
|
||||
glDeleteFramebuffers(6, sky->framebuffers);
|
||||
glDeleteTextures(6, sky->textures);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -241,12 +241,27 @@ API void fullscreen_quad_ycbcr_flipped( texture_t texture_YCbCr[3] );
|
|||
typedef struct cubemap_t {
|
||||
unsigned id; // texture id
|
||||
vec3 sh[9]; // precomputed spherical harmonics coefficients
|
||||
|
||||
// bake data
|
||||
int framebuffers[6];
|
||||
int textures[6];
|
||||
int depth_buffers[6];
|
||||
unsigned width, height;
|
||||
float *pixels;
|
||||
int step;
|
||||
vec3 pos;
|
||||
} cubemap_t;
|
||||
|
||||
API cubemap_t cubemap( const image_t image, int flags ); // 1 equirectangular panorama
|
||||
API cubemap_t cubemap6( const image_t images[6], int flags ); // 6 cubemap faces
|
||||
API void cubemap_destroy(cubemap_t *c);
|
||||
API cubemap_t* cubemap_get_active();
|
||||
API void cubemap_bake_begin(cubemap_t *c, vec3 pos, unsigned width, unsigned height);
|
||||
API bool cubemap_bake_step(cubemap_t *c, mat44 proj /* out */, mat44 view /* out */);
|
||||
API void cubemap_bake_end(cubemap_t *c, float sky_intensity);
|
||||
API void cubemap_sh_reset(cubemap_t *c);
|
||||
API void cubemap_sh_shader(cubemap_t *c);
|
||||
API void cubemap_sh_add_light(cubemap_t *c, vec3 light, vec3 dir, float strength);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// fbos
|
||||
|
@ -485,15 +500,11 @@ enum SKYBOX_FLAGS {
|
|||
};
|
||||
|
||||
typedef struct skybox_t {
|
||||
handle program;
|
||||
handle program, rayleigh_program;
|
||||
mesh_t geometry;
|
||||
cubemap_t cubemap;
|
||||
int flags;
|
||||
|
||||
// mie
|
||||
int framebuffers[6];
|
||||
int textures[6];
|
||||
float *pixels;
|
||||
bool rayleigh_immediate;
|
||||
|
||||
// pbr
|
||||
texture_t sky, refl, env;
|
||||
|
@ -504,9 +515,9 @@ API skybox_t skybox_pbr(const char *sky_map, const char *refl_map, const char *e
|
|||
API int skybox_render(skybox_t *sky, mat44 proj, mat44 view);
|
||||
API void skybox_destroy(skybox_t *sky);
|
||||
API void skybox_mie_calc_sh(skybox_t *sky, float sky_intensity);
|
||||
API void skybox_sh_reset(skybox_t *sky);
|
||||
API void skybox_sh_shader(skybox_t *sky);
|
||||
API void skybox_sh_add_light(skybox_t *sky, vec3 light, vec3 dir, float strength);
|
||||
API void skybox_sh_reset(skybox_t *sky); /* @deprecated */
|
||||
API void skybox_sh_shader(skybox_t *sky); /* @deprecated */
|
||||
API void skybox_sh_add_light(skybox_t *sky, vec3 light, vec3 dir, float strength); /* @deprecated */
|
||||
|
||||
API int skybox_push_state(skybox_t *sky, mat44 proj, mat44 view); // @to deprecate
|
||||
API int skybox_pop_state(); // @to deprecate
|
||||
|
|
338
engine/v4k.c
338
engine/v4k.c
|
@ -18732,6 +18732,13 @@ cubemap_t cubemap( const image_t in, int flags ) {
|
|||
void cubemap_destroy(cubemap_t *c) {
|
||||
glDeleteTextures(1, &c->id);
|
||||
c->id = 0; // do not destroy SH coefficients still. they might be useful in the future.
|
||||
|
||||
if (c->pixels) {
|
||||
FREE(c->pixels);
|
||||
glDeleteFramebuffers(6, c->framebuffers);
|
||||
glDeleteTextures(6, c->textures);
|
||||
glDeleteRenderbuffers(6, c->depth_buffers);
|
||||
}
|
||||
}
|
||||
|
||||
static cubemap_t *last_cubemap;
|
||||
|
@ -18740,6 +18747,166 @@ cubemap_t* cubemap_get_active() {
|
|||
return last_cubemap;
|
||||
}
|
||||
|
||||
// cubemap baker
|
||||
|
||||
static int sky_last_fb;
|
||||
static int sky_last_vp[4];
|
||||
void cubemap_bake_begin(cubemap_t *c, vec3 pos, unsigned width, unsigned height) {
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &sky_last_fb);
|
||||
glGetIntegerv(GL_VIEWPORT, sky_last_vp);
|
||||
c->step = 0;
|
||||
c->pos = pos;
|
||||
|
||||
if (!c->pixels || (c->width != width || c->height != height)) {
|
||||
c->pixels = REALLOC(c->pixels, width*height*12);
|
||||
c->width = width;
|
||||
c->height = height;
|
||||
|
||||
if (!c->framebuffers[0]) {
|
||||
glDeleteFramebuffers(6, c->framebuffers);
|
||||
glDeleteTextures(6, c->textures);
|
||||
glDeleteRenderbuffers(6, c->depth_buffers);
|
||||
for(int i = 0; i < 6; ++i) {
|
||||
c->framebuffers[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!c->framebuffers[0]) {
|
||||
for(int i = 0; i < 6; ++i) {
|
||||
glGenFramebuffers(1, &c->framebuffers[i]);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, c->framebuffers[i]);
|
||||
|
||||
glGenTextures(1, &c->textures[i]);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, c->textures[i]);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_FLOAT, NULL);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, c->textures[i], 0);
|
||||
|
||||
// attach depth buffer
|
||||
glGenRenderbuffers(1, &c->depth_buffers[i]);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, c->depth_buffers[i]);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, c->depth_buffers[i]);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool cubemap_bake_step(cubemap_t *c, mat44 proj /* out */, mat44 view /* out */) {
|
||||
if (c->step >= 6) return false;
|
||||
|
||||
static vec3 directions[6] = {{ 1, 0, 0},{-1, 0, 0},{ 0, 1, 0},{ 0,-1, 0},{ 0, 0, 1},{ 0, 0,-1}};
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, c->framebuffers[c->step]);
|
||||
glViewport(0, 0, c->width, c->height);
|
||||
glClearColor(0, 0, 0, 1);
|
||||
glClearDepth(1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
perspective44(proj, 90.0f, c->width / (float)c->height, 0.1f, 1000.f);
|
||||
lookat44(view, c->pos, add3(c->pos, directions[c->step]), vec3(0,-1,0));
|
||||
++c->step;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void cubemap_bake_end(cubemap_t *c, float sky_intensity) {
|
||||
if (!sky_intensity) {
|
||||
sky_intensity = 1.0f;
|
||||
}
|
||||
|
||||
if (c->id) {
|
||||
glDeleteTextures(1, &c->id);
|
||||
c->id = 0;
|
||||
}
|
||||
|
||||
glGenTextures(1, &c->id);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, c->id);
|
||||
|
||||
int samples = 0;
|
||||
for (int i = 0; i < 6; i++) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, c->framebuffers[i]);
|
||||
glReadPixels(0, 0, c->width, c->height, GL_RGB, GL_FLOAT, c->pixels);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, c->width, c->height, 0, GL_RGB, GL_FLOAT, c->pixels);
|
||||
|
||||
// calculate SH coefficients (@ands)
|
||||
// copied from cubemap6 method
|
||||
const vec3 skyDir[] = {{ 1, 0, 0},{-1, 0, 0},{ 0, 1, 0},{ 0,-1, 0},{ 0, 0, 1},{ 0, 0,-1}};
|
||||
const vec3 skyX[] = {{ 0, 0,-1},{ 0, 0, 1},{ 1, 0, 0},{ 1, 0, 0},{ 1, 0, 0},{-1, 0, 0}};
|
||||
const vec3 skyY[] = {{ 0, 1, 0},{ 0, 1, 0},{ 0, 0,-1},{ 0, 0, 1},{ 0, 1, 0},{ 0, 1, 0}};
|
||||
int step = 16;
|
||||
for (int y = 0; y < c->height; y += step) {
|
||||
float *p = (float*)(c->pixels + y * c->width * 3);
|
||||
for (int x = 0; x < c->width; x += step) {
|
||||
vec3 n = add3(
|
||||
add3(
|
||||
scale3(skyX[i], 2.0f * (x / (c->width - 1.0f)) - 1.0f),
|
||||
scale3(skyY[i], -2.0f * (y / (c->height - 1.0f)) + 1.0f)),
|
||||
skyDir[i]); // texelDirection;
|
||||
float l = len3(n);
|
||||
vec3 light = scale3(vec3(p[0], p[1], p[2]), (1 / (l * l * l)) * sky_intensity); // texelSolidAngle * texel_radiance;
|
||||
n = norm3(n);
|
||||
c->sh[0] = add3(c->sh[0], scale3(light, 0.282095f));
|
||||
c->sh[1] = add3(c->sh[1], scale3(light, -0.488603f * n.y * 2.0 / 3.0));
|
||||
c->sh[2] = add3(c->sh[2], scale3(light, 0.488603f * n.z * 2.0 / 3.0));
|
||||
c->sh[3] = add3(c->sh[3], scale3(light, -0.488603f * n.x * 2.0 / 3.0));
|
||||
c->sh[4] = add3(c->sh[4], scale3(light, 1.092548f * n.x * n.y / 4.0));
|
||||
c->sh[5] = add3(c->sh[5], scale3(light, -1.092548f * n.y * n.z / 4.0));
|
||||
c->sh[6] = add3(c->sh[6], scale3(light, 0.315392f * (3.0f * n.z * n.z - 1.0f) / 4.0));
|
||||
c->sh[7] = add3(c->sh[7], scale3(light, -1.092548f * n.x * n.z / 4.0));
|
||||
c->sh[8] = add3(c->sh[8], scale3(light, 0.546274f * (n.x * n.x - n.y * n.y) / 4.0));
|
||||
p += 3 * step;
|
||||
samples++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int s = 0; s < 9; s++) {
|
||||
c->sh[s] = scale3(c->sh[s], 32.f / samples);
|
||||
}
|
||||
|
||||
glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, sky_last_fb);
|
||||
glViewport(sky_last_vp[0], sky_last_vp[1], sky_last_vp[2], sky_last_vp[3]);
|
||||
}
|
||||
|
||||
void cubemap_sh_reset(cubemap_t *c) {
|
||||
for (int s = 0; s < 9; s++) {
|
||||
c->sh[s] = vec3(0,0,0);
|
||||
}
|
||||
}
|
||||
|
||||
void cubemap_sh_shader(cubemap_t *c) {
|
||||
shader_vec3v("u_coefficients_sh", 9, c->sh);
|
||||
}
|
||||
|
||||
void cubemap_sh_add_light(cubemap_t *c, vec3 light, vec3 dir, float strength) {
|
||||
// Normalize the direction
|
||||
vec3 norm_dir = norm3(dir);
|
||||
|
||||
// Scale the light color and intensity
|
||||
vec3 scaled_light = scale3(light, strength);
|
||||
|
||||
// Add light to the SH coefficients
|
||||
c->sh[0] = add3(c->sh[0], scale3(scaled_light, 0.282095f));
|
||||
c->sh[1] = add3(c->sh[1], scale3(scaled_light, -0.488603f * norm_dir.y));
|
||||
c->sh[2] = add3(c->sh[2], scale3(scaled_light, 0.488603f * norm_dir.z));
|
||||
c->sh[3] = add3(c->sh[3], scale3(scaled_light, -0.488603f * norm_dir.x));
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// skyboxes
|
||||
|
||||
|
@ -18754,7 +18921,10 @@ skybox_t skybox(const char *asset, int flags) {
|
|||
// sky program
|
||||
sky.flags = flags && flags != SKYBOX_PBR ? flags : !!asset ? SKYBOX_CUBEMAP : SKYBOX_RAYLEIGH; // either cubemap or rayleigh
|
||||
sky.program = shader(vfs_read("shaders/vs_3_3_skybox.glsl"),
|
||||
sky.flags ? vfs_read("fs_3_4_skybox.glsl") : vfs_read("shaders/fs_3_4_skybox_rayleigh.glsl"),
|
||||
vfs_read("fs_3_4_skybox.glsl"),
|
||||
"att_position", "fragcolor", NULL);
|
||||
sky.rayleigh_program = shader(vfs_read("shaders/vs_3_3_skybox.glsl"),
|
||||
vfs_read("shaders/fs_3_4_skybox_rayleigh.glsl"),
|
||||
"att_position", "fragcolor", NULL);
|
||||
|
||||
// sky cubemap & SH
|
||||
|
@ -18778,7 +18948,7 @@ skybox_t skybox(const char *asset, int flags) {
|
|||
}
|
||||
} else {
|
||||
// set up mie defaults // @fixme: use shader params instead
|
||||
shader_bind(sky.program);
|
||||
shader_bind(sky.rayleigh_program);
|
||||
shader_vec3("uSunPos", vec3( 0, 0.1, -1 ));
|
||||
shader_vec3("uRayOrigin", vec3(0.0, 6372000.0, 0.0));
|
||||
shader_float("uSunIntensity", 22.0);
|
||||
|
@ -18849,120 +19019,58 @@ skybox_t skybox_pbr(const char *sky_map, const char *refl_map, const char *env_m
|
|||
return sky;
|
||||
}
|
||||
|
||||
static renderstate_t skybox_rs;
|
||||
API vec4 window_getcolor_(); // internal use, not public
|
||||
|
||||
static inline
|
||||
void skybox_render_rayleigh(skybox_t *sky, mat44 proj, mat44 view) {
|
||||
last_cubemap = &sky->cubemap;
|
||||
|
||||
do_once {
|
||||
skybox_rs = renderstate();
|
||||
skybox_rs.depth_test_enabled = 1;
|
||||
skybox_rs.cull_face_enabled = 0;
|
||||
skybox_rs.front_face = GL_CCW;
|
||||
}
|
||||
|
||||
// we have to reset clear color here, because of wrong alpha compositing issues on native transparent windows otherwise
|
||||
// vec4 bgcolor = window_getcolor_();
|
||||
// skybox_rs.clear_color[0] = bgcolor.r;
|
||||
// skybox_rs.clear_color[1] = bgcolor.g;
|
||||
// skybox_rs.clear_color[2] = bgcolor.b;
|
||||
// skybox_rs.clear_color[3] = 1; // @transparent
|
||||
|
||||
mat44 mvp; multiply44x2(mvp, proj, view);
|
||||
|
||||
//glDepthMask(GL_FALSE);
|
||||
shader_bind(sky->rayleigh_program);
|
||||
shader_mat44("u_mvp", mvp);
|
||||
|
||||
renderstate_apply(&skybox_rs);
|
||||
mesh_render(&sky->geometry);
|
||||
}
|
||||
|
||||
void skybox_mie_calc_sh(skybox_t *sky, float sky_intensity) {
|
||||
unsigned WIDTH = 1024, HEIGHT = 1024;
|
||||
int last_fb;
|
||||
int vp[4];
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &last_fb);
|
||||
glGetIntegerv(GL_VIEWPORT, vp);
|
||||
|
||||
if (!sky_intensity) {
|
||||
sky_intensity = 1.0f;
|
||||
cubemap_bake_begin(&sky->cubemap, vec3(0, 0, 0), 1024, 1024);
|
||||
mat44 proj, view;
|
||||
while (cubemap_bake_step(&sky->cubemap, proj, view)) {
|
||||
skybox_render_rayleigh(sky, proj, view);
|
||||
}
|
||||
|
||||
if (!sky->pixels)
|
||||
sky->pixels = MALLOC(WIDTH*HEIGHT*12);
|
||||
|
||||
if (!sky->framebuffers[0]) {
|
||||
for(int i = 0; i < 6; ++i) {
|
||||
glGenFramebuffers(1, &sky->framebuffers[i]);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, sky->framebuffers[i]);
|
||||
|
||||
glGenTextures(1, &sky->textures[i]);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, sky->textures[i]);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, WIDTH, HEIGHT, 0, GL_RGB, GL_FLOAT, NULL);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, sky->textures[i], 0);
|
||||
}
|
||||
}
|
||||
|
||||
static vec3 directions[6] = {{ 1, 0, 0},{-1, 0, 0},{ 0, 1, 0},{ 0,-1, 0},{ 0, 0, 1},{ 0, 0,-1}};
|
||||
|
||||
int samples = 0;
|
||||
for(int i = 0; i < 6; ++i) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, sky->framebuffers[i]);
|
||||
glViewport(0, 0, WIDTH, HEIGHT);
|
||||
glUseProgram(sky->program);
|
||||
|
||||
mat44 proj; perspective44(proj, 90.0f, WIDTH / (float)HEIGHT, 0.1f, 500.f);
|
||||
mat44 view; lookat44(view, vec3(0,0,0), directions[i], vec3(0,-1,0));
|
||||
|
||||
skybox_render(sky, proj, view);
|
||||
|
||||
glReadPixels(0, 0, WIDTH, HEIGHT, GL_RGB, GL_FLOAT, sky->pixels);
|
||||
|
||||
// calculate SH coefficients (@ands)
|
||||
// copied from cubemap6 method
|
||||
const vec3 skyDir[] = {{ 1, 0, 0},{-1, 0, 0},{ 0, 1, 0},{ 0,-1, 0},{ 0, 0, 1},{ 0, 0,-1}};
|
||||
const vec3 skyX[] = {{ 0, 0,-1},{ 0, 0, 1},{ 1, 0, 0},{ 1, 0, 0},{ 1, 0, 0},{-1, 0, 0}};
|
||||
const vec3 skyY[] = {{ 0, 1, 0},{ 0, 1, 0},{ 0, 0,-1},{ 0, 0, 1},{ 0, 1, 0},{ 0, 1, 0}};
|
||||
int step = 16;
|
||||
for (int y = 0; y < HEIGHT; y += step) {
|
||||
float *p = (float*)(sky->pixels + y * WIDTH * 3);
|
||||
for (int x = 0; x < WIDTH; x += step) {
|
||||
vec3 n = add3(
|
||||
add3(
|
||||
scale3(skyX[i], 2.0f * (x / (WIDTH - 1.0f)) - 1.0f),
|
||||
scale3(skyY[i], -2.0f * (y / (HEIGHT - 1.0f)) + 1.0f)),
|
||||
skyDir[i]); // texelDirection;
|
||||
float l = len3(n);
|
||||
vec3 light = scale3(vec3(p[0], p[1], p[2]), (1 / (l * l * l)) * sky_intensity); // texelSolidAngle * texel_radiance;
|
||||
n = norm3(n);
|
||||
sky->cubemap.sh[0] = add3(sky->cubemap.sh[0], scale3(light, 0.282095f));
|
||||
sky->cubemap.sh[1] = add3(sky->cubemap.sh[1], scale3(light, -0.488603f * n.y * 2.0 / 3.0));
|
||||
sky->cubemap.sh[2] = add3(sky->cubemap.sh[2], scale3(light, 0.488603f * n.z * 2.0 / 3.0));
|
||||
sky->cubemap.sh[3] = add3(sky->cubemap.sh[3], scale3(light, -0.488603f * n.x * 2.0 / 3.0));
|
||||
sky->cubemap.sh[4] = add3(sky->cubemap.sh[4], scale3(light, 1.092548f * n.x * n.y / 4.0));
|
||||
sky->cubemap.sh[5] = add3(sky->cubemap.sh[5], scale3(light, -1.092548f * n.y * n.z / 4.0));
|
||||
sky->cubemap.sh[6] = add3(sky->cubemap.sh[6], scale3(light, 0.315392f * (3.0f * n.z * n.z - 1.0f) / 4.0));
|
||||
sky->cubemap.sh[7] = add3(sky->cubemap.sh[7], scale3(light, -1.092548f * n.x * n.z / 4.0));
|
||||
sky->cubemap.sh[8] = add3(sky->cubemap.sh[8], scale3(light, 0.546274f * (n.x * n.x - n.y * n.y) / 4.0));
|
||||
p += 3 * step;
|
||||
samples++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int s = 0; s < 9; s++) {
|
||||
sky->cubemap.sh[s] = scale3(sky->cubemap.sh[s], 32.f / samples);
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, last_fb);
|
||||
glViewport(vp[0], vp[1], vp[2], vp[3]);
|
||||
cubemap_bake_end(&sky->cubemap, sky_intensity);
|
||||
}
|
||||
|
||||
void skybox_sh_reset(skybox_t *sky) {
|
||||
for (int s = 0; s < 9; s++) {
|
||||
sky->cubemap.sh[s] = vec3(0,0,0);
|
||||
}
|
||||
cubemap_sh_reset(&sky->cubemap);
|
||||
}
|
||||
|
||||
void skybox_sh_shader(skybox_t *sky) {
|
||||
shader_vec3v("u_coefficients_sh", 9, sky->cubemap.sh);
|
||||
cubemap_sh_shader(&sky->cubemap);
|
||||
}
|
||||
|
||||
void skybox_sh_add_light(skybox_t *sky, vec3 light, vec3 dir, float strength) {
|
||||
// Normalize the direction
|
||||
vec3 norm_dir = norm3(dir);
|
||||
|
||||
// Scale the light color and intensity
|
||||
vec3 scaled_light = scale3(light, strength);
|
||||
|
||||
// Add light to the SH coefficients
|
||||
sky->cubemap.sh[0] = add3(sky->cubemap.sh[0], scale3(scaled_light, 0.282095f));
|
||||
sky->cubemap.sh[1] = add3(sky->cubemap.sh[1], scale3(scaled_light, -0.488603f * norm_dir.y));
|
||||
sky->cubemap.sh[2] = add3(sky->cubemap.sh[2], scale3(scaled_light, 0.488603f * norm_dir.z));
|
||||
sky->cubemap.sh[3] = add3(sky->cubemap.sh[3], scale3(scaled_light, -0.488603f * norm_dir.x));
|
||||
cubemap_sh_add_light(&sky->cubemap, light, dir, strength);
|
||||
}
|
||||
|
||||
API vec4 window_getcolor_(); // internal use, not public
|
||||
|
||||
static renderstate_t skybox_rs;
|
||||
|
||||
int skybox_push_state(skybox_t *sky, mat44 proj, mat44 view) {
|
||||
last_cubemap = &sky->cubemap;
|
||||
|
||||
|
@ -18974,20 +19082,18 @@ int skybox_push_state(skybox_t *sky, mat44 proj, mat44 view) {
|
|||
}
|
||||
|
||||
// we have to reset clear color here, because of wrong alpha compositing issues on native transparent windows otherwise
|
||||
vec4 bgcolor = window_getcolor_();
|
||||
skybox_rs.clear_color[0] = bgcolor.r;
|
||||
skybox_rs.clear_color[1] = bgcolor.g;
|
||||
skybox_rs.clear_color[2] = bgcolor.b;
|
||||
skybox_rs.clear_color[3] = 1; // @transparent
|
||||
// vec4 bgcolor = window_getcolor_();
|
||||
// skybox_rs.clear_color[0] = bgcolor.r;
|
||||
// skybox_rs.clear_color[1] = bgcolor.g;
|
||||
// skybox_rs.clear_color[2] = bgcolor.b;
|
||||
// skybox_rs.clear_color[3] = 1; // @transparent
|
||||
|
||||
mat44 mvp; multiply44x2(mvp, proj, view);
|
||||
|
||||
//glDepthMask(GL_FALSE);
|
||||
shader_bind(sky->program);
|
||||
shader_mat44("u_mvp", mvp);
|
||||
if( sky->flags ) {
|
||||
shader_cubemap("u_cubemap", sky->cubemap.id);
|
||||
}
|
||||
shader_cubemap("u_cubemap", sky->cubemap.id);
|
||||
|
||||
renderstate_apply(&skybox_rs);
|
||||
return 0; // @fixme: return sortable hash here?
|
||||
|
@ -18999,6 +19105,10 @@ int skybox_pop_state() {
|
|||
return 0;
|
||||
}
|
||||
int skybox_render(skybox_t *sky, mat44 proj, mat44 view) {
|
||||
if (sky->rayleigh_immediate && !sky->flags) {
|
||||
skybox_render_rayleigh(sky, proj, view);
|
||||
return 0;
|
||||
}
|
||||
skybox_push_state(sky, proj, view);
|
||||
mesh_render(&sky->geometry);
|
||||
skybox_pop_state();
|
||||
|
@ -19008,12 +19118,6 @@ void skybox_destroy(skybox_t *sky) {
|
|||
glDeleteProgram(sky->program);
|
||||
cubemap_destroy(&sky->cubemap);
|
||||
mesh_destroy(&sky->geometry);
|
||||
|
||||
if (sky->pixels) {
|
||||
FREE(sky->pixels);
|
||||
glDeleteFramebuffers(6, sky->framebuffers);
|
||||
glDeleteTextures(6, sky->textures);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
29
engine/v4k.h
29
engine/v4k.h
|
@ -3276,12 +3276,27 @@ API void fullscreen_quad_ycbcr_flipped( texture_t texture_YCbCr[3] );
|
|||
typedef struct cubemap_t {
|
||||
unsigned id; // texture id
|
||||
vec3 sh[9]; // precomputed spherical harmonics coefficients
|
||||
|
||||
// bake data
|
||||
int framebuffers[6];
|
||||
int textures[6];
|
||||
int depth_buffers[6];
|
||||
unsigned width, height;
|
||||
float *pixels;
|
||||
int step;
|
||||
vec3 pos;
|
||||
} cubemap_t;
|
||||
|
||||
API cubemap_t cubemap( const image_t image, int flags ); // 1 equirectangular panorama
|
||||
API cubemap_t cubemap6( const image_t images[6], int flags ); // 6 cubemap faces
|
||||
API void cubemap_destroy(cubemap_t *c);
|
||||
API cubemap_t* cubemap_get_active();
|
||||
API void cubemap_bake_begin(cubemap_t *c, vec3 pos, unsigned width, unsigned height);
|
||||
API bool cubemap_bake_step(cubemap_t *c, mat44 proj /* out */, mat44 view /* out */);
|
||||
API void cubemap_bake_end(cubemap_t *c, float sky_intensity);
|
||||
API void cubemap_sh_reset(cubemap_t *c);
|
||||
API void cubemap_sh_shader(cubemap_t *c);
|
||||
API void cubemap_sh_add_light(cubemap_t *c, vec3 light, vec3 dir, float strength);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// fbos
|
||||
|
@ -3520,15 +3535,11 @@ enum SKYBOX_FLAGS {
|
|||
};
|
||||
|
||||
typedef struct skybox_t {
|
||||
handle program;
|
||||
handle program, rayleigh_program;
|
||||
mesh_t geometry;
|
||||
cubemap_t cubemap;
|
||||
int flags;
|
||||
|
||||
// mie
|
||||
int framebuffers[6];
|
||||
int textures[6];
|
||||
float *pixels;
|
||||
bool rayleigh_immediate;
|
||||
|
||||
// pbr
|
||||
texture_t sky, refl, env;
|
||||
|
@ -3539,9 +3550,9 @@ API skybox_t skybox_pbr(const char *sky_map, const char *refl_map, const char *e
|
|||
API int skybox_render(skybox_t *sky, mat44 proj, mat44 view);
|
||||
API void skybox_destroy(skybox_t *sky);
|
||||
API void skybox_mie_calc_sh(skybox_t *sky, float sky_intensity);
|
||||
API void skybox_sh_reset(skybox_t *sky);
|
||||
API void skybox_sh_shader(skybox_t *sky);
|
||||
API void skybox_sh_add_light(skybox_t *sky, vec3 light, vec3 dir, float strength);
|
||||
API void skybox_sh_reset(skybox_t *sky); /* @deprecated */
|
||||
API void skybox_sh_shader(skybox_t *sky); /* @deprecated */
|
||||
API void skybox_sh_add_light(skybox_t *sky, vec3 light, vec3 dir, float strength); /* @deprecated */
|
||||
|
||||
API int skybox_push_state(skybox_t *sky, mat44 proj, mat44 view); // @to deprecate
|
||||
API int skybox_pop_state(); // @to deprecate
|
||||
|
|
Loading…
Reference in New Issue