improved shadows again
parent
aa64db6e7f
commit
7fd64941f3
21
bind/v4k.lua
21
bind/v4k.lua
|
@ -1145,7 +1145,7 @@ enum LIGHT_TYPE {
|
||||||
};
|
};
|
||||||
enum SHADOW_TECHNIQUE {
|
enum SHADOW_TECHNIQUE {
|
||||||
SHADOW_VSM,
|
SHADOW_VSM,
|
||||||
SHADOW_PCF,
|
SHADOW_CSM,
|
||||||
};
|
};
|
||||||
typedef struct light_t {
|
typedef struct light_t {
|
||||||
char type;
|
char type;
|
||||||
|
@ -1181,28 +1181,31 @@ typedef struct shadowmap_t {
|
||||||
mat44 V;
|
mat44 V;
|
||||||
mat44 PV;
|
mat44 PV;
|
||||||
int vsm_texture_width;
|
int vsm_texture_width;
|
||||||
int pcf_texture_width;
|
int csm_texture_width;
|
||||||
int step;
|
int step;
|
||||||
int light_step;
|
int light_step;
|
||||||
int cascade_index;
|
int cascade_index;
|
||||||
unsigned shadow_technique;
|
unsigned shadow_technique;
|
||||||
float cascade_splits[6];
|
float cascade_splits[6];
|
||||||
bool blur_pcf;
|
bool blur_csm;
|
||||||
float blur_scale;
|
bool blur_vsm;
|
||||||
|
float csm_blur_scale;
|
||||||
|
float vsm_blur_scale;
|
||||||
bool skip_render;
|
bool skip_render;
|
||||||
int lights_pushed;
|
int lights_pushed;
|
||||||
|
handle fbo;
|
||||||
struct {
|
struct {
|
||||||
unsigned shadow_technique;
|
unsigned shadow_technique;
|
||||||
handle fbos[6], texture, depth_texture;
|
handle texture, depth_texture;
|
||||||
handle fbo_2d[6], texture_2d[6], depth_texture_2d[6];
|
handle texture_2d[6], depth_texture_2d[6];
|
||||||
handle blur_fbo_2d, blur_texture_2d;
|
handle blur_texture, blur_texture_2d;
|
||||||
float cascade_distances[6];
|
float cascade_distances[6];
|
||||||
} maps[MAX_LIGHTS];
|
} maps[MAX_LIGHTS];
|
||||||
handle saved_fb;
|
handle saved_fb;
|
||||||
handle saved_pass;
|
handle saved_pass;
|
||||||
int saved_vp[4];
|
int saved_vp[4];
|
||||||
} shadowmap_t;
|
} shadowmap_t;
|
||||||
shadowmap_t shadowmap(int vsm_texture_width, int pcf_texture_width);
|
shadowmap_t shadowmap(int vsm_texture_width, int csm_texture_width);
|
||||||
void shadowmap_destroy(shadowmap_t *s);
|
void shadowmap_destroy(shadowmap_t *s);
|
||||||
void shadowmap_begin(shadowmap_t *s);
|
void shadowmap_begin(shadowmap_t *s);
|
||||||
bool shadowmap_step(shadowmap_t *s);
|
bool shadowmap_step(shadowmap_t *s);
|
||||||
|
@ -1410,7 +1413,7 @@ enum RENDER_PASS {
|
||||||
RENDER_PASS_TRANSPARENT,
|
RENDER_PASS_TRANSPARENT,
|
||||||
RENDER_PASS_OVERRIDES_BEGIN,
|
RENDER_PASS_OVERRIDES_BEGIN,
|
||||||
RENDER_PASS_SHADOW_BEGIN,
|
RENDER_PASS_SHADOW_BEGIN,
|
||||||
RENDER_PASS_SHADOW_PCF,
|
RENDER_PASS_SHADOW_CSM,
|
||||||
RENDER_PASS_SHADOW_VSM,
|
RENDER_PASS_SHADOW_VSM,
|
||||||
RENDER_PASS_SHADOW_END,
|
RENDER_PASS_SHADOW_END,
|
||||||
RENDER_PASS_LIGHTMAP,
|
RENDER_PASS_LIGHTMAP,
|
||||||
|
|
|
@ -203,6 +203,11 @@ int main(int argc, char** argv) {
|
||||||
if( ui_list("Model", OBJ_MDLS, countof(OBJ_MDLS), &OBJ_MDL) ) {
|
if( ui_list("Model", OBJ_MDLS, countof(OBJ_MDLS), &OBJ_MDL) ) {
|
||||||
must_reload = 1;
|
must_reload = 1;
|
||||||
}
|
}
|
||||||
|
ui_separator();
|
||||||
|
ui_bool("CSM Blur", &sm.blur_csm);
|
||||||
|
ui_slider("CSM Blur Scale", &sm.csm_blur_scale);
|
||||||
|
ui_bool("VSM Blur", &sm.blur_vsm);
|
||||||
|
ui_slider("VSM Blur Scale", &sm.vsm_blur_scale);
|
||||||
ui_panel_end();
|
ui_panel_end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,32 +14,47 @@ const float bias_modifier[NUM_SHADOW_CASCADES] = float[NUM_SHADOW_CASCADES](0.95
|
||||||
//// From http://fabiensanglard.net/shadowmappingVSM/index.php
|
//// From http://fabiensanglard.net/shadowmappingVSM/index.php
|
||||||
float shadow_vsm(float distance, vec3 dir, int light_index) {
|
float shadow_vsm(float distance, vec3 dir, int light_index) {
|
||||||
distance = distance/200;
|
distance = distance/200;
|
||||||
vec2 moments = texture(shadowMap[light_index], dir).rg;
|
|
||||||
|
|
||||||
// If the shadow map is sampled outside of its bounds, return 1.0
|
// Define offsets for 2x2 PCF
|
||||||
|
vec3 offsets[4] = vec3[4](
|
||||||
|
vec3(-1, -1, 0) * 0.01,
|
||||||
|
vec3( 1, -1, 0) * 0.01,
|
||||||
|
vec3(-1, 1, 0) * 0.01,
|
||||||
|
vec3( 1, 1, 0) * 0.01
|
||||||
|
);
|
||||||
|
|
||||||
|
float shadow = 0.0;
|
||||||
|
|
||||||
|
// Perform 2x2 PCF
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
vec3 sampleDir = dir + offsets[i] * (rand(vec2(v_position_ws.x + offsets[i].x, v_position_ws.y + offsets[i].y))*1.75f + 1.25f);
|
||||||
|
vec2 moments = texture(shadowMap[light_index], sampleDir).rg;
|
||||||
|
|
||||||
|
// If the shadow map is sampled outside of its bounds, add 1.0
|
||||||
if (moments.x == 1.0 && moments.y == 1.0) {
|
if (moments.x == 1.0 && moments.y == 1.0) {
|
||||||
return 1.0;
|
shadow += 1.0;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Surface is fully lit. as the current fragment is before the light occluder
|
// Surface is fully lit if the current fragment is before the light occluder
|
||||||
if (distance <= moments.x) {
|
if (distance <= moments.x) {
|
||||||
return 1.0;
|
shadow += 1.0;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The fragment is either in shadow or penumbra. We now use chebyshev's upperBound to check
|
// Calculate VSM for this sample
|
||||||
// How likely this pixel is to be lit (p_max)
|
float variance = max(moments.y - (moments.x * moments.x), 0.0002);
|
||||||
float variance = moments.y - (moments.x*moments.x);
|
|
||||||
//variance = max(variance, 0.000002);
|
|
||||||
// variance = max(variance, 0.00002);
|
|
||||||
variance = max(variance, 0.0002);
|
|
||||||
|
|
||||||
float d = distance - moments.x;
|
float d = distance - moments.x;
|
||||||
float p_max = variance / (variance + d*d);
|
float p_max = variance / (variance + d*d);
|
||||||
|
|
||||||
return p_max;
|
shadow += p_max;
|
||||||
}
|
}
|
||||||
|
|
||||||
float shadow_pcf(float distance, vec3 lightDir, int light_index) {
|
// Average the results
|
||||||
|
return shadow / 4.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float shadow_csm(float distance, vec3 lightDir, int light_index) {
|
||||||
// Determine which cascade to use
|
// Determine which cascade to use
|
||||||
int cascade_index = -1;
|
int cascade_index = -1;
|
||||||
int min_cascades_range = light_index * NUM_SHADOW_CASCADES;
|
int min_cascades_range = light_index * NUM_SHADOW_CASCADES;
|
||||||
|
@ -76,7 +91,7 @@ float shadow_pcf(float distance, vec3 lightDir, int light_index) {
|
||||||
float bias = max(0.05 * (1.0 - dot(normal, lightDir)), 0.005);
|
float bias = max(0.05 * (1.0 - dot(normal, lightDir)), 0.005);
|
||||||
bias *= 1 / (u_cascade_distances[cascade_index] * bias_modifier[matrix_index]);
|
bias *= 1 / (u_cascade_distances[cascade_index] * bias_modifier[matrix_index]);
|
||||||
|
|
||||||
// PCF
|
// CSM
|
||||||
float shadow = 0.0;
|
float shadow = 0.0;
|
||||||
vec2 texelSize = 1.0 / textureSize(shadowMap2D[cascade_index], 0);
|
vec2 texelSize = 1.0 / textureSize(shadowMap2D[cascade_index], 0);
|
||||||
|
|
||||||
|
@ -85,8 +100,8 @@ float shadow_pcf(float distance, vec3 lightDir, int light_index) {
|
||||||
{
|
{
|
||||||
for(int y = -3; y <= 3; ++y)
|
for(int y = -3; y <= 3; ++y)
|
||||||
{
|
{
|
||||||
float pcfDepth = texture(shadowMap2D[cascade_index], projCoords.xy + vec2(x, y) * texelSize * (rand(vec2(projCoords.x + x, projCoords.y + y))*0.75f + 0.25f)).r;
|
float csmDepth = texture(shadowMap2D[cascade_index], projCoords.xy + vec2(x, y) * texelSize * (rand(vec2(projCoords.x + x, projCoords.y + y))*0.75f + 0.25f)).r;
|
||||||
shadow += currentDepth - bias > pcfDepth ? 1.0 : 0.0;
|
shadow += currentDepth - bias > csmDepth ? 1.0 : 0.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
shadow /= 36.0;
|
shadow /= 36.0;
|
||||||
|
@ -95,8 +110,8 @@ float shadow_pcf(float distance, vec3 lightDir, int light_index) {
|
||||||
{
|
{
|
||||||
for(int y = -1; y <= 1; ++y)
|
for(int y = -1; y <= 1; ++y)
|
||||||
{
|
{
|
||||||
float pcfDepth = texture(shadowMap2D[cascade_index], projCoords.xy + vec2(x, y) * texelSize).r;
|
float csmDepth = texture(shadowMap2D[cascade_index], projCoords.xy + vec2(x, y) * texelSize).r;
|
||||||
shadow += currentDepth - bias > pcfDepth ? 1.0 : 0.0;
|
shadow += currentDepth - bias > csmDepth ? 1.0 : 0.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
shadow /= 9.0;
|
shadow /= 9.0;
|
||||||
|
@ -111,7 +126,7 @@ vec4 shadowmap(int idx, in vec4 peye, in vec4 neye) {
|
||||||
|
|
||||||
if (light.processed_shadows) {
|
if (light.processed_shadows) {
|
||||||
if (light.type == LIGHT_DIRECTIONAL) {
|
if (light.type == LIGHT_DIRECTIONAL) {
|
||||||
shadowFactor = shadow_pcf(-peye.z, light.dir, idx);
|
shadowFactor = shadow_csm(-peye.z, light.dir, idx);
|
||||||
} else if (light.type == LIGHT_POINT || light.type == LIGHT_SPOT) {
|
} else if (light.type == LIGHT_POINT || light.type == LIGHT_SPOT) {
|
||||||
vec3 light_pos = (view * vec4(light.pos, 1.0)).xyz;
|
vec3 light_pos = (view * vec4(light.pos, 1.0)).xyz;
|
||||||
vec3 dir = light_pos - fragment;
|
vec3 dir = light_pos - fragment;
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
in vec3 TexCoords;
|
||||||
|
out vec4 FragColor;
|
||||||
|
|
||||||
|
uniform samplerCube textureSource;
|
||||||
|
uniform vec2 ScaleU;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec3 sampleDir = normalize(TexCoords);
|
||||||
|
vec3 right = normalize(cross(sampleDir, vec3(0.0, 1.0, 0.0)));
|
||||||
|
vec3 up = normalize(cross(right, sampleDir));
|
||||||
|
|
||||||
|
vec3 color = vec3(0.0);
|
||||||
|
float total = 0.0;
|
||||||
|
for (float x = -4.0; x <= 4.0; x += 1.0) {
|
||||||
|
for (float y = -4.0; y <= 4.0; y += 1.0) {
|
||||||
|
vec3 offset = right * ScaleU.x * x + up * ScaleU.y * y;
|
||||||
|
color += texture(textureSource, normalize(sampleDir + offset)).rgb;
|
||||||
|
total += 1.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FragColor = vec4(color / total, 1.0);
|
||||||
|
}
|
|
@ -2,7 +2,7 @@ in vec3 v_position;
|
||||||
out vec4 fragcolor;
|
out vec4 fragcolor;
|
||||||
|
|
||||||
const int SHADOW_VSM = 0;
|
const int SHADOW_VSM = 0;
|
||||||
const int SHADOW_PCF = 1;
|
const int SHADOW_CSM = 1;
|
||||||
|
|
||||||
uniform int shadow_technique;
|
uniform int shadow_technique;
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ void main() {
|
||||||
moment2 += 0.25*(dx*dx+dy*dy);
|
moment2 += 0.25*(dx*dx+dy*dy);
|
||||||
fragcolor = vec4( moment1, moment2, 0.0, 1.0);
|
fragcolor = vec4( moment1, moment2, 0.0, 1.0);
|
||||||
}
|
}
|
||||||
else if (shadow_technique == SHADOW_PCF) {
|
else if (shadow_technique == SHADOW_CSM) {
|
||||||
fragcolor = vec4(vec3(gl_FragCoord.z), 1.0);
|
fragcolor = vec4(vec3(gl_FragCoord.z), 1.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
out vec3 TexCoords;
|
||||||
|
uniform int face;
|
||||||
|
|
||||||
|
vec3 cubemapCoord(vec2 uv, int face) {
|
||||||
|
vec2 UV = 2.0 * uv - 1.0;
|
||||||
|
if (face == 0) return vec3(1.0, -UV.y, -UV.x); // +X
|
||||||
|
else if (face == 1) return vec3(-1.0, -UV.y, UV.x); // -X
|
||||||
|
else if (face == 2) return vec3(UV.x, 1.0, -UV.y); // +Y
|
||||||
|
else if (face == 3) return vec3(UV.x, -1.0, UV.y); // -Y
|
||||||
|
else if (face == 4) return vec3(UV.x, -UV.y, 1.0); // +Z
|
||||||
|
else return vec3(-UV.x, -UV.y, -1.0); // -Z
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
// Generate a fullscreen quad
|
||||||
|
vec2 positions[6] = vec2[6](
|
||||||
|
vec2(-1.0, -1.0),
|
||||||
|
vec2( 1.0, -1.0),
|
||||||
|
vec2(-1.0, 1.0),
|
||||||
|
vec2(-1.0, 1.0),
|
||||||
|
vec2( 1.0, -1.0),
|
||||||
|
vec2( 1.0, 1.0)
|
||||||
|
);
|
||||||
|
|
||||||
|
gl_Position = vec4(positions[gl_VertexID], 0.0, 1.0);
|
||||||
|
|
||||||
|
// Calculate texture coordinates for cubemap
|
||||||
|
vec2 texCoord = positions[gl_VertexID] * 0.5 + 0.5;
|
||||||
|
TexCoords = cubemapCoord(texCoord, face);
|
||||||
|
}
|
|
@ -17264,7 +17264,7 @@ enum LIGHT_TYPE {
|
||||||
|
|
||||||
enum SHADOW_TECHNIQUE {
|
enum SHADOW_TECHNIQUE {
|
||||||
SHADOW_VSM,
|
SHADOW_VSM,
|
||||||
SHADOW_PCF,
|
SHADOW_CSM,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NUM_SHADOW_CASCADES 6
|
#define NUM_SHADOW_CASCADES 6
|
||||||
|
@ -17314,24 +17314,28 @@ typedef struct shadowmap_t {
|
||||||
mat44 V;
|
mat44 V;
|
||||||
mat44 PV;
|
mat44 PV;
|
||||||
int vsm_texture_width;
|
int vsm_texture_width;
|
||||||
int pcf_texture_width;
|
int csm_texture_width;
|
||||||
int step;
|
int step;
|
||||||
int light_step;
|
int light_step;
|
||||||
int cascade_index;
|
int cascade_index;
|
||||||
unsigned shadow_technique;
|
unsigned shadow_technique;
|
||||||
float cascade_splits[NUM_SHADOW_CASCADES];
|
float cascade_splits[NUM_SHADOW_CASCADES];
|
||||||
bool blur_pcf;
|
bool blur_csm;
|
||||||
float blur_scale;
|
bool blur_vsm;
|
||||||
|
float csm_blur_scale;
|
||||||
|
float vsm_blur_scale;
|
||||||
|
|
||||||
// signals
|
// signals
|
||||||
bool skip_render;
|
bool skip_render;
|
||||||
int lights_pushed;
|
int lights_pushed;
|
||||||
|
handle fbo;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
unsigned shadow_technique;
|
unsigned shadow_technique;
|
||||||
handle fbos[6], texture, depth_texture;
|
handle texture, depth_texture;
|
||||||
handle fbo_2d[NUM_SHADOW_CASCADES], texture_2d[NUM_SHADOW_CASCADES], depth_texture_2d[NUM_SHADOW_CASCADES];
|
handle texture_2d[NUM_SHADOW_CASCADES], depth_texture_2d[NUM_SHADOW_CASCADES];
|
||||||
handle blur_fbo_2d, blur_texture_2d;
|
handle blur_texture, blur_texture_2d;
|
||||||
|
// handle blur_fbo_cubemap, blur_texture_cubemap;
|
||||||
float cascade_distances[NUM_SHADOW_CASCADES];
|
float cascade_distances[NUM_SHADOW_CASCADES];
|
||||||
} maps[MAX_LIGHTS];
|
} maps[MAX_LIGHTS];
|
||||||
|
|
||||||
|
@ -17340,7 +17344,7 @@ typedef struct shadowmap_t {
|
||||||
int saved_vp[4];
|
int saved_vp[4];
|
||||||
} shadowmap_t;
|
} shadowmap_t;
|
||||||
|
|
||||||
API shadowmap_t shadowmap(int vsm_texture_width, int pcf_texture_width); // = 512, 4096
|
API shadowmap_t shadowmap(int vsm_texture_width, int csm_texture_width); // = 512, 4096
|
||||||
API void shadowmap_destroy(shadowmap_t *s);
|
API void shadowmap_destroy(shadowmap_t *s);
|
||||||
|
|
||||||
API void shadowmap_begin(shadowmap_t *s);
|
API void shadowmap_begin(shadowmap_t *s);
|
||||||
|
@ -17681,7 +17685,7 @@ enum RENDER_PASS {
|
||||||
RENDER_PASS_OVERRIDES_BEGIN,
|
RENDER_PASS_OVERRIDES_BEGIN,
|
||||||
|
|
||||||
RENDER_PASS_SHADOW_BEGIN,
|
RENDER_PASS_SHADOW_BEGIN,
|
||||||
RENDER_PASS_SHADOW_PCF,
|
RENDER_PASS_SHADOW_CSM,
|
||||||
RENDER_PASS_SHADOW_VSM,
|
RENDER_PASS_SHADOW_VSM,
|
||||||
RENDER_PASS_SHADOW_END,
|
RENDER_PASS_SHADOW_END,
|
||||||
|
|
||||||
|
@ -383342,22 +383346,10 @@ shadowmap_init_caster_vsm(shadowmap_t *s, int light_index, int texture_width) {
|
||||||
glTexParameterfv(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BORDER_COLOR, borderColor);
|
glTexParameterfv(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BORDER_COLOR, borderColor);
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
|
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
|
||||||
|
|
||||||
// Create 6 framebuffers for each face of the cubemap
|
|
||||||
glGenFramebuffers(6, s->maps[light_index].fbos);
|
|
||||||
for (int i = 0; i < 6; i++) {
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, s->maps[light_index].fbos[i]);
|
|
||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, s->maps[light_index].texture, 0);
|
|
||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, s->maps[light_index].depth_texture, 0);
|
|
||||||
GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
|
||||||
if (GL_FRAMEBUFFER_COMPLETE != result) {
|
|
||||||
PANIC("ERROR: Framebuffer is not complete: %x\n", result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
shadowmap_init_caster_pcf(shadowmap_t *s, int light_index, int texture_width) {
|
shadowmap_init_caster_csm(shadowmap_t *s, int light_index, int texture_width) {
|
||||||
float borderColor[] = {1.0, 1.0, 1.0, 1.0};
|
float borderColor[] = {1.0, 1.0, 1.0, 1.0};
|
||||||
|
|
||||||
if (s->maps[light_index].texture_2d[0]) {
|
if (s->maps[light_index].texture_2d[0]) {
|
||||||
|
@ -383386,56 +383378,30 @@ shadowmap_init_caster_pcf(shadowmap_t *s, int light_index, int texture_width) {
|
||||||
}
|
}
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
for (int i = 0; i < NUM_SHADOW_CASCADES; i++) {
|
|
||||||
glGenFramebuffers(1, &s->maps[light_index].fbo_2d[i]);
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, s->maps[light_index].fbo_2d[i]);
|
|
||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, s->maps[light_index].texture_2d[i], 0);
|
|
||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, s->maps[light_index].depth_texture_2d[i], 0);
|
|
||||||
GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
|
||||||
if (GL_FRAMEBUFFER_COMPLETE != result) {
|
|
||||||
PANIC("ERROR: Framebuffer is not complete: %x\n", result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Blur texture
|
|
||||||
glGenTextures(1, &s->maps[light_index].blur_texture_2d);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, s->maps[light_index].blur_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_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
||||||
|
|
||||||
// Blur FBO
|
|
||||||
glGenFramebuffers(1, &s->maps[light_index].blur_fbo_2d);
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, s->maps[light_index].blur_fbo_2d);
|
|
||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, s->maps[light_index].blur_texture_2d, 0);
|
|
||||||
GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
|
||||||
if (GL_FRAMEBUFFER_COMPLETE != result) {
|
|
||||||
PANIC("ERROR: Framebuffer is not complete: %x\n", result);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
shadowmap_init_caster(shadowmap_t *s, int light_index) {
|
shadowmap_init_caster(shadowmap_t *s, int light_index) {
|
||||||
shadowmap_init_caster_vsm(s, light_index, s->vsm_texture_width);
|
shadowmap_init_caster_vsm(s, light_index, s->vsm_texture_width);
|
||||||
shadowmap_init_caster_pcf(s, light_index, s->pcf_texture_width);
|
shadowmap_init_caster_csm(s, light_index, s->csm_texture_width);
|
||||||
}
|
}
|
||||||
|
|
||||||
shadowmap_t shadowmap(int vsm_texture_width, int pcf_texture_width) { // = 512, 4096
|
shadowmap_t shadowmap(int vsm_texture_width, int csm_texture_width) { // = 512, 4096
|
||||||
shadowmap_t s = {0};
|
shadowmap_t s = {0};
|
||||||
s.vsm_texture_width = vsm_texture_width;
|
s.vsm_texture_width = vsm_texture_width;
|
||||||
s.pcf_texture_width = pcf_texture_width;
|
s.csm_texture_width = csm_texture_width;
|
||||||
s.saved_fb = 0;
|
s.saved_fb = 0;
|
||||||
s.blur_pcf = false;
|
s.blur_csm = false;
|
||||||
s.blur_scale = 0.5f;
|
s.blur_vsm = false;
|
||||||
|
s.csm_blur_scale = 0.5f;
|
||||||
|
s.vsm_blur_scale = 0.75f;
|
||||||
s.cascade_splits[0] = 0.1f;
|
s.cascade_splits[0] = 0.1f;
|
||||||
s.cascade_splits[1] = 0.3f;
|
s.cascade_splits[1] = 0.3f;
|
||||||
s.cascade_splits[2] = 0.7f;
|
s.cascade_splits[2] = 0.7f;
|
||||||
s.cascade_splits[3] = 1.0f;
|
s.cascade_splits[3] = 1.0f;
|
||||||
s.cascade_splits[4] = 1.0f;
|
s.cascade_splits[4] = 1.0f;
|
||||||
s.cascade_splits[5] = 1.0f; /* sticks to camera far plane */
|
s.cascade_splits[5] = 1.0f; /* sticks to camera far plane */
|
||||||
|
glGenFramebuffers(1, &s.fbo);
|
||||||
|
|
||||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &s.saved_fb);
|
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &s.saved_fb);
|
||||||
|
|
||||||
|
@ -383458,9 +383424,9 @@ shadowmap_t shadowmap(int vsm_texture_width, int pcf_texture_width) { // = 512,
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
void shadowmap_destroy_light(shadowmap_t *s, int light_index) {
|
void shadowmap_destroy_light(shadowmap_t *s, int light_index) {
|
||||||
if (s->maps[light_index].fbos[0]) {
|
if (s->fbo) {
|
||||||
glDeleteFramebuffers(6, s->maps[light_index].fbos);
|
glDeleteFramebuffers(1, &s->fbo);
|
||||||
s->maps[light_index].fbos[0] = 0;
|
s->fbo = 0;
|
||||||
}
|
}
|
||||||
if (s->maps[light_index].texture) {
|
if (s->maps[light_index].texture) {
|
||||||
glDeleteTextures(1, &s->maps[light_index].texture);
|
glDeleteTextures(1, &s->maps[light_index].texture);
|
||||||
|
@ -383472,10 +383438,6 @@ void shadowmap_destroy_light(shadowmap_t *s, int light_index) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < NUM_SHADOW_CASCADES; i++) {
|
for (int i = 0; i < NUM_SHADOW_CASCADES; i++) {
|
||||||
if (s->maps[light_index].fbo_2d[i]) {
|
|
||||||
glDeleteFramebuffers(1, &s->maps[light_index].fbo_2d[i]);
|
|
||||||
s->maps[light_index].fbo_2d[i] = 0;
|
|
||||||
}
|
|
||||||
if (s->maps[light_index].texture_2d[i]) {
|
if (s->maps[light_index].texture_2d[i]) {
|
||||||
glDeleteTextures(1, &s->maps[light_index].texture_2d[i]);
|
glDeleteTextures(1, &s->maps[light_index].texture_2d[i]);
|
||||||
s->maps[light_index].texture_2d[i] = 0;
|
s->maps[light_index].texture_2d[i] = 0;
|
||||||
|
@ -383486,10 +383448,6 @@ void shadowmap_destroy_light(shadowmap_t *s, int light_index) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s->maps[light_index].blur_fbo_2d) {
|
|
||||||
glDeleteFramebuffers(1, &s->maps[light_index].blur_fbo_2d);
|
|
||||||
s->maps[light_index].blur_fbo_2d = 0;
|
|
||||||
}
|
|
||||||
if (s->maps[light_index].blur_texture_2d) {
|
if (s->maps[light_index].blur_texture_2d) {
|
||||||
glDeleteTextures(1, &s->maps[light_index].blur_texture_2d);
|
glDeleteTextures(1, &s->maps[light_index].blur_texture_2d);
|
||||||
s->maps[light_index].blur_texture_2d = 0;
|
s->maps[light_index].blur_texture_2d = 0;
|
||||||
|
@ -383641,19 +383599,31 @@ static void shadowmap_light_directional(shadowmap_t *s, light_t *l, int dir, flo
|
||||||
copy44(l->shadow_matrix[s->cascade_index], PV);
|
copy44(l->shadow_matrix[s->cascade_index], PV);
|
||||||
|
|
||||||
l->processed_shadows = true;
|
l->processed_shadows = true;
|
||||||
s->shadow_technique = l->shadow_technique = SHADOW_PCF;
|
s->shadow_technique = l->shadow_technique = SHADOW_CSM;
|
||||||
model_setpass(RENDER_PASS_SHADOW_PCF);
|
model_setpass(RENDER_PASS_SHADOW_CSM);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
void shadowmap_blur_pcf(shadowmap_t *s, int light_index) {
|
void shadowmap_blur_csm(shadowmap_t *s, int light_index) {
|
||||||
if (!s->blur_pcf) {
|
if (!s->blur_csm) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
float blur_scale = 1.999 * (1 - s->blur_scale) + 0.001;
|
float blur_scale = 1.999 * (1 - s->csm_blur_scale) + 0.001;
|
||||||
// blur_scale = 0.1f;
|
// blur_scale = 0.1f;
|
||||||
|
|
||||||
|
if (s->maps[light_index].blur_texture_2d == 0) {
|
||||||
|
// Blur texture
|
||||||
|
float borderColor[] = {1.0, 1.0, 1.0, 1.0};
|
||||||
|
glGenTextures(1, &s->maps[light_index].blur_texture_2d);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, s->maps[light_index].blur_texture_2d);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, s->csm_texture_width, s->csm_texture_width, 0, GL_RGB, GL_FLOAT, 0);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
}
|
||||||
|
|
||||||
static renderstate_t rs;
|
static renderstate_t rs;
|
||||||
static int program = -1, vao = -1, u_scale = -1, u_source = -1;
|
static int program = -1, vao = -1, u_scale = -1, u_source = -1;
|
||||||
if (program < 0) {
|
if (program < 0) {
|
||||||
|
@ -383671,8 +383641,8 @@ void shadowmap_blur_pcf(shadowmap_t *s, int light_index) {
|
||||||
glGenVertexArrays(1, &vao);
|
glGenVertexArrays(1, &vao);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderstate_apply(&rs);
|
// renderstate_apply(&rs);
|
||||||
glViewport(0, 0, s->pcf_texture_width, s->pcf_texture_width);
|
glViewport(0, 0, s->csm_texture_width, s->csm_texture_width);
|
||||||
|
|
||||||
unsigned oldprog = last_shader;
|
unsigned oldprog = last_shader;
|
||||||
glUseProgram(program);
|
glUseProgram(program);
|
||||||
|
@ -383682,8 +383652,9 @@ void shadowmap_blur_pcf(shadowmap_t *s, int light_index) {
|
||||||
|
|
||||||
// Horizontal pass
|
// Horizontal pass
|
||||||
for (int i = 0; i < NUM_SHADOW_CASCADES; i++) {
|
for (int i = 0; i < NUM_SHADOW_CASCADES; i++) {
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, s->maps[light_index].blur_fbo_2d);
|
glBindFramebuffer(GL_FRAMEBUFFER, s->fbo);
|
||||||
glUniform2f(u_scale, 1.0f / (s->pcf_texture_width * blur_scale), 0);
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, s->maps[light_index].blur_texture_2d, 0);
|
||||||
|
glUniform2f(u_scale, 1.0f / (s->csm_texture_width * blur_scale), 0);
|
||||||
glBindTexture(GL_TEXTURE_2D, s->maps[light_index].texture_2d[i]);
|
glBindTexture(GL_TEXTURE_2D, s->maps[light_index].texture_2d[i]);
|
||||||
glUniform1i(u_source, 0);
|
glUniform1i(u_source, 0);
|
||||||
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
@ -383693,8 +383664,9 @@ void shadowmap_blur_pcf(shadowmap_t *s, int light_index) {
|
||||||
profile_incstat("Render.num_triangles", +2);
|
profile_incstat("Render.num_triangles", +2);
|
||||||
|
|
||||||
// Vertical pass
|
// Vertical pass
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, s->maps[light_index].fbo_2d[i]);
|
glBindFramebuffer(GL_FRAMEBUFFER, s->fbo);
|
||||||
glUniform2f(u_scale, 0, 1.0f / (s->pcf_texture_width * blur_scale));
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, s->maps[light_index].texture_2d[i], 0);
|
||||||
|
glUniform2f(u_scale, 0, 1.0f / (s->csm_texture_width * blur_scale));
|
||||||
glBindTexture(GL_TEXTURE_2D, s->maps[light_index].blur_texture_2d);
|
glBindTexture(GL_TEXTURE_2D, s->maps[light_index].blur_texture_2d);
|
||||||
glUniform1i(u_source, 0);
|
glUniform1i(u_source, 0);
|
||||||
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
@ -383708,15 +383680,97 @@ void shadowmap_blur_pcf(shadowmap_t *s, int light_index) {
|
||||||
glUseProgram(oldprog);
|
glUseProgram(oldprog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
void shadowmap_blur_vsm(shadowmap_t *s, int light_index) {
|
||||||
|
if (!s->blur_vsm) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float blur_scale = 1.999 * (1 - s->vsm_blur_scale) + 0.001;
|
||||||
|
|
||||||
|
if (s->maps[light_index].blur_texture == 0) {
|
||||||
|
// Blur texture
|
||||||
|
float borderColor[] = {1.0, 1.0, 1.0, 1.0};
|
||||||
|
glGenTextures(1, &s->maps[light_index].blur_texture);
|
||||||
|
glBindTexture(GL_TEXTURE_CUBE_MAP, s->maps[light_index].blur_texture);
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
|
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB32F, s->vsm_texture_width, s->vsm_texture_width, 0, GL_RGB, GL_FLOAT, 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
static renderstate_t rs;
|
||||||
|
static int program = -1, vao = -1, u_scale = -1, u_source = -1, u_face = -1;
|
||||||
|
if (program < 0) {
|
||||||
|
rs = renderstate(); {
|
||||||
|
rs.depth_test_enabled = false;
|
||||||
|
rs.depth_write_enabled = false;
|
||||||
|
rs.blend_enabled = false;
|
||||||
|
}
|
||||||
|
const char* vs = vfs_read("shaders/vs_shadow_blur_cubemap.glsl");
|
||||||
|
const char* fs = vfs_read("shaders/fs_shadow_blur_cubemap.glsl");
|
||||||
|
|
||||||
|
program = shader(vs, fs, "", "fragcolor", NULL);
|
||||||
|
u_scale = glGetUniformLocation(program, "ScaleU");
|
||||||
|
u_source = glGetUniformLocation(program, "textureSource");
|
||||||
|
u_face = glGetUniformLocation(program, "face");
|
||||||
|
glGenVertexArrays(1, &vao);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderstate_apply(&rs);
|
||||||
|
// return;
|
||||||
|
glViewport(0, 0, s->vsm_texture_width, s->vsm_texture_width);
|
||||||
|
|
||||||
|
unsigned oldprog = last_shader;
|
||||||
|
glUseProgram(program);
|
||||||
|
|
||||||
|
glBindVertexArray(vao);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
|
for (int face = 0; face < 6; face++) {
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, s->fbo);
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, s->maps[light_index].blur_texture, 0);
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, 0);
|
||||||
|
glUniform2f(u_scale, 1.0f / (s->vsm_texture_width * blur_scale), 0);
|
||||||
|
glBindTexture(GL_TEXTURE_CUBE_MAP, s->maps[light_index].texture);
|
||||||
|
glUniform1i(u_source, 0);
|
||||||
|
glUniform1i(u_face, face);
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||||
|
profile_incstat("Render.num_drawcalls", +1);
|
||||||
|
profile_incstat("Render.num_triangles", +2);
|
||||||
|
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, s->maps[light_index].texture, 0);
|
||||||
|
glUniform2f(u_scale, 0, 1.0f / (s->vsm_texture_width * blur_scale));
|
||||||
|
glBindTexture(GL_TEXTURE_CUBE_MAP, s->maps[light_index].blur_texture);
|
||||||
|
glUniform1i(u_source, 0);
|
||||||
|
glUniform1i(u_face, face);
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||||
|
profile_incstat("Render.num_drawcalls", +1);
|
||||||
|
profile_incstat("Render.num_triangles", +2);
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindVertexArray(0);
|
||||||
|
glUseProgram(oldprog);
|
||||||
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
bool shadowmap_step_finish(shadowmap_t *s) {
|
bool shadowmap_step_finish(shadowmap_t *s) {
|
||||||
if (s->shadow_technique == SHADOW_PCF) {
|
if (s->shadow_technique == SHADOW_CSM) {
|
||||||
if (s->cascade_index < NUM_SHADOW_CASCADES-1) {
|
if (s->cascade_index < NUM_SHADOW_CASCADES-1) {
|
||||||
s->cascade_index++;
|
s->cascade_index++;
|
||||||
s->step = 0;
|
s->step = 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
shadowmap_blur_pcf(s, s->light_step);
|
shadowmap_blur_csm(s, s->light_step);
|
||||||
|
} else {
|
||||||
|
shadowmap_blur_vsm(s, s->light_step);
|
||||||
}
|
}
|
||||||
|
|
||||||
s->step = 0;
|
s->step = 0;
|
||||||
|
@ -383727,7 +383781,7 @@ bool shadowmap_step_finish(shadowmap_t *s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool shadowmap_step(shadowmap_t *s) {
|
bool shadowmap_step(shadowmap_t *s) {
|
||||||
int max_steps = s->shadow_technique == 0xffff ? 1 : s->shadow_technique == SHADOW_PCF ? 1 : 6;
|
int max_steps = s->shadow_technique == 0xffff ? 1 : s->shadow_technique == SHADOW_CSM ? 1 : 6;
|
||||||
if (s->step >= max_steps) {
|
if (s->step >= max_steps) {
|
||||||
if (shadowmap_step_finish(s)) {
|
if (shadowmap_step_finish(s)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -383764,9 +383818,7 @@ void shadowmap_light(shadowmap_t *s, light_t *l, mat44 cam_proj, mat44 cam_view)
|
||||||
cam_far *= 0.5f;
|
cam_far *= 0.5f;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (l->type == LIGHT_POINT) {
|
if (l->type == LIGHT_POINT || l->type == LIGHT_SPOT) {
|
||||||
shadowmap_light_point(s, l, step);
|
|
||||||
} else if (l->type == LIGHT_SPOT) {
|
|
||||||
shadowmap_light_point(s, l, step);
|
shadowmap_light_point(s, l, step);
|
||||||
} else if (l->type == LIGHT_DIRECTIONAL) {
|
} else if (l->type == LIGHT_DIRECTIONAL) {
|
||||||
shadowmap_light_directional(s, l, step, cam_fov, cam_far, cam_view);
|
shadowmap_light_directional(s, l, step, cam_fov, cam_far, cam_view);
|
||||||
|
@ -383780,8 +383832,8 @@ void shadowmap_light(shadowmap_t *s, light_t *l, mat44 cam_proj, mat44 cam_view)
|
||||||
// shadowmap_destroy_light(s, s->light_step); // @todo: we might wanna free the other set
|
// shadowmap_destroy_light(s, s->light_step); // @todo: we might wanna free the other set
|
||||||
if (l->shadow_technique == SHADOW_VSM) {
|
if (l->shadow_technique == SHADOW_VSM) {
|
||||||
shadowmap_init_caster_vsm(s, s->light_step, s->vsm_texture_width);
|
shadowmap_init_caster_vsm(s, s->light_step, s->vsm_texture_width);
|
||||||
} else if (l->shadow_technique == SHADOW_PCF) {
|
} else if (l->shadow_technique == SHADOW_CSM) {
|
||||||
shadowmap_init_caster_pcf(s, s->light_step, s->pcf_texture_width);
|
shadowmap_init_caster_csm(s, s->light_step, s->csm_texture_width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -383791,14 +383843,18 @@ void shadowmap_light(shadowmap_t *s, light_t *l, mat44 cam_proj, mat44 cam_view)
|
||||||
s->lights_pushed++;
|
s->lights_pushed++;
|
||||||
|
|
||||||
if (l->type == LIGHT_DIRECTIONAL) {
|
if (l->type == LIGHT_DIRECTIONAL) {
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, s->maps[s->light_step].fbo_2d[s->cascade_index]);
|
glBindFramebuffer(GL_FRAMEBUFFER, s->fbo);
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, s->maps[s->light_step].texture_2d[s->cascade_index], 0);
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, s->maps[s->light_step].depth_texture_2d[s->cascade_index], 0);
|
||||||
shadowmap_clear_fbo();
|
shadowmap_clear_fbo();
|
||||||
} else {
|
} else {
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, s->maps[s->light_step].fbos[step]);
|
glBindFramebuffer(GL_FRAMEBUFFER, s->fbo);
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + step, s->maps[s->light_step].texture, 0);
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + step, s->maps[s->light_step].depth_texture, 0);
|
||||||
shadowmap_clear_fbo();
|
shadowmap_clear_fbo();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned texture_width = s->shadow_technique == SHADOW_VSM ? s->vsm_texture_width : s->pcf_texture_width;
|
unsigned texture_width = s->shadow_technique == SHADOW_VSM ? s->vsm_texture_width : s->csm_texture_width;
|
||||||
glViewport(0, 0, texture_width, texture_width);
|
glViewport(0, 0, texture_width, texture_width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -386620,15 +386676,17 @@ void model_set_renderstates(model_t *m) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shadow pass
|
// Shadow pass
|
||||||
renderstate_t *pcf_shadow_rs = &m->rs[RENDER_PASS_SHADOW_PCF];
|
renderstate_t *csm_shadow_rs = &m->rs[RENDER_PASS_SHADOW_CSM];
|
||||||
{
|
{
|
||||||
pcf_shadow_rs->blend_enabled = 1;
|
csm_shadow_rs->blend_enabled = 1;
|
||||||
pcf_shadow_rs->blend_src = GL_SRC_ALPHA;
|
csm_shadow_rs->blend_src = GL_SRC_ALPHA;
|
||||||
pcf_shadow_rs->blend_dst = GL_ONE_MINUS_SRC_ALPHA;
|
csm_shadow_rs->blend_dst = GL_ONE_MINUS_SRC_ALPHA;
|
||||||
pcf_shadow_rs->cull_face_enabled = 1;
|
csm_shadow_rs->depth_test_enabled = true;
|
||||||
pcf_shadow_rs->cull_face_mode = GL_BACK;
|
csm_shadow_rs->depth_write_enabled = true;
|
||||||
pcf_shadow_rs->front_face = GL_CW;
|
csm_shadow_rs->cull_face_enabled = 1;
|
||||||
pcf_shadow_rs->depth_clamp_enabled = 1;
|
csm_shadow_rs->cull_face_mode = GL_BACK;
|
||||||
|
csm_shadow_rs->front_face = GL_CW;
|
||||||
|
csm_shadow_rs->depth_clamp_enabled = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderstate_t *vsm_shadow_rs = &m->rs[RENDER_PASS_SHADOW_VSM];
|
renderstate_t *vsm_shadow_rs = &m->rs[RENDER_PASS_SHADOW_VSM];
|
||||||
|
@ -386636,6 +386694,8 @@ void model_set_renderstates(model_t *m) {
|
||||||
vsm_shadow_rs->blend_enabled = 1;
|
vsm_shadow_rs->blend_enabled = 1;
|
||||||
vsm_shadow_rs->blend_src = GL_SRC_ALPHA;
|
vsm_shadow_rs->blend_src = GL_SRC_ALPHA;
|
||||||
vsm_shadow_rs->blend_dst = GL_ONE_MINUS_SRC_ALPHA;
|
vsm_shadow_rs->blend_dst = GL_ONE_MINUS_SRC_ALPHA;
|
||||||
|
vsm_shadow_rs->depth_test_enabled = true;
|
||||||
|
vsm_shadow_rs->depth_write_enabled = true;
|
||||||
vsm_shadow_rs->cull_face_enabled = 1;
|
vsm_shadow_rs->cull_face_enabled = 1;
|
||||||
vsm_shadow_rs->cull_face_mode = GL_BACK;
|
vsm_shadow_rs->cull_face_mode = GL_BACK;
|
||||||
vsm_shadow_rs->front_face = GL_CW;
|
vsm_shadow_rs->front_face = GL_CW;
|
||||||
|
|
|
@ -1612,22 +1612,10 @@ shadowmap_init_caster_vsm(shadowmap_t *s, int light_index, int texture_width) {
|
||||||
glTexParameterfv(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BORDER_COLOR, borderColor);
|
glTexParameterfv(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BORDER_COLOR, borderColor);
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
|
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
|
||||||
|
|
||||||
// Create 6 framebuffers for each face of the cubemap
|
|
||||||
glGenFramebuffers(6, s->maps[light_index].fbos);
|
|
||||||
for (int i = 0; i < 6; i++) {
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, s->maps[light_index].fbos[i]);
|
|
||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, s->maps[light_index].texture, 0);
|
|
||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, s->maps[light_index].depth_texture, 0);
|
|
||||||
GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
|
||||||
if (GL_FRAMEBUFFER_COMPLETE != result) {
|
|
||||||
PANIC("ERROR: Framebuffer is not complete: %x\n", result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
shadowmap_init_caster_pcf(shadowmap_t *s, int light_index, int texture_width) {
|
shadowmap_init_caster_csm(shadowmap_t *s, int light_index, int texture_width) {
|
||||||
float borderColor[] = {1.0, 1.0, 1.0, 1.0};
|
float borderColor[] = {1.0, 1.0, 1.0, 1.0};
|
||||||
|
|
||||||
if (s->maps[light_index].texture_2d[0]) {
|
if (s->maps[light_index].texture_2d[0]) {
|
||||||
|
@ -1656,56 +1644,30 @@ shadowmap_init_caster_pcf(shadowmap_t *s, int light_index, int texture_width) {
|
||||||
}
|
}
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
for (int i = 0; i < NUM_SHADOW_CASCADES; i++) {
|
|
||||||
glGenFramebuffers(1, &s->maps[light_index].fbo_2d[i]);
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, s->maps[light_index].fbo_2d[i]);
|
|
||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, s->maps[light_index].texture_2d[i], 0);
|
|
||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, s->maps[light_index].depth_texture_2d[i], 0);
|
|
||||||
GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
|
||||||
if (GL_FRAMEBUFFER_COMPLETE != result) {
|
|
||||||
PANIC("ERROR: Framebuffer is not complete: %x\n", result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Blur texture
|
|
||||||
glGenTextures(1, &s->maps[light_index].blur_texture_2d);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, s->maps[light_index].blur_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_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
||||||
|
|
||||||
// Blur FBO
|
|
||||||
glGenFramebuffers(1, &s->maps[light_index].blur_fbo_2d);
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, s->maps[light_index].blur_fbo_2d);
|
|
||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, s->maps[light_index].blur_texture_2d, 0);
|
|
||||||
GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
|
||||||
if (GL_FRAMEBUFFER_COMPLETE != result) {
|
|
||||||
PANIC("ERROR: Framebuffer is not complete: %x\n", result);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
shadowmap_init_caster(shadowmap_t *s, int light_index) {
|
shadowmap_init_caster(shadowmap_t *s, int light_index) {
|
||||||
shadowmap_init_caster_vsm(s, light_index, s->vsm_texture_width);
|
shadowmap_init_caster_vsm(s, light_index, s->vsm_texture_width);
|
||||||
shadowmap_init_caster_pcf(s, light_index, s->pcf_texture_width);
|
shadowmap_init_caster_csm(s, light_index, s->csm_texture_width);
|
||||||
}
|
}
|
||||||
|
|
||||||
shadowmap_t shadowmap(int vsm_texture_width, int pcf_texture_width) { // = 512, 4096
|
shadowmap_t shadowmap(int vsm_texture_width, int csm_texture_width) { // = 512, 4096
|
||||||
shadowmap_t s = {0};
|
shadowmap_t s = {0};
|
||||||
s.vsm_texture_width = vsm_texture_width;
|
s.vsm_texture_width = vsm_texture_width;
|
||||||
s.pcf_texture_width = pcf_texture_width;
|
s.csm_texture_width = csm_texture_width;
|
||||||
s.saved_fb = 0;
|
s.saved_fb = 0;
|
||||||
s.blur_pcf = false;
|
s.blur_csm = false;
|
||||||
s.blur_scale = 0.5f;
|
s.blur_vsm = false;
|
||||||
|
s.csm_blur_scale = 0.5f;
|
||||||
|
s.vsm_blur_scale = 0.75f;
|
||||||
s.cascade_splits[0] = 0.1f;
|
s.cascade_splits[0] = 0.1f;
|
||||||
s.cascade_splits[1] = 0.3f;
|
s.cascade_splits[1] = 0.3f;
|
||||||
s.cascade_splits[2] = 0.7f;
|
s.cascade_splits[2] = 0.7f;
|
||||||
s.cascade_splits[3] = 1.0f;
|
s.cascade_splits[3] = 1.0f;
|
||||||
s.cascade_splits[4] = 1.0f;
|
s.cascade_splits[4] = 1.0f;
|
||||||
s.cascade_splits[5] = 1.0f; /* sticks to camera far plane */
|
s.cascade_splits[5] = 1.0f; /* sticks to camera far plane */
|
||||||
|
glGenFramebuffers(1, &s.fbo);
|
||||||
|
|
||||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &s.saved_fb);
|
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &s.saved_fb);
|
||||||
|
|
||||||
|
@ -1728,9 +1690,9 @@ shadowmap_t shadowmap(int vsm_texture_width, int pcf_texture_width) { // = 512,
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
void shadowmap_destroy_light(shadowmap_t *s, int light_index) {
|
void shadowmap_destroy_light(shadowmap_t *s, int light_index) {
|
||||||
if (s->maps[light_index].fbos[0]) {
|
if (s->fbo) {
|
||||||
glDeleteFramebuffers(6, s->maps[light_index].fbos);
|
glDeleteFramebuffers(1, &s->fbo);
|
||||||
s->maps[light_index].fbos[0] = 0;
|
s->fbo = 0;
|
||||||
}
|
}
|
||||||
if (s->maps[light_index].texture) {
|
if (s->maps[light_index].texture) {
|
||||||
glDeleteTextures(1, &s->maps[light_index].texture);
|
glDeleteTextures(1, &s->maps[light_index].texture);
|
||||||
|
@ -1742,10 +1704,6 @@ void shadowmap_destroy_light(shadowmap_t *s, int light_index) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < NUM_SHADOW_CASCADES; i++) {
|
for (int i = 0; i < NUM_SHADOW_CASCADES; i++) {
|
||||||
if (s->maps[light_index].fbo_2d[i]) {
|
|
||||||
glDeleteFramebuffers(1, &s->maps[light_index].fbo_2d[i]);
|
|
||||||
s->maps[light_index].fbo_2d[i] = 0;
|
|
||||||
}
|
|
||||||
if (s->maps[light_index].texture_2d[i]) {
|
if (s->maps[light_index].texture_2d[i]) {
|
||||||
glDeleteTextures(1, &s->maps[light_index].texture_2d[i]);
|
glDeleteTextures(1, &s->maps[light_index].texture_2d[i]);
|
||||||
s->maps[light_index].texture_2d[i] = 0;
|
s->maps[light_index].texture_2d[i] = 0;
|
||||||
|
@ -1756,10 +1714,6 @@ void shadowmap_destroy_light(shadowmap_t *s, int light_index) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s->maps[light_index].blur_fbo_2d) {
|
|
||||||
glDeleteFramebuffers(1, &s->maps[light_index].blur_fbo_2d);
|
|
||||||
s->maps[light_index].blur_fbo_2d = 0;
|
|
||||||
}
|
|
||||||
if (s->maps[light_index].blur_texture_2d) {
|
if (s->maps[light_index].blur_texture_2d) {
|
||||||
glDeleteTextures(1, &s->maps[light_index].blur_texture_2d);
|
glDeleteTextures(1, &s->maps[light_index].blur_texture_2d);
|
||||||
s->maps[light_index].blur_texture_2d = 0;
|
s->maps[light_index].blur_texture_2d = 0;
|
||||||
|
@ -1911,19 +1865,31 @@ static void shadowmap_light_directional(shadowmap_t *s, light_t *l, int dir, flo
|
||||||
copy44(l->shadow_matrix[s->cascade_index], PV);
|
copy44(l->shadow_matrix[s->cascade_index], PV);
|
||||||
|
|
||||||
l->processed_shadows = true;
|
l->processed_shadows = true;
|
||||||
s->shadow_technique = l->shadow_technique = SHADOW_PCF;
|
s->shadow_technique = l->shadow_technique = SHADOW_CSM;
|
||||||
model_setpass(RENDER_PASS_SHADOW_PCF);
|
model_setpass(RENDER_PASS_SHADOW_CSM);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
void shadowmap_blur_pcf(shadowmap_t *s, int light_index) {
|
void shadowmap_blur_csm(shadowmap_t *s, int light_index) {
|
||||||
if (!s->blur_pcf) {
|
if (!s->blur_csm) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
float blur_scale = 1.999 * (1 - s->blur_scale) + 0.001;
|
float blur_scale = 1.999 * (1 - s->csm_blur_scale) + 0.001;
|
||||||
// blur_scale = 0.1f;
|
// blur_scale = 0.1f;
|
||||||
|
|
||||||
|
if (s->maps[light_index].blur_texture_2d == 0) {
|
||||||
|
// Blur texture
|
||||||
|
float borderColor[] = {1.0, 1.0, 1.0, 1.0};
|
||||||
|
glGenTextures(1, &s->maps[light_index].blur_texture_2d);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, s->maps[light_index].blur_texture_2d);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, s->csm_texture_width, s->csm_texture_width, 0, GL_RGB, GL_FLOAT, 0);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
}
|
||||||
|
|
||||||
static renderstate_t rs;
|
static renderstate_t rs;
|
||||||
static int program = -1, vao = -1, u_scale = -1, u_source = -1;
|
static int program = -1, vao = -1, u_scale = -1, u_source = -1;
|
||||||
if (program < 0) {
|
if (program < 0) {
|
||||||
|
@ -1941,8 +1907,8 @@ void shadowmap_blur_pcf(shadowmap_t *s, int light_index) {
|
||||||
glGenVertexArrays(1, &vao);
|
glGenVertexArrays(1, &vao);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderstate_apply(&rs);
|
// renderstate_apply(&rs);
|
||||||
glViewport(0, 0, s->pcf_texture_width, s->pcf_texture_width);
|
glViewport(0, 0, s->csm_texture_width, s->csm_texture_width);
|
||||||
|
|
||||||
unsigned oldprog = last_shader;
|
unsigned oldprog = last_shader;
|
||||||
glUseProgram(program);
|
glUseProgram(program);
|
||||||
|
@ -1952,8 +1918,9 @@ void shadowmap_blur_pcf(shadowmap_t *s, int light_index) {
|
||||||
|
|
||||||
// Horizontal pass
|
// Horizontal pass
|
||||||
for (int i = 0; i < NUM_SHADOW_CASCADES; i++) {
|
for (int i = 0; i < NUM_SHADOW_CASCADES; i++) {
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, s->maps[light_index].blur_fbo_2d);
|
glBindFramebuffer(GL_FRAMEBUFFER, s->fbo);
|
||||||
glUniform2f(u_scale, 1.0f / (s->pcf_texture_width * blur_scale), 0);
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, s->maps[light_index].blur_texture_2d, 0);
|
||||||
|
glUniform2f(u_scale, 1.0f / (s->csm_texture_width * blur_scale), 0);
|
||||||
glBindTexture(GL_TEXTURE_2D, s->maps[light_index].texture_2d[i]);
|
glBindTexture(GL_TEXTURE_2D, s->maps[light_index].texture_2d[i]);
|
||||||
glUniform1i(u_source, 0);
|
glUniform1i(u_source, 0);
|
||||||
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
@ -1963,8 +1930,9 @@ void shadowmap_blur_pcf(shadowmap_t *s, int light_index) {
|
||||||
profile_incstat("Render.num_triangles", +2);
|
profile_incstat("Render.num_triangles", +2);
|
||||||
|
|
||||||
// Vertical pass
|
// Vertical pass
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, s->maps[light_index].fbo_2d[i]);
|
glBindFramebuffer(GL_FRAMEBUFFER, s->fbo);
|
||||||
glUniform2f(u_scale, 0, 1.0f / (s->pcf_texture_width * blur_scale));
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, s->maps[light_index].texture_2d[i], 0);
|
||||||
|
glUniform2f(u_scale, 0, 1.0f / (s->csm_texture_width * blur_scale));
|
||||||
glBindTexture(GL_TEXTURE_2D, s->maps[light_index].blur_texture_2d);
|
glBindTexture(GL_TEXTURE_2D, s->maps[light_index].blur_texture_2d);
|
||||||
glUniform1i(u_source, 0);
|
glUniform1i(u_source, 0);
|
||||||
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
@ -1978,15 +1946,97 @@ void shadowmap_blur_pcf(shadowmap_t *s, int light_index) {
|
||||||
glUseProgram(oldprog);
|
glUseProgram(oldprog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
void shadowmap_blur_vsm(shadowmap_t *s, int light_index) {
|
||||||
|
if (!s->blur_vsm) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float blur_scale = 1.999 * (1 - s->vsm_blur_scale) + 0.001;
|
||||||
|
|
||||||
|
if (s->maps[light_index].blur_texture == 0) {
|
||||||
|
// Blur texture
|
||||||
|
float borderColor[] = {1.0, 1.0, 1.0, 1.0};
|
||||||
|
glGenTextures(1, &s->maps[light_index].blur_texture);
|
||||||
|
glBindTexture(GL_TEXTURE_CUBE_MAP, s->maps[light_index].blur_texture);
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
|
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB32F, s->vsm_texture_width, s->vsm_texture_width, 0, GL_RGB, GL_FLOAT, 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
static renderstate_t rs;
|
||||||
|
static int program = -1, vao = -1, u_scale = -1, u_source = -1, u_face = -1;
|
||||||
|
if (program < 0) {
|
||||||
|
rs = renderstate(); {
|
||||||
|
rs.depth_test_enabled = false;
|
||||||
|
rs.depth_write_enabled = false;
|
||||||
|
rs.blend_enabled = false;
|
||||||
|
}
|
||||||
|
const char* vs = vfs_read("shaders/vs_shadow_blur_cubemap.glsl");
|
||||||
|
const char* fs = vfs_read("shaders/fs_shadow_blur_cubemap.glsl");
|
||||||
|
|
||||||
|
program = shader(vs, fs, "", "fragcolor", NULL);
|
||||||
|
u_scale = glGetUniformLocation(program, "ScaleU");
|
||||||
|
u_source = glGetUniformLocation(program, "textureSource");
|
||||||
|
u_face = glGetUniformLocation(program, "face");
|
||||||
|
glGenVertexArrays(1, &vao);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderstate_apply(&rs);
|
||||||
|
// return;
|
||||||
|
glViewport(0, 0, s->vsm_texture_width, s->vsm_texture_width);
|
||||||
|
|
||||||
|
unsigned oldprog = last_shader;
|
||||||
|
glUseProgram(program);
|
||||||
|
|
||||||
|
glBindVertexArray(vao);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
|
for (int face = 0; face < 6; face++) {
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, s->fbo);
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, s->maps[light_index].blur_texture, 0);
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, 0);
|
||||||
|
glUniform2f(u_scale, 1.0f / (s->vsm_texture_width * blur_scale), 0);
|
||||||
|
glBindTexture(GL_TEXTURE_CUBE_MAP, s->maps[light_index].texture);
|
||||||
|
glUniform1i(u_source, 0);
|
||||||
|
glUniform1i(u_face, face);
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||||
|
profile_incstat("Render.num_drawcalls", +1);
|
||||||
|
profile_incstat("Render.num_triangles", +2);
|
||||||
|
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, s->maps[light_index].texture, 0);
|
||||||
|
glUniform2f(u_scale, 0, 1.0f / (s->vsm_texture_width * blur_scale));
|
||||||
|
glBindTexture(GL_TEXTURE_CUBE_MAP, s->maps[light_index].blur_texture);
|
||||||
|
glUniform1i(u_source, 0);
|
||||||
|
glUniform1i(u_face, face);
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||||
|
profile_incstat("Render.num_drawcalls", +1);
|
||||||
|
profile_incstat("Render.num_triangles", +2);
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindVertexArray(0);
|
||||||
|
glUseProgram(oldprog);
|
||||||
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
bool shadowmap_step_finish(shadowmap_t *s) {
|
bool shadowmap_step_finish(shadowmap_t *s) {
|
||||||
if (s->shadow_technique == SHADOW_PCF) {
|
if (s->shadow_technique == SHADOW_CSM) {
|
||||||
if (s->cascade_index < NUM_SHADOW_CASCADES-1) {
|
if (s->cascade_index < NUM_SHADOW_CASCADES-1) {
|
||||||
s->cascade_index++;
|
s->cascade_index++;
|
||||||
s->step = 0;
|
s->step = 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
shadowmap_blur_pcf(s, s->light_step);
|
shadowmap_blur_csm(s, s->light_step);
|
||||||
|
} else {
|
||||||
|
shadowmap_blur_vsm(s, s->light_step);
|
||||||
}
|
}
|
||||||
|
|
||||||
s->step = 0;
|
s->step = 0;
|
||||||
|
@ -1997,7 +2047,7 @@ bool shadowmap_step_finish(shadowmap_t *s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool shadowmap_step(shadowmap_t *s) {
|
bool shadowmap_step(shadowmap_t *s) {
|
||||||
int max_steps = s->shadow_technique == 0xffff ? 1 : s->shadow_technique == SHADOW_PCF ? 1 : 6;
|
int max_steps = s->shadow_technique == 0xffff ? 1 : s->shadow_technique == SHADOW_CSM ? 1 : 6;
|
||||||
if (s->step >= max_steps) {
|
if (s->step >= max_steps) {
|
||||||
if (shadowmap_step_finish(s)) {
|
if (shadowmap_step_finish(s)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -2034,9 +2084,7 @@ void shadowmap_light(shadowmap_t *s, light_t *l, mat44 cam_proj, mat44 cam_view)
|
||||||
cam_far *= 0.5f;
|
cam_far *= 0.5f;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (l->type == LIGHT_POINT) {
|
if (l->type == LIGHT_POINT || l->type == LIGHT_SPOT) {
|
||||||
shadowmap_light_point(s, l, step);
|
|
||||||
} else if (l->type == LIGHT_SPOT) {
|
|
||||||
shadowmap_light_point(s, l, step);
|
shadowmap_light_point(s, l, step);
|
||||||
} else if (l->type == LIGHT_DIRECTIONAL) {
|
} else if (l->type == LIGHT_DIRECTIONAL) {
|
||||||
shadowmap_light_directional(s, l, step, cam_fov, cam_far, cam_view);
|
shadowmap_light_directional(s, l, step, cam_fov, cam_far, cam_view);
|
||||||
|
@ -2050,8 +2098,8 @@ void shadowmap_light(shadowmap_t *s, light_t *l, mat44 cam_proj, mat44 cam_view)
|
||||||
// shadowmap_destroy_light(s, s->light_step); // @todo: we might wanna free the other set
|
// shadowmap_destroy_light(s, s->light_step); // @todo: we might wanna free the other set
|
||||||
if (l->shadow_technique == SHADOW_VSM) {
|
if (l->shadow_technique == SHADOW_VSM) {
|
||||||
shadowmap_init_caster_vsm(s, s->light_step, s->vsm_texture_width);
|
shadowmap_init_caster_vsm(s, s->light_step, s->vsm_texture_width);
|
||||||
} else if (l->shadow_technique == SHADOW_PCF) {
|
} else if (l->shadow_technique == SHADOW_CSM) {
|
||||||
shadowmap_init_caster_pcf(s, s->light_step, s->pcf_texture_width);
|
shadowmap_init_caster_csm(s, s->light_step, s->csm_texture_width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2061,14 +2109,18 @@ void shadowmap_light(shadowmap_t *s, light_t *l, mat44 cam_proj, mat44 cam_view)
|
||||||
s->lights_pushed++;
|
s->lights_pushed++;
|
||||||
|
|
||||||
if (l->type == LIGHT_DIRECTIONAL) {
|
if (l->type == LIGHT_DIRECTIONAL) {
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, s->maps[s->light_step].fbo_2d[s->cascade_index]);
|
glBindFramebuffer(GL_FRAMEBUFFER, s->fbo);
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, s->maps[s->light_step].texture_2d[s->cascade_index], 0);
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, s->maps[s->light_step].depth_texture_2d[s->cascade_index], 0);
|
||||||
shadowmap_clear_fbo();
|
shadowmap_clear_fbo();
|
||||||
} else {
|
} else {
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, s->maps[s->light_step].fbos[step]);
|
glBindFramebuffer(GL_FRAMEBUFFER, s->fbo);
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + step, s->maps[s->light_step].texture, 0);
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + step, s->maps[s->light_step].depth_texture, 0);
|
||||||
shadowmap_clear_fbo();
|
shadowmap_clear_fbo();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned texture_width = s->shadow_technique == SHADOW_VSM ? s->vsm_texture_width : s->pcf_texture_width;
|
unsigned texture_width = s->shadow_technique == SHADOW_VSM ? s->vsm_texture_width : s->csm_texture_width;
|
||||||
glViewport(0, 0, texture_width, texture_width);
|
glViewport(0, 0, texture_width, texture_width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4890,15 +4942,17 @@ void model_set_renderstates(model_t *m) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shadow pass
|
// Shadow pass
|
||||||
renderstate_t *pcf_shadow_rs = &m->rs[RENDER_PASS_SHADOW_PCF];
|
renderstate_t *csm_shadow_rs = &m->rs[RENDER_PASS_SHADOW_CSM];
|
||||||
{
|
{
|
||||||
pcf_shadow_rs->blend_enabled = 1;
|
csm_shadow_rs->blend_enabled = 1;
|
||||||
pcf_shadow_rs->blend_src = GL_SRC_ALPHA;
|
csm_shadow_rs->blend_src = GL_SRC_ALPHA;
|
||||||
pcf_shadow_rs->blend_dst = GL_ONE_MINUS_SRC_ALPHA;
|
csm_shadow_rs->blend_dst = GL_ONE_MINUS_SRC_ALPHA;
|
||||||
pcf_shadow_rs->cull_face_enabled = 1;
|
csm_shadow_rs->depth_test_enabled = true;
|
||||||
pcf_shadow_rs->cull_face_mode = GL_BACK;
|
csm_shadow_rs->depth_write_enabled = true;
|
||||||
pcf_shadow_rs->front_face = GL_CW;
|
csm_shadow_rs->cull_face_enabled = 1;
|
||||||
pcf_shadow_rs->depth_clamp_enabled = 1;
|
csm_shadow_rs->cull_face_mode = GL_BACK;
|
||||||
|
csm_shadow_rs->front_face = GL_CW;
|
||||||
|
csm_shadow_rs->depth_clamp_enabled = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderstate_t *vsm_shadow_rs = &m->rs[RENDER_PASS_SHADOW_VSM];
|
renderstate_t *vsm_shadow_rs = &m->rs[RENDER_PASS_SHADOW_VSM];
|
||||||
|
@ -4906,6 +4960,8 @@ void model_set_renderstates(model_t *m) {
|
||||||
vsm_shadow_rs->blend_enabled = 1;
|
vsm_shadow_rs->blend_enabled = 1;
|
||||||
vsm_shadow_rs->blend_src = GL_SRC_ALPHA;
|
vsm_shadow_rs->blend_src = GL_SRC_ALPHA;
|
||||||
vsm_shadow_rs->blend_dst = GL_ONE_MINUS_SRC_ALPHA;
|
vsm_shadow_rs->blend_dst = GL_ONE_MINUS_SRC_ALPHA;
|
||||||
|
vsm_shadow_rs->depth_test_enabled = true;
|
||||||
|
vsm_shadow_rs->depth_write_enabled = true;
|
||||||
vsm_shadow_rs->cull_face_enabled = 1;
|
vsm_shadow_rs->cull_face_enabled = 1;
|
||||||
vsm_shadow_rs->cull_face_mode = GL_BACK;
|
vsm_shadow_rs->cull_face_mode = GL_BACK;
|
||||||
vsm_shadow_rs->front_face = GL_CW;
|
vsm_shadow_rs->front_face = GL_CW;
|
||||||
|
|
|
@ -296,7 +296,7 @@ enum LIGHT_TYPE {
|
||||||
|
|
||||||
enum SHADOW_TECHNIQUE {
|
enum SHADOW_TECHNIQUE {
|
||||||
SHADOW_VSM,
|
SHADOW_VSM,
|
||||||
SHADOW_PCF,
|
SHADOW_CSM,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NUM_SHADOW_CASCADES 6
|
#define NUM_SHADOW_CASCADES 6
|
||||||
|
@ -346,24 +346,28 @@ typedef struct shadowmap_t {
|
||||||
mat44 V;
|
mat44 V;
|
||||||
mat44 PV;
|
mat44 PV;
|
||||||
int vsm_texture_width;
|
int vsm_texture_width;
|
||||||
int pcf_texture_width;
|
int csm_texture_width;
|
||||||
int step;
|
int step;
|
||||||
int light_step;
|
int light_step;
|
||||||
int cascade_index;
|
int cascade_index;
|
||||||
unsigned shadow_technique;
|
unsigned shadow_technique;
|
||||||
float cascade_splits[NUM_SHADOW_CASCADES];
|
float cascade_splits[NUM_SHADOW_CASCADES];
|
||||||
bool blur_pcf;
|
bool blur_csm;
|
||||||
float blur_scale;
|
bool blur_vsm;
|
||||||
|
float csm_blur_scale;
|
||||||
|
float vsm_blur_scale;
|
||||||
|
|
||||||
// signals
|
// signals
|
||||||
bool skip_render;
|
bool skip_render;
|
||||||
int lights_pushed;
|
int lights_pushed;
|
||||||
|
handle fbo;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
unsigned shadow_technique;
|
unsigned shadow_technique;
|
||||||
handle fbos[6], texture, depth_texture;
|
handle texture, depth_texture;
|
||||||
handle fbo_2d[NUM_SHADOW_CASCADES], texture_2d[NUM_SHADOW_CASCADES], depth_texture_2d[NUM_SHADOW_CASCADES];
|
handle texture_2d[NUM_SHADOW_CASCADES], depth_texture_2d[NUM_SHADOW_CASCADES];
|
||||||
handle blur_fbo_2d, blur_texture_2d;
|
handle blur_texture, blur_texture_2d;
|
||||||
|
// handle blur_fbo_cubemap, blur_texture_cubemap;
|
||||||
float cascade_distances[NUM_SHADOW_CASCADES];
|
float cascade_distances[NUM_SHADOW_CASCADES];
|
||||||
} maps[MAX_LIGHTS];
|
} maps[MAX_LIGHTS];
|
||||||
|
|
||||||
|
@ -372,7 +376,7 @@ typedef struct shadowmap_t {
|
||||||
int saved_vp[4];
|
int saved_vp[4];
|
||||||
} shadowmap_t;
|
} shadowmap_t;
|
||||||
|
|
||||||
API shadowmap_t shadowmap(int vsm_texture_width, int pcf_texture_width); // = 512, 4096
|
API shadowmap_t shadowmap(int vsm_texture_width, int csm_texture_width); // = 512, 4096
|
||||||
API void shadowmap_destroy(shadowmap_t *s);
|
API void shadowmap_destroy(shadowmap_t *s);
|
||||||
|
|
||||||
API void shadowmap_begin(shadowmap_t *s);
|
API void shadowmap_begin(shadowmap_t *s);
|
||||||
|
@ -713,7 +717,7 @@ enum RENDER_PASS {
|
||||||
RENDER_PASS_OVERRIDES_BEGIN,
|
RENDER_PASS_OVERRIDES_BEGIN,
|
||||||
|
|
||||||
RENDER_PASS_SHADOW_BEGIN,
|
RENDER_PASS_SHADOW_BEGIN,
|
||||||
RENDER_PASS_SHADOW_PCF,
|
RENDER_PASS_SHADOW_CSM,
|
||||||
RENDER_PASS_SHADOW_VSM,
|
RENDER_PASS_SHADOW_VSM,
|
||||||
RENDER_PASS_SHADOW_END,
|
RENDER_PASS_SHADOW_END,
|
||||||
|
|
||||||
|
|
232
engine/v4k.c
232
engine/v4k.c
|
@ -18411,22 +18411,10 @@ shadowmap_init_caster_vsm(shadowmap_t *s, int light_index, int texture_width) {
|
||||||
glTexParameterfv(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BORDER_COLOR, borderColor);
|
glTexParameterfv(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BORDER_COLOR, borderColor);
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
|
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
|
||||||
|
|
||||||
// Create 6 framebuffers for each face of the cubemap
|
|
||||||
glGenFramebuffers(6, s->maps[light_index].fbos);
|
|
||||||
for (int i = 0; i < 6; i++) {
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, s->maps[light_index].fbos[i]);
|
|
||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, s->maps[light_index].texture, 0);
|
|
||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, s->maps[light_index].depth_texture, 0);
|
|
||||||
GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
|
||||||
if (GL_FRAMEBUFFER_COMPLETE != result) {
|
|
||||||
PANIC("ERROR: Framebuffer is not complete: %x\n", result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
shadowmap_init_caster_pcf(shadowmap_t *s, int light_index, int texture_width) {
|
shadowmap_init_caster_csm(shadowmap_t *s, int light_index, int texture_width) {
|
||||||
float borderColor[] = {1.0, 1.0, 1.0, 1.0};
|
float borderColor[] = {1.0, 1.0, 1.0, 1.0};
|
||||||
|
|
||||||
if (s->maps[light_index].texture_2d[0]) {
|
if (s->maps[light_index].texture_2d[0]) {
|
||||||
|
@ -18455,56 +18443,30 @@ shadowmap_init_caster_pcf(shadowmap_t *s, int light_index, int texture_width) {
|
||||||
}
|
}
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
for (int i = 0; i < NUM_SHADOW_CASCADES; i++) {
|
|
||||||
glGenFramebuffers(1, &s->maps[light_index].fbo_2d[i]);
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, s->maps[light_index].fbo_2d[i]);
|
|
||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, s->maps[light_index].texture_2d[i], 0);
|
|
||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, s->maps[light_index].depth_texture_2d[i], 0);
|
|
||||||
GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
|
||||||
if (GL_FRAMEBUFFER_COMPLETE != result) {
|
|
||||||
PANIC("ERROR: Framebuffer is not complete: %x\n", result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Blur texture
|
|
||||||
glGenTextures(1, &s->maps[light_index].blur_texture_2d);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, s->maps[light_index].blur_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_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
||||||
|
|
||||||
// Blur FBO
|
|
||||||
glGenFramebuffers(1, &s->maps[light_index].blur_fbo_2d);
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, s->maps[light_index].blur_fbo_2d);
|
|
||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, s->maps[light_index].blur_texture_2d, 0);
|
|
||||||
GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
|
||||||
if (GL_FRAMEBUFFER_COMPLETE != result) {
|
|
||||||
PANIC("ERROR: Framebuffer is not complete: %x\n", result);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
shadowmap_init_caster(shadowmap_t *s, int light_index) {
|
shadowmap_init_caster(shadowmap_t *s, int light_index) {
|
||||||
shadowmap_init_caster_vsm(s, light_index, s->vsm_texture_width);
|
shadowmap_init_caster_vsm(s, light_index, s->vsm_texture_width);
|
||||||
shadowmap_init_caster_pcf(s, light_index, s->pcf_texture_width);
|
shadowmap_init_caster_csm(s, light_index, s->csm_texture_width);
|
||||||
}
|
}
|
||||||
|
|
||||||
shadowmap_t shadowmap(int vsm_texture_width, int pcf_texture_width) { // = 512, 4096
|
shadowmap_t shadowmap(int vsm_texture_width, int csm_texture_width) { // = 512, 4096
|
||||||
shadowmap_t s = {0};
|
shadowmap_t s = {0};
|
||||||
s.vsm_texture_width = vsm_texture_width;
|
s.vsm_texture_width = vsm_texture_width;
|
||||||
s.pcf_texture_width = pcf_texture_width;
|
s.csm_texture_width = csm_texture_width;
|
||||||
s.saved_fb = 0;
|
s.saved_fb = 0;
|
||||||
s.blur_pcf = false;
|
s.blur_csm = false;
|
||||||
s.blur_scale = 0.5f;
|
s.blur_vsm = false;
|
||||||
|
s.csm_blur_scale = 0.5f;
|
||||||
|
s.vsm_blur_scale = 0.75f;
|
||||||
s.cascade_splits[0] = 0.1f;
|
s.cascade_splits[0] = 0.1f;
|
||||||
s.cascade_splits[1] = 0.3f;
|
s.cascade_splits[1] = 0.3f;
|
||||||
s.cascade_splits[2] = 0.7f;
|
s.cascade_splits[2] = 0.7f;
|
||||||
s.cascade_splits[3] = 1.0f;
|
s.cascade_splits[3] = 1.0f;
|
||||||
s.cascade_splits[4] = 1.0f;
|
s.cascade_splits[4] = 1.0f;
|
||||||
s.cascade_splits[5] = 1.0f; /* sticks to camera far plane */
|
s.cascade_splits[5] = 1.0f; /* sticks to camera far plane */
|
||||||
|
glGenFramebuffers(1, &s.fbo);
|
||||||
|
|
||||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &s.saved_fb);
|
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &s.saved_fb);
|
||||||
|
|
||||||
|
@ -18527,9 +18489,9 @@ shadowmap_t shadowmap(int vsm_texture_width, int pcf_texture_width) { // = 512,
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
void shadowmap_destroy_light(shadowmap_t *s, int light_index) {
|
void shadowmap_destroy_light(shadowmap_t *s, int light_index) {
|
||||||
if (s->maps[light_index].fbos[0]) {
|
if (s->fbo) {
|
||||||
glDeleteFramebuffers(6, s->maps[light_index].fbos);
|
glDeleteFramebuffers(1, &s->fbo);
|
||||||
s->maps[light_index].fbos[0] = 0;
|
s->fbo = 0;
|
||||||
}
|
}
|
||||||
if (s->maps[light_index].texture) {
|
if (s->maps[light_index].texture) {
|
||||||
glDeleteTextures(1, &s->maps[light_index].texture);
|
glDeleteTextures(1, &s->maps[light_index].texture);
|
||||||
|
@ -18541,10 +18503,6 @@ void shadowmap_destroy_light(shadowmap_t *s, int light_index) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < NUM_SHADOW_CASCADES; i++) {
|
for (int i = 0; i < NUM_SHADOW_CASCADES; i++) {
|
||||||
if (s->maps[light_index].fbo_2d[i]) {
|
|
||||||
glDeleteFramebuffers(1, &s->maps[light_index].fbo_2d[i]);
|
|
||||||
s->maps[light_index].fbo_2d[i] = 0;
|
|
||||||
}
|
|
||||||
if (s->maps[light_index].texture_2d[i]) {
|
if (s->maps[light_index].texture_2d[i]) {
|
||||||
glDeleteTextures(1, &s->maps[light_index].texture_2d[i]);
|
glDeleteTextures(1, &s->maps[light_index].texture_2d[i]);
|
||||||
s->maps[light_index].texture_2d[i] = 0;
|
s->maps[light_index].texture_2d[i] = 0;
|
||||||
|
@ -18555,10 +18513,6 @@ void shadowmap_destroy_light(shadowmap_t *s, int light_index) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s->maps[light_index].blur_fbo_2d) {
|
|
||||||
glDeleteFramebuffers(1, &s->maps[light_index].blur_fbo_2d);
|
|
||||||
s->maps[light_index].blur_fbo_2d = 0;
|
|
||||||
}
|
|
||||||
if (s->maps[light_index].blur_texture_2d) {
|
if (s->maps[light_index].blur_texture_2d) {
|
||||||
glDeleteTextures(1, &s->maps[light_index].blur_texture_2d);
|
glDeleteTextures(1, &s->maps[light_index].blur_texture_2d);
|
||||||
s->maps[light_index].blur_texture_2d = 0;
|
s->maps[light_index].blur_texture_2d = 0;
|
||||||
|
@ -18710,19 +18664,31 @@ static void shadowmap_light_directional(shadowmap_t *s, light_t *l, int dir, flo
|
||||||
copy44(l->shadow_matrix[s->cascade_index], PV);
|
copy44(l->shadow_matrix[s->cascade_index], PV);
|
||||||
|
|
||||||
l->processed_shadows = true;
|
l->processed_shadows = true;
|
||||||
s->shadow_technique = l->shadow_technique = SHADOW_PCF;
|
s->shadow_technique = l->shadow_technique = SHADOW_CSM;
|
||||||
model_setpass(RENDER_PASS_SHADOW_PCF);
|
model_setpass(RENDER_PASS_SHADOW_CSM);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
void shadowmap_blur_pcf(shadowmap_t *s, int light_index) {
|
void shadowmap_blur_csm(shadowmap_t *s, int light_index) {
|
||||||
if (!s->blur_pcf) {
|
if (!s->blur_csm) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
float blur_scale = 1.999 * (1 - s->blur_scale) + 0.001;
|
float blur_scale = 1.999 * (1 - s->csm_blur_scale) + 0.001;
|
||||||
// blur_scale = 0.1f;
|
// blur_scale = 0.1f;
|
||||||
|
|
||||||
|
if (s->maps[light_index].blur_texture_2d == 0) {
|
||||||
|
// Blur texture
|
||||||
|
float borderColor[] = {1.0, 1.0, 1.0, 1.0};
|
||||||
|
glGenTextures(1, &s->maps[light_index].blur_texture_2d);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, s->maps[light_index].blur_texture_2d);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, s->csm_texture_width, s->csm_texture_width, 0, GL_RGB, GL_FLOAT, 0);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
}
|
||||||
|
|
||||||
static renderstate_t rs;
|
static renderstate_t rs;
|
||||||
static int program = -1, vao = -1, u_scale = -1, u_source = -1;
|
static int program = -1, vao = -1, u_scale = -1, u_source = -1;
|
||||||
if (program < 0) {
|
if (program < 0) {
|
||||||
|
@ -18740,8 +18706,8 @@ void shadowmap_blur_pcf(shadowmap_t *s, int light_index) {
|
||||||
glGenVertexArrays(1, &vao);
|
glGenVertexArrays(1, &vao);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderstate_apply(&rs);
|
// renderstate_apply(&rs);
|
||||||
glViewport(0, 0, s->pcf_texture_width, s->pcf_texture_width);
|
glViewport(0, 0, s->csm_texture_width, s->csm_texture_width);
|
||||||
|
|
||||||
unsigned oldprog = last_shader;
|
unsigned oldprog = last_shader;
|
||||||
glUseProgram(program);
|
glUseProgram(program);
|
||||||
|
@ -18751,8 +18717,9 @@ void shadowmap_blur_pcf(shadowmap_t *s, int light_index) {
|
||||||
|
|
||||||
// Horizontal pass
|
// Horizontal pass
|
||||||
for (int i = 0; i < NUM_SHADOW_CASCADES; i++) {
|
for (int i = 0; i < NUM_SHADOW_CASCADES; i++) {
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, s->maps[light_index].blur_fbo_2d);
|
glBindFramebuffer(GL_FRAMEBUFFER, s->fbo);
|
||||||
glUniform2f(u_scale, 1.0f / (s->pcf_texture_width * blur_scale), 0);
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, s->maps[light_index].blur_texture_2d, 0);
|
||||||
|
glUniform2f(u_scale, 1.0f / (s->csm_texture_width * blur_scale), 0);
|
||||||
glBindTexture(GL_TEXTURE_2D, s->maps[light_index].texture_2d[i]);
|
glBindTexture(GL_TEXTURE_2D, s->maps[light_index].texture_2d[i]);
|
||||||
glUniform1i(u_source, 0);
|
glUniform1i(u_source, 0);
|
||||||
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
@ -18762,8 +18729,9 @@ void shadowmap_blur_pcf(shadowmap_t *s, int light_index) {
|
||||||
profile_incstat("Render.num_triangles", +2);
|
profile_incstat("Render.num_triangles", +2);
|
||||||
|
|
||||||
// Vertical pass
|
// Vertical pass
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, s->maps[light_index].fbo_2d[i]);
|
glBindFramebuffer(GL_FRAMEBUFFER, s->fbo);
|
||||||
glUniform2f(u_scale, 0, 1.0f / (s->pcf_texture_width * blur_scale));
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, s->maps[light_index].texture_2d[i], 0);
|
||||||
|
glUniform2f(u_scale, 0, 1.0f / (s->csm_texture_width * blur_scale));
|
||||||
glBindTexture(GL_TEXTURE_2D, s->maps[light_index].blur_texture_2d);
|
glBindTexture(GL_TEXTURE_2D, s->maps[light_index].blur_texture_2d);
|
||||||
glUniform1i(u_source, 0);
|
glUniform1i(u_source, 0);
|
||||||
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
@ -18777,15 +18745,97 @@ void shadowmap_blur_pcf(shadowmap_t *s, int light_index) {
|
||||||
glUseProgram(oldprog);
|
glUseProgram(oldprog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
void shadowmap_blur_vsm(shadowmap_t *s, int light_index) {
|
||||||
|
if (!s->blur_vsm) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float blur_scale = 1.999 * (1 - s->vsm_blur_scale) + 0.001;
|
||||||
|
|
||||||
|
if (s->maps[light_index].blur_texture == 0) {
|
||||||
|
// Blur texture
|
||||||
|
float borderColor[] = {1.0, 1.0, 1.0, 1.0};
|
||||||
|
glGenTextures(1, &s->maps[light_index].blur_texture);
|
||||||
|
glBindTexture(GL_TEXTURE_CUBE_MAP, s->maps[light_index].blur_texture);
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
|
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB32F, s->vsm_texture_width, s->vsm_texture_width, 0, GL_RGB, GL_FLOAT, 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
static renderstate_t rs;
|
||||||
|
static int program = -1, vao = -1, u_scale = -1, u_source = -1, u_face = -1;
|
||||||
|
if (program < 0) {
|
||||||
|
rs = renderstate(); {
|
||||||
|
rs.depth_test_enabled = false;
|
||||||
|
rs.depth_write_enabled = false;
|
||||||
|
rs.blend_enabled = false;
|
||||||
|
}
|
||||||
|
const char* vs = vfs_read("shaders/vs_shadow_blur_cubemap.glsl");
|
||||||
|
const char* fs = vfs_read("shaders/fs_shadow_blur_cubemap.glsl");
|
||||||
|
|
||||||
|
program = shader(vs, fs, "", "fragcolor", NULL);
|
||||||
|
u_scale = glGetUniformLocation(program, "ScaleU");
|
||||||
|
u_source = glGetUniformLocation(program, "textureSource");
|
||||||
|
u_face = glGetUniformLocation(program, "face");
|
||||||
|
glGenVertexArrays(1, &vao);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderstate_apply(&rs);
|
||||||
|
// return;
|
||||||
|
glViewport(0, 0, s->vsm_texture_width, s->vsm_texture_width);
|
||||||
|
|
||||||
|
unsigned oldprog = last_shader;
|
||||||
|
glUseProgram(program);
|
||||||
|
|
||||||
|
glBindVertexArray(vao);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
|
for (int face = 0; face < 6; face++) {
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, s->fbo);
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, s->maps[light_index].blur_texture, 0);
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, 0);
|
||||||
|
glUniform2f(u_scale, 1.0f / (s->vsm_texture_width * blur_scale), 0);
|
||||||
|
glBindTexture(GL_TEXTURE_CUBE_MAP, s->maps[light_index].texture);
|
||||||
|
glUniform1i(u_source, 0);
|
||||||
|
glUniform1i(u_face, face);
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||||
|
profile_incstat("Render.num_drawcalls", +1);
|
||||||
|
profile_incstat("Render.num_triangles", +2);
|
||||||
|
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, s->maps[light_index].texture, 0);
|
||||||
|
glUniform2f(u_scale, 0, 1.0f / (s->vsm_texture_width * blur_scale));
|
||||||
|
glBindTexture(GL_TEXTURE_CUBE_MAP, s->maps[light_index].blur_texture);
|
||||||
|
glUniform1i(u_source, 0);
|
||||||
|
glUniform1i(u_face, face);
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||||
|
profile_incstat("Render.num_drawcalls", +1);
|
||||||
|
profile_incstat("Render.num_triangles", +2);
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindVertexArray(0);
|
||||||
|
glUseProgram(oldprog);
|
||||||
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
bool shadowmap_step_finish(shadowmap_t *s) {
|
bool shadowmap_step_finish(shadowmap_t *s) {
|
||||||
if (s->shadow_technique == SHADOW_PCF) {
|
if (s->shadow_technique == SHADOW_CSM) {
|
||||||
if (s->cascade_index < NUM_SHADOW_CASCADES-1) {
|
if (s->cascade_index < NUM_SHADOW_CASCADES-1) {
|
||||||
s->cascade_index++;
|
s->cascade_index++;
|
||||||
s->step = 0;
|
s->step = 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
shadowmap_blur_pcf(s, s->light_step);
|
shadowmap_blur_csm(s, s->light_step);
|
||||||
|
} else {
|
||||||
|
shadowmap_blur_vsm(s, s->light_step);
|
||||||
}
|
}
|
||||||
|
|
||||||
s->step = 0;
|
s->step = 0;
|
||||||
|
@ -18796,7 +18846,7 @@ bool shadowmap_step_finish(shadowmap_t *s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool shadowmap_step(shadowmap_t *s) {
|
bool shadowmap_step(shadowmap_t *s) {
|
||||||
int max_steps = s->shadow_technique == 0xffff ? 1 : s->shadow_technique == SHADOW_PCF ? 1 : 6;
|
int max_steps = s->shadow_technique == 0xffff ? 1 : s->shadow_technique == SHADOW_CSM ? 1 : 6;
|
||||||
if (s->step >= max_steps) {
|
if (s->step >= max_steps) {
|
||||||
if (shadowmap_step_finish(s)) {
|
if (shadowmap_step_finish(s)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -18833,9 +18883,7 @@ void shadowmap_light(shadowmap_t *s, light_t *l, mat44 cam_proj, mat44 cam_view)
|
||||||
cam_far *= 0.5f;
|
cam_far *= 0.5f;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (l->type == LIGHT_POINT) {
|
if (l->type == LIGHT_POINT || l->type == LIGHT_SPOT) {
|
||||||
shadowmap_light_point(s, l, step);
|
|
||||||
} else if (l->type == LIGHT_SPOT) {
|
|
||||||
shadowmap_light_point(s, l, step);
|
shadowmap_light_point(s, l, step);
|
||||||
} else if (l->type == LIGHT_DIRECTIONAL) {
|
} else if (l->type == LIGHT_DIRECTIONAL) {
|
||||||
shadowmap_light_directional(s, l, step, cam_fov, cam_far, cam_view);
|
shadowmap_light_directional(s, l, step, cam_fov, cam_far, cam_view);
|
||||||
|
@ -18849,8 +18897,8 @@ void shadowmap_light(shadowmap_t *s, light_t *l, mat44 cam_proj, mat44 cam_view)
|
||||||
// shadowmap_destroy_light(s, s->light_step); // @todo: we might wanna free the other set
|
// shadowmap_destroy_light(s, s->light_step); // @todo: we might wanna free the other set
|
||||||
if (l->shadow_technique == SHADOW_VSM) {
|
if (l->shadow_technique == SHADOW_VSM) {
|
||||||
shadowmap_init_caster_vsm(s, s->light_step, s->vsm_texture_width);
|
shadowmap_init_caster_vsm(s, s->light_step, s->vsm_texture_width);
|
||||||
} else if (l->shadow_technique == SHADOW_PCF) {
|
} else if (l->shadow_technique == SHADOW_CSM) {
|
||||||
shadowmap_init_caster_pcf(s, s->light_step, s->pcf_texture_width);
|
shadowmap_init_caster_csm(s, s->light_step, s->csm_texture_width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18860,14 +18908,18 @@ void shadowmap_light(shadowmap_t *s, light_t *l, mat44 cam_proj, mat44 cam_view)
|
||||||
s->lights_pushed++;
|
s->lights_pushed++;
|
||||||
|
|
||||||
if (l->type == LIGHT_DIRECTIONAL) {
|
if (l->type == LIGHT_DIRECTIONAL) {
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, s->maps[s->light_step].fbo_2d[s->cascade_index]);
|
glBindFramebuffer(GL_FRAMEBUFFER, s->fbo);
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, s->maps[s->light_step].texture_2d[s->cascade_index], 0);
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, s->maps[s->light_step].depth_texture_2d[s->cascade_index], 0);
|
||||||
shadowmap_clear_fbo();
|
shadowmap_clear_fbo();
|
||||||
} else {
|
} else {
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, s->maps[s->light_step].fbos[step]);
|
glBindFramebuffer(GL_FRAMEBUFFER, s->fbo);
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + step, s->maps[s->light_step].texture, 0);
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + step, s->maps[s->light_step].depth_texture, 0);
|
||||||
shadowmap_clear_fbo();
|
shadowmap_clear_fbo();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned texture_width = s->shadow_technique == SHADOW_VSM ? s->vsm_texture_width : s->pcf_texture_width;
|
unsigned texture_width = s->shadow_technique == SHADOW_VSM ? s->vsm_texture_width : s->csm_texture_width;
|
||||||
glViewport(0, 0, texture_width, texture_width);
|
glViewport(0, 0, texture_width, texture_width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21689,15 +21741,17 @@ void model_set_renderstates(model_t *m) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shadow pass
|
// Shadow pass
|
||||||
renderstate_t *pcf_shadow_rs = &m->rs[RENDER_PASS_SHADOW_PCF];
|
renderstate_t *csm_shadow_rs = &m->rs[RENDER_PASS_SHADOW_CSM];
|
||||||
{
|
{
|
||||||
pcf_shadow_rs->blend_enabled = 1;
|
csm_shadow_rs->blend_enabled = 1;
|
||||||
pcf_shadow_rs->blend_src = GL_SRC_ALPHA;
|
csm_shadow_rs->blend_src = GL_SRC_ALPHA;
|
||||||
pcf_shadow_rs->blend_dst = GL_ONE_MINUS_SRC_ALPHA;
|
csm_shadow_rs->blend_dst = GL_ONE_MINUS_SRC_ALPHA;
|
||||||
pcf_shadow_rs->cull_face_enabled = 1;
|
csm_shadow_rs->depth_test_enabled = true;
|
||||||
pcf_shadow_rs->cull_face_mode = GL_BACK;
|
csm_shadow_rs->depth_write_enabled = true;
|
||||||
pcf_shadow_rs->front_face = GL_CW;
|
csm_shadow_rs->cull_face_enabled = 1;
|
||||||
pcf_shadow_rs->depth_clamp_enabled = 1;
|
csm_shadow_rs->cull_face_mode = GL_BACK;
|
||||||
|
csm_shadow_rs->front_face = GL_CW;
|
||||||
|
csm_shadow_rs->depth_clamp_enabled = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderstate_t *vsm_shadow_rs = &m->rs[RENDER_PASS_SHADOW_VSM];
|
renderstate_t *vsm_shadow_rs = &m->rs[RENDER_PASS_SHADOW_VSM];
|
||||||
|
@ -21705,6 +21759,8 @@ void model_set_renderstates(model_t *m) {
|
||||||
vsm_shadow_rs->blend_enabled = 1;
|
vsm_shadow_rs->blend_enabled = 1;
|
||||||
vsm_shadow_rs->blend_src = GL_SRC_ALPHA;
|
vsm_shadow_rs->blend_src = GL_SRC_ALPHA;
|
||||||
vsm_shadow_rs->blend_dst = GL_ONE_MINUS_SRC_ALPHA;
|
vsm_shadow_rs->blend_dst = GL_ONE_MINUS_SRC_ALPHA;
|
||||||
|
vsm_shadow_rs->depth_test_enabled = true;
|
||||||
|
vsm_shadow_rs->depth_write_enabled = true;
|
||||||
vsm_shadow_rs->cull_face_enabled = 1;
|
vsm_shadow_rs->cull_face_enabled = 1;
|
||||||
vsm_shadow_rs->cull_face_mode = GL_BACK;
|
vsm_shadow_rs->cull_face_mode = GL_BACK;
|
||||||
vsm_shadow_rs->front_face = GL_CW;
|
vsm_shadow_rs->front_face = GL_CW;
|
||||||
|
|
22
engine/v4k.h
22
engine/v4k.h
|
@ -3331,7 +3331,7 @@ enum LIGHT_TYPE {
|
||||||
|
|
||||||
enum SHADOW_TECHNIQUE {
|
enum SHADOW_TECHNIQUE {
|
||||||
SHADOW_VSM,
|
SHADOW_VSM,
|
||||||
SHADOW_PCF,
|
SHADOW_CSM,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NUM_SHADOW_CASCADES 6
|
#define NUM_SHADOW_CASCADES 6
|
||||||
|
@ -3381,24 +3381,28 @@ typedef struct shadowmap_t {
|
||||||
mat44 V;
|
mat44 V;
|
||||||
mat44 PV;
|
mat44 PV;
|
||||||
int vsm_texture_width;
|
int vsm_texture_width;
|
||||||
int pcf_texture_width;
|
int csm_texture_width;
|
||||||
int step;
|
int step;
|
||||||
int light_step;
|
int light_step;
|
||||||
int cascade_index;
|
int cascade_index;
|
||||||
unsigned shadow_technique;
|
unsigned shadow_technique;
|
||||||
float cascade_splits[NUM_SHADOW_CASCADES];
|
float cascade_splits[NUM_SHADOW_CASCADES];
|
||||||
bool blur_pcf;
|
bool blur_csm;
|
||||||
float blur_scale;
|
bool blur_vsm;
|
||||||
|
float csm_blur_scale;
|
||||||
|
float vsm_blur_scale;
|
||||||
|
|
||||||
// signals
|
// signals
|
||||||
bool skip_render;
|
bool skip_render;
|
||||||
int lights_pushed;
|
int lights_pushed;
|
||||||
|
handle fbo;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
unsigned shadow_technique;
|
unsigned shadow_technique;
|
||||||
handle fbos[6], texture, depth_texture;
|
handle texture, depth_texture;
|
||||||
handle fbo_2d[NUM_SHADOW_CASCADES], texture_2d[NUM_SHADOW_CASCADES], depth_texture_2d[NUM_SHADOW_CASCADES];
|
handle texture_2d[NUM_SHADOW_CASCADES], depth_texture_2d[NUM_SHADOW_CASCADES];
|
||||||
handle blur_fbo_2d, blur_texture_2d;
|
handle blur_texture, blur_texture_2d;
|
||||||
|
// handle blur_fbo_cubemap, blur_texture_cubemap;
|
||||||
float cascade_distances[NUM_SHADOW_CASCADES];
|
float cascade_distances[NUM_SHADOW_CASCADES];
|
||||||
} maps[MAX_LIGHTS];
|
} maps[MAX_LIGHTS];
|
||||||
|
|
||||||
|
@ -3407,7 +3411,7 @@ typedef struct shadowmap_t {
|
||||||
int saved_vp[4];
|
int saved_vp[4];
|
||||||
} shadowmap_t;
|
} shadowmap_t;
|
||||||
|
|
||||||
API shadowmap_t shadowmap(int vsm_texture_width, int pcf_texture_width); // = 512, 4096
|
API shadowmap_t shadowmap(int vsm_texture_width, int csm_texture_width); // = 512, 4096
|
||||||
API void shadowmap_destroy(shadowmap_t *s);
|
API void shadowmap_destroy(shadowmap_t *s);
|
||||||
|
|
||||||
API void shadowmap_begin(shadowmap_t *s);
|
API void shadowmap_begin(shadowmap_t *s);
|
||||||
|
@ -3748,7 +3752,7 @@ enum RENDER_PASS {
|
||||||
RENDER_PASS_OVERRIDES_BEGIN,
|
RENDER_PASS_OVERRIDES_BEGIN,
|
||||||
|
|
||||||
RENDER_PASS_SHADOW_BEGIN,
|
RENDER_PASS_SHADOW_BEGIN,
|
||||||
RENDER_PASS_SHADOW_PCF,
|
RENDER_PASS_SHADOW_CSM,
|
||||||
RENDER_PASS_SHADOW_VSM,
|
RENDER_PASS_SHADOW_VSM,
|
||||||
RENDER_PASS_SHADOW_END,
|
RENDER_PASS_SHADOW_END,
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue