pcf shadows for dir light
parent
2744bbbc47
commit
6319b11df6
11
bind/v4k.lua
11
bind/v4k.lua
|
@ -1142,6 +1142,10 @@ enum LIGHT_TYPE {
|
|||
LIGHT_POINT,
|
||||
LIGHT_SPOT,
|
||||
};
|
||||
enum SHADOW_TECHNIQUE {
|
||||
SHADOW_VSM,
|
||||
SHADOW_PCF,
|
||||
};
|
||||
typedef struct light_t {
|
||||
char type;
|
||||
vec3 diffuse, specular, ambient;
|
||||
|
@ -1153,8 +1157,10 @@ typedef struct light_t {
|
|||
float specularPower;
|
||||
float innerCone, outerCone;
|
||||
bool cast_shadows;
|
||||
unsigned shadow_technique;
|
||||
float shadow_distance;
|
||||
float shadow_bias;
|
||||
mat44 shadow_matrix;
|
||||
bool cached;
|
||||
} light_t;
|
||||
light_t light();
|
||||
|
@ -1175,8 +1181,12 @@ typedef struct shadowmap_t {
|
|||
int texture_width;
|
||||
int step;
|
||||
int light_step;
|
||||
unsigned shadow_technique;
|
||||
bool skip_render;
|
||||
int lights_pushed;
|
||||
struct {
|
||||
handle fbos[6], texture, depth_texture;
|
||||
handle fbo_2d, texture_2d, depth_texture_2d;
|
||||
} maps[MAX_LIGHTS];
|
||||
handle saved_fb;
|
||||
handle saved_pass;
|
||||
|
@ -1184,7 +1194,6 @@ typedef struct shadowmap_t {
|
|||
} shadowmap_t;
|
||||
shadowmap_t shadowmap(int texture_width);
|
||||
void shadowmap_destroy(shadowmap_t *s);
|
||||
void shadowmap_set_shadowmatrix(shadowmap_t *s, vec3 aLightPos, vec3 aLightAt, vec3 aLightUp, const mat44 projection);
|
||||
void shadowmap_begin(shadowmap_t *s);
|
||||
bool shadowmap_step(shadowmap_t *s);
|
||||
void shadowmap_light(shadowmap_t *s, light_t *l);
|
||||
|
|
|
@ -39,10 +39,26 @@ int main(int argc, char** argv) {
|
|||
lit2.cast_shadows = true;
|
||||
lit2.diffuse = vec3(1, 0.7, 0.8);
|
||||
}
|
||||
light_t lit3 = light(); {
|
||||
lit3.type = LIGHT_SPOT;
|
||||
lit3.cast_shadows = true;
|
||||
lit3.diffuse = vec3(1, 0.7, 0.8);
|
||||
}
|
||||
light_t lit4 = light(); {
|
||||
lit4.type = LIGHT_DIRECTIONAL;
|
||||
lit4.cast_shadows = true;
|
||||
lit4.diffuse = vec3(1, 0.7, 0.8);
|
||||
}
|
||||
|
||||
array(light_t) lights = 0;
|
||||
array_push(lights, lit);
|
||||
array_push(lights, lit2);
|
||||
array(light_t) point_lights = 0;
|
||||
array_push(point_lights, lit);
|
||||
array_push(point_lights, lit2);
|
||||
|
||||
array(light_t) spot_lights = 0;
|
||||
array_push(spot_lights, lit3);
|
||||
|
||||
array(light_t) directional_lights = 0;
|
||||
array_push(directional_lights, lit4);
|
||||
|
||||
bool initialized = 0;
|
||||
bool must_reload = 0;
|
||||
|
@ -75,7 +91,24 @@ int main(int argc, char** argv) {
|
|||
camera_moveby(&cam, wasdec);
|
||||
camera_fps(&cam, mouse.x,mouse.y);
|
||||
|
||||
enum {
|
||||
POINT, SPOT, DIR
|
||||
};
|
||||
static unsigned mode = POINT;
|
||||
|
||||
if (input_down(KEY_1)) mode = POINT;
|
||||
if (input_down(KEY_2)) mode = SPOT;
|
||||
if (input_down(KEY_3)) mode = DIR;
|
||||
|
||||
light_t *lights = 0;
|
||||
switch (mode) {
|
||||
case POINT: lights = point_lights; break;
|
||||
case SPOT: lights = spot_lights; break;
|
||||
case DIR: lights = directional_lights; break;
|
||||
}
|
||||
|
||||
// Animate light
|
||||
if (mode == POINT) {
|
||||
lights[0].pos = vec3(0, 5.5, 1);
|
||||
lights[0].pos.x += sinf(window_time()*2)*4.5f;
|
||||
lights[0].pos.y += cosf(window_time()*2)*1.0;
|
||||
|
@ -85,6 +118,18 @@ int main(int argc, char** argv) {
|
|||
lights[1].pos.x += sinf(window_time()*4)*4.5f;
|
||||
lights[1].pos.y += cosf(window_time()*4)*1.0;
|
||||
lights[1].pos.z += cosf(window_time()*4)*6.0;
|
||||
}
|
||||
|
||||
static bool camera_spot = true;
|
||||
if (input_down(KEY_SPACE)) camera_spot = !camera_spot;
|
||||
if (mode == SPOT && camera_spot) {
|
||||
lights[0].pos = cam.position;
|
||||
lights[0].dir = cam.lookdir;
|
||||
}
|
||||
|
||||
if (mode == DIR) {
|
||||
lights[0].dir = vec3(1,-1,-1);
|
||||
}
|
||||
|
||||
// Render shadowmap
|
||||
shadowmap_begin(&sm);
|
||||
|
@ -106,9 +151,9 @@ int main(int argc, char** argv) {
|
|||
shader_int("u_textured", false);
|
||||
light_update(array_count(lights), lights);
|
||||
|
||||
ddraw_sphere(lights[0].pos, 0.1f);
|
||||
ddraw_sphere(lights[1].pos, 0.1f);
|
||||
ddraw_flush();
|
||||
// ddraw_sphere(lights[0].pos, 0.1f);
|
||||
// ddraw_sphere(lights[1].pos, 0.1f);
|
||||
// ddraw_flush();
|
||||
|
||||
model_shadow(&mdl, &sm);
|
||||
model_render(mdl, cam.proj, cam.view, mdl.pivot, 0);
|
||||
|
|
|
@ -21,6 +21,9 @@ struct light_t {
|
|||
float constant;
|
||||
float linear;
|
||||
float quadratic;
|
||||
|
||||
// shadows
|
||||
mat4 shadow_matrix;
|
||||
};
|
||||
|
||||
#define MAX_LIGHTS 16
|
||||
|
|
|
@ -2,9 +2,10 @@ in vec4 vpeye;
|
|||
in vec4 vneye;
|
||||
uniform bool u_shadow_receiver;
|
||||
uniform samplerCube shadowMap[MAX_LIGHTS];
|
||||
uniform sampler2D shadowMap2D[MAX_LIGHTS];
|
||||
|
||||
//// From http://fabiensanglard.net/shadowmappingVSM/index.php
|
||||
float chebyshevUpperBound(float distance, vec3 dir, int light_index) {
|
||||
float shadow_vsm(float distance, vec3 dir, int light_index) {
|
||||
distance = distance/20;
|
||||
vec2 moments = texture(shadowMap[light_index], dir).rg;
|
||||
|
||||
|
@ -25,6 +26,43 @@ float chebyshevUpperBound(float distance, vec3 dir, int light_index) {
|
|||
return p_max;
|
||||
}
|
||||
|
||||
float shadow_pcf(vec4 fragPosLightSpace, vec3 lightDir, int light_index) {
|
||||
// Perform perspective divide
|
||||
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
|
||||
|
||||
// Transform to [0,1] range
|
||||
projCoords = projCoords * 0.5 + 0.5;
|
||||
|
||||
// Get closest depth value from light's perspective (using [0,1] range fragPosLight as coords)
|
||||
float closestDepth = texture(shadowMap2D[light_index], projCoords.xy).r;
|
||||
|
||||
// Get depth of current fragment from light's perspective
|
||||
float currentDepth = projCoords.z;
|
||||
|
||||
// Calculate bias (based on depth map resolution and slope)
|
||||
vec3 normal = normalize(vneye.xyz);
|
||||
float bias = max(0.05 * (1.0 - dot(normal, -lightDir)), 0.005);
|
||||
|
||||
// PCF
|
||||
float shadow = 0.0;
|
||||
vec2 texelSize = 1.0 / textureSize(shadowMap2D[light_index], 0);
|
||||
for(int x = -1; x <= 1; ++x)
|
||||
{
|
||||
for(int y = -1; y <= 1; ++y)
|
||||
{
|
||||
float pcfDepth = texture(shadowMap2D[light_index], projCoords.xy + vec2(x, y) * texelSize).r;
|
||||
shadow += currentDepth - bias > pcfDepth ? 1.0 : 0.0;
|
||||
}
|
||||
}
|
||||
shadow /= 9.0;
|
||||
|
||||
// Keep the shadow at 0.0 when outside the far_plane region of the light's frustum.
|
||||
if(projCoords.z >= 0.9)
|
||||
shadow = 0.0;
|
||||
|
||||
return 1.0 - shadow;
|
||||
}
|
||||
|
||||
vec4 shadowmap(in vec4 peye, in vec4 neye) {
|
||||
float shadowFactor = 0.0;
|
||||
vec3 fragment = vec3(peye);
|
||||
|
@ -35,21 +73,27 @@ vec4 shadowmap(in vec4 peye, in vec4 neye) {
|
|||
float factor = 0.0;
|
||||
|
||||
if (light.type == LIGHT_DIRECTIONAL) {
|
||||
// shadowFactor = chebyshevUpperBound(distance, light.dir);
|
||||
total_casters++;
|
||||
vec4 frag_pos = light.shadow_matrix * vec4(v_position_ws, 1.0);
|
||||
factor += shadow_pcf(frag_pos, light.dir, i);
|
||||
} else if (light.type == LIGHT_POINT) {
|
||||
total_casters++;
|
||||
vec3 light_pos = (view * vec4(light.pos, 1.0)).xyz;
|
||||
vec3 dir = light_pos - fragment;
|
||||
vec4 sc = inv_view * vec4(dir, 0.0);
|
||||
factor += chebyshevUpperBound(length(dir), -sc.xyz, i);
|
||||
factor += shadow_vsm(length(dir), -sc.xyz, i);
|
||||
} else if (light.type == LIGHT_SPOT) {
|
||||
// shadowFactor = chebyshevUpperBound(distance, light.pos);
|
||||
total_casters++;
|
||||
vec3 light_pos = (view * vec4(light.pos, 1.0)).xyz;
|
||||
vec3 dir = light_pos - fragment;
|
||||
vec4 sc = inv_view * vec4(dir, 0.0);
|
||||
factor += shadow_vsm(length(dir), -sc.xyz, i);
|
||||
}
|
||||
|
||||
shadowFactor += factor;
|
||||
}
|
||||
|
||||
if (u_num_lights == 0) {
|
||||
if (total_casters == 0) {
|
||||
shadowFactor = 1.0;
|
||||
} else {
|
||||
shadowFactor /= total_casters;
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
in vec3 v_position;
|
||||
out vec4 fragcolor;
|
||||
|
||||
const int SHADOW_VSM = 0;
|
||||
const int SHADOW_PCF = 1;
|
||||
|
||||
uniform int shadow_technique;
|
||||
|
||||
void main() {
|
||||
if (shadow_technique == SHADOW_VSM) {
|
||||
float depth = length(v_position) / 20;
|
||||
|
||||
float moment1 = depth;
|
||||
|
@ -12,3 +18,7 @@ void main() {
|
|||
moment2 += 0.25*(dx*dx+dy*dy);
|
||||
fragcolor = vec4( moment1, moment2, 0.0, 1.0);
|
||||
}
|
||||
else if (shadow_technique == SHADOW_PCF) {
|
||||
fragcolor = vec4(vec3(gl_FragCoord.z), 1.0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17259,6 +17259,11 @@ enum LIGHT_TYPE {
|
|||
LIGHT_SPOT,
|
||||
};
|
||||
|
||||
enum SHADOW_TECHNIQUE {
|
||||
SHADOW_VSM,
|
||||
SHADOW_PCF,
|
||||
};
|
||||
|
||||
typedef struct light_t {
|
||||
char type;
|
||||
vec3 diffuse, specular, ambient;
|
||||
|
@ -17273,8 +17278,10 @@ typedef struct light_t {
|
|||
|
||||
// Shadowmapping
|
||||
bool cast_shadows;
|
||||
unsigned shadow_technique;
|
||||
float shadow_distance;
|
||||
float shadow_bias;
|
||||
mat44 shadow_matrix;
|
||||
|
||||
// internals
|
||||
bool cached; //< used by scene to invalidate cached light data
|
||||
|
@ -17310,9 +17317,15 @@ typedef struct shadowmap_t {
|
|||
int texture_width;
|
||||
int step;
|
||||
int light_step;
|
||||
unsigned shadow_technique;
|
||||
|
||||
// signals
|
||||
bool skip_render;
|
||||
int lights_pushed;
|
||||
|
||||
struct {
|
||||
handle fbos[6], texture, depth_texture;
|
||||
handle fbo_2d, texture_2d, depth_texture_2d;
|
||||
} maps[MAX_LIGHTS];
|
||||
|
||||
handle saved_fb;
|
||||
|
@ -17323,10 +17336,9 @@ typedef struct shadowmap_t {
|
|||
API shadowmap_t shadowmap(int texture_width); // = 1024
|
||||
API void shadowmap_destroy(shadowmap_t *s);
|
||||
|
||||
API void shadowmap_set_shadowmatrix(shadowmap_t *s, vec3 aLightPos, vec3 aLightAt, vec3 aLightUp, const mat44 projection);
|
||||
API void shadowmap_begin(shadowmap_t *s);
|
||||
API bool shadowmap_step(shadowmap_t *s);
|
||||
API void shadowmap_light(shadowmap_t *s, light_t *l);
|
||||
API void shadowmap_light(shadowmap_t *s, light_t *l); //< can be called once per shadowmap_step
|
||||
API void shadowmap_end(shadowmap_t *s);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -383254,6 +383266,7 @@ void light_update(unsigned num_lights, light_t *lv) {
|
|||
shader_float(va("u_lights[%d].quadratic", i), lv[i].falloff.quadratic);
|
||||
shader_float(va("u_lights[%d].innerCone", i), lv[i].innerCone);
|
||||
shader_float(va("u_lights[%d].outerCone", i), lv[i].outerCone);
|
||||
shader_mat44(va("u_lights[%d].shadow_matrix", i), lv[i].shadow_matrix);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -383263,6 +383276,8 @@ void light_update(unsigned num_lights, light_t *lv) {
|
|||
|
||||
static inline
|
||||
shadowmap_init_caster(shadowmap_t *s, int light_index, int texture_width) {
|
||||
float borderColor[] = {1.0, 1.0, 1.0, 1.0};
|
||||
|
||||
// Create a cubemap color texture
|
||||
glGenTextures(1, &s->maps[light_index].texture);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, s->maps[light_index].texture);
|
||||
|
@ -383273,6 +383288,10 @@ shadowmap_init_caster(shadowmap_t *s, int light_index, int texture_width) {
|
|||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||
glTexParameterfv(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BORDER_COLOR, borderColor);
|
||||
|
||||
// Create a cubemap depth texture
|
||||
glGenTextures(1, &s->maps[light_index].depth_texture);
|
||||
|
@ -383282,9 +383301,10 @@ shadowmap_init_caster(shadowmap_t *s, int light_index, int texture_width) {
|
|||
}
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||
glTexParameterfv(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BORDER_COLOR, borderColor);
|
||||
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
|
||||
|
||||
|
@ -383298,7 +383318,46 @@ shadowmap_init_caster(shadowmap_t *s, int light_index, int texture_width) {
|
|||
if (GL_FRAMEBUFFER_COMPLETE != result) {
|
||||
PANIC("ERROR: Framebuffer is not complete: %x\n", result);
|
||||
}
|
||||
// #if is(ems)
|
||||
// GLenum nones[] = { GL_NONE };
|
||||
// glDrawBuffers(1, nones);
|
||||
// glReadBuffer(GL_NONE);
|
||||
// #else
|
||||
// glDrawBuffer(GL_NONE);
|
||||
// glReadBuffer(GL_NONE);
|
||||
// #endif
|
||||
}
|
||||
|
||||
// Initialise shadow map 2D
|
||||
glGenTextures(1, &s->maps[light_index].texture_2d);
|
||||
glBindTexture(GL_TEXTURE_2D, s->maps[light_index].texture_2d);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, texture_width, texture_width, 0, GL_RGB, GL_FLOAT, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
|
||||
|
||||
glGenTextures(1, &s->maps[light_index].depth_texture_2d);
|
||||
glBindTexture(GL_TEXTURE_2D, s->maps[light_index].depth_texture_2d);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, texture_width, texture_width, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
glGenFramebuffers(1, &s->maps[light_index].fbo_2d);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, s->maps[light_index].fbo_2d);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, s->maps[light_index].texture_2d, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, s->maps[light_index].depth_texture_2d, 0);
|
||||
GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (GL_FRAMEBUFFER_COMPLETE != result) {
|
||||
PANIC("ERROR: Framebuffer is not complete: %x\n", result);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
shadowmap_t shadowmap(int texture_width) { // = 1024
|
||||
|
@ -383320,25 +383379,14 @@ void shadowmap_destroy(shadowmap_t *s) {
|
|||
glDeleteFramebuffers(6, s->maps[i].fbos);
|
||||
glDeleteTextures(1, &s->maps[i].texture);
|
||||
glDeleteTextures(1, &s->maps[i].depth_texture);
|
||||
glDeleteFramebuffers(1, &s->maps[i].fbo_2d);
|
||||
glDeleteTextures(1, &s->maps[i].texture_2d);
|
||||
glDeleteTextures(1, &s->maps[i].depth_texture_2d);
|
||||
}
|
||||
shadowmap_t z = {0};
|
||||
*s = z;
|
||||
}
|
||||
|
||||
void shadowmap_set_shadowmatrix(shadowmap_t *s, vec3 aLightPos, vec3 aLightAt, vec3 aLightUp, const mat44 projection) {
|
||||
// copy44(s->proj, projection);
|
||||
// lookat44(s->mv, aLightPos, aLightAt, aLightUp);
|
||||
|
||||
// mat44 bias = {
|
||||
// 0.5, 0.0, 0.0, 0.0,
|
||||
// 0.0, 0.5, 0.0, 0.0,
|
||||
// 0.0, 0.0, 0.5, 0.0,
|
||||
// 0.5, 0.5, 0.5, 1.0 };
|
||||
|
||||
// multiply44x3(s->shadowmatrix, bias, s->proj, s->mv);
|
||||
// multiply44x2(s->mvp, projection, s->mv);
|
||||
}
|
||||
|
||||
static shadowmap_t *active_shadowmap = NULL;
|
||||
|
||||
void shadowmap_begin(shadowmap_t *s) {
|
||||
|
@ -383349,15 +383397,6 @@ void shadowmap_begin(shadowmap_t *s) {
|
|||
s->step = 0;
|
||||
s->light_step = 0;
|
||||
active_shadowmap = s;
|
||||
|
||||
for (int i = 0; i < MAX_LIGHTS; i++) {
|
||||
for (int j = 0; j < 6; j++) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, s->maps[i].fbos[j]);
|
||||
glClearColor(0, 0, 0, 0);
|
||||
glClearDepth(1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void shadowmap_light_point(shadowmap_t *s, light_t *l, int dir) {
|
||||
|
@ -383376,6 +383415,42 @@ static void shadowmap_light_point(shadowmap_t *s, light_t *l, int dir) {
|
|||
|
||||
copy44(s->V, V);
|
||||
copy44(s->PV, PV);
|
||||
|
||||
s->shadow_technique = l->shadow_technique = SHADOW_VSM;
|
||||
}
|
||||
|
||||
static void shadowmap_light_directional(shadowmap_t *s, light_t *l, int dir) {
|
||||
if (dir != 0) {
|
||||
s->skip_render = true;
|
||||
return;
|
||||
}
|
||||
|
||||
mat44 P, V, PV;
|
||||
l->shadow_distance = 25.0f;
|
||||
ortho44(P,
|
||||
-l->shadow_distance/2.0, l->shadow_distance/2.0,
|
||||
-l->shadow_distance/2.0, l->shadow_distance/2.0,
|
||||
l->shadow_bias, l->shadow_distance);
|
||||
|
||||
vec3 lightDir = norm3(l->dir);
|
||||
vec3 up = vec3(0, 1, 0);
|
||||
|
||||
// Ensure up vector is not parallel to light direction
|
||||
if (fabs(dot3(lightDir, up)) > 0.99f) {
|
||||
up = vec3(0, 0, 1);
|
||||
}
|
||||
|
||||
vec3 center = vec3(0, 0, 0);
|
||||
vec3 lightPos = sub3(center, scale3(lightDir, l->shadow_distance*0.5f));
|
||||
lookat44(V, lightPos, center, up);
|
||||
|
||||
multiply44x2(PV, P, V);
|
||||
|
||||
copy44(s->V, V);
|
||||
copy44(s->PV, PV);
|
||||
copy44(l->shadow_matrix, PV);
|
||||
|
||||
s->shadow_technique = l->shadow_technique = SHADOW_PCF;
|
||||
}
|
||||
|
||||
bool shadowmap_step(shadowmap_t *s) {
|
||||
|
@ -383385,13 +383460,21 @@ bool shadowmap_step(shadowmap_t *s) {
|
|||
return false;
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, s->maps[s->light_step].fbos[s->step]);
|
||||
glViewport(0, 0, s->texture_width, s->texture_width);
|
||||
|
||||
s->step++;
|
||||
s->skip_render = false;
|
||||
s->lights_pushed = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline
|
||||
void shadowmap_clear_fbo() {
|
||||
glClearColor(0, 0, 0, 0);
|
||||
glClearDepth(1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
void shadowmap_light(shadowmap_t *s, light_t *l) {
|
||||
if (l->cast_shadows) {
|
||||
int step = s->step - 1;
|
||||
|
@ -383399,9 +383482,24 @@ void shadowmap_light(shadowmap_t *s, light_t *l) {
|
|||
if (l->type == LIGHT_POINT) {
|
||||
shadowmap_light_point(s, l, step);
|
||||
} else if (l->type == LIGHT_SPOT) {
|
||||
// spot light
|
||||
shadowmap_light_point(s, l, step);
|
||||
} else if (l->type == LIGHT_DIRECTIONAL) {
|
||||
// directional light
|
||||
shadowmap_light_directional(s, l, step);
|
||||
}
|
||||
|
||||
if (s->skip_render) {
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT(s->lights_pushed == 0);
|
||||
s->lights_pushed++;
|
||||
|
||||
if (l->type == LIGHT_DIRECTIONAL) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, s->maps[s->light_step].fbo_2d);
|
||||
shadowmap_clear_fbo();
|
||||
} else {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, s->maps[s->light_step].fbos[step]);
|
||||
shadowmap_clear_fbo();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -383413,16 +383511,6 @@ void shadowmap_end(shadowmap_t *s) {
|
|||
active_shadowmap = NULL;
|
||||
}
|
||||
|
||||
// shadowmap utils
|
||||
|
||||
void shadowmatrix_proj(mat44 shm_proj, float aLightFov, float znear, float zfar) {
|
||||
perspective44(shm_proj, aLightFov, 1.0f, znear, zfar);
|
||||
}
|
||||
|
||||
void shadowmatrix_ortho(mat44 shm_proj, float left, float right, float bottom, float top, float znear, float zfar) {
|
||||
ortho44(shm_proj, left, right, bottom, top, znear, zfar);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Occlusion queries
|
||||
|
||||
|
@ -385592,6 +385680,7 @@ void model_set_uniforms(model_t m, int shader, mat44 mv, mat44 proj, mat44 view,
|
|||
ASSERT(sm);
|
||||
shader_mat44("cameraToShadowView", sm->V);
|
||||
shader_mat44("cameraToShadowProjector", sm->PV);
|
||||
shader_int("shadow_technique", sm->shadow_technique);
|
||||
}
|
||||
|
||||
// shadow receiving
|
||||
|
@ -385600,6 +385689,7 @@ void model_set_uniforms(model_t m, int shader, mat44 mv, mat44 proj, mat44 view,
|
|||
shader_bool("u_shadow_receiver", GL_TRUE);
|
||||
for (int i = 0; i < MAX_LIGHTS; i++) {
|
||||
shader_cubemap(va("shadowMap[%d]", i), m.shadow_map->maps[i].texture);
|
||||
shader_texture_unit(va("shadowMap2D[%d]", i), m.shadow_map->maps[i].texture_2d, texture_unit());
|
||||
}
|
||||
} else {
|
||||
shader_bool("u_shadow_receiver", GL_FALSE);
|
||||
|
@ -386750,6 +386840,10 @@ void model_render_instanced_pass(model_t m, mat44 proj, mat44 view, mat44* model
|
|||
if(!m.iqm) return;
|
||||
iqm_t *q = m.iqm;
|
||||
|
||||
if (active_shadowmap && active_shadowmap->skip_render) {
|
||||
return;
|
||||
}
|
||||
|
||||
mat44 mv; multiply44x2(mv, view, models[0]);
|
||||
|
||||
if( count != m.num_instances ) {
|
||||
|
|
|
@ -1552,6 +1552,7 @@ void light_update(unsigned num_lights, light_t *lv) {
|
|||
shader_float(va("u_lights[%d].quadratic", i), lv[i].falloff.quadratic);
|
||||
shader_float(va("u_lights[%d].innerCone", i), lv[i].innerCone);
|
||||
shader_float(va("u_lights[%d].outerCone", i), lv[i].outerCone);
|
||||
shader_mat44(va("u_lights[%d].shadow_matrix", i), lv[i].shadow_matrix);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1561,6 +1562,8 @@ void light_update(unsigned num_lights, light_t *lv) {
|
|||
|
||||
static inline
|
||||
shadowmap_init_caster(shadowmap_t *s, int light_index, int texture_width) {
|
||||
float borderColor[] = {1.0, 1.0, 1.0, 1.0};
|
||||
|
||||
// Create a cubemap color texture
|
||||
glGenTextures(1, &s->maps[light_index].texture);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, s->maps[light_index].texture);
|
||||
|
@ -1571,6 +1574,10 @@ shadowmap_init_caster(shadowmap_t *s, int light_index, int texture_width) {
|
|||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||
glTexParameterfv(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BORDER_COLOR, borderColor);
|
||||
|
||||
// Create a cubemap depth texture
|
||||
glGenTextures(1, &s->maps[light_index].depth_texture);
|
||||
|
@ -1580,9 +1587,10 @@ shadowmap_init_caster(shadowmap_t *s, int light_index, int texture_width) {
|
|||
}
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||
glTexParameterfv(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BORDER_COLOR, borderColor);
|
||||
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
|
||||
|
||||
|
@ -1596,7 +1604,46 @@ shadowmap_init_caster(shadowmap_t *s, int light_index, int texture_width) {
|
|||
if (GL_FRAMEBUFFER_COMPLETE != result) {
|
||||
PANIC("ERROR: Framebuffer is not complete: %x\n", result);
|
||||
}
|
||||
// #if is(ems)
|
||||
// GLenum nones[] = { GL_NONE };
|
||||
// glDrawBuffers(1, nones);
|
||||
// glReadBuffer(GL_NONE);
|
||||
// #else
|
||||
// glDrawBuffer(GL_NONE);
|
||||
// glReadBuffer(GL_NONE);
|
||||
// #endif
|
||||
}
|
||||
|
||||
// Initialise shadow map 2D
|
||||
glGenTextures(1, &s->maps[light_index].texture_2d);
|
||||
glBindTexture(GL_TEXTURE_2D, s->maps[light_index].texture_2d);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, texture_width, texture_width, 0, GL_RGB, GL_FLOAT, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
|
||||
|
||||
glGenTextures(1, &s->maps[light_index].depth_texture_2d);
|
||||
glBindTexture(GL_TEXTURE_2D, s->maps[light_index].depth_texture_2d);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, texture_width, texture_width, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
glGenFramebuffers(1, &s->maps[light_index].fbo_2d);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, s->maps[light_index].fbo_2d);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, s->maps[light_index].texture_2d, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, s->maps[light_index].depth_texture_2d, 0);
|
||||
GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (GL_FRAMEBUFFER_COMPLETE != result) {
|
||||
PANIC("ERROR: Framebuffer is not complete: %x\n", result);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
shadowmap_t shadowmap(int texture_width) { // = 1024
|
||||
|
@ -1618,25 +1665,14 @@ void shadowmap_destroy(shadowmap_t *s) {
|
|||
glDeleteFramebuffers(6, s->maps[i].fbos);
|
||||
glDeleteTextures(1, &s->maps[i].texture);
|
||||
glDeleteTextures(1, &s->maps[i].depth_texture);
|
||||
glDeleteFramebuffers(1, &s->maps[i].fbo_2d);
|
||||
glDeleteTextures(1, &s->maps[i].texture_2d);
|
||||
glDeleteTextures(1, &s->maps[i].depth_texture_2d);
|
||||
}
|
||||
shadowmap_t z = {0};
|
||||
*s = z;
|
||||
}
|
||||
|
||||
void shadowmap_set_shadowmatrix(shadowmap_t *s, vec3 aLightPos, vec3 aLightAt, vec3 aLightUp, const mat44 projection) {
|
||||
// copy44(s->proj, projection);
|
||||
// lookat44(s->mv, aLightPos, aLightAt, aLightUp);
|
||||
|
||||
// mat44 bias = {
|
||||
// 0.5, 0.0, 0.0, 0.0,
|
||||
// 0.0, 0.5, 0.0, 0.0,
|
||||
// 0.0, 0.0, 0.5, 0.0,
|
||||
// 0.5, 0.5, 0.5, 1.0 };
|
||||
|
||||
// multiply44x3(s->shadowmatrix, bias, s->proj, s->mv);
|
||||
// multiply44x2(s->mvp, projection, s->mv);
|
||||
}
|
||||
|
||||
static shadowmap_t *active_shadowmap = NULL;
|
||||
|
||||
void shadowmap_begin(shadowmap_t *s) {
|
||||
|
@ -1647,15 +1683,6 @@ void shadowmap_begin(shadowmap_t *s) {
|
|||
s->step = 0;
|
||||
s->light_step = 0;
|
||||
active_shadowmap = s;
|
||||
|
||||
for (int i = 0; i < MAX_LIGHTS; i++) {
|
||||
for (int j = 0; j < 6; j++) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, s->maps[i].fbos[j]);
|
||||
glClearColor(0, 0, 0, 0);
|
||||
glClearDepth(1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void shadowmap_light_point(shadowmap_t *s, light_t *l, int dir) {
|
||||
|
@ -1674,6 +1701,42 @@ static void shadowmap_light_point(shadowmap_t *s, light_t *l, int dir) {
|
|||
|
||||
copy44(s->V, V);
|
||||
copy44(s->PV, PV);
|
||||
|
||||
s->shadow_technique = l->shadow_technique = SHADOW_VSM;
|
||||
}
|
||||
|
||||
static void shadowmap_light_directional(shadowmap_t *s, light_t *l, int dir) {
|
||||
if (dir != 0) {
|
||||
s->skip_render = true;
|
||||
return;
|
||||
}
|
||||
|
||||
mat44 P, V, PV;
|
||||
l->shadow_distance = 25.0f;
|
||||
ortho44(P,
|
||||
-l->shadow_distance/2.0, l->shadow_distance/2.0,
|
||||
-l->shadow_distance/2.0, l->shadow_distance/2.0,
|
||||
l->shadow_bias, l->shadow_distance);
|
||||
|
||||
vec3 lightDir = norm3(l->dir);
|
||||
vec3 up = vec3(0, 1, 0);
|
||||
|
||||
// Ensure up vector is not parallel to light direction
|
||||
if (fabs(dot3(lightDir, up)) > 0.99f) {
|
||||
up = vec3(0, 0, 1);
|
||||
}
|
||||
|
||||
vec3 center = vec3(0, 0, 0);
|
||||
vec3 lightPos = sub3(center, scale3(lightDir, l->shadow_distance*0.5f));
|
||||
lookat44(V, lightPos, center, up);
|
||||
|
||||
multiply44x2(PV, P, V);
|
||||
|
||||
copy44(s->V, V);
|
||||
copy44(s->PV, PV);
|
||||
copy44(l->shadow_matrix, PV);
|
||||
|
||||
s->shadow_technique = l->shadow_technique = SHADOW_PCF;
|
||||
}
|
||||
|
||||
bool shadowmap_step(shadowmap_t *s) {
|
||||
|
@ -1683,13 +1746,21 @@ bool shadowmap_step(shadowmap_t *s) {
|
|||
return false;
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, s->maps[s->light_step].fbos[s->step]);
|
||||
glViewport(0, 0, s->texture_width, s->texture_width);
|
||||
|
||||
s->step++;
|
||||
s->skip_render = false;
|
||||
s->lights_pushed = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline
|
||||
void shadowmap_clear_fbo() {
|
||||
glClearColor(0, 0, 0, 0);
|
||||
glClearDepth(1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
void shadowmap_light(shadowmap_t *s, light_t *l) {
|
||||
if (l->cast_shadows) {
|
||||
int step = s->step - 1;
|
||||
|
@ -1697,9 +1768,24 @@ void shadowmap_light(shadowmap_t *s, light_t *l) {
|
|||
if (l->type == LIGHT_POINT) {
|
||||
shadowmap_light_point(s, l, step);
|
||||
} else if (l->type == LIGHT_SPOT) {
|
||||
// spot light
|
||||
shadowmap_light_point(s, l, step);
|
||||
} else if (l->type == LIGHT_DIRECTIONAL) {
|
||||
// directional light
|
||||
shadowmap_light_directional(s, l, step);
|
||||
}
|
||||
|
||||
if (s->skip_render) {
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT(s->lights_pushed == 0);
|
||||
s->lights_pushed++;
|
||||
|
||||
if (l->type == LIGHT_DIRECTIONAL) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, s->maps[s->light_step].fbo_2d);
|
||||
shadowmap_clear_fbo();
|
||||
} else {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, s->maps[s->light_step].fbos[step]);
|
||||
shadowmap_clear_fbo();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1711,16 +1797,6 @@ void shadowmap_end(shadowmap_t *s) {
|
|||
active_shadowmap = NULL;
|
||||
}
|
||||
|
||||
// shadowmap utils
|
||||
|
||||
void shadowmatrix_proj(mat44 shm_proj, float aLightFov, float znear, float zfar) {
|
||||
perspective44(shm_proj, aLightFov, 1.0f, znear, zfar);
|
||||
}
|
||||
|
||||
void shadowmatrix_ortho(mat44 shm_proj, float left, float right, float bottom, float top, float znear, float zfar) {
|
||||
ortho44(shm_proj, left, right, bottom, top, znear, zfar);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Occlusion queries
|
||||
|
||||
|
@ -3890,6 +3966,7 @@ void model_set_uniforms(model_t m, int shader, mat44 mv, mat44 proj, mat44 view,
|
|||
ASSERT(sm);
|
||||
shader_mat44("cameraToShadowView", sm->V);
|
||||
shader_mat44("cameraToShadowProjector", sm->PV);
|
||||
shader_int("shadow_technique", sm->shadow_technique);
|
||||
}
|
||||
|
||||
// shadow receiving
|
||||
|
@ -3898,6 +3975,7 @@ void model_set_uniforms(model_t m, int shader, mat44 mv, mat44 proj, mat44 view,
|
|||
shader_bool("u_shadow_receiver", GL_TRUE);
|
||||
for (int i = 0; i < MAX_LIGHTS; i++) {
|
||||
shader_cubemap(va("shadowMap[%d]", i), m.shadow_map->maps[i].texture);
|
||||
shader_texture_unit(va("shadowMap2D[%d]", i), m.shadow_map->maps[i].texture_2d, texture_unit());
|
||||
}
|
||||
} else {
|
||||
shader_bool("u_shadow_receiver", GL_FALSE);
|
||||
|
@ -5048,6 +5126,10 @@ void model_render_instanced_pass(model_t m, mat44 proj, mat44 view, mat44* model
|
|||
if(!m.iqm) return;
|
||||
iqm_t *q = m.iqm;
|
||||
|
||||
if (active_shadowmap && active_shadowmap->skip_render) {
|
||||
return;
|
||||
}
|
||||
|
||||
mat44 mv; multiply44x2(mv, view, models[0]);
|
||||
|
||||
if( count != m.num_instances ) {
|
||||
|
|
|
@ -291,6 +291,11 @@ enum LIGHT_TYPE {
|
|||
LIGHT_SPOT,
|
||||
};
|
||||
|
||||
enum SHADOW_TECHNIQUE {
|
||||
SHADOW_VSM,
|
||||
SHADOW_PCF,
|
||||
};
|
||||
|
||||
typedef struct light_t {
|
||||
char type;
|
||||
vec3 diffuse, specular, ambient;
|
||||
|
@ -305,8 +310,10 @@ typedef struct light_t {
|
|||
|
||||
// Shadowmapping
|
||||
bool cast_shadows;
|
||||
unsigned shadow_technique;
|
||||
float shadow_distance;
|
||||
float shadow_bias;
|
||||
mat44 shadow_matrix;
|
||||
|
||||
// internals
|
||||
bool cached; //< used by scene to invalidate cached light data
|
||||
|
@ -342,9 +349,15 @@ typedef struct shadowmap_t {
|
|||
int texture_width;
|
||||
int step;
|
||||
int light_step;
|
||||
unsigned shadow_technique;
|
||||
|
||||
// signals
|
||||
bool skip_render;
|
||||
int lights_pushed;
|
||||
|
||||
struct {
|
||||
handle fbos[6], texture, depth_texture;
|
||||
handle fbo_2d, texture_2d, depth_texture_2d;
|
||||
} maps[MAX_LIGHTS];
|
||||
|
||||
handle saved_fb;
|
||||
|
@ -355,10 +368,9 @@ typedef struct shadowmap_t {
|
|||
API shadowmap_t shadowmap(int texture_width); // = 1024
|
||||
API void shadowmap_destroy(shadowmap_t *s);
|
||||
|
||||
API void shadowmap_set_shadowmatrix(shadowmap_t *s, vec3 aLightPos, vec3 aLightAt, vec3 aLightUp, const mat44 projection);
|
||||
API void shadowmap_begin(shadowmap_t *s);
|
||||
API bool shadowmap_step(shadowmap_t *s);
|
||||
API void shadowmap_light(shadowmap_t *s, light_t *l);
|
||||
API void shadowmap_light(shadowmap_t *s, light_t *l); //< can be called once per shadowmap_step
|
||||
API void shadowmap_end(shadowmap_t *s);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
160
engine/v4k.c
160
engine/v4k.c
|
@ -18351,6 +18351,7 @@ void light_update(unsigned num_lights, light_t *lv) {
|
|||
shader_float(va("u_lights[%d].quadratic", i), lv[i].falloff.quadratic);
|
||||
shader_float(va("u_lights[%d].innerCone", i), lv[i].innerCone);
|
||||
shader_float(va("u_lights[%d].outerCone", i), lv[i].outerCone);
|
||||
shader_mat44(va("u_lights[%d].shadow_matrix", i), lv[i].shadow_matrix);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18360,6 +18361,8 @@ void light_update(unsigned num_lights, light_t *lv) {
|
|||
|
||||
static inline
|
||||
shadowmap_init_caster(shadowmap_t *s, int light_index, int texture_width) {
|
||||
float borderColor[] = {1.0, 1.0, 1.0, 1.0};
|
||||
|
||||
// Create a cubemap color texture
|
||||
glGenTextures(1, &s->maps[light_index].texture);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, s->maps[light_index].texture);
|
||||
|
@ -18370,6 +18373,10 @@ shadowmap_init_caster(shadowmap_t *s, int light_index, int texture_width) {
|
|||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||
glTexParameterfv(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BORDER_COLOR, borderColor);
|
||||
|
||||
// Create a cubemap depth texture
|
||||
glGenTextures(1, &s->maps[light_index].depth_texture);
|
||||
|
@ -18379,9 +18386,10 @@ shadowmap_init_caster(shadowmap_t *s, int light_index, int texture_width) {
|
|||
}
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||
glTexParameterfv(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BORDER_COLOR, borderColor);
|
||||
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
|
||||
|
||||
|
@ -18395,7 +18403,46 @@ shadowmap_init_caster(shadowmap_t *s, int light_index, int texture_width) {
|
|||
if (GL_FRAMEBUFFER_COMPLETE != result) {
|
||||
PANIC("ERROR: Framebuffer is not complete: %x\n", result);
|
||||
}
|
||||
// #if is(ems)
|
||||
// GLenum nones[] = { GL_NONE };
|
||||
// glDrawBuffers(1, nones);
|
||||
// glReadBuffer(GL_NONE);
|
||||
// #else
|
||||
// glDrawBuffer(GL_NONE);
|
||||
// glReadBuffer(GL_NONE);
|
||||
// #endif
|
||||
}
|
||||
|
||||
// Initialise shadow map 2D
|
||||
glGenTextures(1, &s->maps[light_index].texture_2d);
|
||||
glBindTexture(GL_TEXTURE_2D, s->maps[light_index].texture_2d);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, texture_width, texture_width, 0, GL_RGB, GL_FLOAT, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
|
||||
|
||||
glGenTextures(1, &s->maps[light_index].depth_texture_2d);
|
||||
glBindTexture(GL_TEXTURE_2D, s->maps[light_index].depth_texture_2d);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, texture_width, texture_width, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
glGenFramebuffers(1, &s->maps[light_index].fbo_2d);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, s->maps[light_index].fbo_2d);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, s->maps[light_index].texture_2d, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, s->maps[light_index].depth_texture_2d, 0);
|
||||
GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (GL_FRAMEBUFFER_COMPLETE != result) {
|
||||
PANIC("ERROR: Framebuffer is not complete: %x\n", result);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
shadowmap_t shadowmap(int texture_width) { // = 1024
|
||||
|
@ -18417,25 +18464,14 @@ void shadowmap_destroy(shadowmap_t *s) {
|
|||
glDeleteFramebuffers(6, s->maps[i].fbos);
|
||||
glDeleteTextures(1, &s->maps[i].texture);
|
||||
glDeleteTextures(1, &s->maps[i].depth_texture);
|
||||
glDeleteFramebuffers(1, &s->maps[i].fbo_2d);
|
||||
glDeleteTextures(1, &s->maps[i].texture_2d);
|
||||
glDeleteTextures(1, &s->maps[i].depth_texture_2d);
|
||||
}
|
||||
shadowmap_t z = {0};
|
||||
*s = z;
|
||||
}
|
||||
|
||||
void shadowmap_set_shadowmatrix(shadowmap_t *s, vec3 aLightPos, vec3 aLightAt, vec3 aLightUp, const mat44 projection) {
|
||||
// copy44(s->proj, projection);
|
||||
// lookat44(s->mv, aLightPos, aLightAt, aLightUp);
|
||||
|
||||
// mat44 bias = {
|
||||
// 0.5, 0.0, 0.0, 0.0,
|
||||
// 0.0, 0.5, 0.0, 0.0,
|
||||
// 0.0, 0.0, 0.5, 0.0,
|
||||
// 0.5, 0.5, 0.5, 1.0 };
|
||||
|
||||
// multiply44x3(s->shadowmatrix, bias, s->proj, s->mv);
|
||||
// multiply44x2(s->mvp, projection, s->mv);
|
||||
}
|
||||
|
||||
static shadowmap_t *active_shadowmap = NULL;
|
||||
|
||||
void shadowmap_begin(shadowmap_t *s) {
|
||||
|
@ -18446,15 +18482,6 @@ void shadowmap_begin(shadowmap_t *s) {
|
|||
s->step = 0;
|
||||
s->light_step = 0;
|
||||
active_shadowmap = s;
|
||||
|
||||
for (int i = 0; i < MAX_LIGHTS; i++) {
|
||||
for (int j = 0; j < 6; j++) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, s->maps[i].fbos[j]);
|
||||
glClearColor(0, 0, 0, 0);
|
||||
glClearDepth(1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void shadowmap_light_point(shadowmap_t *s, light_t *l, int dir) {
|
||||
|
@ -18473,6 +18500,42 @@ static void shadowmap_light_point(shadowmap_t *s, light_t *l, int dir) {
|
|||
|
||||
copy44(s->V, V);
|
||||
copy44(s->PV, PV);
|
||||
|
||||
s->shadow_technique = l->shadow_technique = SHADOW_VSM;
|
||||
}
|
||||
|
||||
static void shadowmap_light_directional(shadowmap_t *s, light_t *l, int dir) {
|
||||
if (dir != 0) {
|
||||
s->skip_render = true;
|
||||
return;
|
||||
}
|
||||
|
||||
mat44 P, V, PV;
|
||||
l->shadow_distance = 25.0f;
|
||||
ortho44(P,
|
||||
-l->shadow_distance/2.0, l->shadow_distance/2.0,
|
||||
-l->shadow_distance/2.0, l->shadow_distance/2.0,
|
||||
l->shadow_bias, l->shadow_distance);
|
||||
|
||||
vec3 lightDir = norm3(l->dir);
|
||||
vec3 up = vec3(0, 1, 0);
|
||||
|
||||
// Ensure up vector is not parallel to light direction
|
||||
if (fabs(dot3(lightDir, up)) > 0.99f) {
|
||||
up = vec3(0, 0, 1);
|
||||
}
|
||||
|
||||
vec3 center = vec3(0, 0, 0);
|
||||
vec3 lightPos = sub3(center, scale3(lightDir, l->shadow_distance*0.5f));
|
||||
lookat44(V, lightPos, center, up);
|
||||
|
||||
multiply44x2(PV, P, V);
|
||||
|
||||
copy44(s->V, V);
|
||||
copy44(s->PV, PV);
|
||||
copy44(l->shadow_matrix, PV);
|
||||
|
||||
s->shadow_technique = l->shadow_technique = SHADOW_PCF;
|
||||
}
|
||||
|
||||
bool shadowmap_step(shadowmap_t *s) {
|
||||
|
@ -18482,13 +18545,21 @@ bool shadowmap_step(shadowmap_t *s) {
|
|||
return false;
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, s->maps[s->light_step].fbos[s->step]);
|
||||
glViewport(0, 0, s->texture_width, s->texture_width);
|
||||
|
||||
s->step++;
|
||||
s->skip_render = false;
|
||||
s->lights_pushed = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline
|
||||
void shadowmap_clear_fbo() {
|
||||
glClearColor(0, 0, 0, 0);
|
||||
glClearDepth(1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
void shadowmap_light(shadowmap_t *s, light_t *l) {
|
||||
if (l->cast_shadows) {
|
||||
int step = s->step - 1;
|
||||
|
@ -18496,9 +18567,24 @@ void shadowmap_light(shadowmap_t *s, light_t *l) {
|
|||
if (l->type == LIGHT_POINT) {
|
||||
shadowmap_light_point(s, l, step);
|
||||
} else if (l->type == LIGHT_SPOT) {
|
||||
// spot light
|
||||
shadowmap_light_point(s, l, step);
|
||||
} else if (l->type == LIGHT_DIRECTIONAL) {
|
||||
// directional light
|
||||
shadowmap_light_directional(s, l, step);
|
||||
}
|
||||
|
||||
if (s->skip_render) {
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT(s->lights_pushed == 0);
|
||||
s->lights_pushed++;
|
||||
|
||||
if (l->type == LIGHT_DIRECTIONAL) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, s->maps[s->light_step].fbo_2d);
|
||||
shadowmap_clear_fbo();
|
||||
} else {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, s->maps[s->light_step].fbos[step]);
|
||||
shadowmap_clear_fbo();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18510,16 +18596,6 @@ void shadowmap_end(shadowmap_t *s) {
|
|||
active_shadowmap = NULL;
|
||||
}
|
||||
|
||||
// shadowmap utils
|
||||
|
||||
void shadowmatrix_proj(mat44 shm_proj, float aLightFov, float znear, float zfar) {
|
||||
perspective44(shm_proj, aLightFov, 1.0f, znear, zfar);
|
||||
}
|
||||
|
||||
void shadowmatrix_ortho(mat44 shm_proj, float left, float right, float bottom, float top, float znear, float zfar) {
|
||||
ortho44(shm_proj, left, right, bottom, top, znear, zfar);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Occlusion queries
|
||||
|
||||
|
@ -20689,6 +20765,7 @@ void model_set_uniforms(model_t m, int shader, mat44 mv, mat44 proj, mat44 view,
|
|||
ASSERT(sm);
|
||||
shader_mat44("cameraToShadowView", sm->V);
|
||||
shader_mat44("cameraToShadowProjector", sm->PV);
|
||||
shader_int("shadow_technique", sm->shadow_technique);
|
||||
}
|
||||
|
||||
// shadow receiving
|
||||
|
@ -20697,6 +20774,7 @@ void model_set_uniforms(model_t m, int shader, mat44 mv, mat44 proj, mat44 view,
|
|||
shader_bool("u_shadow_receiver", GL_TRUE);
|
||||
for (int i = 0; i < MAX_LIGHTS; i++) {
|
||||
shader_cubemap(va("shadowMap[%d]", i), m.shadow_map->maps[i].texture);
|
||||
shader_texture_unit(va("shadowMap2D[%d]", i), m.shadow_map->maps[i].texture_2d, texture_unit());
|
||||
}
|
||||
} else {
|
||||
shader_bool("u_shadow_receiver", GL_FALSE);
|
||||
|
@ -21847,6 +21925,10 @@ void model_render_instanced_pass(model_t m, mat44 proj, mat44 view, mat44* model
|
|||
if(!m.iqm) return;
|
||||
iqm_t *q = m.iqm;
|
||||
|
||||
if (active_shadowmap && active_shadowmap->skip_render) {
|
||||
return;
|
||||
}
|
||||
|
||||
mat44 mv; multiply44x2(mv, view, models[0]);
|
||||
|
||||
if( count != m.num_instances ) {
|
||||
|
|
16
engine/v4k.h
16
engine/v4k.h
|
@ -3326,6 +3326,11 @@ enum LIGHT_TYPE {
|
|||
LIGHT_SPOT,
|
||||
};
|
||||
|
||||
enum SHADOW_TECHNIQUE {
|
||||
SHADOW_VSM,
|
||||
SHADOW_PCF,
|
||||
};
|
||||
|
||||
typedef struct light_t {
|
||||
char type;
|
||||
vec3 diffuse, specular, ambient;
|
||||
|
@ -3340,8 +3345,10 @@ typedef struct light_t {
|
|||
|
||||
// Shadowmapping
|
||||
bool cast_shadows;
|
||||
unsigned shadow_technique;
|
||||
float shadow_distance;
|
||||
float shadow_bias;
|
||||
mat44 shadow_matrix;
|
||||
|
||||
// internals
|
||||
bool cached; //< used by scene to invalidate cached light data
|
||||
|
@ -3377,9 +3384,15 @@ typedef struct shadowmap_t {
|
|||
int texture_width;
|
||||
int step;
|
||||
int light_step;
|
||||
unsigned shadow_technique;
|
||||
|
||||
// signals
|
||||
bool skip_render;
|
||||
int lights_pushed;
|
||||
|
||||
struct {
|
||||
handle fbos[6], texture, depth_texture;
|
||||
handle fbo_2d, texture_2d, depth_texture_2d;
|
||||
} maps[MAX_LIGHTS];
|
||||
|
||||
handle saved_fb;
|
||||
|
@ -3390,10 +3403,9 @@ typedef struct shadowmap_t {
|
|||
API shadowmap_t shadowmap(int texture_width); // = 1024
|
||||
API void shadowmap_destroy(shadowmap_t *s);
|
||||
|
||||
API void shadowmap_set_shadowmatrix(shadowmap_t *s, vec3 aLightPos, vec3 aLightAt, vec3 aLightUp, const mat44 projection);
|
||||
API void shadowmap_begin(shadowmap_t *s);
|
||||
API bool shadowmap_step(shadowmap_t *s);
|
||||
API void shadowmap_light(shadowmap_t *s, light_t *l);
|
||||
API void shadowmap_light(shadowmap_t *s, light_t *l); //< can be called once per shadowmap_step
|
||||
API void shadowmap_end(shadowmap_t *s);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
Loading…
Reference in New Issue