scene: WIP lighting pass

main
Dominik Madarász 2023-09-23 17:22:48 +02:00
parent 8129920be2
commit 0beb264e2b
12 changed files with 524 additions and 49 deletions

View File

@ -13,6 +13,7 @@ if "%1"=="help" (
echo %0 [cook] ; cook .zipfiles with tools/cook.ini cookbook echo %0 [cook] ; cook .zipfiles with tools/cook.ini cookbook
echo %0 [sync] ; sync repo to latest echo %0 [sync] ; sync repo to latest
echo %0 [fwk] ; prepare files for fwk PR echo %0 [fwk] ; prepare files for fwk PR
echo %0 [fwk_sync] ; update fwk-mirror fork
echo %0 [lua] ; execute lua script with v4k echo %0 [lua] ; execute lua script with v4k
echo %0 [html5] ; build HTML5 demo echo %0 [html5] ; build HTML5 demo
echo %0 [web] ; run Python webserver in html5 dir echo %0 [web] ; run Python webserver in html5 dir
@ -214,6 +215,14 @@ if "%1"=="vps" (
exit /b exit /b
) )
if "%1"=="fwk_sync" (
pushd ..\fwk-mirror
call MAKE.bat sync
popd
call MAKE.bat fwk
exit /b
)
if "%1"=="fwk" ( if "%1"=="fwk" (
if not exist "_fwk" mkdir "_fwk" if not exist "_fwk" mkdir "_fwk"
if not exist "_fwk\demos" mkdir "_fwk\demos" if not exist "_fwk\demos" mkdir "_fwk\demos"

View File

@ -39,6 +39,10 @@ int main() {
object_move(obj3, vec3(-10+5*1,0,-10)); object_move(obj3, vec3(-10+5*1,0,-10));
object_pivot(obj3, vec3(0,90,0)); object_pivot(obj3, vec3(0,90,0));
// create point light
light_t* l = scene_spawn_light();
light_type(l, LIGHT_POINT);
while(window_swap() && !input(KEY_ESC)) { while(window_swap() && !input(KEY_ESC)) {
// draw environment // draw environment
viewport_color( RGB3(22,22,32) ); viewport_color( RGB3(22,22,32) );
@ -47,8 +51,11 @@ int main() {
// update video // update video
video_decode( v ); video_decode( v );
// update light position
light_teleport(l, cam.position);
// draw scene // draw scene
scene_render(SCENE_FOREGROUND|SCENE_BACKGROUND); scene_render(SCENE_FOREGROUND|SCENE_BACKGROUND|SCENE_UPDATE_SH_COEF);
// fps camera // fps camera
bool active = ui_active() || ui_hover() || gizmo_active() ? false : input(MOUSE_L) || input(MOUSE_M) || input(MOUSE_R); bool active = ui_active() || ui_hover() || gizmo_active() ? false : input(MOUSE_L) || input(MOUSE_M) || input(MOUSE_R);

View File

@ -6,8 +6,8 @@ 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);
#ifdef RIM
in vec3 v_position; in vec3 v_position;
#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);
@ -28,33 +28,81 @@ vec4 shadowing() {
return shadowmap(vpeye, vneye, v_texcoord, sc); return shadowmap(vpeye, vneye, v_texcoord, sc);
} }
uniform int u_num_lights;
struct light_t {
int type;
vec3 color;
vec3 pos;
vec3 dir;
float radius;
};
#define MAX_LIGHTS 16
const int LIGHT_DIRECTIONAL = 0;
const int LIGHT_POINT = 1;
const int LIGHT_SPOT = 2;
uniform light_t u_lights[MAX_LIGHTS];
vec3 calculate_light(light_t l, vec3 normal, vec3 fragPos, vec3 viewDir) {
vec3 lightColor = l.color;
vec3 lightDir;
float attenuation = 1.0;
if (l.type == LIGHT_DIRECTIONAL) {
lightDir = normalize(-l.dir);
} else if (l.type == LIGHT_POINT) {
vec3 toLight = fragPos - l.pos;
lightDir = normalize(toLight);
float distance = length(toLight);
float factor = distance / l.radius;
attenuation = clamp(1.0 - factor, 0.0, 1.0);
}
float diff = max(dot(normal, lightDir), 0.0);
vec3 diffuse = diff * lightColor;
// vec3 reflectDir = reflect(-lightDir, normal);
// float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
// vec3 specular = spec * lightColor;
return (diffuse /* + specular */) * l.color;
}
void main() { void main() {
vec3 n = /*normalize*/(v_normal); vec3 n = /*normalize*/(v_normal);
vec4 lit = vec4(1.0, 1.0, 1.0, 1.0);
// SH lighting
{
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];
if( (result.x*result.x+result.y*result.y+result.z*result.z) > 0.0 ) lit = vec4(result, 1.0);
}
// SH lighting // analytical lights (phong shading)
vec4 lit = vec4(1.0, 1.0, 1.0, 1.0); // @todo: support more shading models (blinn-phong, ue4 brdf, ...)
vec3 SHLightResult[9]; // for (int i=0; i<u_num_lights; i++) {
SHLightResult[0] = 0.282095f * u_coefficients_sh[0]; // lit += vec4(calculate_light(u_lights[i], n, v_position, /* @todo: push vdeye */ vec3(1.0,1.0,1.0)), 0.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];
if( (result.x*result.x+result.y*result.y+result.z*result.z) > 0.0 ) lit = vec4(result, 1.0); // base
vec4 diffuse;
if(u_matcaps) {
// 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 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)); diffuse = texture(u_texture2d, vec2(muv.x, 1.0-muv.y));
} else if(u_textured) { } else if(u_textured) {
@ -78,4 +126,4 @@ if(u_matcaps) {
vec3 col = u_rimcolor*(pow(smoothstep(1.0-u_rimrange.x,u_rimrange.y,rim), u_rimrange.z)); vec3 col = u_rimcolor*(pow(smoothstep(1.0-u_rimrange.x,u_rimrange.y,rim), u_rimrange.z));
fragcolor += vec4(col, 1.0);} fragcolor += vec4(col, 1.0);}
#endif #endif
} }

View File

@ -1392,6 +1392,17 @@ ffi.cdef([[
//lcpp INF [0000] vec3: macro name but used as C declaration in:API void object_scale(object_t *obj, vec3 sca); //lcpp INF [0000] vec3: macro name but used as C declaration in:API void object_scale(object_t *obj, vec3 sca);
//lcpp INF [0000] vec3: macro name but used as C declaration in:STATIC void object_scale(object_t *obj, vec3 sca); //lcpp INF [0000] vec3: macro name but used as C declaration in:STATIC void object_scale(object_t *obj, vec3 sca);
//lcpp INF [0000] vec3: macro name but used as C declaration in: void object_scale(object_t *obj, vec3 sca); //lcpp INF [0000] vec3: macro name but used as C declaration in: void object_scale(object_t *obj, vec3 sca);
//lcpp INF [0000] vec3: macro name but used as C declaration in:vec3 color;
//lcpp INF [0000] vec3: macro name but used as C declaration in:vec3 pos, dir;
//lcpp INF [0000] vec3: macro name but used as C declaration in:API void light_color(light_t* l, vec3 color);
//lcpp INF [0000] vec3: macro name but used as C declaration in:STATIC void light_color(light_t* l, vec3 color);
//lcpp INF [0000] vec3: macro name but used as C declaration in: void light_color(light_t* l, vec3 color);
//lcpp INF [0000] vec3: macro name but used as C declaration in:API void light_teleport(light_t* l, vec3 pos);
//lcpp INF [0000] vec3: macro name but used as C declaration in:STATIC void light_teleport(light_t* l, vec3 pos);
//lcpp INF [0000] vec3: macro name but used as C declaration in: void light_teleport(light_t* l, vec3 pos);
//lcpp INF [0000] vec3: macro name but used as C declaration in:API void light_dir(light_t* l, vec3 dir);
//lcpp INF [0000] vec3: macro name but used as C declaration in:STATIC void light_dir(light_t* l, vec3 dir);
//lcpp INF [0000] vec3: macro name but used as C declaration in: void light_dir(light_t* l, vec3 dir);
//lcpp INF [0000] vec2: macro name but used as C declaration in:API vec2 ui_get_dims(); //lcpp INF [0000] vec2: macro name but used as C declaration in:API vec2 ui_get_dims();
//lcpp INF [0000] vec2: macro name but used as C declaration in:STATIC vec2 ui_get_dims(); //lcpp INF [0000] vec2: macro name but used as C declaration in:STATIC vec2 ui_get_dims();
//lcpp INF [0000] vec2: macro name but used as C declaration in: vec2 ui_get_dims(); //lcpp INF [0000] vec2: macro name but used as C declaration in: vec2 ui_get_dims();
@ -2660,6 +2671,7 @@ handle* textures;
model_t model; model_t model;
aabb bounds; aabb bounds;
unsigned billboard; unsigned billboard;
bool light_cached;
} object_t; } object_t;
object_t object(); object_t object();
void object_rotate(object_t *obj, vec3 euler); void object_rotate(object_t *obj, vec3 euler);
@ -2673,15 +2685,39 @@ unsigned billboard;
void object_diffuse_push(object_t *obj, texture_t tex); void object_diffuse_push(object_t *obj, texture_t tex);
void object_diffuse_pop(object_t *obj); void object_diffuse_pop(object_t *obj);
void object_billboard(object_t *obj, unsigned mode); void object_billboard(object_t *obj, unsigned mode);
enum LIGHT_TYPE {
LIGHT_DIRECTIONAL,
LIGHT_POINT,
LIGHT_SPOT,
};
enum LIGHT_FLAGS {
LIGHT_CAST_SHADOWS = 1,
};
typedef struct light_t {
char type;
vec3 color;
vec3 pos, dir;
float radius;
bool cached;
} light_t;
light_t light();
void light_type(light_t* l, char type);
void light_color(light_t* l, vec3 color);
void light_teleport(light_t* l, vec3 pos);
void light_dir(light_t* l, vec3 dir);
void light_radius(light_t* l, float radius);
void light_update(unsigned num_lights, light_t *lv);
enum SCENE_FLAGS { enum SCENE_FLAGS {
SCENE_WIREFRAME = 1, SCENE_WIREFRAME = 1,
SCENE_CULLFACE = 2, SCENE_CULLFACE = 2,
SCENE_BACKGROUND = 4, SCENE_BACKGROUND = 4,
SCENE_FOREGROUND = 8, SCENE_FOREGROUND = 8,
SCENE_UPDATE_SH_COEF = 16,
}; };
typedef struct scene_t { typedef struct scene_t {
handle program; handle program;
object_t* objs; object_t* objs;
light_t* lights;
skybox_t skybox; skybox_t skybox;
int u_coefficients_sh; int u_coefficients_sh;
} scene_t; } scene_t;
@ -2693,6 +2729,9 @@ int u_coefficients_sh;
object_t* scene_spawn(); object_t* scene_spawn();
unsigned scene_count(); unsigned scene_count();
object_t* scene_index(unsigned index); object_t* scene_index(unsigned index);
light_t* scene_spawn_light();
unsigned scene_count_light();
light_t* scene_index_light(unsigned index);
void script_init(); void script_init();
void script_run(const char *script); void script_run(const char *script);
void script_runfile(const char *pathfile); void script_runfile(const char *pathfile);

View File

@ -17131,6 +17131,7 @@ typedef struct object_t {
model_t model; model_t model;
aabb bounds; aabb bounds;
unsigned billboard; // [0..7] x(4),y(2),z(1) masks unsigned billboard; // [0..7] x(4),y(2),z(1) masks
bool light_cached; //< used by scene to update light data
} object_t; } object_t;
API object_t object(); API object_t object();
@ -17149,6 +17150,37 @@ API void object_billboard(object_t *obj, unsigned mode);
// object_pose(transform); // @todo // object_pose(transform); // @todo
// light
enum LIGHT_TYPE {
LIGHT_DIRECTIONAL,
LIGHT_POINT,
LIGHT_SPOT,
};
enum LIGHT_FLAGS {
LIGHT_CAST_SHADOWS = 1,
};
typedef struct light_t {
char type;
vec3 color;
vec3 pos, dir;
float radius;
bool cached; //< used by scene to invalidate cached light data
//@todo: inner/outer cone, flags, cookie, flare
} light_t;
API light_t light();
// API void light_flags(int flags);
API void light_type(light_t* l, char type);
API void light_color(light_t* l, vec3 color);
API void light_teleport(light_t* l, vec3 pos);
API void light_dir(light_t* l, vec3 dir);
API void light_radius(light_t* l, float radius);
// API void light_cone(light_t* l, float inner, float outer);
API void light_update(unsigned num_lights, light_t *lv);
// scene // scene
enum SCENE_FLAGS { enum SCENE_FLAGS {
@ -17156,12 +17188,14 @@ enum SCENE_FLAGS {
SCENE_CULLFACE = 2, SCENE_CULLFACE = 2,
SCENE_BACKGROUND = 4, SCENE_BACKGROUND = 4,
SCENE_FOREGROUND = 8, SCENE_FOREGROUND = 8,
SCENE_UPDATE_SH_COEF = 16,
}; };
typedef struct scene_t { typedef struct scene_t {
handle program; handle program;
array(object_t) objs; array(object_t) objs;
array(light_t) lights;
// special objects below: // special objects below:
skybox_t skybox; skybox_t skybox;
@ -17178,6 +17212,10 @@ API void scene_render(int flags);
API object_t* scene_spawn(); API object_t* scene_spawn();
API unsigned scene_count(); API unsigned scene_count();
API object_t* scene_index(unsigned index); API object_t* scene_index(unsigned index);
API light_t* scene_spawn_light();
API unsigned scene_count_light();
API light_t* scene_index_light(unsigned index);
#line 0 #line 0
#line 1 "v4k_script.h" #line 1 "v4k_script.h"
@ -342062,6 +342100,7 @@ skybox_t skybox(const char *asset, int flags) {
shader_float("uRayleighScaleHeight", 8000.0); shader_float("uRayleighScaleHeight", 8000.0);
shader_float("uMieScaleHeight", 1200.0); shader_float("uMieScaleHeight", 1200.0);
shader_float("uMiePreferredDirection", 0.758); shader_float("uMiePreferredDirection", 0.758);
skybox_mie_calc_sh(&sky, 1.2);
} }
return sky; return sky;
@ -345154,6 +345193,54 @@ void object_billboard(object_t *obj, unsigned mode) {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
light_t light() {
light_t l = {0};
l.color = vec3(1,1,1);
l.radius = 2.5f;
l.dir = vec3(1,-1,-1);
return l;
}
void light_type(light_t* l, char type) {
l->cached = 0;
l->type = type;
}
void light_color(light_t* l, vec3 color) {
l->cached = 0;
l->color = color;
}
void light_teleport(light_t* l, vec3 pos) {
l->cached = 0;
l->pos = pos;
}
void light_dir(light_t* l, vec3 dir) {
l->cached = 0;
l->dir = dir;
}
void light_radius(light_t* l, float radius) {
l->cached = 0;
l->radius = radius;
}
void light_update(unsigned num_lights, light_t *lv) {
shader_int("u_num_lights", num_lights);
for (unsigned i=0; i < num_lights; ++i) {
lv[i].cached = 1;
shader_int(va("u_lights[%d].type", i), lv[i].type);
shader_vec3(va("u_lights[%d].color", i), lv[i].color);
shader_vec3(va("u_lights[%d].pos", i), lv[i].pos);
shader_vec3(va("u_lights[%d].dir", i), lv[i].dir);
}
}
// -----------------------------------------------------------------------------
array(scene_t*) scenes; array(scene_t*) scenes;
scene_t* last_scene; scene_t* last_scene;
@ -345257,6 +345344,24 @@ object_t* scene_index(unsigned obj_index) {
return &last_scene->objs[obj_index]; return &last_scene->objs[obj_index];
} }
light_t* scene_spawn_light() {
light_t l = light();
array_push(last_scene->lights, l);
return array_back(last_scene->lights);
}
unsigned scene_count_light() {
return array_count(last_scene->lights);
}
light_t* scene_index_light(unsigned light_index) {
unsigned light_count = scene_count_light();
ASSERT(light_index < light_count, "Light index %d exceeds number (%d) of spawned lights", light_index, light_count);
return &last_scene->lights[light_index];
}
void scene_render(int flags) { void scene_render(int flags) {
camera_t *cam = camera_get_active(); camera_t *cam = camera_get_active();
@ -345293,6 +345398,14 @@ void scene_render(int flags) {
// @todo texture mode // @todo texture mode
if( flags & SCENE_FOREGROUND ) { if( flags & SCENE_FOREGROUND ) {
bool do_relighting = 0;
for (unsigned j = 0; j < array_count(last_scene->lights); ++j) {
if (!last_scene->lights[j].cached) {
do_relighting = 1;
break;
}
}
for(unsigned j = 0, obj_count = scene_count(); j < obj_count; ++j ) { for(unsigned j = 0, obj_count = scene_count(); j < obj_count; ++j ) {
object_t *obj = scene_index(j); object_t *obj = scene_index(j);
model_t *model = &obj->model; model_t *model = &obj->model;
@ -345309,6 +345422,17 @@ void scene_render(int flags) {
} }
} }
if ( do_relighting || !obj->light_cached ) {
obj->light_cached = 1;
shader_bind(model->program);
light_update(array_count(last_scene->lights), last_scene->lights);
}
if ( flags&SCENE_UPDATE_SH_COEF ) {
shader_bind(model->program);
shader_vec3v("u_coefficients_sh", 9, last_scene->skybox.cubemap.sh);
}
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, 0);

View File

@ -2490,6 +2490,7 @@ skybox_t skybox(const char *asset, int flags) {
shader_float("uRayleighScaleHeight", 8000.0); shader_float("uRayleighScaleHeight", 8000.0);
shader_float("uMieScaleHeight", 1200.0); shader_float("uMieScaleHeight", 1200.0);
shader_float("uMiePreferredDirection", 0.758); shader_float("uMiePreferredDirection", 0.758);
skybox_mie_calc_sh(&sky, 1.2);
} }
return sky; return sky;

View File

@ -241,6 +241,54 @@ void object_billboard(object_t *obj, unsigned mode) {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
light_t light() {
light_t l = {0};
l.color = vec3(1,1,1);
l.radius = 2.5f;
l.dir = vec3(1,-1,-1);
return l;
}
void light_type(light_t* l, char type) {
l->cached = 0;
l->type = type;
}
void light_color(light_t* l, vec3 color) {
l->cached = 0;
l->color = color;
}
void light_teleport(light_t* l, vec3 pos) {
l->cached = 0;
l->pos = pos;
}
void light_dir(light_t* l, vec3 dir) {
l->cached = 0;
l->dir = dir;
}
void light_radius(light_t* l, float radius) {
l->cached = 0;
l->radius = radius;
}
void light_update(unsigned num_lights, light_t *lv) {
shader_int("u_num_lights", num_lights);
for (unsigned i=0; i < num_lights; ++i) {
lv[i].cached = 1;
shader_int(va("u_lights[%d].type", i), lv[i].type);
shader_vec3(va("u_lights[%d].color", i), lv[i].color);
shader_vec3(va("u_lights[%d].pos", i), lv[i].pos);
shader_vec3(va("u_lights[%d].dir", i), lv[i].dir);
}
}
// -----------------------------------------------------------------------------
array(scene_t*) scenes; array(scene_t*) scenes;
scene_t* last_scene; scene_t* last_scene;
@ -344,6 +392,24 @@ object_t* scene_index(unsigned obj_index) {
return &last_scene->objs[obj_index]; return &last_scene->objs[obj_index];
} }
light_t* scene_spawn_light() {
light_t l = light();
array_push(last_scene->lights, l);
return array_back(last_scene->lights);
}
unsigned scene_count_light() {
return array_count(last_scene->lights);
}
light_t* scene_index_light(unsigned light_index) {
unsigned light_count = scene_count_light();
ASSERT(light_index < light_count, "Light index %d exceeds number (%d) of spawned lights", light_index, light_count);
return &last_scene->lights[light_index];
}
void scene_render(int flags) { void scene_render(int flags) {
camera_t *cam = camera_get_active(); camera_t *cam = camera_get_active();
@ -380,6 +446,14 @@ void scene_render(int flags) {
// @todo texture mode // @todo texture mode
if( flags & SCENE_FOREGROUND ) { if( flags & SCENE_FOREGROUND ) {
bool do_relighting = 0;
for (unsigned j = 0; j < array_count(last_scene->lights); ++j) {
if (!last_scene->lights[j].cached) {
do_relighting = 1;
break;
}
}
for(unsigned j = 0, obj_count = scene_count(); j < obj_count; ++j ) { for(unsigned j = 0, obj_count = scene_count(); j < obj_count; ++j ) {
object_t *obj = scene_index(j); object_t *obj = scene_index(j);
model_t *model = &obj->model; model_t *model = &obj->model;
@ -396,6 +470,17 @@ void scene_render(int flags) {
} }
} }
if ( do_relighting || !obj->light_cached ) {
obj->light_cached = 1;
shader_bind(model->program);
light_update(array_count(last_scene->lights), last_scene->lights);
}
if ( flags&SCENE_UPDATE_SH_COEF ) {
shader_bind(model->program);
shader_vec3v("u_coefficients_sh", 9, last_scene->skybox.cubemap.sh);
}
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, 0);

View File

@ -33,6 +33,7 @@ typedef struct object_t {
model_t model; model_t model;
aabb bounds; aabb bounds;
unsigned billboard; // [0..7] x(4),y(2),z(1) masks unsigned billboard; // [0..7] x(4),y(2),z(1) masks
bool light_cached; //< used by scene to update light data
} object_t; } object_t;
API object_t object(); API object_t object();
@ -51,6 +52,37 @@ API void object_billboard(object_t *obj, unsigned mode);
// object_pose(transform); // @todo // object_pose(transform); // @todo
// light
enum LIGHT_TYPE {
LIGHT_DIRECTIONAL,
LIGHT_POINT,
LIGHT_SPOT,
};
enum LIGHT_FLAGS {
LIGHT_CAST_SHADOWS = 1,
};
typedef struct light_t {
char type;
vec3 color;
vec3 pos, dir;
float radius;
bool cached; //< used by scene to invalidate cached light data
//@todo: inner/outer cone, flags, cookie, flare
} light_t;
API light_t light();
// API void light_flags(int flags);
API void light_type(light_t* l, char type);
API void light_color(light_t* l, vec3 color);
API void light_teleport(light_t* l, vec3 pos);
API void light_dir(light_t* l, vec3 dir);
API void light_radius(light_t* l, float radius);
// API void light_cone(light_t* l, float inner, float outer);
API void light_update(unsigned num_lights, light_t *lv);
// scene // scene
enum SCENE_FLAGS { enum SCENE_FLAGS {
@ -58,12 +90,14 @@ enum SCENE_FLAGS {
SCENE_CULLFACE = 2, SCENE_CULLFACE = 2,
SCENE_BACKGROUND = 4, SCENE_BACKGROUND = 4,
SCENE_FOREGROUND = 8, SCENE_FOREGROUND = 8,
SCENE_UPDATE_SH_COEF = 16,
}; };
typedef struct scene_t { typedef struct scene_t {
handle program; handle program;
array(object_t) objs; array(object_t) objs;
array(light_t) lights;
// special objects below: // special objects below:
skybox_t skybox; skybox_t skybox;
@ -80,3 +114,7 @@ API void scene_render(int flags);
API object_t* scene_spawn(); API object_t* scene_spawn();
API unsigned scene_count(); API unsigned scene_count();
API object_t* scene_index(unsigned index); API object_t* scene_index(unsigned index);
API light_t* scene_spawn_light();
API unsigned scene_count_light();
API light_t* scene_index_light(unsigned index);

View File

@ -12754,6 +12754,7 @@ skybox_t skybox(const char *asset, int flags) {
shader_float("uRayleighScaleHeight", 8000.0); shader_float("uRayleighScaleHeight", 8000.0);
shader_float("uMieScaleHeight", 1200.0); shader_float("uMieScaleHeight", 1200.0);
shader_float("uMiePreferredDirection", 0.758); shader_float("uMiePreferredDirection", 0.758);
skybox_mie_calc_sh(&sky, 1.2);
} }
return sky; return sky;
@ -15846,6 +15847,54 @@ void object_billboard(object_t *obj, unsigned mode) {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
light_t light() {
light_t l = {0};
l.color = vec3(1,1,1);
l.radius = 2.5f;
l.dir = vec3(1,-1,-1);
return l;
}
void light_type(light_t* l, char type) {
l->cached = 0;
l->type = type;
}
void light_color(light_t* l, vec3 color) {
l->cached = 0;
l->color = color;
}
void light_teleport(light_t* l, vec3 pos) {
l->cached = 0;
l->pos = pos;
}
void light_dir(light_t* l, vec3 dir) {
l->cached = 0;
l->dir = dir;
}
void light_radius(light_t* l, float radius) {
l->cached = 0;
l->radius = radius;
}
void light_update(unsigned num_lights, light_t *lv) {
shader_int("u_num_lights", num_lights);
for (unsigned i=0; i < num_lights; ++i) {
lv[i].cached = 1;
shader_int(va("u_lights[%d].type", i), lv[i].type);
shader_vec3(va("u_lights[%d].color", i), lv[i].color);
shader_vec3(va("u_lights[%d].pos", i), lv[i].pos);
shader_vec3(va("u_lights[%d].dir", i), lv[i].dir);
}
}
// -----------------------------------------------------------------------------
array(scene_t*) scenes; array(scene_t*) scenes;
scene_t* last_scene; scene_t* last_scene;
@ -15949,6 +15998,24 @@ object_t* scene_index(unsigned obj_index) {
return &last_scene->objs[obj_index]; return &last_scene->objs[obj_index];
} }
light_t* scene_spawn_light() {
light_t l = light();
array_push(last_scene->lights, l);
return array_back(last_scene->lights);
}
unsigned scene_count_light() {
return array_count(last_scene->lights);
}
light_t* scene_index_light(unsigned light_index) {
unsigned light_count = scene_count_light();
ASSERT(light_index < light_count, "Light index %d exceeds number (%d) of spawned lights", light_index, light_count);
return &last_scene->lights[light_index];
}
void scene_render(int flags) { void scene_render(int flags) {
camera_t *cam = camera_get_active(); camera_t *cam = camera_get_active();
@ -15985,6 +16052,14 @@ void scene_render(int flags) {
// @todo texture mode // @todo texture mode
if( flags & SCENE_FOREGROUND ) { if( flags & SCENE_FOREGROUND ) {
bool do_relighting = 0;
for (unsigned j = 0; j < array_count(last_scene->lights); ++j) {
if (!last_scene->lights[j].cached) {
do_relighting = 1;
break;
}
}
for(unsigned j = 0, obj_count = scene_count(); j < obj_count; ++j ) { for(unsigned j = 0, obj_count = scene_count(); j < obj_count; ++j ) {
object_t *obj = scene_index(j); object_t *obj = scene_index(j);
model_t *model = &obj->model; model_t *model = &obj->model;
@ -16001,6 +16076,17 @@ void scene_render(int flags) {
} }
} }
if ( do_relighting || !obj->light_cached ) {
obj->light_cached = 1;
shader_bind(model->program);
light_update(array_count(last_scene->lights), last_scene->lights);
}
if ( flags&SCENE_UPDATE_SH_COEF ) {
shader_bind(model->program);
shader_vec3v("u_coefficients_sh", 9, last_scene->skybox.cubemap.sh);
}
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, 0);

View File

@ -3214,6 +3214,7 @@ typedef struct object_t {
model_t model; model_t model;
aabb bounds; aabb bounds;
unsigned billboard; // [0..7] x(4),y(2),z(1) masks unsigned billboard; // [0..7] x(4),y(2),z(1) masks
bool light_cached; //< used by scene to update light data
} object_t; } object_t;
API object_t object(); API object_t object();
@ -3232,6 +3233,37 @@ API void object_billboard(object_t *obj, unsigned mode);
// object_pose(transform); // @todo // object_pose(transform); // @todo
// light
enum LIGHT_TYPE {
LIGHT_DIRECTIONAL,
LIGHT_POINT,
LIGHT_SPOT,
};
enum LIGHT_FLAGS {
LIGHT_CAST_SHADOWS = 1,
};
typedef struct light_t {
char type;
vec3 color;
vec3 pos, dir;
float radius;
bool cached; //< used by scene to invalidate cached light data
//@todo: inner/outer cone, flags, cookie, flare
} light_t;
API light_t light();
// API void light_flags(int flags);
API void light_type(light_t* l, char type);
API void light_color(light_t* l, vec3 color);
API void light_teleport(light_t* l, vec3 pos);
API void light_dir(light_t* l, vec3 dir);
API void light_radius(light_t* l, float radius);
// API void light_cone(light_t* l, float inner, float outer);
API void light_update(unsigned num_lights, light_t *lv);
// scene // scene
enum SCENE_FLAGS { enum SCENE_FLAGS {
@ -3239,12 +3271,14 @@ enum SCENE_FLAGS {
SCENE_CULLFACE = 2, SCENE_CULLFACE = 2,
SCENE_BACKGROUND = 4, SCENE_BACKGROUND = 4,
SCENE_FOREGROUND = 8, SCENE_FOREGROUND = 8,
SCENE_UPDATE_SH_COEF = 16,
}; };
typedef struct scene_t { typedef struct scene_t {
handle program; handle program;
array(object_t) objs; array(object_t) objs;
array(light_t) lights;
// special objects below: // special objects below:
skybox_t skybox; skybox_t skybox;
@ -3261,6 +3295,10 @@ API void scene_render(int flags);
API object_t* scene_spawn(); API object_t* scene_spawn();
API unsigned scene_count(); API unsigned scene_count();
API object_t* scene_index(unsigned index); API object_t* scene_index(unsigned index);
API light_t* scene_spawn_light();
API unsigned scene_count_light();
API light_t* scene_index_light(unsigned index);
#line 0 #line 0
#line 1 "v4k_script.h" #line 1 "v4k_script.h"

View File

@ -1,4 +1,4 @@
; this is where you specify and configure the V4K pipeline. ; this is where you specify and configure the FWK pipeline.
; tweak the pipeline and add new importers just by editing this file. ; tweak the pipeline and add new importers just by editing this file.
; there is no flow control in this script file: lines are parsed and evaluated, from top to bottom. ; there is no flow control in this script file: lines are parsed and evaluated, from top to bottom.

View File

@ -112,14 +112,14 @@ int main() {
load_asset(file); load_asset(file);
show_browser = 1; show_browser = 1;
} }
ui_panel_end();
} }
ui_panel_end();
static bool show_main_window = 1; static bool show_main_window = 1;
if ( ui_window("Workbench", &show_main_window) ) { if ( ui_window("Workbench", &show_main_window) ) {
ui_label("v4.games"); ui_label("v4.games");
ui_window_end();
} }
ui_window_end();
for (int i=0; i<array_count(assets); i++) { for (int i=0; i<array_count(assets); i++) {
asset_t *f = (assets+i); asset_t *f = (assets+i);
@ -145,8 +145,8 @@ int main() {
array_erase(assets, i); array_erase(assets, i);
--i; --i;
} }
ui_window_end();
} }
ui_window_end();
} }
} }
return 0; return 0;