wip: pbr support
parent
c724645949
commit
920d8ecad4
|
@ -1,24 +1,25 @@
|
||||||
.art*.zip
|
default
|
||||||
__pycache__
|
.art*.zip
|
||||||
.vs
|
__pycache__
|
||||||
_deploy
|
.vs
|
||||||
tools/steamcmd
|
_deploy
|
||||||
!tools/steamcmd/steamcmd.exe
|
tools/steamcmd
|
||||||
_builder_output
|
!tools/steamcmd/steamcmd.exe
|
||||||
emsdk
|
_builder_output
|
||||||
demos/html5/*.data
|
emsdk
|
||||||
demos/html5/*.js
|
demos/html5/*.data
|
||||||
demos/html5/*.html
|
demos/html5/*.js
|
||||||
demos/ports/*/*.exe
|
demos/html5/*.html
|
||||||
demos/ports/doom/.doomrc
|
demos/ports/*/*.exe
|
||||||
*.sublime-workspace
|
demos/ports/doom/.doomrc
|
||||||
engine/v4k.html
|
*.sublime-workspace
|
||||||
*.exe.manifest
|
engine/v4k.html
|
||||||
*.log
|
*.exe.manifest
|
||||||
v4k.osx
|
*.log
|
||||||
libv4k.*
|
v4k.osx
|
||||||
*.dSYM
|
libv4k.*
|
||||||
.DS_store
|
*.dSYM
|
||||||
*.raddbg
|
.DS_store
|
||||||
plugins
|
*.raddbg
|
||||||
tools/assimp-vc*-mt.lib
|
plugins
|
||||||
|
tools/assimp-vc*-mt.lib
|
||||||
|
|
53
bind/v4k.lua
53
bind/v4k.lua
|
@ -1250,6 +1250,31 @@ typedef struct mesh_t {
|
||||||
void mesh_render_prim(mesh_t *sm, unsigned prim);
|
void mesh_render_prim(mesh_t *sm, unsigned prim);
|
||||||
void mesh_destroy(mesh_t *m);
|
void mesh_destroy(mesh_t *m);
|
||||||
aabb mesh_bounds(mesh_t *m);
|
aabb mesh_bounds(mesh_t *m);
|
||||||
|
enum SKYBOX_FLAGS {
|
||||||
|
SKYBOX_RAYLEIGH,
|
||||||
|
SKYBOX_CUBEMAP,
|
||||||
|
SKYBOX_PBR,
|
||||||
|
};
|
||||||
|
typedef struct skybox_t {
|
||||||
|
handle program;
|
||||||
|
mesh_t geometry;
|
||||||
|
cubemap_t cubemap;
|
||||||
|
cubemap_t env_cubemap;
|
||||||
|
int flags;
|
||||||
|
int framebuffers[6];
|
||||||
|
int textures[6];
|
||||||
|
float *pixels;
|
||||||
|
texture_t refl, env;
|
||||||
|
} skybox_t;
|
||||||
|
skybox_t skybox(const char *panorama_or_cubemap_folder, int flags);
|
||||||
|
skybox_t skybox_pbr(const char *refl_map, const char *env_map);
|
||||||
|
int skybox_render(skybox_t *sky, mat44 proj, mat44 view);
|
||||||
|
void skybox_destroy(skybox_t *sky);
|
||||||
|
void skybox_mie_calc_sh(skybox_t *sky, float sky_intensity);
|
||||||
|
void skybox_sh_reset(skybox_t *sky);
|
||||||
|
void skybox_sh_add_light(skybox_t *sky, vec3 light, vec3 dir, float strength);
|
||||||
|
int skybox_push_state(skybox_t *sky, mat44 proj, mat44 view);
|
||||||
|
int skybox_pop_state();
|
||||||
enum MATERIAL_ENUMS {
|
enum MATERIAL_ENUMS {
|
||||||
MAX_CHANNELS_PER_MATERIAL = 8
|
MAX_CHANNELS_PER_MATERIAL = 8
|
||||||
};
|
};
|
||||||
|
@ -1309,12 +1334,20 @@ enum MODEL_FLAGS {
|
||||||
MODEL_MATCAPS = 16,
|
MODEL_MATCAPS = 16,
|
||||||
MODEL_RIMLIGHT = 32,
|
MODEL_RIMLIGHT = 32,
|
||||||
};
|
};
|
||||||
|
enum SHADING_MODE {
|
||||||
|
SHADING_NONE,
|
||||||
|
SHADING_PHONG,
|
||||||
|
SHADING_PBR,
|
||||||
|
};
|
||||||
typedef struct model_t {
|
typedef struct model_t {
|
||||||
struct iqm_t *iqm;
|
struct iqm_t *iqm;
|
||||||
|
int shading;
|
||||||
unsigned num_textures;
|
unsigned num_textures;
|
||||||
handle *textures;
|
handle *textures;
|
||||||
char **texture_names;
|
char **texture_names;
|
||||||
material_t* materials;
|
material_t* materials;
|
||||||
|
pbr_material_t pbr_material;
|
||||||
|
texture_t sky_refl, sky_env;
|
||||||
texture_t lightmap;
|
texture_t lightmap;
|
||||||
float *lmdata;
|
float *lmdata;
|
||||||
unsigned num_meshes;
|
unsigned num_meshes;
|
||||||
|
@ -1335,6 +1368,7 @@ typedef struct model_t {
|
||||||
unsigned billboard;
|
unsigned billboard;
|
||||||
float *instanced_matrices;
|
float *instanced_matrices;
|
||||||
unsigned num_instances;
|
unsigned num_instances;
|
||||||
|
int stored_flags;
|
||||||
} model_t;
|
} model_t;
|
||||||
enum BILLBOARD_MODE {
|
enum BILLBOARD_MODE {
|
||||||
BILLBOARD_X = 0x1,
|
BILLBOARD_X = 0x1,
|
||||||
|
@ -1349,6 +1383,8 @@ enum BILLBOARD_MODE {
|
||||||
float model_animate_clip(model_t, float curframe, int minframe, int maxframe, bool loop);
|
float model_animate_clip(model_t, float curframe, int minframe, int maxframe, bool loop);
|
||||||
float model_animate_blends(model_t m, anim_t *primary, anim_t *secondary, float delta);
|
float model_animate_blends(model_t m, anim_t *primary, anim_t *secondary, float delta);
|
||||||
aabb model_aabb(model_t, mat44 transform);
|
aabb model_aabb(model_t, mat44 transform);
|
||||||
|
void model_shading(model_t*, int shading);
|
||||||
|
void model_skybox(model_t*, skybox_t sky, bool load_sh);
|
||||||
void model_render(model_t, mat44 proj, mat44 view, mat44 model, int shader);
|
void model_render(model_t, mat44 proj, mat44 view, mat44 model, int shader);
|
||||||
void model_render_skeleton(model_t, mat44 model);
|
void model_render_skeleton(model_t, mat44 model);
|
||||||
void model_render_instanced(model_t, mat44 proj, mat44 view, mat44 *models, int shader, unsigned count);
|
void model_render_instanced(model_t, mat44 proj, mat44 view, mat44 *models, int shader, unsigned count);
|
||||||
|
@ -1375,23 +1411,6 @@ typedef struct lightmap_t {
|
||||||
void lightmap_setup(lightmap_t *lm, int w, int h);
|
void lightmap_setup(lightmap_t *lm, int w, int h);
|
||||||
void lightmap_bake(lightmap_t *lm, int bounces, void (*drawscene)(lightmap_t *lm, model_t *m, float *view, float *proj, void *userdata), void (*progressupdate)(float progress), void *userdata);
|
void lightmap_bake(lightmap_t *lm, int bounces, void (*drawscene)(lightmap_t *lm, model_t *m, float *view, float *proj, void *userdata), void (*progressupdate)(float progress), void *userdata);
|
||||||
void lightmap_destroy(lightmap_t *lm);
|
void lightmap_destroy(lightmap_t *lm);
|
||||||
typedef struct skybox_t {
|
|
||||||
handle program;
|
|
||||||
mesh_t geometry;
|
|
||||||
cubemap_t cubemap;
|
|
||||||
int flags;
|
|
||||||
int framebuffers[6];
|
|
||||||
int textures[6];
|
|
||||||
float *pixels;
|
|
||||||
} skybox_t;
|
|
||||||
skybox_t skybox(const char *panorama_or_cubemap_folder, int flags);
|
|
||||||
int skybox_render(skybox_t *sky, mat44 proj, mat44 view);
|
|
||||||
void skybox_destroy(skybox_t *sky);
|
|
||||||
void skybox_mie_calc_sh(skybox_t *sky, float sky_intensity);
|
|
||||||
void skybox_sh_reset(skybox_t *sky);
|
|
||||||
void skybox_sh_add_light(skybox_t *sky, vec3 light, vec3 dir, float strength);
|
|
||||||
int skybox_push_state(skybox_t *sky, mat44 proj, mat44 view);
|
|
||||||
int skybox_pop_state();
|
|
||||||
void viewport_color(unsigned color);
|
void viewport_color(unsigned color);
|
||||||
void viewport_clear(bool color, bool depth);
|
void viewport_clear(bool color, bool depth);
|
||||||
void viewport_clip(vec2 from, vec2 to);
|
void viewport_clip(vec2 from, vec2 to);
|
||||||
|
|
|
@ -1,74 +1,86 @@
|
||||||
// material demo
|
// material demo
|
||||||
// - rlyeh, public domain
|
// - rlyeh, public domain
|
||||||
//
|
//
|
||||||
// @todo: object_print(obj, "");
|
// @todo: object_print(obj, "");
|
||||||
|
|
||||||
#include "v4k.h"
|
#include "v4k.h"
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
// create the window
|
// create the window
|
||||||
window_create( 0.75f, WINDOW_MSAA8 );
|
window_create( 0.75f, WINDOW_MSAA8 );
|
||||||
window_color( GRAY );
|
window_color( GRAY );
|
||||||
|
|
||||||
// create camera
|
// create camera
|
||||||
camera_t cam = camera();
|
camera_t cam = camera();
|
||||||
// load video, RGB texture, no audio
|
// load video, RGB texture, no audio
|
||||||
video_t *v = video( "pexels-pachon-in-motion-17486489.mp4", VIDEO_RGB | VIDEO_NO_AUDIO | VIDEO_LOOP ); video_seek(v, 30);
|
video_t *v = video( "pexels-pachon-in-motion-17486489.mp4", VIDEO_RGB | VIDEO_NO_AUDIO | VIDEO_LOOP ); video_seek(v, 30);
|
||||||
// load texture
|
// load texture
|
||||||
texture_t t1 = texture("kgirl/g01_texture.png", TEXTURE_RGB);
|
texture_t t1 = texture("kgirl/g01_texture.png", TEXTURE_RGB);
|
||||||
texture_t t2 = texture("matcaps/material3", 0);
|
texture_t t2 = texture("matcaps/material3", 0);
|
||||||
// load model
|
// load model
|
||||||
model_t m1 = model("suzanne.obj", MODEL_NO_ANIMATIONS);
|
model_t m1 = model("suzanne.obj", MODEL_NO_ANIMATIONS);
|
||||||
model_t m2 = model("suzanne.obj", MODEL_NO_ANIMATIONS|MODEL_MATCAPS);
|
model_t m2 = model("suzanne.obj", MODEL_NO_ANIMATIONS|MODEL_MATCAPS);
|
||||||
|
model_t m3 = model("damagedhelmet.gltf", MODEL_NO_ANIMATIONS);
|
||||||
// spawn object1 (diffuse)
|
model_shading(&m3, SHADING_PBR);
|
||||||
object_t* obj1 = scene_spawn();
|
|
||||||
object_model(obj1, m1);
|
// spawn object1 (diffuse)
|
||||||
object_diffuse(obj1, t1);
|
object_t* obj1 = scene_spawn();
|
||||||
object_scale(obj1, vec3(3,3,3));
|
object_model(obj1, m1);
|
||||||
object_move(obj1, vec3(-10+5*0,0,-10));
|
object_diffuse(obj1, t1);
|
||||||
object_pivot(obj1, vec3(0,90,0));
|
object_scale(obj1, vec3(3,3,3));
|
||||||
|
object_move(obj1, vec3(-10+5*0,0,-10));
|
||||||
// spawn object2 (matcap)
|
object_pivot(obj1, vec3(0,90,0));
|
||||||
object_t* obj2 = scene_spawn();
|
|
||||||
object_model(obj2, m2);
|
// spawn object2 (matcap)
|
||||||
object_diffuse(obj2, t2);
|
object_t* obj2 = scene_spawn();
|
||||||
object_scale(obj2, vec3(3,3,3));
|
object_model(obj2, m2);
|
||||||
object_move(obj2, vec3(-10+5*2,0,-10));
|
object_diffuse(obj2, t2);
|
||||||
object_pivot(obj2, vec3(0,90,0));
|
object_scale(obj2, vec3(3,3,3));
|
||||||
|
object_move(obj2, vec3(-10+5*2,0,-10));
|
||||||
// spawn object2 (video)
|
object_pivot(obj2, vec3(0,90,0));
|
||||||
object_t* obj3 = scene_spawn();
|
|
||||||
object_model(obj3, m1);
|
// spawn object3 (video)
|
||||||
object_diffuse(obj3, video_textures(v)[0]);
|
object_t* obj3 = scene_spawn();
|
||||||
object_scale(obj3, vec3(3,3,3));
|
object_model(obj3, m1);
|
||||||
object_move(obj3, vec3(-10+5*1,0,-10));
|
object_diffuse(obj3, video_textures(v)[0]);
|
||||||
object_pivot(obj3, vec3(0,90,0));
|
object_scale(obj3, vec3(3,3,3));
|
||||||
|
object_move(obj3, vec3(-10+5*1,0,-10));
|
||||||
// create point light
|
object_pivot(obj3, vec3(0,90,0));
|
||||||
light_t* l = scene_spawn_light();
|
|
||||||
light_type(l, LIGHT_POINT);
|
// spawn object4 (pbr)
|
||||||
|
object_t* obj4 = scene_spawn();
|
||||||
while(window_swap() && !input(KEY_ESC)) {
|
object_model(obj4, m3);
|
||||||
// draw environment
|
object_scale(obj4, vec3(3,3,3));
|
||||||
ddraw_grid(0);
|
object_move(obj4, vec3(-10+6*3,0,-10));
|
||||||
|
object_pivot(obj4, vec3(0,90,0));
|
||||||
// update video
|
|
||||||
video_decode( v );
|
// create point light
|
||||||
|
light_t* l = scene_spawn_light();
|
||||||
// update light position
|
light_type(l, LIGHT_POINT);
|
||||||
light_teleport(l, cam.position);
|
|
||||||
|
// load skybox
|
||||||
// draw scene
|
scene_get_active()->skybox = skybox_pbr("hdr/Tokyo_BigSight_1k.hdr","hdr/Tokyo_BigSight_Env.hdr");
|
||||||
scene_render(SCENE_FOREGROUND|SCENE_BACKGROUND|SCENE_UPDATE_SH_COEF);
|
|
||||||
|
while(window_swap() && !input(KEY_ESC)) {
|
||||||
// fps camera
|
// draw environment
|
||||||
bool active = ui_active() || ui_hover() || gizmo_active() ? false : input(MOUSE_L) || input(MOUSE_M) || input(MOUSE_R);
|
ddraw_grid(0);
|
||||||
if( active ) cam.speed = clampf(cam.speed + input_diff(MOUSE_W) / 10, 0.05f, 5.0f);
|
|
||||||
vec2 mouselook = scale2(vec2(input_diff(MOUSE_X), -input_diff(MOUSE_Y)), 0.2f * active);
|
// update video
|
||||||
vec3 wasdec = scale3(vec3(input(KEY_D)-input(KEY_A),input(KEY_E)-input(KEY_C),input(KEY_W)-input(KEY_S)), cam.speed);
|
video_decode( v );
|
||||||
camera_moveby(&cam, wasdec);
|
|
||||||
camera_fps(&cam, mouselook.x,mouselook.y);
|
// update light position
|
||||||
window_cursor( !active );
|
light_teleport(l, cam.position);
|
||||||
}
|
|
||||||
}
|
// draw scene
|
||||||
|
scene_render(SCENE_FOREGROUND|SCENE_BACKGROUND|SCENE_UPDATE_SH_COEF);
|
||||||
|
|
||||||
|
// fps camera
|
||||||
|
bool active = ui_active() || ui_hover() || gizmo_active() ? false : input(MOUSE_L) || input(MOUSE_M) || input(MOUSE_R);
|
||||||
|
if( active ) cam.speed = clampf(cam.speed + input_diff(MOUSE_W) / 10, 0.05f, 5.0f);
|
||||||
|
vec2 mouselook = 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, mouselook.x,mouselook.y);
|
||||||
|
window_cursor( !active );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
frame: 0-50 AlienArmature|Alien_Clapping
|
frame: 0-50 AlienArmature|Alien_Clapping
|
||||||
frame: 51-106 AlienArmature|Alien_Death
|
frame: 51-106 AlienArmature|Alien_Death
|
||||||
frame: 107-207 AlienArmature|Alien_Idle
|
frame: 107-207 AlienArmature|Alien_Idle
|
||||||
frame: 208-308 AlienArmature|Alien_IdleHold
|
frame: 208-308 AlienArmature|Alien_IdleHold
|
||||||
frame: 309-334 AlienArmature|Alien_Jump
|
frame: 309-334 AlienArmature|Alien_Jump
|
||||||
frame: 335-357 AlienArmature|Alien_Punch
|
frame: 335-357 AlienArmature|Alien_Punch
|
||||||
frame: 358-379 AlienArmature|Alien_Run
|
frame: 358-379 AlienArmature|Alien_Run
|
||||||
frame: 380-401 AlienArmature|Alien_RunHold
|
frame: 380-401 AlienArmature|Alien_RunHold
|
||||||
frame: 402-432 AlienArmature|Alien_RunningJump
|
frame: 402-432 AlienArmature|Alien_RunningJump
|
||||||
frame: 433-459 AlienArmature|Alien_Sitting
|
frame: 433-459 AlienArmature|Alien_Sitting
|
||||||
frame: 460-475 AlienArmature|Alien_Standing
|
frame: 460-475 AlienArmature|Alien_Standing
|
||||||
frame: 476-508 AlienArmature|Alien_Swimming
|
frame: 476-508 AlienArmature|Alien_Swimming
|
||||||
frame: 509-534 AlienArmature|Alien_SwordSlash
|
frame: 509-534 AlienArmature|Alien_SwordSlash
|
||||||
frame: 535-560 AlienArmature|Alien_Walk
|
frame: 535-560 AlienArmature|Alien_Walk
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
frame: 0-50 AlienArmature|Alien_Clapping
|
frame: 0-50 AlienArmature|Alien_Clapping
|
||||||
frame: 51-106 AlienArmature|Alien_Death
|
frame: 51-106 AlienArmature|Alien_Death
|
||||||
frame: 107-207 AlienArmature|Alien_Idle
|
frame: 107-207 AlienArmature|Alien_Idle
|
||||||
frame: 208-308 AlienArmature|Alien_IdleHold
|
frame: 208-308 AlienArmature|Alien_IdleHold
|
||||||
frame: 309-334 AlienArmature|Alien_Jump
|
frame: 309-334 AlienArmature|Alien_Jump
|
||||||
frame: 335-357 AlienArmature|Alien_Punch
|
frame: 335-357 AlienArmature|Alien_Punch
|
||||||
frame: 358-379 AlienArmature|Alien_Run
|
frame: 358-379 AlienArmature|Alien_Run
|
||||||
frame: 380-401 AlienArmature|Alien_RunHold
|
frame: 380-401 AlienArmature|Alien_RunHold
|
||||||
frame: 402-432 AlienArmature|Alien_RunningJump
|
frame: 402-432 AlienArmature|Alien_RunningJump
|
||||||
frame: 433-459 AlienArmature|Alien_Sitting
|
frame: 433-459 AlienArmature|Alien_Sitting
|
||||||
frame: 460-475 AlienArmature|Alien_Standing
|
frame: 460-475 AlienArmature|Alien_Standing
|
||||||
frame: 476-508 AlienArmature|Alien_Swimming
|
frame: 476-508 AlienArmature|Alien_Swimming
|
||||||
frame: 509-534 AlienArmature|Alien_SwordSlash
|
frame: 509-534 AlienArmature|Alien_SwordSlash
|
||||||
frame: 535-560 AlienArmature|Alien_Walk
|
frame: 535-560 AlienArmature|Alien_Walk
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
frame: 0-506 Take 001
|
frame: 0-506 Take 001
|
||||||
|
|
|
@ -1,40 +1,40 @@
|
||||||
frame: 0-100 Idle
|
frame: 0-100 Idle
|
||||||
frame: 101-125 Dance
|
frame: 101-125 Dance
|
||||||
frame: 126-169 Death
|
frame: 126-169 Death
|
||||||
frame: 170-215 Hello
|
frame: 170-215 Hello
|
||||||
frame: 216-228 HitRecieve_1
|
frame: 216-228 HitRecieve_1
|
||||||
frame: 229-241 HitRecieve_2
|
frame: 229-241 HitRecieve_2
|
||||||
frame: 242-268 Jump
|
frame: 242-268 Jump
|
||||||
frame: 269-310 No
|
frame: 269-310 No
|
||||||
frame: 311-353 Pickup
|
frame: 311-353 Pickup
|
||||||
frame: 354-371 Punch
|
frame: 354-371 Punch
|
||||||
frame: 372-397 Run
|
frame: 372-397 Run
|
||||||
frame: 398-423 Run_Holding
|
frame: 398-423 Run_Holding
|
||||||
frame: 424-449 Run_Tall
|
frame: 424-449 Run_Tall
|
||||||
frame: 450-465 Shoot
|
frame: 450-465 Shoot
|
||||||
frame: 466-484 SwordSlash
|
frame: 466-484 SwordSlash
|
||||||
frame: 485-510 Walk
|
frame: 485-510 Walk
|
||||||
frame: 511-536 Walk_Holding
|
frame: 511-536 Walk_Holding
|
||||||
frame: 537-562 Walk_Tall
|
frame: 537-562 Walk_Tall
|
||||||
frame: 563-604 Yes
|
frame: 563-604 Yes
|
||||||
frame: 605-623 Kick
|
frame: 605-623 Kick
|
||||||
frame: 624-648 RobotArmature|Dance
|
frame: 624-648 RobotArmature|Dance
|
||||||
frame: 649-692 RobotArmature|Death
|
frame: 649-692 RobotArmature|Death
|
||||||
frame: 693-738 RobotArmature|Hello
|
frame: 693-738 RobotArmature|Hello
|
||||||
frame: 739-751 RobotArmature|HitRecieve_1
|
frame: 739-751 RobotArmature|HitRecieve_1
|
||||||
frame: 752-764 RobotArmature|HitRecieve_2
|
frame: 752-764 RobotArmature|HitRecieve_2
|
||||||
frame: 765-865 RobotArmature|Idle
|
frame: 765-865 RobotArmature|Idle
|
||||||
frame: 866-892 RobotArmature|Jump
|
frame: 866-892 RobotArmature|Jump
|
||||||
frame: 893-911 RobotArmature|Kick
|
frame: 893-911 RobotArmature|Kick
|
||||||
frame: 912-953 RobotArmature|No
|
frame: 912-953 RobotArmature|No
|
||||||
frame: 954-996 RobotArmature|Pickup
|
frame: 954-996 RobotArmature|Pickup
|
||||||
frame: 997-1014 RobotArmature|Punch
|
frame: 997-1014 RobotArmature|Punch
|
||||||
frame: 1015-1040 RobotArmature|Run
|
frame: 1015-1040 RobotArmature|Run
|
||||||
frame: 1041-1066 RobotArmature|Run_Holding
|
frame: 1041-1066 RobotArmature|Run_Holding
|
||||||
frame: 1067-1092 RobotArmature|Run_Tall
|
frame: 1067-1092 RobotArmature|Run_Tall
|
||||||
frame: 1093-1108 RobotArmature|Shoot
|
frame: 1093-1108 RobotArmature|Shoot
|
||||||
frame: 1109-1127 RobotArmature|SwordSlash
|
frame: 1109-1127 RobotArmature|SwordSlash
|
||||||
frame: 1128-1153 RobotArmature|Walk
|
frame: 1128-1153 RobotArmature|Walk
|
||||||
frame: 1154-1179 RobotArmature|Walk_Holding
|
frame: 1154-1179 RobotArmature|Walk_Holding
|
||||||
frame: 1180-1205 RobotArmature|Walk_Tall
|
frame: 1180-1205 RobotArmature|Walk_Tall
|
||||||
frame: 1206-1247 RobotArmature|Yes
|
frame: 1206-1247 RobotArmature|Yes
|
||||||
|
|
|
@ -1,36 +1,36 @@
|
||||||
frame: 0-24 Dance
|
frame: 0-24 Dance
|
||||||
frame: 25-68 Death
|
frame: 25-68 Death
|
||||||
frame: 69-114 Hello
|
frame: 69-114 Hello
|
||||||
frame: 115-127 HitRecieve_1
|
frame: 115-127 HitRecieve_1
|
||||||
frame: 128-140 HitRecieve_2
|
frame: 128-140 HitRecieve_2
|
||||||
frame: 141-241 Idle
|
frame: 141-241 Idle
|
||||||
frame: 242-268 Jump
|
frame: 242-268 Jump
|
||||||
frame: 269-287 Kick
|
frame: 269-287 Kick
|
||||||
frame: 288-329 No
|
frame: 288-329 No
|
||||||
frame: 330-372 Pickup
|
frame: 330-372 Pickup
|
||||||
frame: 373-390 Punch
|
frame: 373-390 Punch
|
||||||
frame: 391-416 Run
|
frame: 391-416 Run
|
||||||
frame: 417-442 Run_Tall
|
frame: 417-442 Run_Tall
|
||||||
frame: 443-458 Shoot
|
frame: 443-458 Shoot
|
||||||
frame: 459-477 SwordSlash
|
frame: 459-477 SwordSlash
|
||||||
frame: 478-503 Walk
|
frame: 478-503 Walk
|
||||||
frame: 504-529 Walk_Tall
|
frame: 504-529 Walk_Tall
|
||||||
frame: 530-572 Yes
|
frame: 530-572 Yes
|
||||||
frame: 573-597 RobotArmature|Dance
|
frame: 573-597 RobotArmature|Dance
|
||||||
frame: 598-641 RobotArmature|Death
|
frame: 598-641 RobotArmature|Death
|
||||||
frame: 642-687 RobotArmature|Hello
|
frame: 642-687 RobotArmature|Hello
|
||||||
frame: 688-700 RobotArmature|HitRecieve_1
|
frame: 688-700 RobotArmature|HitRecieve_1
|
||||||
frame: 701-713 RobotArmature|HitRecieve_2
|
frame: 701-713 RobotArmature|HitRecieve_2
|
||||||
frame: 714-814 RobotArmature|Idle
|
frame: 714-814 RobotArmature|Idle
|
||||||
frame: 815-841 RobotArmature|Jump
|
frame: 815-841 RobotArmature|Jump
|
||||||
frame: 842-860 RobotArmature|Kick
|
frame: 842-860 RobotArmature|Kick
|
||||||
frame: 861-902 RobotArmature|No
|
frame: 861-902 RobotArmature|No
|
||||||
frame: 903-945 RobotArmature|Pickup
|
frame: 903-945 RobotArmature|Pickup
|
||||||
frame: 946-963 RobotArmature|Punch
|
frame: 946-963 RobotArmature|Punch
|
||||||
frame: 964-989 RobotArmature|Run
|
frame: 964-989 RobotArmature|Run
|
||||||
frame: 990-1015 RobotArmature|Run_Tall
|
frame: 990-1015 RobotArmature|Run_Tall
|
||||||
frame: 1016-1031 RobotArmature|Shoot
|
frame: 1016-1031 RobotArmature|Shoot
|
||||||
frame: 1032-1050 RobotArmature|SwordSlash
|
frame: 1032-1050 RobotArmature|SwordSlash
|
||||||
frame: 1051-1076 RobotArmature|Walk
|
frame: 1051-1076 RobotArmature|Walk
|
||||||
frame: 1077-1102 RobotArmature|Walk_Tall
|
frame: 1077-1102 RobotArmature|Walk_Tall
|
||||||
frame: 1103-1145 RobotArmature|Yes
|
frame: 1103-1145 RobotArmature|Yes
|
||||||
|
|
|
@ -1,36 +1,36 @@
|
||||||
frame: 0-100 Idle
|
frame: 0-100 Idle
|
||||||
frame: 101-125 Dance
|
frame: 101-125 Dance
|
||||||
frame: 126-169 Death
|
frame: 126-169 Death
|
||||||
frame: 170-215 Hello
|
frame: 170-215 Hello
|
||||||
frame: 216-228 HitRecieve_1
|
frame: 216-228 HitRecieve_1
|
||||||
frame: 229-241 HitRecieve_2
|
frame: 229-241 HitRecieve_2
|
||||||
frame: 242-268 Jump
|
frame: 242-268 Jump
|
||||||
frame: 269-311 No
|
frame: 269-311 No
|
||||||
frame: 312-354 Pickup
|
frame: 312-354 Pickup
|
||||||
frame: 355-372 Punch
|
frame: 355-372 Punch
|
||||||
frame: 373-398 Run
|
frame: 373-398 Run
|
||||||
frame: 399-424 Run_Holding
|
frame: 399-424 Run_Holding
|
||||||
frame: 425-440 Shoot
|
frame: 425-440 Shoot
|
||||||
frame: 441-459 SwordSlash
|
frame: 441-459 SwordSlash
|
||||||
frame: 460-485 Walk
|
frame: 460-485 Walk
|
||||||
frame: 486-528 Yes
|
frame: 486-528 Yes
|
||||||
frame: 529-547 Kick
|
frame: 529-547 Kick
|
||||||
frame: 548-573 Walk_Holding
|
frame: 548-573 Walk_Holding
|
||||||
frame: 574-598 RobotArmature|Dance
|
frame: 574-598 RobotArmature|Dance
|
||||||
frame: 599-642 RobotArmature|Death
|
frame: 599-642 RobotArmature|Death
|
||||||
frame: 643-688 RobotArmature|Hello
|
frame: 643-688 RobotArmature|Hello
|
||||||
frame: 689-701 RobotArmature|HitRecieve_1
|
frame: 689-701 RobotArmature|HitRecieve_1
|
||||||
frame: 702-714 RobotArmature|HitRecieve_2
|
frame: 702-714 RobotArmature|HitRecieve_2
|
||||||
frame: 715-815 RobotArmature|Idle
|
frame: 715-815 RobotArmature|Idle
|
||||||
frame: 816-842 RobotArmature|Jump
|
frame: 816-842 RobotArmature|Jump
|
||||||
frame: 843-861 RobotArmature|Kick
|
frame: 843-861 RobotArmature|Kick
|
||||||
frame: 862-904 RobotArmature|No
|
frame: 862-904 RobotArmature|No
|
||||||
frame: 905-947 RobotArmature|Pickup
|
frame: 905-947 RobotArmature|Pickup
|
||||||
frame: 948-965 RobotArmature|Punch
|
frame: 948-965 RobotArmature|Punch
|
||||||
frame: 966-991 RobotArmature|Run
|
frame: 966-991 RobotArmature|Run
|
||||||
frame: 992-1017 RobotArmature|Run_Holding
|
frame: 992-1017 RobotArmature|Run_Holding
|
||||||
frame: 1018-1033 RobotArmature|Shoot
|
frame: 1018-1033 RobotArmature|Shoot
|
||||||
frame: 1034-1052 RobotArmature|SwordSlash
|
frame: 1034-1052 RobotArmature|SwordSlash
|
||||||
frame: 1053-1078 RobotArmature|Walk
|
frame: 1053-1078 RobotArmature|Walk
|
||||||
frame: 1079-1104 RobotArmature|Walk_Holding
|
frame: 1079-1104 RobotArmature|Walk_Holding
|
||||||
frame: 1105-1147 RobotArmature|Yes
|
frame: 1105-1147 RobotArmature|Yes
|
||||||
|
|
|
@ -1,36 +1,36 @@
|
||||||
frame: 0-100 Idle
|
frame: 0-100 Idle
|
||||||
frame: 101-125 Dance
|
frame: 101-125 Dance
|
||||||
frame: 126-169 Death
|
frame: 126-169 Death
|
||||||
frame: 170-215 Hello
|
frame: 170-215 Hello
|
||||||
frame: 216-228 HitRecieve_1
|
frame: 216-228 HitRecieve_1
|
||||||
frame: 229-241 HitRecieve_2
|
frame: 229-241 HitRecieve_2
|
||||||
frame: 242-268 Jump
|
frame: 242-268 Jump
|
||||||
frame: 269-311 No
|
frame: 269-311 No
|
||||||
frame: 312-354 Pickup
|
frame: 312-354 Pickup
|
||||||
frame: 355-372 Punch
|
frame: 355-372 Punch
|
||||||
frame: 373-398 Run
|
frame: 373-398 Run
|
||||||
frame: 399-424 Run_Holding
|
frame: 399-424 Run_Holding
|
||||||
frame: 425-440 Shoot
|
frame: 425-440 Shoot
|
||||||
frame: 441-459 SwordSlash
|
frame: 441-459 SwordSlash
|
||||||
frame: 460-485 Walk
|
frame: 460-485 Walk
|
||||||
frame: 486-528 Yes
|
frame: 486-528 Yes
|
||||||
frame: 529-547 Kick
|
frame: 529-547 Kick
|
||||||
frame: 548-573 Walk_Holding
|
frame: 548-573 Walk_Holding
|
||||||
frame: 574-598 RobotArmature|Dance
|
frame: 574-598 RobotArmature|Dance
|
||||||
frame: 599-642 RobotArmature|Death
|
frame: 599-642 RobotArmature|Death
|
||||||
frame: 643-688 RobotArmature|Hello
|
frame: 643-688 RobotArmature|Hello
|
||||||
frame: 689-701 RobotArmature|HitRecieve_1
|
frame: 689-701 RobotArmature|HitRecieve_1
|
||||||
frame: 702-714 RobotArmature|HitRecieve_2
|
frame: 702-714 RobotArmature|HitRecieve_2
|
||||||
frame: 715-815 RobotArmature|Idle
|
frame: 715-815 RobotArmature|Idle
|
||||||
frame: 816-842 RobotArmature|Jump
|
frame: 816-842 RobotArmature|Jump
|
||||||
frame: 843-861 RobotArmature|Kick
|
frame: 843-861 RobotArmature|Kick
|
||||||
frame: 862-904 RobotArmature|No
|
frame: 862-904 RobotArmature|No
|
||||||
frame: 905-947 RobotArmature|Pickup
|
frame: 905-947 RobotArmature|Pickup
|
||||||
frame: 948-965 RobotArmature|Punch
|
frame: 948-965 RobotArmature|Punch
|
||||||
frame: 966-991 RobotArmature|Run
|
frame: 966-991 RobotArmature|Run
|
||||||
frame: 992-1017 RobotArmature|Run_Holding
|
frame: 992-1017 RobotArmature|Run_Holding
|
||||||
frame: 1018-1033 RobotArmature|Shoot
|
frame: 1018-1033 RobotArmature|Shoot
|
||||||
frame: 1034-1052 RobotArmature|SwordSlash
|
frame: 1034-1052 RobotArmature|SwordSlash
|
||||||
frame: 1053-1078 RobotArmature|Walk
|
frame: 1053-1078 RobotArmature|Walk
|
||||||
frame: 1079-1104 RobotArmature|Walk_Holding
|
frame: 1079-1104 RobotArmature|Walk_Holding
|
||||||
frame: 1105-1147 RobotArmature|Yes
|
frame: 1105-1147 RobotArmature|Yes
|
||||||
|
|
|
@ -1,209 +1,733 @@
|
||||||
uniform mat4 model, view;
|
uniform mat4 model, view;
|
||||||
uniform sampler2D u_texture2d;
|
uniform sampler2D u_texture2d;
|
||||||
uniform vec3 u_coefficients_sh[9];
|
uniform vec3 u_coefficients_sh[9];
|
||||||
uniform bool u_textured = true;
|
uniform bool u_textured = true;
|
||||||
uniform bool u_lit = false;
|
uniform bool u_lit = false;
|
||||||
uniform bool u_matcaps = false;
|
uniform bool u_matcaps = false;
|
||||||
uniform vec4 u_diffuse = vec4(1.0,1.0,1.0,1.0);
|
uniform vec4 u_diffuse = vec4(1.0,1.0,1.0,1.0);
|
||||||
|
|
||||||
// lightmapping
|
// lightmapping
|
||||||
uniform sampler2D u_lightmap;
|
uniform sampler2D u_lightmap;
|
||||||
uniform bool u_texlit;
|
uniform bool u_texlit;
|
||||||
uniform bool u_texmod = true;
|
uniform bool u_texmod = true;
|
||||||
uniform float u_litboost = 1.0;
|
uniform float u_litboost = 1.0;
|
||||||
|
|
||||||
in vec3 v_position;
|
in vec3 v_position;
|
||||||
in vec3 v_position_ws;
|
in vec3 v_position_ws;
|
||||||
#ifdef RIM
|
#ifdef RIM
|
||||||
uniform mat4 M; // RIM
|
uniform mat4 M; // RIM
|
||||||
uniform vec3 u_rimcolor = vec3(0.2,0.2,0.2);
|
uniform vec3 u_rimcolor = vec3(0.2,0.2,0.2);
|
||||||
uniform vec3 u_rimrange = vec3(0.11,0.98,0.5);
|
uniform vec3 u_rimrange = vec3(0.11,0.98,0.5);
|
||||||
uniform vec3 u_rimpivot = vec3(0,0,0);
|
uniform vec3 u_rimpivot = vec3(0,0,0);
|
||||||
uniform bool u_rimambient = true;
|
uniform bool u_rimambient = true;
|
||||||
#endif
|
#endif
|
||||||
in vec3 v_normal, v_normal_ws;
|
in vec3 v_normal, v_normal_ws;
|
||||||
in vec2 v_texcoord, v_texcoord2;
|
in vec2 v_texcoord, v_texcoord2;
|
||||||
in vec4 v_color;
|
in vec4 v_color;
|
||||||
out vec4 fragcolor;
|
in vec3 v_tangent;
|
||||||
|
in vec3 v_binormal;
|
||||||
|
in vec3 v_to_camera;
|
||||||
{{include-shadowmap}}
|
out vec4 fragcolor;
|
||||||
in vec4 vpeye;
|
|
||||||
in vec4 vneye;
|
|
||||||
in vec4 sc;
|
{{include-shadowmap}}
|
||||||
vec4 shadowing() {
|
in vec4 vpeye;
|
||||||
return shadowmap(vpeye, vneye, v_texcoord, sc);
|
in vec4 vneye;
|
||||||
}
|
in vec4 sc;
|
||||||
|
vec4 shadowing() {
|
||||||
uniform vec3 u_cam_pos;
|
return shadowmap(vpeye, vneye, v_texcoord, sc);
|
||||||
uniform vec3 u_cam_dir;
|
}
|
||||||
|
|
||||||
uniform int u_num_lights;
|
uniform vec3 u_cam_pos;
|
||||||
|
uniform vec3 u_cam_dir;
|
||||||
struct light_t {
|
|
||||||
int type;
|
uniform int u_num_lights;
|
||||||
vec3 diffuse;
|
|
||||||
vec3 specular;
|
struct light_t {
|
||||||
vec3 ambient;
|
int type;
|
||||||
vec3 pos;
|
vec3 diffuse;
|
||||||
vec3 dir;
|
vec3 specular;
|
||||||
float power;
|
vec3 ambient;
|
||||||
float innerCone;
|
vec3 pos;
|
||||||
float outerCone;
|
vec3 dir;
|
||||||
|
float power;
|
||||||
// falloff
|
float innerCone;
|
||||||
float constant;
|
float outerCone;
|
||||||
float linear;
|
|
||||||
float quadratic;
|
// falloff
|
||||||
};
|
float constant;
|
||||||
|
float linear;
|
||||||
#define MAX_LIGHTS 16
|
float quadratic;
|
||||||
const int LIGHT_DIRECTIONAL = 0;
|
};
|
||||||
const int LIGHT_POINT = 1;
|
|
||||||
const int LIGHT_SPOT = 2;
|
#define MAX_LIGHTS 16
|
||||||
|
const int LIGHT_DIRECTIONAL = 0;
|
||||||
uniform light_t u_lights[MAX_LIGHTS];
|
const int LIGHT_POINT = 1;
|
||||||
|
const int LIGHT_SPOT = 2;
|
||||||
#ifdef SHADING_PHONG
|
|
||||||
vec3 shading_phong(light_t l) {
|
uniform light_t u_lights[MAX_LIGHTS];
|
||||||
vec3 lightDir;
|
|
||||||
float attenuation = 1.0;
|
#ifdef SHADING_PHONG
|
||||||
|
vec3 shading_phong(light_t l) {
|
||||||
if (l.type == LIGHT_DIRECTIONAL) {
|
vec3 lightDir;
|
||||||
lightDir = normalize(-l.dir);
|
float attenuation = 1.0;
|
||||||
} else if (l.type == LIGHT_POINT || l.type == LIGHT_SPOT) {
|
|
||||||
vec3 toLight = l.pos - v_position_ws;
|
if (l.type == LIGHT_DIRECTIONAL) {
|
||||||
lightDir = normalize(toLight);
|
lightDir = normalize(-l.dir);
|
||||||
float distance = length(toLight);
|
} else if (l.type == LIGHT_POINT || l.type == LIGHT_SPOT) {
|
||||||
attenuation = 1.0 / (l.constant + l.linear * distance + l.quadratic * (distance * distance));
|
vec3 toLight = l.pos - v_position_ws;
|
||||||
|
lightDir = normalize(toLight);
|
||||||
if (l.type == LIGHT_SPOT) {
|
float distance = length(toLight);
|
||||||
float angle = dot(l.dir, -lightDir);
|
attenuation = 1.0 / (l.constant + l.linear * distance + l.quadratic * (distance * distance));
|
||||||
if (angle > l.outerCone) {
|
|
||||||
float intensity = (angle-l.outerCone)/(l.innerCone-l.outerCone);
|
if (l.type == LIGHT_SPOT) {
|
||||||
attenuation *= clamp(intensity, 0.0, 1.0);
|
float angle = dot(l.dir, -lightDir);
|
||||||
} else {
|
if (angle > l.outerCone) {
|
||||||
attenuation = 0.0;
|
float intensity = (angle-l.outerCone)/(l.innerCone-l.outerCone);
|
||||||
}
|
attenuation *= clamp(intensity, 0.0, 1.0);
|
||||||
}
|
} else {
|
||||||
}
|
attenuation = 0.0;
|
||||||
|
}
|
||||||
// fast-rejection for faraway vertices
|
}
|
||||||
if (attenuation <= 0.01) {
|
}
|
||||||
return vec3(0,0,0);
|
|
||||||
}
|
// fast-rejection for faraway vertices
|
||||||
|
if (attenuation <= 0.01) {
|
||||||
vec3 n = normalize(v_normal_ws);
|
return vec3(0,0,0);
|
||||||
|
}
|
||||||
float diffuse = max(dot(n, lightDir), 0.0);
|
|
||||||
|
vec3 n = normalize(v_normal_ws);
|
||||||
vec3 halfVec = normalize(lightDir + u_cam_dir);
|
|
||||||
float specular = pow(max(dot(n, halfVec), 0.0), l.power);
|
float diffuse = max(dot(n, lightDir), 0.0);
|
||||||
|
|
||||||
return (attenuation*l.ambient + diffuse*attenuation*l.diffuse + specular*attenuation*l.specular);
|
vec3 halfVec = normalize(lightDir + u_cam_dir);
|
||||||
}
|
float specular = pow(max(dot(n, halfVec), 0.0), l.power);
|
||||||
#endif
|
|
||||||
|
return (attenuation*l.ambient + diffuse*attenuation*l.diffuse + specular*attenuation*l.specular);
|
||||||
vec3 lighting() {
|
}
|
||||||
vec3 lit = vec3(0,0,0);
|
#endif
|
||||||
#ifndef SHADING_NONE
|
|
||||||
for (int i=0; i<u_num_lights; i++) {
|
#ifdef SHADING_PBR
|
||||||
#ifdef SHADING_PHONG
|
uniform vec2 resolution = vec2(640.0,480.0); // debug options below use this (USE_MAP_DEBUGGING, USE_AMBIENT_DEBUGGING)
|
||||||
lit += shading_phong(u_lights[i]);
|
|
||||||
#endif
|
#define USE_BRUTEFORCE_IRRADIANCE false // Samples irradiance from tex_skysphere when enabled.
|
||||||
}
|
#define USE_WRAPAROUND_SPECULAR true // Makes silhouettes more reflective to avoid black pixels.
|
||||||
#endif
|
#define USE_SPECULAR_AO_ATTENUATION true // Dampens IBL specular ambient with AO if enabled.
|
||||||
return lit;
|
#define USE_NORMAL_VARIATION_TO_ROUGHNESS true // Increases roughness if normal map has variation and was minified.
|
||||||
}
|
#define USE_MAP_DEBUGGING false // Shows all ColorMaps as horizontal bars
|
||||||
|
#define USE_AMBIENT_DEBUGGING false // Splits the screen in two and shows image-based specular (left), full shading (middle), diffuse shading (right).
|
||||||
vec3 sh_lighting(vec3 n) {
|
#define BOOST_LIGHTING 2.00f // Multiplies analytic light's color with this constant because otherwise they look really pathetic.
|
||||||
vec3 SHLightResult[9];
|
#define BOOST_SPECULAR 1.50f
|
||||||
SHLightResult[0] = 0.282095f * u_coefficients_sh[0];
|
#define BOOST_NOISE 2.50f
|
||||||
SHLightResult[1] = -0.488603f * u_coefficients_sh[1] * n.y;
|
|
||||||
SHLightResult[2] = 0.488603f * u_coefficients_sh[2] * n.z;
|
struct ColorMap
|
||||||
SHLightResult[3] = -0.488603f * u_coefficients_sh[3] * n.x;
|
{
|
||||||
SHLightResult[4] = 1.092548f * u_coefficients_sh[4] * n.x * n.y;
|
bool has_tex;
|
||||||
SHLightResult[5] = -1.092548f * u_coefficients_sh[5] * n.y * n.z;
|
vec4 color;
|
||||||
SHLightResult[6] = 0.315392f * u_coefficients_sh[6] * (3.0f * n.z * n.z - 1.0f);
|
};
|
||||||
SHLightResult[7] = -1.092548f * u_coefficients_sh[7] * n.x * n.z;
|
|
||||||
SHLightResult[8] = 0.546274f * u_coefficients_sh[8] * (n.x * n.x - n.y * n.y);
|
uniform ColorMap map_albedo; uniform sampler2D map_albedo_tex;
|
||||||
vec3 result = vec3(0.0);
|
uniform ColorMap map_diffuse; uniform sampler2D map_diffuse_tex;
|
||||||
for (int i = 0; i < 9; ++i)
|
uniform ColorMap map_specular; uniform sampler2D map_specular_tex; // not used
|
||||||
result += SHLightResult[i];
|
uniform ColorMap map_normals; uniform sampler2D map_normals_tex;
|
||||||
return result;
|
uniform ColorMap map_roughness; uniform sampler2D map_roughness_tex;
|
||||||
}
|
uniform ColorMap map_metallic; uniform sampler2D map_metallic_tex;
|
||||||
|
uniform ColorMap map_ao; uniform sampler2D map_ao_tex;
|
||||||
#ifdef LIGHTMAP_BAKING
|
uniform ColorMap map_ambient; uniform sampler2D map_ambient_tex;
|
||||||
void main() {
|
uniform ColorMap map_emissive; uniform sampler2D map_emissive_tex;
|
||||||
vec3 n = normalize(v_normal_ws);
|
|
||||||
vec4 diffuse;
|
#define sample_colormap(ColorMap_, uv_) \
|
||||||
|
(ColorMap_.has_tex ? texture( ColorMap_##_tex, uv_ ) : ColorMap_.color)
|
||||||
if(u_textured) {
|
|
||||||
diffuse = texture(u_texture2d, v_texcoord);
|
uniform float skysphere_rotation;
|
||||||
} else {
|
uniform float skysphere_mip_count;
|
||||||
diffuse = u_diffuse; // * v_color;
|
uniform float exposure=1;
|
||||||
}
|
// uniform uint frame_count;
|
||||||
|
uniform float specular_shininess;
|
||||||
if (u_texlit) {
|
|
||||||
vec4 litsample = texture(u_lightmap, v_texcoord);
|
uniform sampler2D tex_skysphere;
|
||||||
diffuse *= litsample;
|
uniform sampler2D tex_skyenv;
|
||||||
}
|
uniform sampler2D tex_brdf_lut;
|
||||||
|
|
||||||
fragcolor = vec4(diffuse.rgb*u_litboost, 1.0);
|
uniform bool has_tex_skysphere;
|
||||||
}
|
uniform bool has_tex_skyenv;
|
||||||
#else
|
|
||||||
void main() {
|
const float PI = 3.1415926536;
|
||||||
vec3 n = normalize(v_normal_ws);
|
|
||||||
|
// MurMurHash 3 finalizer. Implementation is in public domain.
|
||||||
vec4 lit = vec4(1.0, 1.0, 1.0, 1.0);
|
uint hash( uint h )
|
||||||
// SH lighting
|
{
|
||||||
if (!u_texlit) {
|
h ^= h >> 16;
|
||||||
vec3 result = sh_lighting(n);
|
h *= 0x85ebca6bU;
|
||||||
if( (result.x*result.x+result.y*result.y+result.z*result.z) > 0.0 ) lit = vec4(result, 1.0);
|
h ^= h >> 13;
|
||||||
}
|
h *= 0xc2b2ae35U;
|
||||||
|
h ^= h >> 16;
|
||||||
// analytical lights (phong shading)
|
return h;
|
||||||
lit += vec4(lighting(), 0.0);
|
}
|
||||||
|
|
||||||
// base
|
// Random function using the idea of StackOverflow user "Spatial" https://stackoverflow.com/a/17479300
|
||||||
vec4 diffuse;
|
// Creates random 23 bits and puts them into the fraction bits of an 32-bit float.
|
||||||
|
float random( uvec3 h )
|
||||||
if(u_matcaps) {
|
{
|
||||||
vec2 muv = vec2(view * vec4(v_normal_ws, 0))*0.5+vec2(0.5,0.5); // normal (model space) to view space
|
uint m = hash(h.x ^ hash( h.y ) ^ hash( h.z ));
|
||||||
diffuse = texture(u_texture2d, vec2(muv.x, 1.0-muv.y));
|
return uintBitsToFloat( ( m & 0x007FFFFFu ) | 0x3f800000u ) - 1.;
|
||||||
} else if(u_textured) {
|
}
|
||||||
diffuse = texture(u_texture2d, v_texcoord);
|
|
||||||
} else {
|
float random( vec3 v )
|
||||||
diffuse = u_diffuse; // * v_color;
|
{
|
||||||
}
|
return random(floatBitsToUint( v ));
|
||||||
|
}
|
||||||
if (u_texlit) {
|
|
||||||
vec4 litsample = texture(u_lightmap, v_texcoord);
|
vec3 fresnel_schlick( vec3 H, vec3 V, vec3 F0 )
|
||||||
|
{
|
||||||
if (u_texmod) {
|
float cosTheta = clamp( dot( H, V ), 0., 1. );
|
||||||
diffuse *= litsample;
|
return F0 + ( vec3( 1.0 ) - F0 ) * pow( 1. - cosTheta, 5.0 );
|
||||||
} else {
|
}
|
||||||
diffuse += litsample;
|
|
||||||
}
|
// A Fresnel term that dampens rough specular reflections.
|
||||||
|
// https://seblagarde.wordpress.com/2011/08/17/hello-world/
|
||||||
diffuse.rgb += sh_lighting(n);
|
vec3 fresnel_schlick_roughness( vec3 H, vec3 V, vec3 F0, float roughness )
|
||||||
}
|
{
|
||||||
|
float cosTheta = clamp( dot( H, V ), 0., 1. );
|
||||||
// lighting mix
|
return F0 + ( max( vec3( 1.0 - roughness ), F0 ) - F0 ) * pow( 1. - cosTheta, 5.0 );
|
||||||
fragcolor = diffuse * lit * shadowing();
|
}
|
||||||
|
|
||||||
// rimlight
|
float distribution_ggx( vec3 N, vec3 H, float roughness )
|
||||||
#ifdef RIM
|
{
|
||||||
{
|
float a = roughness * roughness;
|
||||||
vec3 n = normalize(mat3(M) * v_normal); // convert normal to view space
|
float a2 = a * a;
|
||||||
vec3 p = (M * vec4(v_position,1.0)).xyz; // convert position to view space
|
float NdotH = max( 0., dot( N, H ) );
|
||||||
vec3 v = vec3(0,-1,0);
|
float factor = NdotH * NdotH * ( a2 - 1. ) + 1.;
|
||||||
if (!u_rimambient) {
|
|
||||||
v = normalize(u_rimpivot-p);
|
return a2 / ( PI * factor * factor );
|
||||||
}
|
}
|
||||||
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));
|
float geometry_schlick_ggx( vec3 N, vec3 V, float k )
|
||||||
fragcolor += vec4(col, 1.0);}
|
{
|
||||||
#endif
|
float NdotV = max( 0., dot( N, V ) );
|
||||||
}
|
return NdotV / (NdotV * ( 1. - k ) + k );
|
||||||
#endif
|
}
|
||||||
|
|
||||||
|
float geometry_smith( vec3 N, vec3 V, vec3 L, float roughness )
|
||||||
|
{
|
||||||
|
#if 1 // original
|
||||||
|
float r = roughness + 1.;
|
||||||
|
float k = (r * r) / 8.;
|
||||||
|
#elif 0 // vries
|
||||||
|
float a = roughness;
|
||||||
|
float k = (a * a) / 2.0;
|
||||||
|
#elif 0 // vries improved?
|
||||||
|
float a = roughness * roughness;
|
||||||
|
float k = a / 2.0;
|
||||||
|
#endif
|
||||||
|
return geometry_schlick_ggx( N, V, k ) * geometry_schlick_ggx( N, L, k );
|
||||||
|
}
|
||||||
|
|
||||||
|
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 );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Our vertically GL_CLAMPed textures seem to blend towards black when sampling the half-pixel edge.
|
||||||
|
// Not sure if it has a border, or this if is a driver bug, but can repro on multiple nvidia cards.
|
||||||
|
// Knowing the texture height we can limit sampling to the centers of the top and bottom pixel rows.
|
||||||
|
vec2 sphere_to_polar_clamp_y( vec3 normal, float texture_height )
|
||||||
|
{
|
||||||
|
normal = normalize( normal );
|
||||||
|
return vec2( ( atan( normal.z, normal.x ) + skysphere_rotation ) / PI / 2.0 + 0.5, clamp(acos( normal.y ) / PI, 0.5 / texture_height, 1.0 - 0.5 / texture_height) );
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 sample_sky( vec3 normal )
|
||||||
|
{
|
||||||
|
vec2 polar = sphere_to_polar( normal );
|
||||||
|
return texture( tex_skysphere, polar ).rgb * exposure;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Takes samples around the hemisphere, converts them to radiances via weighting and
|
||||||
|
// returns a normalized sum.
|
||||||
|
vec3 sample_irradiance_slow( vec3 normal, vec3 vertex_tangent )
|
||||||
|
{
|
||||||
|
float delta = 0.10;
|
||||||
|
|
||||||
|
vec3 up = abs( normal.y ) < 0.999 ? vec3( 0., 1., 0. ) : vec3( 0., 0., 1. );
|
||||||
|
vec3 tangent_x = normalize( cross( up, normal ) );
|
||||||
|
vec3 tangent_y = cross( normal, tangent_x );
|
||||||
|
|
||||||
|
int numIrradianceSamples = 0;
|
||||||
|
|
||||||
|
vec3 irradiance = vec3(0.);
|
||||||
|
|
||||||
|
for ( float phi = 0.; phi < 2. * PI ; phi += delta )
|
||||||
|
{
|
||||||
|
for ( float theta = 0.; theta < 0.5 * PI; theta += delta )
|
||||||
|
{
|
||||||
|
vec3 tangent_space = vec3(
|
||||||
|
sin( theta ) * cos( phi ),
|
||||||
|
sin( theta ) * sin( phi ),
|
||||||
|
cos( theta ) );
|
||||||
|
|
||||||
|
vec3 world_space = tangent_space.x * tangent_x + tangent_space.y + tangent_y + tangent_space.z * normal;
|
||||||
|
|
||||||
|
vec3 color = sample_sky( world_space );
|
||||||
|
irradiance += color * cos( theta ) * sin( theta );
|
||||||
|
numIrradianceSamples++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
irradiance = PI * irradiance / float( numIrradianceSamples );
|
||||||
|
return irradiance;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 );
|
||||||
|
return textureLod( tex_skyenv, polar, 0.0 ).rgb * exposure;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vec2 polar = sphere_to_polar( normal );
|
||||||
|
return textureLod( tex_skysphere, polar, 0.80 * skysphere_mip_count ).rgb * exposure;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
vec3 specular_ibl( vec3 V, vec3 N, float roughness, vec3 fresnel )
|
||||||
|
{
|
||||||
|
// What we'd like to do here is take a LOT of skybox samples around the reflection
|
||||||
|
// vector R according to the BRDF lobe.
|
||||||
|
//
|
||||||
|
// Unfortunately it's not possible in real time so we use the following UE4 style approximations:
|
||||||
|
// 1. Integrate incoming light and BRDF separately ("split sum approximation")
|
||||||
|
// 2. Assume V = R = N so that we can just blur the skybox and sample that.
|
||||||
|
// 3. Bake the BRDF integral into a lookup texture so that it can be computed in constant time.
|
||||||
|
//
|
||||||
|
// Here we also simplify approximation #2 by using bilinear mipmaps with a magic formula instead
|
||||||
|
// of properly convolving it with a GGX lobe.
|
||||||
|
//
|
||||||
|
// For details, see Brian Karis, "Real Shading in Unreal Engine 4", 2013.
|
||||||
|
|
||||||
|
vec3 R = 2. * dot( V, N ) * N - V;
|
||||||
|
|
||||||
|
vec2 polar = sphere_to_polar( R );
|
||||||
|
|
||||||
|
// Map roughness from range [0, 1] into a mip LOD [0, skysphere_mip_count].
|
||||||
|
// The magic numbers were chosen empirically.
|
||||||
|
|
||||||
|
float mip = 0.9 * skysphere_mip_count * pow(roughness, 0.25 * BOOST_SPECULAR);
|
||||||
|
|
||||||
|
vec3 prefiltered = textureLod( tex_skysphere, polar, mip ).rgb * exposure;
|
||||||
|
|
||||||
|
float NdotV = dot( N, V );
|
||||||
|
|
||||||
|
// dot( N, V ) seems to produce negative values so we can try to stretch it a bit behind the silhouette
|
||||||
|
// to avoid black pixels.
|
||||||
|
if (USE_WRAPAROUND_SPECULAR)
|
||||||
|
{
|
||||||
|
NdotV = NdotV * 0.9 + 0.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
NdotV = min(0.99, max(0.01, NdotV));
|
||||||
|
|
||||||
|
// A precomputed lookup table contains a scale and a bias term for specular intensity (called "fresnel" here).
|
||||||
|
// See equation (8) in Karis' course notes mentioned above.
|
||||||
|
vec2 envBRDF = texture( tex_brdf_lut, vec2(NdotV, 1.0-roughness) ).xy; // (NdotV,1-roughtness) for green top-left (NdotV,roughness) for green bottom-left
|
||||||
|
vec3 specular = prefiltered * (fresnel * envBRDF.x + vec3(envBRDF.y));
|
||||||
|
|
||||||
|
return specular;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
vec3 lighting() {
|
||||||
|
vec3 lit = vec3(0,0,0);
|
||||||
|
#ifndef SHADING_NONE
|
||||||
|
for (int i=0; i<u_num_lights; i++) {
|
||||||
|
#ifdef SHADING_PHONG
|
||||||
|
lit += shading_phong(u_lights[i]);
|
||||||
|
#endif
|
||||||
|
#ifdef SHADING_PBR
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return lit;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 sh_lighting(vec3 n) {
|
||||||
|
vec3 SHLightResult[9];
|
||||||
|
SHLightResult[0] = 0.282095f * u_coefficients_sh[0];
|
||||||
|
SHLightResult[1] = -0.488603f * u_coefficients_sh[1] * n.y;
|
||||||
|
SHLightResult[2] = 0.488603f * u_coefficients_sh[2] * n.z;
|
||||||
|
SHLightResult[3] = -0.488603f * u_coefficients_sh[3] * n.x;
|
||||||
|
SHLightResult[4] = 1.092548f * u_coefficients_sh[4] * n.x * n.y;
|
||||||
|
SHLightResult[5] = -1.092548f * u_coefficients_sh[5] * n.y * n.z;
|
||||||
|
SHLightResult[6] = 0.315392f * u_coefficients_sh[6] * (3.0f * n.z * n.z - 1.0f);
|
||||||
|
SHLightResult[7] = -1.092548f * u_coefficients_sh[7] * n.x * n.z;
|
||||||
|
SHLightResult[8] = 0.546274f * u_coefficients_sh[8] * (n.x * n.x - n.y * n.y);
|
||||||
|
vec3 result = vec3(0.0);
|
||||||
|
for (int i = 0; i < 9; ++i)
|
||||||
|
result += SHLightResult[i];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LIGHTMAP_BAKING
|
||||||
|
void main() {
|
||||||
|
vec3 n = normalize(v_normal_ws);
|
||||||
|
vec4 diffuse;
|
||||||
|
|
||||||
|
if(u_textured) {
|
||||||
|
diffuse = texture(u_texture2d, v_texcoord);
|
||||||
|
} else {
|
||||||
|
diffuse = u_diffuse; // * v_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (u_texlit) {
|
||||||
|
vec4 litsample = texture(u_lightmap, v_texcoord);
|
||||||
|
diffuse *= litsample;
|
||||||
|
}
|
||||||
|
|
||||||
|
fragcolor = vec4(diffuse.rgb*u_litboost, 1.0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SHADING_PHONG
|
||||||
|
void main() {
|
||||||
|
vec3 n = normalize(v_normal_ws);
|
||||||
|
|
||||||
|
vec4 lit = vec4(1.0, 1.0, 1.0, 1.0);
|
||||||
|
// SH lighting
|
||||||
|
if (!u_texlit) {
|
||||||
|
vec3 result = sh_lighting(n);
|
||||||
|
if( (result.x*result.x+result.y*result.y+result.z*result.z) > 0.0 ) lit = vec4(result, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// analytical lights
|
||||||
|
lit += vec4(lighting(), 0.0);
|
||||||
|
|
||||||
|
// base
|
||||||
|
vec4 diffuse;
|
||||||
|
|
||||||
|
if(u_matcaps) {
|
||||||
|
vec2 muv = vec2(view * vec4(v_normal_ws, 0))*0.5+vec2(0.5,0.5); // normal (model space) to view space
|
||||||
|
diffuse = texture(u_texture2d, vec2(muv.x, 1.0-muv.y));
|
||||||
|
} else if(u_textured) {
|
||||||
|
diffuse = texture(u_texture2d, v_texcoord);
|
||||||
|
} else {
|
||||||
|
diffuse = u_diffuse; // * v_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (u_texlit) {
|
||||||
|
vec4 litsample = texture(u_lightmap, v_texcoord);
|
||||||
|
|
||||||
|
if (u_texmod) {
|
||||||
|
diffuse *= litsample;
|
||||||
|
} else {
|
||||||
|
diffuse += litsample;
|
||||||
|
}
|
||||||
|
|
||||||
|
diffuse.rgb += sh_lighting(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
// lighting mix
|
||||||
|
fragcolor = diffuse * lit * shadowing();
|
||||||
|
|
||||||
|
// rimlight
|
||||||
|
#ifdef RIM
|
||||||
|
{
|
||||||
|
vec3 n = normalize(mat3(M) * v_normal); // 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, 1.0);}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef SHADING_PBR
|
||||||
|
void main(void)
|
||||||
|
{
|
||||||
|
vec3 baseColor = vec3( 0.5, 0.5, 0.5 );
|
||||||
|
float roughness = 1.0;
|
||||||
|
float metallic = 0.0;
|
||||||
|
float ao = 1.0;
|
||||||
|
float alpha = 1.0;
|
||||||
|
|
||||||
|
vec4 baseColor_alpha;
|
||||||
|
if ( map_albedo.has_tex )
|
||||||
|
baseColor_alpha = sample_colormap( map_albedo, v_texcoord );
|
||||||
|
else
|
||||||
|
baseColor_alpha = sample_colormap( map_diffuse, v_texcoord );
|
||||||
|
baseColor = baseColor_alpha.xyz;
|
||||||
|
alpha = baseColor_alpha.w;
|
||||||
|
|
||||||
|
if( map_metallic.has_tex && map_roughness.has_tex ) {
|
||||||
|
metallic = sample_colormap( map_metallic, v_texcoord ).x;
|
||||||
|
roughness = sample_colormap( map_roughness, v_texcoord ).x;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
roughness = sample_colormap( map_roughness, v_texcoord ).g;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( map_ao.has_tex )
|
||||||
|
ao = sample_colormap( map_ao, v_texcoord ).x;
|
||||||
|
else if ( map_ambient.has_tex )
|
||||||
|
ao = sample_colormap( map_ambient, v_texcoord ).x;
|
||||||
|
|
||||||
|
vec3 emissive = sample_colormap( map_emissive, v_texcoord ).rgb;
|
||||||
|
|
||||||
|
vec3 normalmap = texture( map_normals_tex, v_texcoord ).xyz * vec3(2.0) - vec3(1.0);
|
||||||
|
float normalmap_mip = textureQueryLod( map_normals_tex, v_texcoord ).x;
|
||||||
|
float normalmap_length = length(normalmap);
|
||||||
|
normalmap /= normalmap_length;
|
||||||
|
|
||||||
|
vec3 normal = v_normal_ws;
|
||||||
|
|
||||||
|
if ( map_normals.has_tex )
|
||||||
|
{
|
||||||
|
// Mikkelsen's tangent space normal map decoding. See http://mikktspace.com/ for rationale.
|
||||||
|
vec3 bi = cross( v_normal_ws, v_tangent );
|
||||||
|
vec3 nmap = normalmap.xyz;
|
||||||
|
normal = nmap.x * v_tangent + nmap.y * bi + nmap.z * v_normal_ws;
|
||||||
|
}
|
||||||
|
|
||||||
|
normal = normalize( normal );
|
||||||
|
|
||||||
|
if( USE_MAP_DEBUGGING && !USE_AMBIENT_DEBUGGING )
|
||||||
|
{
|
||||||
|
vec3 c = vec3(1., 0., 0.);
|
||||||
|
float x = gl_FragCoord.x / resolution.x;
|
||||||
|
float y = gl_FragCoord.y / resolution.y;
|
||||||
|
if ( y < (7.0/7.0) ) c = vec3(.5) + .5*v_normal_ws;
|
||||||
|
if ( y < (6.0/7.0) ) c = vec3(.5) + .5*normalmap;
|
||||||
|
if ( y < (5.0/7.0) ) c = vec3(ao);
|
||||||
|
if ( y < (4.0/7.0) ) c = vec3(emissive);
|
||||||
|
if ( y < (3.0/7.0) ) c = vec3(metallic);
|
||||||
|
if ( y < (2.0/7.0) ) c = vec3(roughness);
|
||||||
|
if ( y < (1.0/7.0) ) c = baseColor;
|
||||||
|
fragcolor = vec4(c, 1.);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (USE_NORMAL_VARIATION_TO_ROUGHNESS)
|
||||||
|
{
|
||||||
|
// Try to reduce specular aliasing by increasing roughness when minified normal maps have high variation.
|
||||||
|
float variation = 1. - pow( normalmap_length, 8. );
|
||||||
|
float minification = clamp( normalmap_mip - 2., 0., 1. );
|
||||||
|
roughness = mix( roughness, 1.0, variation * minification );
|
||||||
|
}
|
||||||
|
|
||||||
|
fragcolor = baseColor_alpha;
|
||||||
|
|
||||||
|
|
||||||
|
vec3 N = normal;
|
||||||
|
vec3 V = normalize( v_to_camera );
|
||||||
|
|
||||||
|
vec3 Lo = vec3(0.);
|
||||||
|
vec3 F0 = vec3(0.04);
|
||||||
|
F0 = mix( F0, baseColor, metallic );
|
||||||
|
|
||||||
|
bool use_ibl = has_tex_skysphere;
|
||||||
|
|
||||||
|
// Add contributions from analytic lights.
|
||||||
|
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < u_num_lights; i++ )
|
||||||
|
{
|
||||||
|
light_t l = u_lights[i];
|
||||||
|
vec3 lightDir;
|
||||||
|
float attenuation = 1.0;
|
||||||
|
|
||||||
|
if (l.type == LIGHT_DIRECTIONAL) {
|
||||||
|
lightDir = normalize(-l.dir);
|
||||||
|
} else if (l.type == LIGHT_POINT || l.type == LIGHT_SPOT) {
|
||||||
|
vec3 toLight = l.pos - v_position_ws;
|
||||||
|
lightDir = normalize(toLight);
|
||||||
|
float distance = length(toLight);
|
||||||
|
attenuation = 1.0 / (l.constant + l.linear * distance + l.quadratic * (distance * distance));
|
||||||
|
|
||||||
|
if (l.type == LIGHT_SPOT) {
|
||||||
|
float angle = dot(l.dir, -lightDir);
|
||||||
|
if (angle > l.outerCone) {
|
||||||
|
float intensity = (angle-l.outerCone)/(l.innerCone-l.outerCone);
|
||||||
|
attenuation *= clamp(intensity, 0.0, 1.0);
|
||||||
|
} else {
|
||||||
|
attenuation = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fast-rejection for faraway vertices
|
||||||
|
if (attenuation <= 0.01) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// vec3 n = normalize(v_normal_ws);
|
||||||
|
|
||||||
|
// float diffuse = max(dot(n, lightDir), 0.0);
|
||||||
|
|
||||||
|
// vec3 halfVec = normalize(lightDir + u_cam_dir);
|
||||||
|
// float specular = pow(max(dot(n, halfVec), 0.0), l.power);
|
||||||
|
|
||||||
|
// return (attenuation*l.ambient + diffuse*attenuation*l.diffuse + specular*attenuation*l.specular);
|
||||||
|
|
||||||
|
vec3 radiance = l.diffuse;
|
||||||
|
|
||||||
|
vec3 L = normalize( lightDir );
|
||||||
|
vec3 H = normalize( u_cam_dir + L );
|
||||||
|
|
||||||
|
vec3 F = fresnel_schlick( H, u_cam_dir, F0 );
|
||||||
|
vec3 kS = F;
|
||||||
|
vec3 kD = vec3(1.0) - kS;
|
||||||
|
kD *= 1.0 - metallic;
|
||||||
|
|
||||||
|
// Premultiplied alpha applied to the diffuse component only
|
||||||
|
kD *= alpha;
|
||||||
|
|
||||||
|
float D = distribution_ggx( N, H, roughness );
|
||||||
|
float G = geometry_smith( N, u_cam_dir, L, roughness );
|
||||||
|
|
||||||
|
vec3 num = D * F * G;
|
||||||
|
float denom = 4. * max( 0., dot( N, u_cam_dir ) ) * max( 0., dot( N, L ) );
|
||||||
|
|
||||||
|
vec3 specular = kS * (num / max( 0.001, denom ));
|
||||||
|
|
||||||
|
float NdotL = max( 0., dot( N, L ) );
|
||||||
|
|
||||||
|
Lo += ( kD * ( baseColor / PI ) + specular ) * radiance * NdotL * attenuation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 ambient = sample_colormap( map_ambient, v_texcoord ).xyz;
|
||||||
|
vec3 diffuse_ambient;
|
||||||
|
vec3 specular_ambient;
|
||||||
|
|
||||||
|
if ( use_ibl )
|
||||||
|
{
|
||||||
|
// Image based lighting.
|
||||||
|
// Based on https://learnopengl.com/PBR/IBL/Diffuse-irradiance
|
||||||
|
|
||||||
|
vec3 irradiance = vec3(0.);
|
||||||
|
|
||||||
|
if ( USE_BRUTEFORCE_IRRADIANCE )
|
||||||
|
{
|
||||||
|
irradiance = sample_irradiance_slow( normal, v_tangent );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
irradiance = sample_irradiance_fast( normal, v_tangent );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the Fresnel term for a perfect mirror reflection with L = R.
|
||||||
|
// In this case the halfway vector H = N.
|
||||||
|
//
|
||||||
|
// We use a modified Fresnel function that dampens specular reflections of very
|
||||||
|
// rough surfaces to avoid too bright pixels at grazing angles.
|
||||||
|
vec3 F = fresnel_schlick_roughness( N, V, F0, roughness );
|
||||||
|
vec3 kS = F;
|
||||||
|
|
||||||
|
// Subtract the amount of reflected light (specular) to get the energy left for
|
||||||
|
// absorbed (diffuse) light.
|
||||||
|
vec3 kD = vec3(1.) - kS;
|
||||||
|
|
||||||
|
// Metallic surfaces have only a specular reflection.
|
||||||
|
kD *= 1.0 - metallic;
|
||||||
|
|
||||||
|
// Premultiplied alpha applied to the diffuse component only
|
||||||
|
kD *= alpha;
|
||||||
|
|
||||||
|
// Modulate the incoming lighting with the diffuse color: some wavelengths get absorbed.
|
||||||
|
diffuse_ambient = irradiance * baseColor;
|
||||||
|
|
||||||
|
// Ambient light also has a specular part.
|
||||||
|
specular_ambient = specular_ibl( V, normal, roughness, F );
|
||||||
|
|
||||||
|
// Ambient occlusion tells us the fraction of sky light that reaches this point.
|
||||||
|
if (USE_SPECULAR_AO_ATTENUATION)
|
||||||
|
{
|
||||||
|
ambient = ao * (kD * diffuse_ambient + specular_ambient);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We don't attenuate specular_ambient ambient here with AO which might cause flickering in dark cavities.
|
||||||
|
ambient = ao * (kD * diffuse_ambient) + specular_ambient;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 color = (ambient + Lo) + emissive;
|
||||||
|
|
||||||
|
if ( USE_AMBIENT_DEBUGGING )
|
||||||
|
{
|
||||||
|
float y = gl_FragCoord.y / resolution.y;
|
||||||
|
if( USE_MAP_DEBUGGING && y > 0.5 )
|
||||||
|
{
|
||||||
|
if ( (y-0.5) < (7.0/7.0/2.0) ) color = vec3(.5) + .5*v_normal_ws;
|
||||||
|
if ( (y-0.5) < (6.0/7.0/2.0) ) color = vec3(.5) + .5*normalmap;
|
||||||
|
if ( (y-0.5) < (5.0/7.0/2.0) ) color = vec3(ao);
|
||||||
|
if ( (y-0.5) < (4.0/7.0/2.0) ) color = vec3(emissive);
|
||||||
|
if ( (y-0.5) < (3.0/7.0/2.0) ) color = vec3(metallic);
|
||||||
|
if ( (y-0.5) < (2.0/7.0/2.0) ) color = vec3(roughness);
|
||||||
|
if ( (y-0.5) < (1.0/7.0/2.0) ) color = baseColor;
|
||||||
|
} else {
|
||||||
|
float x = gl_FragCoord.x / resolution.x;
|
||||||
|
if ( x < 0.33 )
|
||||||
|
color = specular_ambient;
|
||||||
|
else if( x > 0.66 )
|
||||||
|
color = diffuse_ambient;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// dither with noise.
|
||||||
|
// float dither = random( uvec3( floatBitsToUint( gl_FragCoord.xy ), frame_count ) );
|
||||||
|
// color += BOOST_NOISE * vec3( (-1.0/256.) + (2./256.) * dither );
|
||||||
|
|
||||||
|
#if 0 // original
|
||||||
|
// basic tonemap and gamma correction
|
||||||
|
color = color / ( vec3(1.) + color );
|
||||||
|
color = pow( color, vec3(1. / 2.2) );
|
||||||
|
#elif 0
|
||||||
|
// filmic tonemapper
|
||||||
|
vec3 linearColor = color;
|
||||||
|
vec3 x = max(vec3(0.0), linearColor - 0.004);
|
||||||
|
color = (x * (6.2 * x + 0.5)) / (x * (6.2 * x + 1.7) + 0.06);
|
||||||
|
// gamma correction
|
||||||
|
// color = pow( color, vec3(1. / 2.2) );
|
||||||
|
#elif 1
|
||||||
|
// aces film (CC0, src: https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/)
|
||||||
|
vec3 x = color;
|
||||||
|
float a = 2.51f;
|
||||||
|
float b = 0.03f;
|
||||||
|
float c = 2.43f;
|
||||||
|
float d = 0.59f;
|
||||||
|
float e = 0.14f;
|
||||||
|
color = clamp((x*(a*x+b))/(x*(c*x+d)+e), 0.0, 1.0);
|
||||||
|
// gamma correction
|
||||||
|
color = pow( color, vec3(1. / 2.2) );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// 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, 1.0);}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -1,485 +1,485 @@
|
||||||
#version 400
|
#version 400
|
||||||
|
|
||||||
// original PBR shader by @seece (Public Domain). link: https://github.com/Gargaj/Foxotron/pull/12
|
// original PBR shader by @seece (Public Domain). link: https://github.com/Gargaj/Foxotron/pull/12
|
||||||
|
|
||||||
//#define textureQueryLod(t,c) vec2(0.0,0.0) // #version 400 required
|
//#define textureQueryLod(t,c) vec2(0.0,0.0) // #version 400 required
|
||||||
|
|
||||||
uniform vec2 resolution = vec2(640.0,480.0); // debug options below use this (USE_MAP_DEBUGGING, USE_AMBIENT_DEBUGGING)
|
uniform vec2 resolution = vec2(640.0,480.0); // debug options below use this (USE_MAP_DEBUGGING, USE_AMBIENT_DEBUGGING)
|
||||||
|
|
||||||
#define USE_BRUTEFORCE_IRRADIANCE false // Samples irradiance from tex_skysphere when enabled.
|
#define USE_BRUTEFORCE_IRRADIANCE false // Samples irradiance from tex_skysphere when enabled.
|
||||||
#define USE_WRAPAROUND_SPECULAR true // Makes silhouettes more reflective to avoid black pixels.
|
#define USE_WRAPAROUND_SPECULAR true // Makes silhouettes more reflective to avoid black pixels.
|
||||||
#define USE_SPECULAR_AO_ATTENUATION true // Dampens IBL specular ambient with AO if enabled.
|
#define USE_SPECULAR_AO_ATTENUATION true // Dampens IBL specular ambient with AO if enabled.
|
||||||
#define USE_NORMAL_VARIATION_TO_ROUGHNESS true // Increases roughness if normal map has variation and was minified.
|
#define USE_NORMAL_VARIATION_TO_ROUGHNESS true // Increases roughness if normal map has variation and was minified.
|
||||||
#define USE_MAP_DEBUGGING false // Shows all ColorMaps as horizontal bars
|
#define USE_MAP_DEBUGGING false // Shows all ColorMaps as horizontal bars
|
||||||
#define USE_AMBIENT_DEBUGGING false // Splits the screen in two and shows image-based specular (left), full shading (middle), diffuse shading (right).
|
#define USE_AMBIENT_DEBUGGING false // Splits the screen in two and shows image-based specular (left), full shading (middle), diffuse shading (right).
|
||||||
#define BOOST_LIGHTING 2.00f // Multiplies analytic light's color with this constant because otherwise they look really pathetic.
|
#define BOOST_LIGHTING 2.00f // Multiplies analytic light's color with this constant because otherwise they look really pathetic.
|
||||||
#define BOOST_SPECULAR 1.50f
|
#define BOOST_SPECULAR 1.50f
|
||||||
#define BOOST_NOISE 2.50f
|
#define BOOST_NOISE 2.50f
|
||||||
|
|
||||||
struct Light
|
struct Light
|
||||||
{
|
{
|
||||||
vec3 direction;
|
vec3 direction;
|
||||||
vec3 color;
|
vec3 color;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ColorMap
|
struct ColorMap
|
||||||
{
|
{
|
||||||
bool has_tex;
|
bool has_tex;
|
||||||
vec4 color;
|
vec4 color;
|
||||||
};
|
};
|
||||||
|
|
||||||
uniform ColorMap map_albedo; uniform sampler2D map_albedo_tex;
|
uniform ColorMap map_albedo; uniform sampler2D map_albedo_tex;
|
||||||
uniform ColorMap map_diffuse; uniform sampler2D map_diffuse_tex;
|
uniform ColorMap map_diffuse; uniform sampler2D map_diffuse_tex;
|
||||||
uniform ColorMap map_specular; uniform sampler2D map_specular_tex; // not used
|
uniform ColorMap map_specular; uniform sampler2D map_specular_tex; // not used
|
||||||
uniform ColorMap map_normals; uniform sampler2D map_normals_tex;
|
uniform ColorMap map_normals; uniform sampler2D map_normals_tex;
|
||||||
uniform ColorMap map_roughness; uniform sampler2D map_roughness_tex;
|
uniform ColorMap map_roughness; uniform sampler2D map_roughness_tex;
|
||||||
uniform ColorMap map_metallic; uniform sampler2D map_metallic_tex;
|
uniform ColorMap map_metallic; uniform sampler2D map_metallic_tex;
|
||||||
uniform ColorMap map_ao; uniform sampler2D map_ao_tex;
|
uniform ColorMap map_ao; uniform sampler2D map_ao_tex;
|
||||||
uniform ColorMap map_ambient; uniform sampler2D map_ambient_tex;
|
uniform ColorMap map_ambient; uniform sampler2D map_ambient_tex;
|
||||||
uniform ColorMap map_emissive; uniform sampler2D map_emissive_tex;
|
uniform ColorMap map_emissive; uniform sampler2D map_emissive_tex;
|
||||||
|
|
||||||
#define sample_colormap(ColorMap_, uv_) \
|
#define sample_colormap(ColorMap_, uv_) \
|
||||||
(ColorMap_.has_tex ? texture( ColorMap_##_tex, uv_ ) : ColorMap_.color)
|
(ColorMap_.has_tex ? texture( ColorMap_##_tex, uv_ ) : ColorMap_.color)
|
||||||
|
|
||||||
in vec3 out_normal;
|
in vec3 out_normal;
|
||||||
in vec3 out_tangent;
|
in vec3 out_tangent;
|
||||||
in vec3 out_binormal;
|
in vec3 out_binormal;
|
||||||
in vec2 out_texcoord;
|
in vec2 out_texcoord;
|
||||||
in vec3 out_worldpos;
|
in vec3 out_worldpos;
|
||||||
in vec3 out_to_camera;
|
in vec3 out_to_camera;
|
||||||
|
|
||||||
uniform float skysphere_rotation;
|
uniform float skysphere_rotation;
|
||||||
uniform float skysphere_mip_count;
|
uniform float skysphere_mip_count;
|
||||||
uniform float exposure;
|
uniform float exposure;
|
||||||
uniform uint frame_count;
|
uniform uint frame_count;
|
||||||
uniform float specular_shininess;
|
uniform float specular_shininess;
|
||||||
|
|
||||||
uniform vec3 camera_position;
|
uniform vec3 camera_position;
|
||||||
uniform Light lights[3];
|
uniform Light lights[3];
|
||||||
|
|
||||||
uniform sampler2D tex_skysphere;
|
uniform sampler2D tex_skysphere;
|
||||||
uniform sampler2D tex_skyenv;
|
uniform sampler2D tex_skyenv;
|
||||||
uniform sampler2D tex_brdf_lut;
|
uniform sampler2D tex_brdf_lut;
|
||||||
|
|
||||||
uniform bool has_tex_skysphere;
|
uniform bool has_tex_skysphere;
|
||||||
uniform bool has_tex_skyenv;
|
uniform bool has_tex_skyenv;
|
||||||
|
|
||||||
out vec4 frag_color;
|
out vec4 frag_color;
|
||||||
|
|
||||||
const float PI = 3.1415926536;
|
const float PI = 3.1415926536;
|
||||||
|
|
||||||
// MurMurHash 3 finalizer. Implementation is in public domain.
|
// MurMurHash 3 finalizer. Implementation is in public domain.
|
||||||
uint hash( uint h )
|
uint hash( uint h )
|
||||||
{
|
{
|
||||||
h ^= h >> 16;
|
h ^= h >> 16;
|
||||||
h *= 0x85ebca6bU;
|
h *= 0x85ebca6bU;
|
||||||
h ^= h >> 13;
|
h ^= h >> 13;
|
||||||
h *= 0xc2b2ae35U;
|
h *= 0xc2b2ae35U;
|
||||||
h ^= h >> 16;
|
h ^= h >> 16;
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Random function using the idea of StackOverflow user "Spatial" https://stackoverflow.com/a/17479300
|
// Random function using the idea of StackOverflow user "Spatial" https://stackoverflow.com/a/17479300
|
||||||
// Creates random 23 bits and puts them into the fraction bits of an 32-bit float.
|
// Creates random 23 bits and puts them into the fraction bits of an 32-bit float.
|
||||||
float random( uvec3 h )
|
float random( uvec3 h )
|
||||||
{
|
{
|
||||||
uint m = hash(h.x ^ hash( h.y ) ^ hash( h.z ));
|
uint m = hash(h.x ^ hash( h.y ) ^ hash( h.z ));
|
||||||
return uintBitsToFloat( ( m & 0x007FFFFFu ) | 0x3f800000u ) - 1.;
|
return uintBitsToFloat( ( m & 0x007FFFFFu ) | 0x3f800000u ) - 1.;
|
||||||
}
|
}
|
||||||
|
|
||||||
float random( vec3 v )
|
float random( vec3 v )
|
||||||
{
|
{
|
||||||
return random(floatBitsToUint( v ));
|
return random(floatBitsToUint( v ));
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 fresnel_schlick( vec3 H, vec3 V, vec3 F0 )
|
vec3 fresnel_schlick( vec3 H, vec3 V, vec3 F0 )
|
||||||
{
|
{
|
||||||
float cosTheta = clamp( dot( H, V ), 0., 1. );
|
float cosTheta = clamp( dot( H, V ), 0., 1. );
|
||||||
return F0 + ( vec3( 1.0 ) - F0 ) * pow( 1. - cosTheta, 5.0 );
|
return F0 + ( vec3( 1.0 ) - F0 ) * pow( 1. - cosTheta, 5.0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Fresnel term that dampens rough specular reflections.
|
// A Fresnel term that dampens rough specular reflections.
|
||||||
// https://seblagarde.wordpress.com/2011/08/17/hello-world/
|
// https://seblagarde.wordpress.com/2011/08/17/hello-world/
|
||||||
vec3 fresnel_schlick_roughness( vec3 H, vec3 V, vec3 F0, float roughness )
|
vec3 fresnel_schlick_roughness( vec3 H, vec3 V, vec3 F0, float roughness )
|
||||||
{
|
{
|
||||||
float cosTheta = clamp( dot( H, V ), 0., 1. );
|
float cosTheta = clamp( dot( H, V ), 0., 1. );
|
||||||
return F0 + ( max( vec3( 1.0 - roughness ), F0 ) - F0 ) * pow( 1. - cosTheta, 5.0 );
|
return F0 + ( max( vec3( 1.0 - roughness ), F0 ) - F0 ) * pow( 1. - cosTheta, 5.0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
float distribution_ggx( vec3 N, vec3 H, float roughness )
|
float distribution_ggx( vec3 N, vec3 H, float roughness )
|
||||||
{
|
{
|
||||||
float a = roughness * roughness;
|
float a = roughness * roughness;
|
||||||
float a2 = a * a;
|
float a2 = a * a;
|
||||||
float NdotH = max( 0., dot( N, H ) );
|
float NdotH = max( 0., dot( N, H ) );
|
||||||
float factor = NdotH * NdotH * ( a2 - 1. ) + 1.;
|
float factor = NdotH * NdotH * ( a2 - 1. ) + 1.;
|
||||||
|
|
||||||
return a2 / ( PI * factor * factor );
|
return a2 / ( PI * factor * factor );
|
||||||
}
|
}
|
||||||
|
|
||||||
float geometry_schlick_ggx( vec3 N, vec3 V, float k )
|
float geometry_schlick_ggx( vec3 N, vec3 V, float k )
|
||||||
{
|
{
|
||||||
float NdotV = max( 0., dot( N, V ) );
|
float NdotV = max( 0., dot( N, V ) );
|
||||||
return NdotV / (NdotV * ( 1. - k ) + k );
|
return NdotV / (NdotV * ( 1. - k ) + k );
|
||||||
}
|
}
|
||||||
|
|
||||||
float geometry_smith( vec3 N, vec3 V, vec3 L, float roughness )
|
float geometry_smith( vec3 N, vec3 V, vec3 L, float roughness )
|
||||||
{
|
{
|
||||||
#if 1 // original
|
#if 1 // original
|
||||||
float r = roughness + 1.;
|
float r = roughness + 1.;
|
||||||
float k = (r * r) / 8.;
|
float k = (r * r) / 8.;
|
||||||
#elif 0 // vries
|
#elif 0 // vries
|
||||||
float a = roughness;
|
float a = roughness;
|
||||||
float k = (a * a) / 2.0;
|
float k = (a * a) / 2.0;
|
||||||
#elif 0 // vries improved?
|
#elif 0 // vries improved?
|
||||||
float a = roughness * roughness;
|
float a = roughness * roughness;
|
||||||
float k = a / 2.0;
|
float k = a / 2.0;
|
||||||
#endif
|
#endif
|
||||||
return geometry_schlick_ggx( N, V, k ) * geometry_schlick_ggx( N, L, k );
|
return geometry_schlick_ggx( N, V, k ) * geometry_schlick_ggx( N, L, k );
|
||||||
}
|
}
|
||||||
|
|
||||||
vec2 sphere_to_polar( vec3 normal )
|
vec2 sphere_to_polar( vec3 normal )
|
||||||
{
|
{
|
||||||
normal = normalize( 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 ) + skysphere_rotation ) / 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.
|
// Our vertically GL_CLAMPed textures seem to blend towards black when sampling the half-pixel edge.
|
||||||
// Not sure if it has a border, or this if is a driver bug, but can repro on multiple nvidia cards.
|
// Not sure if it has a border, or this if is a driver bug, but can repro on multiple nvidia cards.
|
||||||
// Knowing the texture height we can limit sampling to the centers of the top and bottom pixel rows.
|
// Knowing the texture height we can limit sampling to the centers of the top and bottom pixel rows.
|
||||||
vec2 sphere_to_polar_clamp_y( vec3 normal, float texture_height )
|
vec2 sphere_to_polar_clamp_y( vec3 normal, float texture_height )
|
||||||
{
|
{
|
||||||
normal = normalize( normal );
|
normal = normalize( normal );
|
||||||
return vec2( ( atan( normal.z, normal.x ) + skysphere_rotation ) / PI / 2.0 + 0.5, clamp(acos( normal.y ) / PI, 0.5 / texture_height, 1.0 - 0.5 / texture_height) );
|
return vec2( ( atan( normal.z, normal.x ) + skysphere_rotation ) / PI / 2.0 + 0.5, clamp(acos( normal.y ) / PI, 0.5 / texture_height, 1.0 - 0.5 / texture_height) );
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 sample_sky( vec3 normal )
|
vec3 sample_sky( vec3 normal )
|
||||||
{
|
{
|
||||||
vec2 polar = sphere_to_polar( normal );
|
vec2 polar = sphere_to_polar( normal );
|
||||||
return texture( tex_skysphere, polar ).rgb * exposure;
|
return texture( tex_skysphere, polar ).rgb * exposure;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Takes samples around the hemisphere, converts them to radiances via weighting and
|
// Takes samples around the hemisphere, converts them to radiances via weighting and
|
||||||
// returns a normalized sum.
|
// returns a normalized sum.
|
||||||
vec3 sample_irradiance_slow( vec3 normal, vec3 vertex_tangent )
|
vec3 sample_irradiance_slow( vec3 normal, vec3 vertex_tangent )
|
||||||
{
|
{
|
||||||
float delta = 0.10;
|
float delta = 0.10;
|
||||||
|
|
||||||
vec3 up = abs( normal.y ) < 0.999 ? vec3( 0., 1., 0. ) : vec3( 0., 0., 1. );
|
vec3 up = abs( normal.y ) < 0.999 ? vec3( 0., 1., 0. ) : vec3( 0., 0., 1. );
|
||||||
vec3 tangent_x = normalize( cross( up, normal ) );
|
vec3 tangent_x = normalize( cross( up, normal ) );
|
||||||
vec3 tangent_y = cross( normal, tangent_x );
|
vec3 tangent_y = cross( normal, tangent_x );
|
||||||
|
|
||||||
int numIrradianceSamples = 0;
|
int numIrradianceSamples = 0;
|
||||||
|
|
||||||
vec3 irradiance = vec3(0.);
|
vec3 irradiance = vec3(0.);
|
||||||
|
|
||||||
for ( float phi = 0.; phi < 2. * PI ; phi += delta )
|
for ( float phi = 0.; phi < 2. * PI ; phi += delta )
|
||||||
{
|
{
|
||||||
for ( float theta = 0.; theta < 0.5 * PI; theta += delta )
|
for ( float theta = 0.; theta < 0.5 * PI; theta += delta )
|
||||||
{
|
{
|
||||||
vec3 tangent_space = vec3(
|
vec3 tangent_space = vec3(
|
||||||
sin( theta ) * cos( phi ),
|
sin( theta ) * cos( phi ),
|
||||||
sin( theta ) * sin( phi ),
|
sin( theta ) * sin( phi ),
|
||||||
cos( theta ) );
|
cos( theta ) );
|
||||||
|
|
||||||
vec3 world_space = tangent_space.x * tangent_x + tangent_space.y + tangent_y + tangent_space.z * normal;
|
vec3 world_space = tangent_space.x * tangent_x + tangent_space.y + tangent_y + tangent_space.z * normal;
|
||||||
|
|
||||||
vec3 color = sample_sky( world_space );
|
vec3 color = sample_sky( world_space );
|
||||||
irradiance += color * cos( theta ) * sin( theta );
|
irradiance += color * cos( theta ) * sin( theta );
|
||||||
numIrradianceSamples++;
|
numIrradianceSamples++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
irradiance = PI * irradiance / float( numIrradianceSamples );
|
irradiance = PI * irradiance / float( numIrradianceSamples );
|
||||||
return irradiance;
|
return irradiance;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 sample_irradiance_fast( vec3 normal, vec3 vertex_tangent )
|
vec3 sample_irradiance_fast( vec3 normal, vec3 vertex_tangent )
|
||||||
{
|
{
|
||||||
// Sample the irradiance map if it exists, otherwise fall back to blurred reflection map.
|
// Sample the irradiance map if it exists, otherwise fall back to blurred reflection map.
|
||||||
if ( has_tex_skyenv )
|
if ( has_tex_skyenv )
|
||||||
{
|
{
|
||||||
vec2 polar = sphere_to_polar_clamp_y( normal, 180.0 );
|
vec2 polar = sphere_to_polar_clamp_y( normal, 180.0 );
|
||||||
return textureLod( tex_skyenv, polar, 0.0 ).rgb * exposure;
|
return textureLod( tex_skyenv, polar, 0.0 ).rgb * exposure;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
vec2 polar = sphere_to_polar( normal );
|
vec2 polar = sphere_to_polar( normal );
|
||||||
return textureLod( tex_skysphere, polar, 0.80 * skysphere_mip_count ).rgb * exposure;
|
return textureLod( tex_skysphere, polar, 0.80 * skysphere_mip_count ).rgb * exposure;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
vec3 specular_ibl( vec3 V, vec3 N, float roughness, vec3 fresnel )
|
vec3 specular_ibl( vec3 V, vec3 N, float roughness, vec3 fresnel )
|
||||||
{
|
{
|
||||||
// What we'd like to do here is take a LOT of skybox samples around the reflection
|
// What we'd like to do here is take a LOT of skybox samples around the reflection
|
||||||
// vector R according to the BRDF lobe.
|
// vector R according to the BRDF lobe.
|
||||||
//
|
//
|
||||||
// Unfortunately it's not possible in real time so we use the following UE4 style approximations:
|
// Unfortunately it's not possible in real time so we use the following UE4 style approximations:
|
||||||
// 1. Integrate incoming light and BRDF separately ("split sum approximation")
|
// 1. Integrate incoming light and BRDF separately ("split sum approximation")
|
||||||
// 2. Assume V = R = N so that we can just blur the skybox and sample that.
|
// 2. Assume V = R = N so that we can just blur the skybox and sample that.
|
||||||
// 3. Bake the BRDF integral into a lookup texture so that it can be computed in constant time.
|
// 3. Bake the BRDF integral into a lookup texture so that it can be computed in constant time.
|
||||||
//
|
//
|
||||||
// Here we also simplify approximation #2 by using bilinear mipmaps with a magic formula instead
|
// Here we also simplify approximation #2 by using bilinear mipmaps with a magic formula instead
|
||||||
// of properly convolving it with a GGX lobe.
|
// of properly convolving it with a GGX lobe.
|
||||||
//
|
//
|
||||||
// For details, see Brian Karis, "Real Shading in Unreal Engine 4", 2013.
|
// For details, see Brian Karis, "Real Shading in Unreal Engine 4", 2013.
|
||||||
|
|
||||||
vec3 R = 2. * dot( V, N ) * N - V;
|
vec3 R = 2. * dot( V, N ) * N - V;
|
||||||
|
|
||||||
vec2 polar = sphere_to_polar( R );
|
vec2 polar = sphere_to_polar( R );
|
||||||
|
|
||||||
// Map roughness from range [0, 1] into a mip LOD [0, skysphere_mip_count].
|
// Map roughness from range [0, 1] into a mip LOD [0, skysphere_mip_count].
|
||||||
// The magic numbers were chosen empirically.
|
// The magic numbers were chosen empirically.
|
||||||
|
|
||||||
float mip = 0.9 * skysphere_mip_count * pow(roughness, 0.25 * BOOST_SPECULAR);
|
float mip = 0.9 * skysphere_mip_count * pow(roughness, 0.25 * BOOST_SPECULAR);
|
||||||
|
|
||||||
vec3 prefiltered = textureLod( tex_skysphere, polar, mip ).rgb * exposure;
|
vec3 prefiltered = textureLod( tex_skysphere, polar, mip ).rgb * exposure;
|
||||||
|
|
||||||
float NdotV = dot( N, V );
|
float NdotV = dot( N, V );
|
||||||
|
|
||||||
// dot( N, V ) seems to produce negative values so we can try to stretch it a bit behind the silhouette
|
// dot( N, V ) seems to produce negative values so we can try to stretch it a bit behind the silhouette
|
||||||
// to avoid black pixels.
|
// to avoid black pixels.
|
||||||
if (USE_WRAPAROUND_SPECULAR)
|
if (USE_WRAPAROUND_SPECULAR)
|
||||||
{
|
{
|
||||||
NdotV = NdotV * 0.9 + 0.1;
|
NdotV = NdotV * 0.9 + 0.1;
|
||||||
}
|
}
|
||||||
|
|
||||||
NdotV = min(0.99, max(0.01, NdotV));
|
NdotV = min(0.99, max(0.01, NdotV));
|
||||||
|
|
||||||
// A precomputed lookup table contains a scale and a bias term for specular intensity (called "fresnel" here).
|
// A precomputed lookup table contains a scale and a bias term for specular intensity (called "fresnel" here).
|
||||||
// See equation (8) in Karis' course notes mentioned above.
|
// See equation (8) in Karis' course notes mentioned above.
|
||||||
vec2 envBRDF = texture( tex_brdf_lut, vec2(NdotV, 1.0-roughness) ).xy; // (NdotV,1-roughtness) for green top-left (NdotV,roughness) for green bottom-left
|
vec2 envBRDF = texture( tex_brdf_lut, vec2(NdotV, 1.0-roughness) ).xy; // (NdotV,1-roughtness) for green top-left (NdotV,roughness) for green bottom-left
|
||||||
vec3 specular = prefiltered * (fresnel * envBRDF.x + vec3(envBRDF.y));
|
vec3 specular = prefiltered * (fresnel * envBRDF.x + vec3(envBRDF.y));
|
||||||
|
|
||||||
return specular;
|
return specular;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void main(void)
|
void main(void)
|
||||||
{
|
{
|
||||||
vec3 baseColor = vec3( 0.5, 0.5, 0.5 );
|
vec3 baseColor = vec3( 0.5, 0.5, 0.5 );
|
||||||
float roughness = 1.0;
|
float roughness = 1.0;
|
||||||
float metallic = 0.0;
|
float metallic = 0.0;
|
||||||
float ao = 1.0;
|
float ao = 1.0;
|
||||||
float alpha = 1.0;
|
float alpha = 1.0;
|
||||||
|
|
||||||
vec4 baseColor_alpha;
|
vec4 baseColor_alpha;
|
||||||
if ( map_albedo.has_tex )
|
if ( map_albedo.has_tex )
|
||||||
baseColor_alpha = sample_colormap( map_albedo, out_texcoord );
|
baseColor_alpha = sample_colormap( map_albedo, out_texcoord );
|
||||||
else
|
else
|
||||||
baseColor_alpha = sample_colormap( map_diffuse, out_texcoord );
|
baseColor_alpha = sample_colormap( map_diffuse, out_texcoord );
|
||||||
baseColor = baseColor_alpha.xyz;
|
baseColor = baseColor_alpha.xyz;
|
||||||
alpha = baseColor_alpha.w;
|
alpha = baseColor_alpha.w;
|
||||||
|
|
||||||
if( map_metallic.has_tex && map_roughness.has_tex ) {
|
if( map_metallic.has_tex && map_roughness.has_tex ) {
|
||||||
metallic = sample_colormap( map_metallic, out_texcoord ).x;
|
metallic = sample_colormap( map_metallic, out_texcoord ).x;
|
||||||
roughness = sample_colormap( map_roughness, out_texcoord ).x;
|
roughness = sample_colormap( map_roughness, out_texcoord ).x;
|
||||||
}
|
}
|
||||||
else if( map_roughness.has_tex ) {
|
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)
|
//< @r-lyeh, metalness B, roughness G, (@todo: self-shadowing occlusion R; for now, any of R/B are metallic)
|
||||||
metallic = sample_colormap( map_roughness, out_texcoord ).b + sample_colormap( map_roughness, out_texcoord ).r;
|
metallic = sample_colormap( map_roughness, out_texcoord ).b + sample_colormap( map_roughness, out_texcoord ).r;
|
||||||
roughness = sample_colormap( map_roughness, out_texcoord ).g;
|
roughness = sample_colormap( map_roughness, out_texcoord ).g;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( map_ao.has_tex )
|
if ( map_ao.has_tex )
|
||||||
ao = sample_colormap( map_ao, out_texcoord ).x;
|
ao = sample_colormap( map_ao, out_texcoord ).x;
|
||||||
else if ( map_ambient.has_tex )
|
else if ( map_ambient.has_tex )
|
||||||
ao = sample_colormap( map_ambient, out_texcoord ).x;
|
ao = sample_colormap( map_ambient, out_texcoord ).x;
|
||||||
|
|
||||||
vec3 emissive = sample_colormap( map_emissive, out_texcoord ).rgb;
|
vec3 emissive = sample_colormap( map_emissive, out_texcoord ).rgb;
|
||||||
|
|
||||||
vec3 normalmap = texture( map_normals_tex, out_texcoord ).xyz * vec3(2.0) - vec3(1.0);
|
vec3 normalmap = texture( map_normals_tex, out_texcoord ).xyz * vec3(2.0) - vec3(1.0);
|
||||||
float normalmap_mip = textureQueryLod( map_normals_tex, out_texcoord ).x;
|
float normalmap_mip = textureQueryLod( map_normals_tex, out_texcoord ).x;
|
||||||
float normalmap_length = length(normalmap);
|
float normalmap_length = length(normalmap);
|
||||||
normalmap /= normalmap_length;
|
normalmap /= normalmap_length;
|
||||||
|
|
||||||
vec3 normal = out_normal;
|
vec3 normal = out_normal;
|
||||||
|
|
||||||
if ( map_normals.has_tex )
|
if ( map_normals.has_tex )
|
||||||
{
|
{
|
||||||
// Mikkelsen's tangent space normal map decoding. See http://mikktspace.com/ for rationale.
|
// Mikkelsen's tangent space normal map decoding. See http://mikktspace.com/ for rationale.
|
||||||
vec3 bi = cross( out_normal, out_tangent );
|
vec3 bi = cross( out_normal, out_tangent );
|
||||||
vec3 nmap = normalmap.xyz;
|
vec3 nmap = normalmap.xyz;
|
||||||
normal = nmap.x * out_tangent + nmap.y * bi + nmap.z * out_normal;
|
normal = nmap.x * out_tangent + nmap.y * bi + nmap.z * out_normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
normal = normalize( normal );
|
normal = normalize( normal );
|
||||||
|
|
||||||
if( USE_MAP_DEBUGGING && !USE_AMBIENT_DEBUGGING )
|
if( USE_MAP_DEBUGGING && !USE_AMBIENT_DEBUGGING )
|
||||||
{
|
{
|
||||||
vec3 c = vec3(1., 0., 0.);
|
vec3 c = vec3(1., 0., 0.);
|
||||||
float x = gl_FragCoord.x / resolution.x;
|
float x = gl_FragCoord.x / resolution.x;
|
||||||
float y = gl_FragCoord.y / resolution.y;
|
float y = gl_FragCoord.y / resolution.y;
|
||||||
if ( y < (7.0/7.0) ) c = vec3(.5) + .5*out_normal;
|
if ( y < (7.0/7.0) ) c = vec3(.5) + .5*out_normal;
|
||||||
if ( y < (6.0/7.0) ) c = vec3(.5) + .5*normalmap;
|
if ( y < (6.0/7.0) ) c = vec3(.5) + .5*normalmap;
|
||||||
if ( y < (5.0/7.0) ) c = vec3(ao);
|
if ( y < (5.0/7.0) ) c = vec3(ao);
|
||||||
if ( y < (4.0/7.0) ) c = vec3(emissive);
|
if ( y < (4.0/7.0) ) c = vec3(emissive);
|
||||||
if ( y < (3.0/7.0) ) c = vec3(metallic);
|
if ( y < (3.0/7.0) ) c = vec3(metallic);
|
||||||
if ( y < (2.0/7.0) ) c = vec3(roughness);
|
if ( y < (2.0/7.0) ) c = vec3(roughness);
|
||||||
if ( y < (1.0/7.0) ) c = baseColor;
|
if ( y < (1.0/7.0) ) c = baseColor;
|
||||||
frag_color = vec4(c, 1.);
|
frag_color = vec4(c, 1.);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (USE_NORMAL_VARIATION_TO_ROUGHNESS)
|
if (USE_NORMAL_VARIATION_TO_ROUGHNESS)
|
||||||
{
|
{
|
||||||
// Try to reduce specular aliasing by increasing roughness when minified normal maps have high variation.
|
// Try to reduce specular aliasing by increasing roughness when minified normal maps have high variation.
|
||||||
float variation = 1. - pow( normalmap_length, 8. );
|
float variation = 1. - pow( normalmap_length, 8. );
|
||||||
float minification = clamp( normalmap_mip - 2., 0., 1. );
|
float minification = clamp( normalmap_mip - 2., 0., 1. );
|
||||||
roughness = mix( roughness, 1.0, variation * minification );
|
roughness = mix( roughness, 1.0, variation * minification );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
vec3 N = normal;
|
vec3 N = normal;
|
||||||
vec3 V = normalize( out_to_camera );
|
vec3 V = normalize( out_to_camera );
|
||||||
|
|
||||||
vec3 Lo = vec3(0.);
|
vec3 Lo = vec3(0.);
|
||||||
vec3 F0 = vec3(0.04);
|
vec3 F0 = vec3(0.04);
|
||||||
F0 = mix( F0, baseColor, metallic );
|
F0 = mix( F0, baseColor, metallic );
|
||||||
|
|
||||||
bool use_ibl = has_tex_skysphere;
|
bool use_ibl = has_tex_skysphere;
|
||||||
|
|
||||||
// Add contributions from analytic lights only if we don't have a skybox.
|
// Add contributions from analytic lights only if we don't have a skybox.
|
||||||
|
|
||||||
{
|
{
|
||||||
int num_lights = use_ibl ? 1 : lights.length();
|
int num_lights = use_ibl ? 1 : lights.length();
|
||||||
for ( int i = 0; i < num_lights; i++ )
|
for ( int i = 0; i < num_lights; i++ )
|
||||||
{
|
{
|
||||||
vec3 radiance = lights[ i ].color * BOOST_LIGHTING;
|
vec3 radiance = lights[ i ].color * BOOST_LIGHTING;
|
||||||
|
|
||||||
vec3 L = -normalize( lights[ i ].direction );
|
vec3 L = -normalize( lights[ i ].direction );
|
||||||
vec3 H = normalize( V + L );
|
vec3 H = normalize( V + L );
|
||||||
|
|
||||||
vec3 F = fresnel_schlick( H, V, F0 );
|
vec3 F = fresnel_schlick( H, V, F0 );
|
||||||
vec3 kS = F;
|
vec3 kS = F;
|
||||||
vec3 kD = vec3(1.0) - kS;
|
vec3 kD = vec3(1.0) - kS;
|
||||||
kD *= 1.0 - metallic;
|
kD *= 1.0 - metallic;
|
||||||
|
|
||||||
// Premultiplied alpha applied to the diffuse component only
|
// Premultiplied alpha applied to the diffuse component only
|
||||||
kD *= alpha;
|
kD *= alpha;
|
||||||
|
|
||||||
float D = distribution_ggx( N, H, roughness );
|
float D = distribution_ggx( N, H, roughness );
|
||||||
float G = geometry_smith( N, V, L, roughness );
|
float G = geometry_smith( N, V, L, roughness );
|
||||||
|
|
||||||
vec3 num = D * F * G;
|
vec3 num = D * F * G;
|
||||||
float denom = 4. * max( 0., dot( N, V ) ) * max( 0., dot( N, L ) );
|
float denom = 4. * max( 0., dot( N, V ) ) * max( 0., dot( N, L ) );
|
||||||
|
|
||||||
vec3 specular = kS * (num / max( 0.001, denom ));
|
vec3 specular = kS * (num / max( 0.001, denom ));
|
||||||
|
|
||||||
float NdotL = max( 0., dot( N, L ) );
|
float NdotL = max( 0., dot( N, L ) );
|
||||||
|
|
||||||
Lo += ( kD * ( baseColor / PI ) + specular ) * radiance * NdotL;
|
Lo += ( kD * ( baseColor / PI ) + specular ) * radiance * NdotL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 ambient = sample_colormap( map_ambient, out_texcoord ).xyz;
|
vec3 ambient = sample_colormap( map_ambient, out_texcoord ).xyz;
|
||||||
vec3 diffuse_ambient;
|
vec3 diffuse_ambient;
|
||||||
vec3 specular_ambient;
|
vec3 specular_ambient;
|
||||||
|
|
||||||
if ( use_ibl )
|
if ( use_ibl )
|
||||||
{
|
{
|
||||||
// Image based lighting.
|
// Image based lighting.
|
||||||
// Based on https://learnopengl.com/PBR/IBL/Diffuse-irradiance
|
// Based on https://learnopengl.com/PBR/IBL/Diffuse-irradiance
|
||||||
|
|
||||||
vec3 irradiance = vec3(0.);
|
vec3 irradiance = vec3(0.);
|
||||||
|
|
||||||
if ( USE_BRUTEFORCE_IRRADIANCE )
|
if ( USE_BRUTEFORCE_IRRADIANCE )
|
||||||
{
|
{
|
||||||
irradiance = sample_irradiance_slow( normal, out_tangent );
|
irradiance = sample_irradiance_slow( normal, out_tangent );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
irradiance = sample_irradiance_fast( normal, out_tangent );
|
irradiance = sample_irradiance_fast( normal, out_tangent );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute the Fresnel term for a perfect mirror reflection with L = R.
|
// Compute the Fresnel term for a perfect mirror reflection with L = R.
|
||||||
// In this case the halfway vector H = N.
|
// In this case the halfway vector H = N.
|
||||||
//
|
//
|
||||||
// We use a modified Fresnel function that dampens specular reflections of very
|
// We use a modified Fresnel function that dampens specular reflections of very
|
||||||
// rough surfaces to avoid too bright pixels at grazing angles.
|
// rough surfaces to avoid too bright pixels at grazing angles.
|
||||||
vec3 F = fresnel_schlick_roughness( N, V, F0, roughness );
|
vec3 F = fresnel_schlick_roughness( N, V, F0, roughness );
|
||||||
vec3 kS = F;
|
vec3 kS = F;
|
||||||
|
|
||||||
// Subtract the amount of reflected light (specular) to get the energy left for
|
// Subtract the amount of reflected light (specular) to get the energy left for
|
||||||
// absorbed (diffuse) light.
|
// absorbed (diffuse) light.
|
||||||
vec3 kD = vec3(1.) - kS;
|
vec3 kD = vec3(1.) - kS;
|
||||||
|
|
||||||
// Metallic surfaces have only a specular reflection.
|
// Metallic surfaces have only a specular reflection.
|
||||||
kD *= 1.0 - metallic;
|
kD *= 1.0 - metallic;
|
||||||
|
|
||||||
// Premultiplied alpha applied to the diffuse component only
|
// Premultiplied alpha applied to the diffuse component only
|
||||||
kD *= alpha;
|
kD *= alpha;
|
||||||
|
|
||||||
// Modulate the incoming lighting with the diffuse color: some wavelengths get absorbed.
|
// Modulate the incoming lighting with the diffuse color: some wavelengths get absorbed.
|
||||||
diffuse_ambient = irradiance * baseColor;
|
diffuse_ambient = irradiance * baseColor;
|
||||||
|
|
||||||
// Ambient light also has a specular part.
|
// Ambient light also has a specular part.
|
||||||
specular_ambient = specular_ibl( V, normal, roughness, F );
|
specular_ambient = specular_ibl( V, normal, roughness, F );
|
||||||
|
|
||||||
// Ambient occlusion tells us the fraction of sky light that reaches this point.
|
// Ambient occlusion tells us the fraction of sky light that reaches this point.
|
||||||
if (USE_SPECULAR_AO_ATTENUATION)
|
if (USE_SPECULAR_AO_ATTENUATION)
|
||||||
{
|
{
|
||||||
ambient = ao * (kD * diffuse_ambient + specular_ambient);
|
ambient = ao * (kD * diffuse_ambient + specular_ambient);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// We don't attenuate specular_ambient ambient here with AO which might cause flickering in dark cavities.
|
// We don't attenuate specular_ambient ambient here with AO which might cause flickering in dark cavities.
|
||||||
ambient = ao * (kD * diffuse_ambient) + specular_ambient;
|
ambient = ao * (kD * diffuse_ambient) + specular_ambient;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 color = (ambient + Lo) + emissive;
|
vec3 color = (ambient + Lo) + emissive;
|
||||||
|
|
||||||
if ( USE_AMBIENT_DEBUGGING )
|
if ( USE_AMBIENT_DEBUGGING )
|
||||||
{
|
{
|
||||||
float y = gl_FragCoord.y / resolution.y;
|
float y = gl_FragCoord.y / resolution.y;
|
||||||
if( USE_MAP_DEBUGGING && y > 0.5 )
|
if( USE_MAP_DEBUGGING && y > 0.5 )
|
||||||
{
|
{
|
||||||
if ( (y-0.5) < (7.0/7.0/2.0) ) color = vec3(.5) + .5*out_normal;
|
if ( (y-0.5) < (7.0/7.0/2.0) ) color = vec3(.5) + .5*out_normal;
|
||||||
if ( (y-0.5) < (6.0/7.0/2.0) ) color = vec3(.5) + .5*normalmap;
|
if ( (y-0.5) < (6.0/7.0/2.0) ) color = vec3(.5) + .5*normalmap;
|
||||||
if ( (y-0.5) < (5.0/7.0/2.0) ) color = vec3(ao);
|
if ( (y-0.5) < (5.0/7.0/2.0) ) color = vec3(ao);
|
||||||
if ( (y-0.5) < (4.0/7.0/2.0) ) color = vec3(emissive);
|
if ( (y-0.5) < (4.0/7.0/2.0) ) color = vec3(emissive);
|
||||||
if ( (y-0.5) < (3.0/7.0/2.0) ) color = vec3(metallic);
|
if ( (y-0.5) < (3.0/7.0/2.0) ) color = vec3(metallic);
|
||||||
if ( (y-0.5) < (2.0/7.0/2.0) ) color = vec3(roughness);
|
if ( (y-0.5) < (2.0/7.0/2.0) ) color = vec3(roughness);
|
||||||
if ( (y-0.5) < (1.0/7.0/2.0) ) color = baseColor;
|
if ( (y-0.5) < (1.0/7.0/2.0) ) color = baseColor;
|
||||||
} else {
|
} else {
|
||||||
float x = gl_FragCoord.x / resolution.x;
|
float x = gl_FragCoord.x / resolution.x;
|
||||||
if ( x < 0.33 )
|
if ( x < 0.33 )
|
||||||
color = specular_ambient;
|
color = specular_ambient;
|
||||||
else if( x > 0.66 )
|
else if( x > 0.66 )
|
||||||
color = diffuse_ambient;
|
color = diffuse_ambient;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0 // original
|
#if 0 // original
|
||||||
// basic tonemap and gamma correction
|
// basic tonemap and gamma correction
|
||||||
color = color / ( vec3(1.) + color );
|
color = color / ( vec3(1.) + color );
|
||||||
color = pow( color, vec3(1. / 2.2) );
|
color = pow( color, vec3(1. / 2.2) );
|
||||||
#elif 0
|
#elif 0
|
||||||
// filmic tonemapper
|
// filmic tonemapper
|
||||||
vec3 linearColor = color;
|
vec3 linearColor = color;
|
||||||
vec3 x = max(vec3(0.0), linearColor - 0.004);
|
vec3 x = max(vec3(0.0), linearColor - 0.004);
|
||||||
color = (x * (6.2 * x + 0.5)) / (x * (6.2 * x + 1.7) + 0.06);
|
color = (x * (6.2 * x + 0.5)) / (x * (6.2 * x + 1.7) + 0.06);
|
||||||
// gamma correction
|
// gamma correction
|
||||||
// color = pow( color, vec3(1. / 2.2) );
|
// color = pow( color, vec3(1. / 2.2) );
|
||||||
#elif 1
|
#elif 1
|
||||||
// aces film (CC0, src: https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/)
|
// aces film (CC0, src: https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/)
|
||||||
vec3 x = color;
|
vec3 x = color;
|
||||||
float a = 2.51f;
|
float a = 2.51f;
|
||||||
float b = 0.03f;
|
float b = 0.03f;
|
||||||
float c = 2.43f;
|
float c = 2.43f;
|
||||||
float d = 0.59f;
|
float d = 0.59f;
|
||||||
float e = 0.14f;
|
float e = 0.14f;
|
||||||
color = clamp((x*(a*x+b))/(x*(c*x+d)+e), 0.0, 1.0);
|
color = clamp((x*(a*x+b))/(x*(c*x+d)+e), 0.0, 1.0);
|
||||||
// gamma correction
|
// gamma correction
|
||||||
color = pow( color, vec3(1. / 2.2) );
|
color = pow( color, vec3(1. / 2.2) );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// dither with noise.
|
// dither with noise.
|
||||||
// float dither = random( uvec3( floatBitsToUint( gl_FragCoord.xy ), frame_count ) );
|
// float dither = random( uvec3( floatBitsToUint( gl_FragCoord.xy ), frame_count ) );
|
||||||
// color += BOOST_NOISE * vec3( (-1.0/256.) + (2./256.) * dither );
|
// color += BOOST_NOISE * vec3( (-1.0/256.) + (2./256.) * dither );
|
||||||
|
|
||||||
// Technically this alpha may be too transparent, if there is a lot of reflected light we wouldn't
|
// 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
|
// see the background, maybe we can approximate it well enough by adding a fresnel term
|
||||||
frag_color = vec4( color, alpha );
|
frag_color = vec4( color, alpha );
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,158 +1,180 @@
|
||||||
#ifndef MAX_BONES
|
#ifndef MAX_BONES
|
||||||
#define MAX_BONES 110
|
#define MAX_BONES 110
|
||||||
#endif
|
#endif
|
||||||
uniform mat3x4 vsBoneMatrix[MAX_BONES];
|
uniform mat3x4 vsBoneMatrix[MAX_BONES];
|
||||||
uniform bool SKINNED = false;
|
uniform bool SKINNED = false;
|
||||||
uniform mat4 M; // RIM
|
uniform mat4 M; // RIM
|
||||||
uniform mat4 VP;
|
uniform mat4 VP;
|
||||||
uniform mat4 P;
|
uniform mat4 P;
|
||||||
uniform int u_billboard;
|
uniform int u_billboard;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// Fetch blend channels from all attached blend deformers.
|
// Fetch blend channels from all attached blend deformers.
|
||||||
for (size_t di = 0; di < mesh->blend_deformers.count; di++) {
|
for (size_t di = 0; di < mesh->blend_deformers.count; di++) {
|
||||||
ufbx_blend_deformer *deformer = mesh->blend_deformers.data[di];
|
ufbx_blend_deformer *deformer = mesh->blend_deformers.data[di];
|
||||||
for (size_t ci = 0; ci < deformer->channels.count; ci++) {
|
for (size_t ci = 0; ci < deformer->channels.count; ci++) {
|
||||||
ufbx_blend_channel *chan = deformer->channels.data[ci];
|
ufbx_blend_channel *chan = deformer->channels.data[ci];
|
||||||
if (chan->keyframes.count == 0) continue;
|
if (chan->keyframes.count == 0) continue;
|
||||||
if (num_blend_shapes < MAX_BLEND_SHAPES) {
|
if (num_blend_shapes < MAX_BLEND_SHAPES) {
|
||||||
blend_channels[num_blend_shapes] = chan;
|
blend_channels[num_blend_shapes] = chan;
|
||||||
vmesh->blend_channel_indices[num_blend_shapes] = (int32_t)chan->typed_id;
|
vmesh->blend_channel_indices[num_blend_shapes] = (int32_t)chan->typed_id;
|
||||||
num_blend_shapes++;
|
num_blend_shapes++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (num_blend_shapes > 0) {
|
if (num_blend_shapes > 0) {
|
||||||
vmesh->blend_shape_image = pack_blend_channels_to_image(mesh, blend_channels, num_blend_shapes);
|
vmesh->blend_shape_image = pack_blend_channels_to_image(mesh, blend_channels, num_blend_shapes);
|
||||||
vmesh->num_blend_shapes = num_blend_shapes;
|
vmesh->num_blend_shapes = num_blend_shapes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ubo.f_num_blend_shapes = (float)mesh->num_blend_shapes;
|
ubo.f_num_blend_shapes = (float)mesh->num_blend_shapes;
|
||||||
for (size_t i = 0; i < mesh->num_blend_shapes; i++) {
|
for (size_t i = 0; i < mesh->num_blend_shapes; i++) {
|
||||||
ubo.blend_weights[i] = view->scene.blend_channels[mesh->blend_channel_indices[i]].weight;
|
ubo.blend_weights[i] = view->scene.blend_channels[mesh->blend_channel_indices[i]].weight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sg_image blend_shapes = mesh->num_blend_shapes > 0 ? mesh->blend_shape_image : view->empty_blend_shape_image;
|
sg_image blend_shapes = mesh->num_blend_shapes > 0 ? mesh->blend_shape_image : view->empty_blend_shape_image;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// for blendshapes
|
// for blendshapes
|
||||||
#ifndef MAX_BLENDSHAPES
|
#ifndef MAX_BLENDSHAPES
|
||||||
#define MAX_BLENDSHAPES 16
|
#define MAX_BLENDSHAPES 16
|
||||||
#endif
|
#endif
|
||||||
uniform vec4 blend_weights[MAX_BLENDSHAPES]; // @todo: implement me
|
uniform vec4 blend_weights[MAX_BLENDSHAPES]; // @todo: implement me
|
||||||
uniform float f_num_blend_shapes; // @todo: implement me
|
uniform float f_num_blend_shapes; // @todo: implement me
|
||||||
uniform sampler2DArray blend_shapes; // @todo: implement me
|
uniform sampler2DArray blend_shapes; // @todo: implement me
|
||||||
|
|
||||||
|
|
||||||
in vec3 att_position; // @todo: reorder ass2iqe to emit p3 n3 u2 t3 b3 c4B i4 w4 instead
|
in vec3 att_position; // @todo: reorder ass2iqe to emit p3 n3 u2 t3 b3 c4B i4 w4 instead
|
||||||
in vec2 att_texcoord;
|
in vec2 att_texcoord;
|
||||||
in vec3 att_normal;
|
in vec3 att_normal;
|
||||||
in vec4 att_tangent; // vec3 + bi sign
|
in vec4 att_tangent; // vec3 + bi sign
|
||||||
in mat4 att_instanced_matrix; // for instanced rendering
|
in mat4 att_instanced_matrix; // for instanced rendering
|
||||||
in vec4 att_indexes; // @fixme: gles might use ivec4 instead?
|
in vec4 att_indexes; // @fixme: gles might use ivec4 instead?
|
||||||
in vec4 att_weights; // @todo: downgrade from float to byte
|
in vec4 att_weights; // @todo: downgrade from float to byte
|
||||||
in float att_vertexindex; // for blendshapes
|
in float att_vertexindex; // for blendshapes
|
||||||
in vec4 att_color;
|
in vec4 att_color;
|
||||||
in vec3 att_bitangent; // @todo: remove? also, ass2iqe might output this
|
in vec3 att_bitangent; // @todo: remove? also, ass2iqe might output this
|
||||||
in vec2 att_texcoord2;
|
in vec2 att_texcoord2;
|
||||||
out vec4 v_color;
|
out vec4 v_color;
|
||||||
out vec3 v_position, v_position_ws;
|
out vec3 v_position, v_position_ws;
|
||||||
out vec3 v_normal, v_normal_ws;
|
out vec3 v_normal, v_normal_ws;
|
||||||
out vec2 v_texcoord, v_texcoord2;
|
out vec2 v_texcoord, v_texcoord2;
|
||||||
|
out vec3 v_tangent;
|
||||||
|
out vec3 v_binormal;
|
||||||
|
out vec3 v_viewpos;
|
||||||
|
out vec3 v_to_camera;
|
||||||
// shadow
|
|
||||||
uniform mat4 model, view;
|
|
||||||
uniform mat4 cameraToShadowProjector;
|
|
||||||
out vec4 vneye;
|
|
||||||
out vec4 vpeye;
|
// shadow
|
||||||
out vec4 sc;
|
uniform mat4 model, view, inv_view;
|
||||||
void do_shadow() {
|
uniform mat4 cameraToShadowProjector;
|
||||||
vneye = view * model * vec4(att_normal, 0.0f);
|
out vec4 vneye;
|
||||||
vpeye = view * model * vec4(att_position, 1.0);
|
out vec4 vpeye;
|
||||||
sc = cameraToShadowProjector * model * vec4(att_position, 1.0f);
|
out vec4 sc;
|
||||||
}
|
void do_shadow() {
|
||||||
|
vneye = view * model * vec4(att_normal, 0.0f);
|
||||||
|
vpeye = view * model * vec4(att_position, 1.0);
|
||||||
// blendshapes
|
sc = cameraToShadowProjector * model * vec4(att_position, 1.0f);
|
||||||
vec3 evaluate_blend_shape(int vertex_index) {
|
}
|
||||||
ivec2 coord = ivec2(vertex_index & (2048 - 1), vertex_index >> 11);
|
|
||||||
int num_blend_shapes = int(f_num_blend_shapes);
|
|
||||||
vec3 offset = vec3(0.0);
|
// blendshapes
|
||||||
for (int i = 0; i < num_blend_shapes; i++) {
|
vec3 evaluate_blend_shape(int vertex_index) {
|
||||||
vec4 packedw = blend_weights[i >> 2];
|
ivec2 coord = ivec2(vertex_index & (2048 - 1), vertex_index >> 11);
|
||||||
float weight = packedw[i & 3];
|
int num_blend_shapes = int(f_num_blend_shapes);
|
||||||
offset += weight * texelFetch(blend_shapes, ivec3(coord, i), 0).xyz;
|
vec3 offset = vec3(0.0);
|
||||||
}
|
for (int i = 0; i < num_blend_shapes; i++) {
|
||||||
return offset;
|
vec4 packedw = blend_weights[i >> 2];
|
||||||
}
|
float weight = packedw[i & 3];
|
||||||
|
offset += weight * texelFetch(blend_shapes, ivec3(coord, i), 0).xyz;
|
||||||
|
}
|
||||||
void main() {
|
return offset;
|
||||||
vec3 objPos;
|
}
|
||||||
if(!SKINNED) {
|
|
||||||
objPos = att_position;
|
|
||||||
v_normal = att_normal;
|
void main() {
|
||||||
} else {
|
vec3 objPos;
|
||||||
mat3x4 m = vsBoneMatrix[int(att_indexes.x)] * att_weights.x;
|
if(!SKINNED) {
|
||||||
m += vsBoneMatrix[int(att_indexes.y)] * att_weights.y;
|
objPos = att_position;
|
||||||
m += vsBoneMatrix[int(att_indexes.z)] * att_weights.z;
|
v_normal = att_normal;
|
||||||
m += vsBoneMatrix[int(att_indexes.w)] * att_weights.w;
|
} else {
|
||||||
objPos = vec4(att_position, 1.0) * m;
|
mat3x4 m = vsBoneMatrix[int(att_indexes.x)] * att_weights.x;
|
||||||
|
m += vsBoneMatrix[int(att_indexes.y)] * att_weights.y;
|
||||||
// blendshapes
|
m += vsBoneMatrix[int(att_indexes.z)] * att_weights.z;
|
||||||
// objPos += evaluate_blend_shape(int(att_vertexindex));
|
m += vsBoneMatrix[int(att_indexes.w)] * att_weights.w;
|
||||||
|
objPos = vec4(att_position, 1.0) * m;
|
||||||
v_normal = vec4(att_normal, 0.0) * m;
|
|
||||||
//@todo: tangents
|
// blendshapes
|
||||||
}
|
// objPos += evaluate_blend_shape(int(att_vertexindex));
|
||||||
|
|
||||||
// vec3 tangent = att_tangent.xyz;
|
v_normal = vec4(att_normal, 0.0) * m;
|
||||||
// vec3 bitangent = cross(att_normal, att_tangent.xyz) * att_tangent.w;
|
//@todo: tangents
|
||||||
v_normal_ws = normalize(vec3(att_instanced_matrix * vec4(v_normal, 0.))); // normal to world/model space
|
}
|
||||||
v_normal = normalize(v_normal);
|
|
||||||
v_position = att_position;
|
// vec3 tangent = att_tangent.xyz;
|
||||||
v_texcoord = att_texcoord;
|
// vec3 bitangent = cross(att_normal, att_tangent.xyz) * att_tangent.w;
|
||||||
v_texcoord2 = att_texcoord2;
|
v_normal_ws = normalize(vec3(att_instanced_matrix * vec4(v_normal, 0.))); // normal to world/model space
|
||||||
v_color = att_color;
|
v_normal = normalize(v_normal);
|
||||||
mat4 modelView = view * att_instanced_matrix;
|
v_position = att_position;
|
||||||
mat4 l_model = att_instanced_matrix;
|
v_texcoord = att_texcoord;
|
||||||
v_position_ws = (l_model * vec4( objPos, 1.0 )).xyz;
|
v_texcoord2 = att_texcoord2;
|
||||||
|
v_color = att_color;
|
||||||
if(u_billboard > 0) {
|
mat4 modelView = view * att_instanced_matrix;
|
||||||
vec3 cameraPosition = -transpose(mat3(view)) * view[3].xyz;
|
mat4 l_model = att_instanced_matrix;
|
||||||
vec3 lookDir = normalize(cameraPosition - v_position_ws);
|
v_position_ws = (l_model * vec4( objPos, 1.0 )).xyz;
|
||||||
|
|
||||||
vec3 up = vec3(modelView[0][1], modelView[1][1], modelView[2][1]);
|
if(u_billboard > 0) {
|
||||||
vec3 right = normalize(cross(up, lookDir));
|
vec3 cameraPosition = -transpose(mat3(view)) * view[3].xyz;
|
||||||
up = cross(lookDir, right);
|
vec3 lookDir = normalize(cameraPosition - v_position_ws);
|
||||||
|
|
||||||
vec3 scale;
|
vec3 up = vec3(modelView[0][1], modelView[1][1], modelView[2][1]);
|
||||||
scale.x = length(vec3(l_model[0]));
|
vec3 right = normalize(cross(up, lookDir));
|
||||||
scale.y = length(vec3(l_model[1]));
|
up = cross(lookDir, right);
|
||||||
scale.z = length(vec3(l_model[2]));
|
|
||||||
// scale.x *= sign(l_model[0][0]);
|
vec3 scale;
|
||||||
// scale.y *= sign(l_model[1][1]);
|
scale.x = length(vec3(l_model[0]));
|
||||||
// scale.z *= sign(l_model[2][2]);
|
scale.y = length(vec3(l_model[1]));
|
||||||
|
scale.z = length(vec3(l_model[2]));
|
||||||
mat4 billboardRotation = mat4(
|
// scale.x *= sign(l_model[0][0]);
|
||||||
vec4(right * scale.x, 0.0),
|
// scale.y *= sign(l_model[1][1]);
|
||||||
vec4(-up * scale.y, 0.0),
|
// scale.z *= sign(l_model[2][2]);
|
||||||
vec4(-lookDir * scale.z, 0.0),
|
|
||||||
vec4(0.0, 0.0, 0.0, 1.0)
|
mat4 billboardRotation = mat4(
|
||||||
);
|
vec4(right * scale.x, 0.0),
|
||||||
|
vec4(-up * scale.y, 0.0),
|
||||||
if((u_billboard & 0x4) != 0) l_model[0] = billboardRotation[0];
|
vec4(-lookDir * scale.z, 0.0),
|
||||||
if((u_billboard & 0x2) != 0) l_model[1] = billboardRotation[1];
|
vec4(0.0, 0.0, 0.0, 1.0)
|
||||||
if((u_billboard & 0x1) != 0) l_model[2] = billboardRotation[2];
|
);
|
||||||
modelView = view * l_model;
|
|
||||||
}
|
if((u_billboard & 0x4) != 0) l_model[0] = billboardRotation[0];
|
||||||
v_position_ws = (l_model * vec4( objPos, 1.0 )).xyz;
|
if((u_billboard & 0x2) != 0) l_model[1] = billboardRotation[1];
|
||||||
gl_Position = P * modelView * vec4( objPos, 1.0 );
|
if((u_billboard & 0x1) != 0) l_model[2] = billboardRotation[2];
|
||||||
do_shadow();
|
modelView = view * l_model;
|
||||||
|
}
|
||||||
|
v_position_ws = (l_model * vec4( objPos, 1.0 )).xyz;
|
||||||
|
v_tangent = normalize(mat3(att_instanced_matrix) * att_tangent.xyz);
|
||||||
|
#if 0
|
||||||
|
// compute tangent T and bitangent B
|
||||||
|
vec3 Q1 = dFdx(att_position);
|
||||||
|
vec3 Q2 = dFdy(att_position);
|
||||||
|
vec2 st1 = dFdx(att_texcoord);
|
||||||
|
vec2 st2 = dFdy(att_texcoord);
|
||||||
|
|
||||||
|
vec3 T = normalize(Q1*st2.t - Q2*st1.t);
|
||||||
|
vec3 B = normalize(-Q1*st2.s + Q2*st1.s);
|
||||||
|
vec3 binormal = B;
|
||||||
|
#else
|
||||||
|
vec3 binormal = cross(att_normal, att_tangent.xyz) * att_tangent.w;
|
||||||
|
#endif
|
||||||
|
v_binormal = normalize(mat3(att_instanced_matrix) * binormal);
|
||||||
|
vec4 finalPos = modelView * vec4( objPos, 1.0 );
|
||||||
|
vec3 to_camera = normalize( -finalPos.xyz );
|
||||||
|
v_to_camera = mat3( inv_view ) * to_camera;
|
||||||
|
gl_Position = P * finalPos;
|
||||||
|
do_shadow();
|
||||||
}
|
}
|
|
@ -1 +1 @@
|
||||||
frame: 0-0 Idle
|
frame: 0-0 Idle
|
||||||
|
|
|
@ -17445,6 +17445,42 @@ API void mesh_render_prim(mesh_t *sm, unsigned prim);
|
||||||
API void mesh_destroy(mesh_t *m);
|
API void mesh_destroy(mesh_t *m);
|
||||||
API aabb mesh_bounds(mesh_t *m);
|
API aabb mesh_bounds(mesh_t *m);
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// skyboxes
|
||||||
|
|
||||||
|
enum SKYBOX_FLAGS {
|
||||||
|
SKYBOX_RAYLEIGH,
|
||||||
|
SKYBOX_CUBEMAP,
|
||||||
|
SKYBOX_PBR,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct skybox_t {
|
||||||
|
handle program;
|
||||||
|
mesh_t geometry;
|
||||||
|
cubemap_t cubemap;
|
||||||
|
cubemap_t env_cubemap;
|
||||||
|
int flags;
|
||||||
|
|
||||||
|
// mie
|
||||||
|
int framebuffers[6];
|
||||||
|
int textures[6];
|
||||||
|
float *pixels;
|
||||||
|
|
||||||
|
// pbr
|
||||||
|
texture_t refl, env;
|
||||||
|
} skybox_t;
|
||||||
|
|
||||||
|
API skybox_t skybox(const char *panorama_or_cubemap_folder, int flags);
|
||||||
|
API skybox_t skybox_pbr(const char *refl_map, const char *env_map);
|
||||||
|
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_add_light(skybox_t *sky, vec3 light, vec3 dir, float strength);
|
||||||
|
|
||||||
|
API int skybox_push_state(skybox_t *sky, mat44 proj, mat44 view); // @to deprecate
|
||||||
|
API int skybox_pop_state(); // @to deprecate
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// materials
|
// materials
|
||||||
|
|
||||||
|
@ -17529,21 +17565,23 @@ enum MODEL_FLAGS {
|
||||||
MODEL_RIMLIGHT = 32,
|
MODEL_RIMLIGHT = 32,
|
||||||
};
|
};
|
||||||
|
|
||||||
//@todo: make this data-driven
|
enum SHADING_MODE {
|
||||||
// enum SHADING_MODE {
|
SHADING_NONE,
|
||||||
// SHADING_NONE,
|
SHADING_PHONG,
|
||||||
// SHADING_PHONG,
|
SHADING_PBR,
|
||||||
// SHADING_CARTOON,
|
};
|
||||||
// // SHADING_PBR,
|
|
||||||
// };
|
|
||||||
|
|
||||||
typedef struct model_t {
|
typedef struct model_t {
|
||||||
struct iqm_t *iqm; // private
|
struct iqm_t *iqm; // private
|
||||||
|
|
||||||
|
int shading; // based on SHADING_MODE
|
||||||
unsigned num_textures;
|
unsigned num_textures;
|
||||||
handle *textures;
|
handle *textures;
|
||||||
char **texture_names;
|
char **texture_names;
|
||||||
array(material_t) materials;
|
array(material_t) materials;
|
||||||
|
|
||||||
|
pbr_material_t pbr_material;
|
||||||
|
texture_t sky_refl, sky_env;
|
||||||
|
|
||||||
texture_t lightmap;
|
texture_t lightmap;
|
||||||
float *lmdata;
|
float *lmdata;
|
||||||
|
@ -17569,6 +17607,8 @@ typedef struct model_t {
|
||||||
|
|
||||||
float *instanced_matrices;
|
float *instanced_matrices;
|
||||||
unsigned num_instances;
|
unsigned num_instances;
|
||||||
|
|
||||||
|
int stored_flags;
|
||||||
} model_t;
|
} model_t;
|
||||||
|
|
||||||
enum BILLBOARD_MODE {
|
enum BILLBOARD_MODE {
|
||||||
|
@ -17586,6 +17626,8 @@ API float model_animate(model_t, float curframe);
|
||||||
API float model_animate_clip(model_t, float curframe, int minframe, int maxframe, bool loop);
|
API float model_animate_clip(model_t, float curframe, int minframe, int maxframe, bool loop);
|
||||||
API float model_animate_blends(model_t m, anim_t *primary, anim_t *secondary, float delta);
|
API float model_animate_blends(model_t m, anim_t *primary, anim_t *secondary, float delta);
|
||||||
API aabb model_aabb(model_t, mat44 transform);
|
API aabb model_aabb(model_t, mat44 transform);
|
||||||
|
API void model_shading(model_t*, int shading);
|
||||||
|
API void model_skybox(model_t*, skybox_t sky, bool load_sh);
|
||||||
API void model_render(model_t, mat44 proj, mat44 view, mat44 model, int shader);
|
API void model_render(model_t, mat44 proj, mat44 view, mat44 model, int shader);
|
||||||
API void model_render_skeleton(model_t, mat44 model);
|
API void model_render_skeleton(model_t, mat44 model);
|
||||||
API void model_render_instanced(model_t, mat44 proj, mat44 view, mat44 *models, int shader, unsigned count);
|
API void model_render_instanced(model_t, mat44 proj, mat44 view, mat44 *models, int shader, unsigned count);
|
||||||
|
@ -17625,31 +17667,6 @@ API void lightmap_setup(lightmap_t *lm, int w, int h);
|
||||||
API void lightmap_bake(lightmap_t *lm, int bounces, void (*drawscene)(lightmap_t *lm, model_t *m, float *view, float *proj, void *userdata), void (*progressupdate)(float progress), void *userdata);
|
API void lightmap_bake(lightmap_t *lm, int bounces, void (*drawscene)(lightmap_t *lm, model_t *m, float *view, float *proj, void *userdata), void (*progressupdate)(float progress), void *userdata);
|
||||||
API void lightmap_destroy(lightmap_t *lm);
|
API void lightmap_destroy(lightmap_t *lm);
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// skyboxes
|
|
||||||
|
|
||||||
typedef struct skybox_t {
|
|
||||||
handle program;
|
|
||||||
mesh_t geometry;
|
|
||||||
cubemap_t cubemap;
|
|
||||||
int flags;
|
|
||||||
|
|
||||||
// mie
|
|
||||||
int framebuffers[6];
|
|
||||||
int textures[6];
|
|
||||||
float *pixels;
|
|
||||||
} skybox_t;
|
|
||||||
|
|
||||||
API skybox_t skybox(const char *panorama_or_cubemap_folder, int flags);
|
|
||||||
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_add_light(skybox_t *sky, vec3 light, vec3 dir, float strength);
|
|
||||||
|
|
||||||
API int skybox_push_state(skybox_t *sky, mat44 proj, mat44 view); // @to deprecate
|
|
||||||
API int skybox_pop_state(); // @to deprecate
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// post-fxs
|
// post-fxs
|
||||||
|
|
||||||
|
@ -370091,7 +370108,7 @@ GLuint shader_compile( GLenum type, const char *source ) {
|
||||||
|
|
||||||
// dump log with line numbers
|
// dump log with line numbers
|
||||||
shader_print( source );
|
shader_print( source );
|
||||||
PRINTF("!ERROR: shader_compile(): %s\n%s\n", type == GL_VERTEX_SHADER ? "Vertex" : "Fragment", buf);
|
PANIC("!ERROR: shader_compile(): %s\n%s\n", type == GL_VERTEX_SHADER ? "Vertex" : "Fragment", buf);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -370112,7 +370129,7 @@ unsigned shader_geom(const char *gs, const char *vs, const char *fs, const char
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *glsl_version = ifdef(ems, "300 es", "150");
|
const char *glsl_version = ifdef(ems, "300 es", "400");
|
||||||
|
|
||||||
if(gs)
|
if(gs)
|
||||||
gs = gs && gs[0] == '#' && gs[1] == 'v' ? gs : va("#version %s\n%s\n%s", glsl_version, glsl_defines, gs ? gs : "");
|
gs = gs && gs[0] == '#' && gs[1] == 'v' ? gs : va("#version %s\n%s\n%s", glsl_version, glsl_defines, gs ? gs : "");
|
||||||
|
@ -370680,7 +370697,6 @@ static
|
||||||
int allocate_texture_unit() {
|
int allocate_texture_unit() {
|
||||||
static int textureUnit = 0, totalTextureUnits = 0;
|
static int textureUnit = 0, totalTextureUnits = 0;
|
||||||
do_once glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &totalTextureUnits);
|
do_once glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &totalTextureUnits);
|
||||||
|
|
||||||
ASSERT(textureUnit < totalTextureUnits, "%d texture units exceeded", totalTextureUnits);
|
ASSERT(textureUnit < totalTextureUnits, "%d texture units exceeded", totalTextureUnits);
|
||||||
return textureUnit++;
|
return textureUnit++;
|
||||||
}
|
}
|
||||||
|
@ -371621,7 +371637,7 @@ skybox_t skybox(const char *asset, int flags) {
|
||||||
mesh_update(&sky.geometry, "p3", 0,countof(vertices),vertices, countof(indices),indices, MESH_TRIANGLE_STRIP);
|
mesh_update(&sky.geometry, "p3", 0,countof(vertices),vertices, countof(indices),indices, MESH_TRIANGLE_STRIP);
|
||||||
|
|
||||||
// sky program
|
// sky program
|
||||||
sky.flags = flags ? flags : !!asset; // either cubemap or rayleigh
|
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.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"),
|
sky.flags ? vfs_read("fs_3_4_skybox.glsl") : vfs_read("shaders/fs_3_4_skybox_rayleigh.glsl"),
|
||||||
"att_position", "fragcolor", NULL);
|
"att_position", "fragcolor", NULL);
|
||||||
|
@ -371664,6 +371680,77 @@ skybox_t skybox(const char *asset, int flags) {
|
||||||
return sky;
|
return sky;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
texture_t load_env_tex( const char *pathfile, unsigned flags ) {
|
||||||
|
int flags_hdr = strendi(pathfile, ".hdr") ? TEXTURE_FLOAT | TEXTURE_RGBA : 0;
|
||||||
|
texture_t t = texture(pathfile, flags | TEXTURE_LINEAR | TEXTURE_MIPMAPS | TEXTURE_REPEAT | flags_hdr);
|
||||||
|
glBindTexture( GL_TEXTURE_2D, t.id );
|
||||||
|
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
|
||||||
|
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
skybox_t skybox_pbr(const char *refl_map, const char *env_map) {
|
||||||
|
skybox_t sky = {0};
|
||||||
|
|
||||||
|
// sky mesh
|
||||||
|
vec3 vertices[] = {{+1,-1,+1},{+1,+1,+1},{+1,+1,-1},{-1,+1,-1},{+1,-1,-1},{-1,-1,-1},{-1,-1,+1},{-1,+1,+1}};
|
||||||
|
unsigned indices[] = { 0, 1, 2, 3, 4, 5, 6, 3, 7, 1, 6, 0, 4, 2 };
|
||||||
|
mesh_update(&sky.geometry, "p3", 0,countof(vertices),vertices, countof(indices),indices, MESH_TRIANGLE_STRIP);
|
||||||
|
|
||||||
|
// sky program
|
||||||
|
sky.flags = SKYBOX_PBR;
|
||||||
|
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"),
|
||||||
|
"att_position", "fragcolor", NULL);
|
||||||
|
|
||||||
|
// sky cubemap & SH
|
||||||
|
if( refl_map ) {
|
||||||
|
int is_panorama = vfs_size( refl_map );
|
||||||
|
if( is_panorama ) { // is file
|
||||||
|
stbi_hdr_to_ldr_gamma(1.2f);
|
||||||
|
image_t panorama = image( refl_map, IMAGE_RGBA );
|
||||||
|
sky.cubemap = cubemap( panorama, 0 ); // RGBA required
|
||||||
|
image_destroy(&panorama);
|
||||||
|
} else { // is folder
|
||||||
|
image_t images[6] = {0};
|
||||||
|
images[0] = image( va("%s/posx", refl_map), IMAGE_RGB ); // cubepx
|
||||||
|
images[1] = image( va("%s/negx", refl_map), IMAGE_RGB ); // cubenx
|
||||||
|
images[2] = image( va("%s/posy", refl_map), IMAGE_RGB ); // cubepy
|
||||||
|
images[3] = image( va("%s/negy", refl_map), IMAGE_RGB ); // cubeny
|
||||||
|
images[4] = image( va("%s/posz", refl_map), IMAGE_RGB ); // cubepz
|
||||||
|
images[5] = image( va("%s/negz", refl_map), IMAGE_RGB ); // cubenz
|
||||||
|
sky.cubemap = cubemap6( images, 0 );
|
||||||
|
for( int i = 0; i < countof(images); ++i ) image_destroy(&images[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
sky.refl = load_env_tex(refl_map, TEXTURE_SRGB);
|
||||||
|
}
|
||||||
|
if( env_map ) {
|
||||||
|
int is_panorama = vfs_size( env_map );
|
||||||
|
if( is_panorama ) { // is file
|
||||||
|
stbi_hdr_to_ldr_gamma(1.2f);
|
||||||
|
image_t panorama = image( env_map, IMAGE_RGBA );
|
||||||
|
sky.env_cubemap = cubemap( panorama, 0 ); // RGBA required
|
||||||
|
image_destroy(&panorama);
|
||||||
|
} else { // is folder
|
||||||
|
image_t images[6] = {0};
|
||||||
|
images[0] = image( va("%s/posx", env_map), IMAGE_RGB ); // cubepx
|
||||||
|
images[1] = image( va("%s/negx", env_map), IMAGE_RGB ); // cubenx
|
||||||
|
images[2] = image( va("%s/posy", env_map), IMAGE_RGB ); // cubepy
|
||||||
|
images[3] = image( va("%s/negy", env_map), IMAGE_RGB ); // cubeny
|
||||||
|
images[4] = image( va("%s/posz", env_map), IMAGE_RGB ); // cubepz
|
||||||
|
images[5] = image( va("%s/negz", env_map), IMAGE_RGB ); // cubenz
|
||||||
|
sky.env_cubemap = cubemap6( images, 0 );
|
||||||
|
for( int i = 0; i < countof(images); ++i ) image_destroy(&images[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
sky.env = load_env_tex(env_map, TEXTURE_SRGB);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sky;
|
||||||
|
}
|
||||||
|
|
||||||
void skybox_mie_calc_sh(skybox_t *sky, float sky_intensity) {
|
void skybox_mie_calc_sh(skybox_t *sky, float sky_intensity) {
|
||||||
unsigned WIDTH = 1024, HEIGHT = 1024;
|
unsigned WIDTH = 1024, HEIGHT = 1024;
|
||||||
int last_fb;
|
int last_fb;
|
||||||
|
@ -372917,6 +373004,11 @@ void model_set_uniforms(model_t m, int shader, mat44 mv, mat44 proj, mat44 view,
|
||||||
if ((loc = glGetUniformLocation(shader, "view")) >= 0) {
|
if ((loc = glGetUniformLocation(shader, "view")) >= 0) {
|
||||||
glUniformMatrix4fv(loc, 1, GL_FALSE, view);
|
glUniformMatrix4fv(loc, 1, GL_FALSE, view);
|
||||||
}
|
}
|
||||||
|
if ((loc = glGetUniformLocation(shader, "inv_view")) >= 0) {
|
||||||
|
mat44 inv_view;
|
||||||
|
invert44( inv_view, view);
|
||||||
|
glUniformMatrix4fv(loc, 1, GL_FALSE, inv_view);
|
||||||
|
}
|
||||||
if ((loc = glGetUniformLocation(shader, "P")) >= 0) {
|
if ((loc = glGetUniformLocation(shader, "P")) >= 0) {
|
||||||
glUniformMatrix4fv(loc, 1, GL_FALSE, proj);
|
glUniformMatrix4fv(loc, 1, GL_FALSE, proj);
|
||||||
}
|
}
|
||||||
|
@ -372931,6 +373023,36 @@ void model_set_uniforms(model_t m, int shader, mat44 mv, mat44 proj, mat44 view,
|
||||||
if ((loc = glGetUniformLocation(shader, "u_matcaps")) >= 0) {
|
if ((loc = glGetUniformLocation(shader, "u_matcaps")) >= 0) {
|
||||||
glUniform1i(loc, m.flags & MODEL_MATCAPS ? GL_TRUE:GL_FALSE);
|
glUniform1i(loc, m.flags & MODEL_MATCAPS ? GL_TRUE:GL_FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m.shading == SHADING_PBR) {
|
||||||
|
const pbr_material_t *material = &m.pbr_material;
|
||||||
|
shader_colormap( "map_diffuse", material->diffuse );
|
||||||
|
shader_colormap( "map_normals", material->normals );
|
||||||
|
shader_colormap( "map_specular", material->specular );
|
||||||
|
shader_colormap( "map_albedo", material->albedo );
|
||||||
|
shader_colormap( "map_roughness", material->roughness );
|
||||||
|
shader_colormap( "map_metallic", material->metallic );
|
||||||
|
shader_colormap( "map_ao", material->ao );
|
||||||
|
shader_colormap( "map_ambient", material->ambient );
|
||||||
|
shader_colormap( "map_emissive", material->emissive );
|
||||||
|
shader_float( "specular_shininess", material->specular_shininess ); // unused, basic_specgloss.fs only
|
||||||
|
|
||||||
|
shader_vec2( "resolution", vec2(window_width(),window_height()));
|
||||||
|
|
||||||
|
bool has_tex_skysphere = m.sky_refl.id != texture_checker().id;
|
||||||
|
bool has_tex_skyenv = m.sky_env.id != texture_checker().id;
|
||||||
|
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 ) );
|
||||||
|
shader_texture("tex_skysphere", m.sky_refl);
|
||||||
|
shader_float( "skysphere_mip_count", mipCount );
|
||||||
|
}
|
||||||
|
if( has_tex_skyenv ) {
|
||||||
|
shader_texture( "tex_skyenv", m.sky_env );
|
||||||
|
}
|
||||||
|
shader_texture( "tex_brdf_lut", brdf_lut() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
static
|
static
|
||||||
void model_set_state(model_t m) {
|
void model_set_state(model_t m) {
|
||||||
|
@ -373368,6 +373490,9 @@ bool model_load_textures(iqm_t *q, const struct iqmheader *hdr, model_t *model,
|
||||||
model_t model_from_mem(const void *mem, int len, int flags) {
|
model_t model_from_mem(const void *mem, int len, int flags) {
|
||||||
model_t m = {0};
|
model_t m = {0};
|
||||||
|
|
||||||
|
m.stored_flags = flags;
|
||||||
|
m.shading = SHADING_PHONG;
|
||||||
|
|
||||||
const char *ptr = (const char *)mem;
|
const char *ptr = (const char *)mem;
|
||||||
// can't cache shader programs since we enable features via flags here
|
// can't cache shader programs since we enable features via flags here
|
||||||
// static int shaderprog = -1;
|
// static int shaderprog = -1;
|
||||||
|
@ -373648,22 +373773,24 @@ void model_draw_call(model_t m, int shader) {
|
||||||
for(int i = 0; i < q->nummeshes; i++) {
|
for(int i = 0; i < q->nummeshes; i++) {
|
||||||
struct iqmmesh *im = &q->meshes[i];
|
struct iqmmesh *im = &q->meshes[i];
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
if (m.shading != SHADING_PBR) {
|
||||||
glBindTexture(GL_TEXTURE_2D, q->textures[i] );
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glUniform1i(glGetUniformLocation(shader, "u_texture2d"), 0 );
|
glBindTexture(GL_TEXTURE_2D, q->textures[i] );
|
||||||
|
glUniform1i(glGetUniformLocation(shader, "u_texture2d"), 0 );
|
||||||
|
|
||||||
int loc;
|
int loc;
|
||||||
if ((loc = glGetUniformLocation(shader, "u_textured")) >= 0) {
|
if ((loc = glGetUniformLocation(shader, "u_textured")) >= 0) {
|
||||||
bool textured = !!q->textures[i] && q->textures[i] != texture_checker().id; // m.materials[i].layer[0].texture != texture_checker().id;
|
bool textured = !!q->textures[i] && q->textures[i] != texture_checker().id; // m.materials[i].layer[0].texture != texture_checker().id;
|
||||||
glUniform1i(loc, textured ? GL_TRUE : GL_FALSE);
|
glUniform1i(loc, textured ? GL_TRUE : GL_FALSE);
|
||||||
if ((loc = glGetUniformLocation(shader, "u_diffuse")) >= 0) {
|
if ((loc = glGetUniformLocation(shader, "u_diffuse")) >= 0) {
|
||||||
glUniform4f(loc, m.materials[i].layer[0].color.r, m.materials[i].layer[0].color.g, m.materials[i].layer[0].color.b, m.materials[i].layer[0].color.a);
|
glUniform4f(loc, m.materials[i].layer[0].color.r, m.materials[i].layer[0].color.g, m.materials[i].layer[0].color.b, m.materials[i].layer[0].color.a);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE1);
|
glActiveTexture(GL_TEXTURE1);
|
||||||
glBindTexture(GL_TEXTURE_2D, m.lightmap.id);
|
glBindTexture(GL_TEXTURE_2D, m.lightmap.id);
|
||||||
glUniform1i(glGetUniformLocation(shader, "u_lightmap"), 1 );
|
glUniform1i(glGetUniformLocation(shader, "u_lightmap"), 1 );
|
||||||
|
}
|
||||||
|
|
||||||
glDrawElementsInstanced(GL_TRIANGLES, 3*im->num_triangles, GL_UNSIGNED_INT, &tris[im->first_triangle], m.num_instances);
|
glDrawElementsInstanced(GL_TRIANGLES, 3*im->num_triangles, GL_UNSIGNED_INT, &tris[im->first_triangle], m.num_instances);
|
||||||
profile_incstat("Render.num_drawcalls", +1);
|
profile_incstat("Render.num_drawcalls", +1);
|
||||||
|
@ -373693,6 +373820,33 @@ void model_render(model_t m, mat44 proj, mat44 view, mat44 model, int shader) {
|
||||||
model_render_instanced(m, proj, view, (mat44*)model, shader, 1);
|
model_render_instanced(m, proj, view, (mat44*)model, shader, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void model_shading(model_t *m, int shading) {
|
||||||
|
m->shading = shading;
|
||||||
|
int flags = m->stored_flags;
|
||||||
|
|
||||||
|
// load pbr material if SHADING_PBR was selected
|
||||||
|
if (shading == SHADING_PBR && array_count(m->materials) > 0) {
|
||||||
|
pbr_material(&m->pbr_material, m->materials[0].name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// rebind shader
|
||||||
|
// @fixme: destroy old shader program
|
||||||
|
const char *symbols[] = { "{{include-shadowmap}}", vfs_read("shaders/fs_0_0_shadowmap_lit.glsl") }; // #define RIM
|
||||||
|
int shaderprog = shader(strlerp(1,symbols,vfs_read("shaders/vs_323444143_16_3322_model.glsl")), strlerp(1,symbols,vfs_read("shaders/fs_32_4_model.glsl")), //fs,
|
||||||
|
"att_position,att_texcoord,att_normal,att_tangent,att_instanced_matrix,,,,att_indexes,att_weights,att_vertexindex,att_color,att_bitangent,att_texcoord2","fragColor",
|
||||||
|
va("%s,%s", shading == SHADING_PBR ? "SHADING_PBR" : "SHADING_PHONG", (flags&MODEL_RIMLIGHT)?"RIM":""));
|
||||||
|
m->program = shaderprog;
|
||||||
|
}
|
||||||
|
|
||||||
|
void model_skybox(model_t *mdl, skybox_t sky, bool load_sh) {
|
||||||
|
if (load_sh) {
|
||||||
|
shader_vec3v("u_coefficients_sh", 9, sky.cubemap.sh);
|
||||||
|
}
|
||||||
|
|
||||||
|
mdl->sky_refl = sky.refl;
|
||||||
|
mdl->sky_env = sky.env;
|
||||||
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
aabb aabb_transform( aabb A, mat44 M ) {
|
aabb aabb_transform( aabb A, mat44 M ) {
|
||||||
// Based on "Transforming Axis-Aligned Bounding Boxes" by Jim Arvo, 1990
|
// Based on "Transforming Axis-Aligned Bounding Boxes" by Jim Arvo, 1990
|
||||||
|
@ -375392,14 +375546,17 @@ void scene_render(int flags) {
|
||||||
shader_bind(model->program);
|
shader_bind(model->program);
|
||||||
shader_vec3v("u_coefficients_sh", 9, last_scene->skybox.cubemap.sh);
|
shader_vec3v("u_coefficients_sh", 9, last_scene->skybox.cubemap.sh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model_skybox(model, last_scene->skybox, 0);
|
||||||
|
|
||||||
if (anim) {
|
if (anim) {
|
||||||
float delta = window_delta() * obj->anim_speed;
|
float delta = window_delta() * obj->anim_speed;
|
||||||
model->curframe = model_animate_clip(*model, model->curframe + delta, anim->from, anim->to, anim->flags & ANIM_LOOP );
|
model->curframe = model_animate_clip(*model, model->curframe + delta, anim->from, anim->to, anim->flags & ANIM_LOOP );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
model->billboard = obj->billboard;
|
model->billboard = obj->billboard;
|
||||||
model_render(*model, cam->proj, cam->view, obj->transform, 0);
|
model_render(*model, cam->proj, cam->view, obj->transform, model->program);
|
||||||
|
|
||||||
if( do_retexturing ) {
|
if( do_retexturing ) {
|
||||||
for(int i = 0; i < model->iqm->nummeshes; ++i) {
|
for(int i = 0; i < model->iqm->nummeshes; ++i) {
|
||||||
|
@ -378862,9 +379019,9 @@ static void mpeg_video_callback( plm_t* plm, plm_frame_t* frame, void* user ) {
|
||||||
if(v->paused) return;
|
if(v->paused) return;
|
||||||
|
|
||||||
if(v->has_ycbcr) {
|
if(v->has_ycbcr) {
|
||||||
mpeg_update_texture(GL_TEXTURE0, v->textureY.id, &frame->y);
|
mpeg_update_texture(GL_TEXTURE4, v->textureY.id, &frame->y);
|
||||||
mpeg_update_texture(GL_TEXTURE1, v->textureCb.id, &frame->cb);
|
mpeg_update_texture(GL_TEXTURE5, v->textureCb.id, &frame->cb);
|
||||||
mpeg_update_texture(GL_TEXTURE2, v->textureCr.id, &frame->cr);
|
mpeg_update_texture(GL_TEXTURE6, v->textureCr.id, &frame->cr);
|
||||||
} else {
|
} else {
|
||||||
plm_frame_to_rgb( frame, v->surface, v->texture.w * 3 );
|
plm_frame_to_rgb( frame, v->surface, v->texture.w * 3 );
|
||||||
texture_update( &v->texture, v->texture.w, v->texture.h, v->texture.n, v->surface, v->texture.flags );
|
texture_update( &v->texture, v->texture.w, v->texture.h, v->texture.n, v->surface, v->texture.flags );
|
||||||
|
|
|
@ -81,7 +81,7 @@ GLuint shader_compile( GLenum type, const char *source ) {
|
||||||
|
|
||||||
// dump log with line numbers
|
// dump log with line numbers
|
||||||
shader_print( source );
|
shader_print( source );
|
||||||
PRINTF("!ERROR: shader_compile(): %s\n%s\n", type == GL_VERTEX_SHADER ? "Vertex" : "Fragment", buf);
|
PANIC("!ERROR: shader_compile(): %s\n%s\n", type == GL_VERTEX_SHADER ? "Vertex" : "Fragment", buf);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,7 +102,7 @@ unsigned shader_geom(const char *gs, const char *vs, const char *fs, const char
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *glsl_version = ifdef(ems, "300 es", "150");
|
const char *glsl_version = ifdef(ems, "300 es", "400");
|
||||||
|
|
||||||
if(gs)
|
if(gs)
|
||||||
gs = gs && gs[0] == '#' && gs[1] == 'v' ? gs : va("#version %s\n%s\n%s", glsl_version, glsl_defines, gs ? gs : "");
|
gs = gs && gs[0] == '#' && gs[1] == 'v' ? gs : va("#version %s\n%s\n%s", glsl_version, glsl_defines, gs ? gs : "");
|
||||||
|
@ -670,7 +670,6 @@ static
|
||||||
int allocate_texture_unit() {
|
int allocate_texture_unit() {
|
||||||
static int textureUnit = 0, totalTextureUnits = 0;
|
static int textureUnit = 0, totalTextureUnits = 0;
|
||||||
do_once glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &totalTextureUnits);
|
do_once glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &totalTextureUnits);
|
||||||
|
|
||||||
ASSERT(textureUnit < totalTextureUnits, "%d texture units exceeded", totalTextureUnits);
|
ASSERT(textureUnit < totalTextureUnits, "%d texture units exceeded", totalTextureUnits);
|
||||||
return textureUnit++;
|
return textureUnit++;
|
||||||
}
|
}
|
||||||
|
@ -1611,7 +1610,7 @@ skybox_t skybox(const char *asset, int flags) {
|
||||||
mesh_update(&sky.geometry, "p3", 0,countof(vertices),vertices, countof(indices),indices, MESH_TRIANGLE_STRIP);
|
mesh_update(&sky.geometry, "p3", 0,countof(vertices),vertices, countof(indices),indices, MESH_TRIANGLE_STRIP);
|
||||||
|
|
||||||
// sky program
|
// sky program
|
||||||
sky.flags = flags ? flags : !!asset; // either cubemap or rayleigh
|
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.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"),
|
sky.flags ? vfs_read("fs_3_4_skybox.glsl") : vfs_read("shaders/fs_3_4_skybox_rayleigh.glsl"),
|
||||||
"att_position", "fragcolor", NULL);
|
"att_position", "fragcolor", NULL);
|
||||||
|
@ -1654,6 +1653,77 @@ skybox_t skybox(const char *asset, int flags) {
|
||||||
return sky;
|
return sky;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
texture_t load_env_tex( const char *pathfile, unsigned flags ) {
|
||||||
|
int flags_hdr = strendi(pathfile, ".hdr") ? TEXTURE_FLOAT | TEXTURE_RGBA : 0;
|
||||||
|
texture_t t = texture(pathfile, flags | TEXTURE_LINEAR | TEXTURE_MIPMAPS | TEXTURE_REPEAT | flags_hdr);
|
||||||
|
glBindTexture( GL_TEXTURE_2D, t.id );
|
||||||
|
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
|
||||||
|
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
skybox_t skybox_pbr(const char *refl_map, const char *env_map) {
|
||||||
|
skybox_t sky = {0};
|
||||||
|
|
||||||
|
// sky mesh
|
||||||
|
vec3 vertices[] = {{+1,-1,+1},{+1,+1,+1},{+1,+1,-1},{-1,+1,-1},{+1,-1,-1},{-1,-1,-1},{-1,-1,+1},{-1,+1,+1}};
|
||||||
|
unsigned indices[] = { 0, 1, 2, 3, 4, 5, 6, 3, 7, 1, 6, 0, 4, 2 };
|
||||||
|
mesh_update(&sky.geometry, "p3", 0,countof(vertices),vertices, countof(indices),indices, MESH_TRIANGLE_STRIP);
|
||||||
|
|
||||||
|
// sky program
|
||||||
|
sky.flags = SKYBOX_PBR;
|
||||||
|
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"),
|
||||||
|
"att_position", "fragcolor", NULL);
|
||||||
|
|
||||||
|
// sky cubemap & SH
|
||||||
|
if( refl_map ) {
|
||||||
|
int is_panorama = vfs_size( refl_map );
|
||||||
|
if( is_panorama ) { // is file
|
||||||
|
stbi_hdr_to_ldr_gamma(1.2f);
|
||||||
|
image_t panorama = image( refl_map, IMAGE_RGBA );
|
||||||
|
sky.cubemap = cubemap( panorama, 0 ); // RGBA required
|
||||||
|
image_destroy(&panorama);
|
||||||
|
} else { // is folder
|
||||||
|
image_t images[6] = {0};
|
||||||
|
images[0] = image( va("%s/posx", refl_map), IMAGE_RGB ); // cubepx
|
||||||
|
images[1] = image( va("%s/negx", refl_map), IMAGE_RGB ); // cubenx
|
||||||
|
images[2] = image( va("%s/posy", refl_map), IMAGE_RGB ); // cubepy
|
||||||
|
images[3] = image( va("%s/negy", refl_map), IMAGE_RGB ); // cubeny
|
||||||
|
images[4] = image( va("%s/posz", refl_map), IMAGE_RGB ); // cubepz
|
||||||
|
images[5] = image( va("%s/negz", refl_map), IMAGE_RGB ); // cubenz
|
||||||
|
sky.cubemap = cubemap6( images, 0 );
|
||||||
|
for( int i = 0; i < countof(images); ++i ) image_destroy(&images[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
sky.refl = load_env_tex(refl_map, TEXTURE_SRGB);
|
||||||
|
}
|
||||||
|
if( env_map ) {
|
||||||
|
int is_panorama = vfs_size( env_map );
|
||||||
|
if( is_panorama ) { // is file
|
||||||
|
stbi_hdr_to_ldr_gamma(1.2f);
|
||||||
|
image_t panorama = image( env_map, IMAGE_RGBA );
|
||||||
|
sky.env_cubemap = cubemap( panorama, 0 ); // RGBA required
|
||||||
|
image_destroy(&panorama);
|
||||||
|
} else { // is folder
|
||||||
|
image_t images[6] = {0};
|
||||||
|
images[0] = image( va("%s/posx", env_map), IMAGE_RGB ); // cubepx
|
||||||
|
images[1] = image( va("%s/negx", env_map), IMAGE_RGB ); // cubenx
|
||||||
|
images[2] = image( va("%s/posy", env_map), IMAGE_RGB ); // cubepy
|
||||||
|
images[3] = image( va("%s/negy", env_map), IMAGE_RGB ); // cubeny
|
||||||
|
images[4] = image( va("%s/posz", env_map), IMAGE_RGB ); // cubepz
|
||||||
|
images[5] = image( va("%s/negz", env_map), IMAGE_RGB ); // cubenz
|
||||||
|
sky.env_cubemap = cubemap6( images, 0 );
|
||||||
|
for( int i = 0; i < countof(images); ++i ) image_destroy(&images[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
sky.env = load_env_tex(env_map, TEXTURE_SRGB);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sky;
|
||||||
|
}
|
||||||
|
|
||||||
void skybox_mie_calc_sh(skybox_t *sky, float sky_intensity) {
|
void skybox_mie_calc_sh(skybox_t *sky, float sky_intensity) {
|
||||||
unsigned WIDTH = 1024, HEIGHT = 1024;
|
unsigned WIDTH = 1024, HEIGHT = 1024;
|
||||||
int last_fb;
|
int last_fb;
|
||||||
|
@ -2907,6 +2977,11 @@ void model_set_uniforms(model_t m, int shader, mat44 mv, mat44 proj, mat44 view,
|
||||||
if ((loc = glGetUniformLocation(shader, "view")) >= 0) {
|
if ((loc = glGetUniformLocation(shader, "view")) >= 0) {
|
||||||
glUniformMatrix4fv(loc, 1, GL_FALSE, view);
|
glUniformMatrix4fv(loc, 1, GL_FALSE, view);
|
||||||
}
|
}
|
||||||
|
if ((loc = glGetUniformLocation(shader, "inv_view")) >= 0) {
|
||||||
|
mat44 inv_view;
|
||||||
|
invert44( inv_view, view);
|
||||||
|
glUniformMatrix4fv(loc, 1, GL_FALSE, inv_view);
|
||||||
|
}
|
||||||
if ((loc = glGetUniformLocation(shader, "P")) >= 0) {
|
if ((loc = glGetUniformLocation(shader, "P")) >= 0) {
|
||||||
glUniformMatrix4fv(loc, 1, GL_FALSE, proj);
|
glUniformMatrix4fv(loc, 1, GL_FALSE, proj);
|
||||||
}
|
}
|
||||||
|
@ -2921,6 +2996,36 @@ void model_set_uniforms(model_t m, int shader, mat44 mv, mat44 proj, mat44 view,
|
||||||
if ((loc = glGetUniformLocation(shader, "u_matcaps")) >= 0) {
|
if ((loc = glGetUniformLocation(shader, "u_matcaps")) >= 0) {
|
||||||
glUniform1i(loc, m.flags & MODEL_MATCAPS ? GL_TRUE:GL_FALSE);
|
glUniform1i(loc, m.flags & MODEL_MATCAPS ? GL_TRUE:GL_FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m.shading == SHADING_PBR) {
|
||||||
|
const pbr_material_t *material = &m.pbr_material;
|
||||||
|
shader_colormap( "map_diffuse", material->diffuse );
|
||||||
|
shader_colormap( "map_normals", material->normals );
|
||||||
|
shader_colormap( "map_specular", material->specular );
|
||||||
|
shader_colormap( "map_albedo", material->albedo );
|
||||||
|
shader_colormap( "map_roughness", material->roughness );
|
||||||
|
shader_colormap( "map_metallic", material->metallic );
|
||||||
|
shader_colormap( "map_ao", material->ao );
|
||||||
|
shader_colormap( "map_ambient", material->ambient );
|
||||||
|
shader_colormap( "map_emissive", material->emissive );
|
||||||
|
shader_float( "specular_shininess", material->specular_shininess ); // unused, basic_specgloss.fs only
|
||||||
|
|
||||||
|
shader_vec2( "resolution", vec2(window_width(),window_height()));
|
||||||
|
|
||||||
|
bool has_tex_skysphere = m.sky_refl.id != texture_checker().id;
|
||||||
|
bool has_tex_skyenv = m.sky_env.id != texture_checker().id;
|
||||||
|
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 ) );
|
||||||
|
shader_texture("tex_skysphere", m.sky_refl);
|
||||||
|
shader_float( "skysphere_mip_count", mipCount );
|
||||||
|
}
|
||||||
|
if( has_tex_skyenv ) {
|
||||||
|
shader_texture( "tex_skyenv", m.sky_env );
|
||||||
|
}
|
||||||
|
shader_texture( "tex_brdf_lut", brdf_lut() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
static
|
static
|
||||||
void model_set_state(model_t m) {
|
void model_set_state(model_t m) {
|
||||||
|
@ -3358,6 +3463,9 @@ bool model_load_textures(iqm_t *q, const struct iqmheader *hdr, model_t *model,
|
||||||
model_t model_from_mem(const void *mem, int len, int flags) {
|
model_t model_from_mem(const void *mem, int len, int flags) {
|
||||||
model_t m = {0};
|
model_t m = {0};
|
||||||
|
|
||||||
|
m.stored_flags = flags;
|
||||||
|
m.shading = SHADING_PHONG;
|
||||||
|
|
||||||
const char *ptr = (const char *)mem;
|
const char *ptr = (const char *)mem;
|
||||||
// can't cache shader programs since we enable features via flags here
|
// can't cache shader programs since we enable features via flags here
|
||||||
// static int shaderprog = -1;
|
// static int shaderprog = -1;
|
||||||
|
@ -3638,22 +3746,24 @@ void model_draw_call(model_t m, int shader) {
|
||||||
for(int i = 0; i < q->nummeshes; i++) {
|
for(int i = 0; i < q->nummeshes; i++) {
|
||||||
struct iqmmesh *im = &q->meshes[i];
|
struct iqmmesh *im = &q->meshes[i];
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
if (m.shading != SHADING_PBR) {
|
||||||
glBindTexture(GL_TEXTURE_2D, q->textures[i] );
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glUniform1i(glGetUniformLocation(shader, "u_texture2d"), 0 );
|
glBindTexture(GL_TEXTURE_2D, q->textures[i] );
|
||||||
|
glUniform1i(glGetUniformLocation(shader, "u_texture2d"), 0 );
|
||||||
|
|
||||||
int loc;
|
int loc;
|
||||||
if ((loc = glGetUniformLocation(shader, "u_textured")) >= 0) {
|
if ((loc = glGetUniformLocation(shader, "u_textured")) >= 0) {
|
||||||
bool textured = !!q->textures[i] && q->textures[i] != texture_checker().id; // m.materials[i].layer[0].texture != texture_checker().id;
|
bool textured = !!q->textures[i] && q->textures[i] != texture_checker().id; // m.materials[i].layer[0].texture != texture_checker().id;
|
||||||
glUniform1i(loc, textured ? GL_TRUE : GL_FALSE);
|
glUniform1i(loc, textured ? GL_TRUE : GL_FALSE);
|
||||||
if ((loc = glGetUniformLocation(shader, "u_diffuse")) >= 0) {
|
if ((loc = glGetUniformLocation(shader, "u_diffuse")) >= 0) {
|
||||||
glUniform4f(loc, m.materials[i].layer[0].color.r, m.materials[i].layer[0].color.g, m.materials[i].layer[0].color.b, m.materials[i].layer[0].color.a);
|
glUniform4f(loc, m.materials[i].layer[0].color.r, m.materials[i].layer[0].color.g, m.materials[i].layer[0].color.b, m.materials[i].layer[0].color.a);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE1);
|
glActiveTexture(GL_TEXTURE1);
|
||||||
glBindTexture(GL_TEXTURE_2D, m.lightmap.id);
|
glBindTexture(GL_TEXTURE_2D, m.lightmap.id);
|
||||||
glUniform1i(glGetUniformLocation(shader, "u_lightmap"), 1 );
|
glUniform1i(glGetUniformLocation(shader, "u_lightmap"), 1 );
|
||||||
|
}
|
||||||
|
|
||||||
glDrawElementsInstanced(GL_TRIANGLES, 3*im->num_triangles, GL_UNSIGNED_INT, &tris[im->first_triangle], m.num_instances);
|
glDrawElementsInstanced(GL_TRIANGLES, 3*im->num_triangles, GL_UNSIGNED_INT, &tris[im->first_triangle], m.num_instances);
|
||||||
profile_incstat("Render.num_drawcalls", +1);
|
profile_incstat("Render.num_drawcalls", +1);
|
||||||
|
@ -3683,6 +3793,33 @@ void model_render(model_t m, mat44 proj, mat44 view, mat44 model, int shader) {
|
||||||
model_render_instanced(m, proj, view, (mat44*)model, shader, 1);
|
model_render_instanced(m, proj, view, (mat44*)model, shader, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void model_shading(model_t *m, int shading) {
|
||||||
|
m->shading = shading;
|
||||||
|
int flags = m->stored_flags;
|
||||||
|
|
||||||
|
// load pbr material if SHADING_PBR was selected
|
||||||
|
if (shading == SHADING_PBR && array_count(m->materials) > 0) {
|
||||||
|
pbr_material(&m->pbr_material, m->materials[0].name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// rebind shader
|
||||||
|
// @fixme: destroy old shader program
|
||||||
|
const char *symbols[] = { "{{include-shadowmap}}", vfs_read("shaders/fs_0_0_shadowmap_lit.glsl") }; // #define RIM
|
||||||
|
int shaderprog = shader(strlerp(1,symbols,vfs_read("shaders/vs_323444143_16_3322_model.glsl")), strlerp(1,symbols,vfs_read("shaders/fs_32_4_model.glsl")), //fs,
|
||||||
|
"att_position,att_texcoord,att_normal,att_tangent,att_instanced_matrix,,,,att_indexes,att_weights,att_vertexindex,att_color,att_bitangent,att_texcoord2","fragColor",
|
||||||
|
va("%s,%s", shading == SHADING_PBR ? "SHADING_PBR" : "SHADING_PHONG", (flags&MODEL_RIMLIGHT)?"RIM":""));
|
||||||
|
m->program = shaderprog;
|
||||||
|
}
|
||||||
|
|
||||||
|
void model_skybox(model_t *mdl, skybox_t sky, bool load_sh) {
|
||||||
|
if (load_sh) {
|
||||||
|
shader_vec3v("u_coefficients_sh", 9, sky.cubemap.sh);
|
||||||
|
}
|
||||||
|
|
||||||
|
mdl->sky_refl = sky.refl;
|
||||||
|
mdl->sky_env = sky.env;
|
||||||
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
aabb aabb_transform( aabb A, mat44 M ) {
|
aabb aabb_transform( aabb A, mat44 M ) {
|
||||||
// Based on "Transforming Axis-Aligned Bounding Boxes" by Jim Arvo, 1990
|
// Based on "Transforming Axis-Aligned Bounding Boxes" by Jim Arvo, 1990
|
||||||
|
|
|
@ -423,6 +423,42 @@ API void mesh_render_prim(mesh_t *sm, unsigned prim);
|
||||||
API void mesh_destroy(mesh_t *m);
|
API void mesh_destroy(mesh_t *m);
|
||||||
API aabb mesh_bounds(mesh_t *m);
|
API aabb mesh_bounds(mesh_t *m);
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// skyboxes
|
||||||
|
|
||||||
|
enum SKYBOX_FLAGS {
|
||||||
|
SKYBOX_RAYLEIGH,
|
||||||
|
SKYBOX_CUBEMAP,
|
||||||
|
SKYBOX_PBR,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct skybox_t {
|
||||||
|
handle program;
|
||||||
|
mesh_t geometry;
|
||||||
|
cubemap_t cubemap;
|
||||||
|
cubemap_t env_cubemap;
|
||||||
|
int flags;
|
||||||
|
|
||||||
|
// mie
|
||||||
|
int framebuffers[6];
|
||||||
|
int textures[6];
|
||||||
|
float *pixels;
|
||||||
|
|
||||||
|
// pbr
|
||||||
|
texture_t refl, env;
|
||||||
|
} skybox_t;
|
||||||
|
|
||||||
|
API skybox_t skybox(const char *panorama_or_cubemap_folder, int flags);
|
||||||
|
API skybox_t skybox_pbr(const char *refl_map, const char *env_map);
|
||||||
|
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_add_light(skybox_t *sky, vec3 light, vec3 dir, float strength);
|
||||||
|
|
||||||
|
API int skybox_push_state(skybox_t *sky, mat44 proj, mat44 view); // @to deprecate
|
||||||
|
API int skybox_pop_state(); // @to deprecate
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// materials
|
// materials
|
||||||
|
|
||||||
|
@ -507,21 +543,23 @@ enum MODEL_FLAGS {
|
||||||
MODEL_RIMLIGHT = 32,
|
MODEL_RIMLIGHT = 32,
|
||||||
};
|
};
|
||||||
|
|
||||||
//@todo: make this data-driven
|
enum SHADING_MODE {
|
||||||
// enum SHADING_MODE {
|
SHADING_NONE,
|
||||||
// SHADING_NONE,
|
SHADING_PHONG,
|
||||||
// SHADING_PHONG,
|
SHADING_PBR,
|
||||||
// SHADING_CARTOON,
|
};
|
||||||
// // SHADING_PBR,
|
|
||||||
// };
|
|
||||||
|
|
||||||
typedef struct model_t {
|
typedef struct model_t {
|
||||||
struct iqm_t *iqm; // private
|
struct iqm_t *iqm; // private
|
||||||
|
|
||||||
|
int shading; // based on SHADING_MODE
|
||||||
unsigned num_textures;
|
unsigned num_textures;
|
||||||
handle *textures;
|
handle *textures;
|
||||||
char **texture_names;
|
char **texture_names;
|
||||||
array(material_t) materials;
|
array(material_t) materials;
|
||||||
|
|
||||||
|
pbr_material_t pbr_material;
|
||||||
|
texture_t sky_refl, sky_env;
|
||||||
|
|
||||||
texture_t lightmap;
|
texture_t lightmap;
|
||||||
float *lmdata;
|
float *lmdata;
|
||||||
|
@ -547,6 +585,8 @@ typedef struct model_t {
|
||||||
|
|
||||||
float *instanced_matrices;
|
float *instanced_matrices;
|
||||||
unsigned num_instances;
|
unsigned num_instances;
|
||||||
|
|
||||||
|
int stored_flags;
|
||||||
} model_t;
|
} model_t;
|
||||||
|
|
||||||
enum BILLBOARD_MODE {
|
enum BILLBOARD_MODE {
|
||||||
|
@ -564,6 +604,8 @@ API float model_animate(model_t, float curframe);
|
||||||
API float model_animate_clip(model_t, float curframe, int minframe, int maxframe, bool loop);
|
API float model_animate_clip(model_t, float curframe, int minframe, int maxframe, bool loop);
|
||||||
API float model_animate_blends(model_t m, anim_t *primary, anim_t *secondary, float delta);
|
API float model_animate_blends(model_t m, anim_t *primary, anim_t *secondary, float delta);
|
||||||
API aabb model_aabb(model_t, mat44 transform);
|
API aabb model_aabb(model_t, mat44 transform);
|
||||||
|
API void model_shading(model_t*, int shading);
|
||||||
|
API void model_skybox(model_t*, skybox_t sky, bool load_sh);
|
||||||
API void model_render(model_t, mat44 proj, mat44 view, mat44 model, int shader);
|
API void model_render(model_t, mat44 proj, mat44 view, mat44 model, int shader);
|
||||||
API void model_render_skeleton(model_t, mat44 model);
|
API void model_render_skeleton(model_t, mat44 model);
|
||||||
API void model_render_instanced(model_t, mat44 proj, mat44 view, mat44 *models, int shader, unsigned count);
|
API void model_render_instanced(model_t, mat44 proj, mat44 view, mat44 *models, int shader, unsigned count);
|
||||||
|
@ -603,31 +645,6 @@ API void lightmap_setup(lightmap_t *lm, int w, int h);
|
||||||
API void lightmap_bake(lightmap_t *lm, int bounces, void (*drawscene)(lightmap_t *lm, model_t *m, float *view, float *proj, void *userdata), void (*progressupdate)(float progress), void *userdata);
|
API void lightmap_bake(lightmap_t *lm, int bounces, void (*drawscene)(lightmap_t *lm, model_t *m, float *view, float *proj, void *userdata), void (*progressupdate)(float progress), void *userdata);
|
||||||
API void lightmap_destroy(lightmap_t *lm);
|
API void lightmap_destroy(lightmap_t *lm);
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// skyboxes
|
|
||||||
|
|
||||||
typedef struct skybox_t {
|
|
||||||
handle program;
|
|
||||||
mesh_t geometry;
|
|
||||||
cubemap_t cubemap;
|
|
||||||
int flags;
|
|
||||||
|
|
||||||
// mie
|
|
||||||
int framebuffers[6];
|
|
||||||
int textures[6];
|
|
||||||
float *pixels;
|
|
||||||
} skybox_t;
|
|
||||||
|
|
||||||
API skybox_t skybox(const char *panorama_or_cubemap_folder, int flags);
|
|
||||||
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_add_light(skybox_t *sky, vec3 light, vec3 dir, float strength);
|
|
||||||
|
|
||||||
API int skybox_push_state(skybox_t *sky, mat44 proj, mat44 view); // @to deprecate
|
|
||||||
API int skybox_pop_state(); // @to deprecate
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// post-fxs
|
// post-fxs
|
||||||
|
|
||||||
|
|
|
@ -569,14 +569,17 @@ void scene_render(int flags) {
|
||||||
shader_bind(model->program);
|
shader_bind(model->program);
|
||||||
shader_vec3v("u_coefficients_sh", 9, last_scene->skybox.cubemap.sh);
|
shader_vec3v("u_coefficients_sh", 9, last_scene->skybox.cubemap.sh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model_skybox(model, last_scene->skybox, 0);
|
||||||
|
|
||||||
if (anim) {
|
if (anim) {
|
||||||
float delta = window_delta() * obj->anim_speed;
|
float delta = window_delta() * obj->anim_speed;
|
||||||
model->curframe = model_animate_clip(*model, model->curframe + delta, anim->from, anim->to, anim->flags & ANIM_LOOP );
|
model->curframe = model_animate_clip(*model, model->curframe + delta, anim->from, anim->to, anim->flags & ANIM_LOOP );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
model->billboard = obj->billboard;
|
model->billboard = obj->billboard;
|
||||||
model_render(*model, cam->proj, cam->view, obj->transform, 0);
|
model_render(*model, cam->proj, cam->view, obj->transform, model->program);
|
||||||
|
|
||||||
if( do_retexturing ) {
|
if( do_retexturing ) {
|
||||||
for(int i = 0; i < model->iqm->nummeshes; ++i) {
|
for(int i = 0; i < model->iqm->nummeshes; ++i) {
|
||||||
|
|
|
@ -35,9 +35,9 @@ static void mpeg_video_callback( plm_t* plm, plm_frame_t* frame, void* user ) {
|
||||||
if(v->paused) return;
|
if(v->paused) return;
|
||||||
|
|
||||||
if(v->has_ycbcr) {
|
if(v->has_ycbcr) {
|
||||||
mpeg_update_texture(GL_TEXTURE0, v->textureY.id, &frame->y);
|
mpeg_update_texture(GL_TEXTURE4, v->textureY.id, &frame->y);
|
||||||
mpeg_update_texture(GL_TEXTURE1, v->textureCb.id, &frame->cb);
|
mpeg_update_texture(GL_TEXTURE5, v->textureCb.id, &frame->cb);
|
||||||
mpeg_update_texture(GL_TEXTURE2, v->textureCr.id, &frame->cr);
|
mpeg_update_texture(GL_TEXTURE6, v->textureCr.id, &frame->cr);
|
||||||
} else {
|
} else {
|
||||||
plm_frame_to_rgb( frame, v->surface, v->texture.w * 3 );
|
plm_frame_to_rgb( frame, v->surface, v->texture.w * 3 );
|
||||||
texture_update( &v->texture, v->texture.w, v->texture.h, v->texture.n, v->surface, v->texture.flags );
|
texture_update( &v->texture, v->texture.w, v->texture.h, v->texture.n, v->surface, v->texture.flags );
|
||||||
|
|
182
engine/v4k.c
182
engine/v4k.c
|
@ -17255,7 +17255,7 @@ GLuint shader_compile( GLenum type, const char *source ) {
|
||||||
|
|
||||||
// dump log with line numbers
|
// dump log with line numbers
|
||||||
shader_print( source );
|
shader_print( source );
|
||||||
PRINTF("!ERROR: shader_compile(): %s\n%s\n", type == GL_VERTEX_SHADER ? "Vertex" : "Fragment", buf);
|
PANIC("!ERROR: shader_compile(): %s\n%s\n", type == GL_VERTEX_SHADER ? "Vertex" : "Fragment", buf);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17276,7 +17276,7 @@ unsigned shader_geom(const char *gs, const char *vs, const char *fs, const char
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *glsl_version = ifdef(ems, "300 es", "150");
|
const char *glsl_version = ifdef(ems, "300 es", "400");
|
||||||
|
|
||||||
if(gs)
|
if(gs)
|
||||||
gs = gs && gs[0] == '#' && gs[1] == 'v' ? gs : va("#version %s\n%s\n%s", glsl_version, glsl_defines, gs ? gs : "");
|
gs = gs && gs[0] == '#' && gs[1] == 'v' ? gs : va("#version %s\n%s\n%s", glsl_version, glsl_defines, gs ? gs : "");
|
||||||
|
@ -17844,7 +17844,6 @@ static
|
||||||
int allocate_texture_unit() {
|
int allocate_texture_unit() {
|
||||||
static int textureUnit = 0, totalTextureUnits = 0;
|
static int textureUnit = 0, totalTextureUnits = 0;
|
||||||
do_once glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &totalTextureUnits);
|
do_once glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &totalTextureUnits);
|
||||||
|
|
||||||
ASSERT(textureUnit < totalTextureUnits, "%d texture units exceeded", totalTextureUnits);
|
ASSERT(textureUnit < totalTextureUnits, "%d texture units exceeded", totalTextureUnits);
|
||||||
return textureUnit++;
|
return textureUnit++;
|
||||||
}
|
}
|
||||||
|
@ -18785,7 +18784,7 @@ skybox_t skybox(const char *asset, int flags) {
|
||||||
mesh_update(&sky.geometry, "p3", 0,countof(vertices),vertices, countof(indices),indices, MESH_TRIANGLE_STRIP);
|
mesh_update(&sky.geometry, "p3", 0,countof(vertices),vertices, countof(indices),indices, MESH_TRIANGLE_STRIP);
|
||||||
|
|
||||||
// sky program
|
// sky program
|
||||||
sky.flags = flags ? flags : !!asset; // either cubemap or rayleigh
|
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.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"),
|
sky.flags ? vfs_read("fs_3_4_skybox.glsl") : vfs_read("shaders/fs_3_4_skybox_rayleigh.glsl"),
|
||||||
"att_position", "fragcolor", NULL);
|
"att_position", "fragcolor", NULL);
|
||||||
|
@ -18828,6 +18827,77 @@ skybox_t skybox(const char *asset, int flags) {
|
||||||
return sky;
|
return sky;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
texture_t load_env_tex( const char *pathfile, unsigned flags ) {
|
||||||
|
int flags_hdr = strendi(pathfile, ".hdr") ? TEXTURE_FLOAT | TEXTURE_RGBA : 0;
|
||||||
|
texture_t t = texture(pathfile, flags | TEXTURE_LINEAR | TEXTURE_MIPMAPS | TEXTURE_REPEAT | flags_hdr);
|
||||||
|
glBindTexture( GL_TEXTURE_2D, t.id );
|
||||||
|
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
|
||||||
|
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
skybox_t skybox_pbr(const char *refl_map, const char *env_map) {
|
||||||
|
skybox_t sky = {0};
|
||||||
|
|
||||||
|
// sky mesh
|
||||||
|
vec3 vertices[] = {{+1,-1,+1},{+1,+1,+1},{+1,+1,-1},{-1,+1,-1},{+1,-1,-1},{-1,-1,-1},{-1,-1,+1},{-1,+1,+1}};
|
||||||
|
unsigned indices[] = { 0, 1, 2, 3, 4, 5, 6, 3, 7, 1, 6, 0, 4, 2 };
|
||||||
|
mesh_update(&sky.geometry, "p3", 0,countof(vertices),vertices, countof(indices),indices, MESH_TRIANGLE_STRIP);
|
||||||
|
|
||||||
|
// sky program
|
||||||
|
sky.flags = SKYBOX_PBR;
|
||||||
|
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"),
|
||||||
|
"att_position", "fragcolor", NULL);
|
||||||
|
|
||||||
|
// sky cubemap & SH
|
||||||
|
if( refl_map ) {
|
||||||
|
int is_panorama = vfs_size( refl_map );
|
||||||
|
if( is_panorama ) { // is file
|
||||||
|
stbi_hdr_to_ldr_gamma(1.2f);
|
||||||
|
image_t panorama = image( refl_map, IMAGE_RGBA );
|
||||||
|
sky.cubemap = cubemap( panorama, 0 ); // RGBA required
|
||||||
|
image_destroy(&panorama);
|
||||||
|
} else { // is folder
|
||||||
|
image_t images[6] = {0};
|
||||||
|
images[0] = image( va("%s/posx", refl_map), IMAGE_RGB ); // cubepx
|
||||||
|
images[1] = image( va("%s/negx", refl_map), IMAGE_RGB ); // cubenx
|
||||||
|
images[2] = image( va("%s/posy", refl_map), IMAGE_RGB ); // cubepy
|
||||||
|
images[3] = image( va("%s/negy", refl_map), IMAGE_RGB ); // cubeny
|
||||||
|
images[4] = image( va("%s/posz", refl_map), IMAGE_RGB ); // cubepz
|
||||||
|
images[5] = image( va("%s/negz", refl_map), IMAGE_RGB ); // cubenz
|
||||||
|
sky.cubemap = cubemap6( images, 0 );
|
||||||
|
for( int i = 0; i < countof(images); ++i ) image_destroy(&images[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
sky.refl = load_env_tex(refl_map, TEXTURE_SRGB);
|
||||||
|
}
|
||||||
|
if( env_map ) {
|
||||||
|
int is_panorama = vfs_size( env_map );
|
||||||
|
if( is_panorama ) { // is file
|
||||||
|
stbi_hdr_to_ldr_gamma(1.2f);
|
||||||
|
image_t panorama = image( env_map, IMAGE_RGBA );
|
||||||
|
sky.env_cubemap = cubemap( panorama, 0 ); // RGBA required
|
||||||
|
image_destroy(&panorama);
|
||||||
|
} else { // is folder
|
||||||
|
image_t images[6] = {0};
|
||||||
|
images[0] = image( va("%s/posx", env_map), IMAGE_RGB ); // cubepx
|
||||||
|
images[1] = image( va("%s/negx", env_map), IMAGE_RGB ); // cubenx
|
||||||
|
images[2] = image( va("%s/posy", env_map), IMAGE_RGB ); // cubepy
|
||||||
|
images[3] = image( va("%s/negy", env_map), IMAGE_RGB ); // cubeny
|
||||||
|
images[4] = image( va("%s/posz", env_map), IMAGE_RGB ); // cubepz
|
||||||
|
images[5] = image( va("%s/negz", env_map), IMAGE_RGB ); // cubenz
|
||||||
|
sky.env_cubemap = cubemap6( images, 0 );
|
||||||
|
for( int i = 0; i < countof(images); ++i ) image_destroy(&images[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
sky.env = load_env_tex(env_map, TEXTURE_SRGB);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sky;
|
||||||
|
}
|
||||||
|
|
||||||
void skybox_mie_calc_sh(skybox_t *sky, float sky_intensity) {
|
void skybox_mie_calc_sh(skybox_t *sky, float sky_intensity) {
|
||||||
unsigned WIDTH = 1024, HEIGHT = 1024;
|
unsigned WIDTH = 1024, HEIGHT = 1024;
|
||||||
int last_fb;
|
int last_fb;
|
||||||
|
@ -20081,6 +20151,11 @@ void model_set_uniforms(model_t m, int shader, mat44 mv, mat44 proj, mat44 view,
|
||||||
if ((loc = glGetUniformLocation(shader, "view")) >= 0) {
|
if ((loc = glGetUniformLocation(shader, "view")) >= 0) {
|
||||||
glUniformMatrix4fv(loc, 1, GL_FALSE, view);
|
glUniformMatrix4fv(loc, 1, GL_FALSE, view);
|
||||||
}
|
}
|
||||||
|
if ((loc = glGetUniformLocation(shader, "inv_view")) >= 0) {
|
||||||
|
mat44 inv_view;
|
||||||
|
invert44( inv_view, view);
|
||||||
|
glUniformMatrix4fv(loc, 1, GL_FALSE, inv_view);
|
||||||
|
}
|
||||||
if ((loc = glGetUniformLocation(shader, "P")) >= 0) {
|
if ((loc = glGetUniformLocation(shader, "P")) >= 0) {
|
||||||
glUniformMatrix4fv(loc, 1, GL_FALSE, proj);
|
glUniformMatrix4fv(loc, 1, GL_FALSE, proj);
|
||||||
}
|
}
|
||||||
|
@ -20095,6 +20170,36 @@ void model_set_uniforms(model_t m, int shader, mat44 mv, mat44 proj, mat44 view,
|
||||||
if ((loc = glGetUniformLocation(shader, "u_matcaps")) >= 0) {
|
if ((loc = glGetUniformLocation(shader, "u_matcaps")) >= 0) {
|
||||||
glUniform1i(loc, m.flags & MODEL_MATCAPS ? GL_TRUE:GL_FALSE);
|
glUniform1i(loc, m.flags & MODEL_MATCAPS ? GL_TRUE:GL_FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m.shading == SHADING_PBR) {
|
||||||
|
const pbr_material_t *material = &m.pbr_material;
|
||||||
|
shader_colormap( "map_diffuse", material->diffuse );
|
||||||
|
shader_colormap( "map_normals", material->normals );
|
||||||
|
shader_colormap( "map_specular", material->specular );
|
||||||
|
shader_colormap( "map_albedo", material->albedo );
|
||||||
|
shader_colormap( "map_roughness", material->roughness );
|
||||||
|
shader_colormap( "map_metallic", material->metallic );
|
||||||
|
shader_colormap( "map_ao", material->ao );
|
||||||
|
shader_colormap( "map_ambient", material->ambient );
|
||||||
|
shader_colormap( "map_emissive", material->emissive );
|
||||||
|
shader_float( "specular_shininess", material->specular_shininess ); // unused, basic_specgloss.fs only
|
||||||
|
|
||||||
|
shader_vec2( "resolution", vec2(window_width(),window_height()));
|
||||||
|
|
||||||
|
bool has_tex_skysphere = m.sky_refl.id != texture_checker().id;
|
||||||
|
bool has_tex_skyenv = m.sky_env.id != texture_checker().id;
|
||||||
|
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 ) );
|
||||||
|
shader_texture("tex_skysphere", m.sky_refl);
|
||||||
|
shader_float( "skysphere_mip_count", mipCount );
|
||||||
|
}
|
||||||
|
if( has_tex_skyenv ) {
|
||||||
|
shader_texture( "tex_skyenv", m.sky_env );
|
||||||
|
}
|
||||||
|
shader_texture( "tex_brdf_lut", brdf_lut() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
static
|
static
|
||||||
void model_set_state(model_t m) {
|
void model_set_state(model_t m) {
|
||||||
|
@ -20532,6 +20637,9 @@ bool model_load_textures(iqm_t *q, const struct iqmheader *hdr, model_t *model,
|
||||||
model_t model_from_mem(const void *mem, int len, int flags) {
|
model_t model_from_mem(const void *mem, int len, int flags) {
|
||||||
model_t m = {0};
|
model_t m = {0};
|
||||||
|
|
||||||
|
m.stored_flags = flags;
|
||||||
|
m.shading = SHADING_PHONG;
|
||||||
|
|
||||||
const char *ptr = (const char *)mem;
|
const char *ptr = (const char *)mem;
|
||||||
// can't cache shader programs since we enable features via flags here
|
// can't cache shader programs since we enable features via flags here
|
||||||
// static int shaderprog = -1;
|
// static int shaderprog = -1;
|
||||||
|
@ -20812,22 +20920,24 @@ void model_draw_call(model_t m, int shader) {
|
||||||
for(int i = 0; i < q->nummeshes; i++) {
|
for(int i = 0; i < q->nummeshes; i++) {
|
||||||
struct iqmmesh *im = &q->meshes[i];
|
struct iqmmesh *im = &q->meshes[i];
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
if (m.shading != SHADING_PBR) {
|
||||||
glBindTexture(GL_TEXTURE_2D, q->textures[i] );
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glUniform1i(glGetUniformLocation(shader, "u_texture2d"), 0 );
|
glBindTexture(GL_TEXTURE_2D, q->textures[i] );
|
||||||
|
glUniform1i(glGetUniformLocation(shader, "u_texture2d"), 0 );
|
||||||
|
|
||||||
int loc;
|
int loc;
|
||||||
if ((loc = glGetUniformLocation(shader, "u_textured")) >= 0) {
|
if ((loc = glGetUniformLocation(shader, "u_textured")) >= 0) {
|
||||||
bool textured = !!q->textures[i] && q->textures[i] != texture_checker().id; // m.materials[i].layer[0].texture != texture_checker().id;
|
bool textured = !!q->textures[i] && q->textures[i] != texture_checker().id; // m.materials[i].layer[0].texture != texture_checker().id;
|
||||||
glUniform1i(loc, textured ? GL_TRUE : GL_FALSE);
|
glUniform1i(loc, textured ? GL_TRUE : GL_FALSE);
|
||||||
if ((loc = glGetUniformLocation(shader, "u_diffuse")) >= 0) {
|
if ((loc = glGetUniformLocation(shader, "u_diffuse")) >= 0) {
|
||||||
glUniform4f(loc, m.materials[i].layer[0].color.r, m.materials[i].layer[0].color.g, m.materials[i].layer[0].color.b, m.materials[i].layer[0].color.a);
|
glUniform4f(loc, m.materials[i].layer[0].color.r, m.materials[i].layer[0].color.g, m.materials[i].layer[0].color.b, m.materials[i].layer[0].color.a);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE1);
|
glActiveTexture(GL_TEXTURE1);
|
||||||
glBindTexture(GL_TEXTURE_2D, m.lightmap.id);
|
glBindTexture(GL_TEXTURE_2D, m.lightmap.id);
|
||||||
glUniform1i(glGetUniformLocation(shader, "u_lightmap"), 1 );
|
glUniform1i(glGetUniformLocation(shader, "u_lightmap"), 1 );
|
||||||
|
}
|
||||||
|
|
||||||
glDrawElementsInstanced(GL_TRIANGLES, 3*im->num_triangles, GL_UNSIGNED_INT, &tris[im->first_triangle], m.num_instances);
|
glDrawElementsInstanced(GL_TRIANGLES, 3*im->num_triangles, GL_UNSIGNED_INT, &tris[im->first_triangle], m.num_instances);
|
||||||
profile_incstat("Render.num_drawcalls", +1);
|
profile_incstat("Render.num_drawcalls", +1);
|
||||||
|
@ -20857,6 +20967,33 @@ void model_render(model_t m, mat44 proj, mat44 view, mat44 model, int shader) {
|
||||||
model_render_instanced(m, proj, view, (mat44*)model, shader, 1);
|
model_render_instanced(m, proj, view, (mat44*)model, shader, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void model_shading(model_t *m, int shading) {
|
||||||
|
m->shading = shading;
|
||||||
|
int flags = m->stored_flags;
|
||||||
|
|
||||||
|
// load pbr material if SHADING_PBR was selected
|
||||||
|
if (shading == SHADING_PBR && array_count(m->materials) > 0) {
|
||||||
|
pbr_material(&m->pbr_material, m->materials[0].name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// rebind shader
|
||||||
|
// @fixme: destroy old shader program
|
||||||
|
const char *symbols[] = { "{{include-shadowmap}}", vfs_read("shaders/fs_0_0_shadowmap_lit.glsl") }; // #define RIM
|
||||||
|
int shaderprog = shader(strlerp(1,symbols,vfs_read("shaders/vs_323444143_16_3322_model.glsl")), strlerp(1,symbols,vfs_read("shaders/fs_32_4_model.glsl")), //fs,
|
||||||
|
"att_position,att_texcoord,att_normal,att_tangent,att_instanced_matrix,,,,att_indexes,att_weights,att_vertexindex,att_color,att_bitangent,att_texcoord2","fragColor",
|
||||||
|
va("%s,%s", shading == SHADING_PBR ? "SHADING_PBR" : "SHADING_PHONG", (flags&MODEL_RIMLIGHT)?"RIM":""));
|
||||||
|
m->program = shaderprog;
|
||||||
|
}
|
||||||
|
|
||||||
|
void model_skybox(model_t *mdl, skybox_t sky, bool load_sh) {
|
||||||
|
if (load_sh) {
|
||||||
|
shader_vec3v("u_coefficients_sh", 9, sky.cubemap.sh);
|
||||||
|
}
|
||||||
|
|
||||||
|
mdl->sky_refl = sky.refl;
|
||||||
|
mdl->sky_env = sky.env;
|
||||||
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
aabb aabb_transform( aabb A, mat44 M ) {
|
aabb aabb_transform( aabb A, mat44 M ) {
|
||||||
// Based on "Transforming Axis-Aligned Bounding Boxes" by Jim Arvo, 1990
|
// Based on "Transforming Axis-Aligned Bounding Boxes" by Jim Arvo, 1990
|
||||||
|
@ -22556,14 +22693,17 @@ void scene_render(int flags) {
|
||||||
shader_bind(model->program);
|
shader_bind(model->program);
|
||||||
shader_vec3v("u_coefficients_sh", 9, last_scene->skybox.cubemap.sh);
|
shader_vec3v("u_coefficients_sh", 9, last_scene->skybox.cubemap.sh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model_skybox(model, last_scene->skybox, 0);
|
||||||
|
|
||||||
if (anim) {
|
if (anim) {
|
||||||
float delta = window_delta() * obj->anim_speed;
|
float delta = window_delta() * obj->anim_speed;
|
||||||
model->curframe = model_animate_clip(*model, model->curframe + delta, anim->from, anim->to, anim->flags & ANIM_LOOP );
|
model->curframe = model_animate_clip(*model, model->curframe + delta, anim->from, anim->to, anim->flags & ANIM_LOOP );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
model->billboard = obj->billboard;
|
model->billboard = obj->billboard;
|
||||||
model_render(*model, cam->proj, cam->view, obj->transform, 0);
|
model_render(*model, cam->proj, cam->view, obj->transform, model->program);
|
||||||
|
|
||||||
if( do_retexturing ) {
|
if( do_retexturing ) {
|
||||||
for(int i = 0; i < model->iqm->nummeshes; ++i) {
|
for(int i = 0; i < model->iqm->nummeshes; ++i) {
|
||||||
|
@ -26026,9 +26166,9 @@ static void mpeg_video_callback( plm_t* plm, plm_frame_t* frame, void* user ) {
|
||||||
if(v->paused) return;
|
if(v->paused) return;
|
||||||
|
|
||||||
if(v->has_ycbcr) {
|
if(v->has_ycbcr) {
|
||||||
mpeg_update_texture(GL_TEXTURE0, v->textureY.id, &frame->y);
|
mpeg_update_texture(GL_TEXTURE4, v->textureY.id, &frame->y);
|
||||||
mpeg_update_texture(GL_TEXTURE1, v->textureCb.id, &frame->cb);
|
mpeg_update_texture(GL_TEXTURE5, v->textureCb.id, &frame->cb);
|
||||||
mpeg_update_texture(GL_TEXTURE2, v->textureCr.id, &frame->cr);
|
mpeg_update_texture(GL_TEXTURE6, v->textureCr.id, &frame->cr);
|
||||||
} else {
|
} else {
|
||||||
plm_frame_to_rgb( frame, v->surface, v->texture.w * 3 );
|
plm_frame_to_rgb( frame, v->surface, v->texture.w * 3 );
|
||||||
texture_update( &v->texture, v->texture.w, v->texture.h, v->texture.n, v->surface, v->texture.flags );
|
texture_update( &v->texture, v->texture.w, v->texture.h, v->texture.n, v->surface, v->texture.flags );
|
||||||
|
|
9933
engine/v4k.h
9933
engine/v4k.h
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue