pcf improved, yes
parent
8d2fd2660e
commit
27b220c104
11
bind/v4k.lua
11
bind/v4k.lua
|
@ -1161,7 +1161,7 @@ typedef struct light_t {
|
|||
unsigned shadow_technique;
|
||||
float shadow_distance;
|
||||
float shadow_bias;
|
||||
mat44 shadow_matrix[4];
|
||||
mat44 shadow_matrix[6];
|
||||
bool cached;
|
||||
} light_t;
|
||||
light_t light();
|
||||
|
@ -1185,8 +1185,8 @@ typedef struct shadowmap_t {
|
|||
int light_step;
|
||||
int cascade_index;
|
||||
unsigned shadow_technique;
|
||||
float cascade_splits[4];
|
||||
float cascade_distances[4];
|
||||
float cascade_splits[6];
|
||||
float cascade_distances[6];
|
||||
bool blur_pcf;
|
||||
float blur_scale;
|
||||
bool skip_render;
|
||||
|
@ -1194,7 +1194,7 @@ typedef struct shadowmap_t {
|
|||
struct {
|
||||
unsigned shadow_technique;
|
||||
handle fbos[6], texture, depth_texture;
|
||||
handle fbo_2d[4], texture_2d[4], depth_texture_2d[4];
|
||||
handle fbo_2d[6], texture_2d[6], depth_texture_2d[6];
|
||||
handle blur_fbo_2d, blur_texture_2d;
|
||||
} maps[MAX_LIGHTS];
|
||||
handle saved_fb;
|
||||
|
@ -1205,7 +1205,7 @@ typedef struct shadowmap_t {
|
|||
void shadowmap_destroy(shadowmap_t *s);
|
||||
void shadowmap_begin(shadowmap_t *s);
|
||||
bool shadowmap_step(shadowmap_t *s);
|
||||
void shadowmap_light(shadowmap_t *s, light_t *l, float cam_fov, float cam_far, mat44 cam_view);
|
||||
void shadowmap_light(shadowmap_t *s, light_t *l, mat44 cam_proj, mat44 cam_view);
|
||||
void shadowmap_end(shadowmap_t *s);
|
||||
unsigned shader(const char *vs, const char *fs, const char *attribs, const char *fragcolor, const char *defines);
|
||||
unsigned shader_geom(const char *gs, const char *vs, const char *fs, const char *attribs, const char *fragcolor, const char *defines);
|
||||
|
@ -1619,6 +1619,7 @@ typedef struct camera_t {
|
|||
vec3 position, updir, lookdir;
|
||||
float yaw, pitch, roll;
|
||||
float speed, fov;
|
||||
float near_clip, far_clip;
|
||||
float move_friction, move_damping;
|
||||
float look_friction, look_damping;
|
||||
vec3 last_look; vec3 last_move;
|
||||
|
|
|
@ -86,8 +86,8 @@ int main(int argc, char** argv) {
|
|||
if( !initialized ) {
|
||||
initialized = 1;
|
||||
sky = skybox(flag("--mie") ? 0 : SKY_DIRS[SKY_DIR], 0);
|
||||
sm = shadowmap(512, 2048);
|
||||
// sm.blur_pcf = 0;
|
||||
sm = shadowmap(512, 4096);
|
||||
// sm.blur_pcf = 1;
|
||||
mdl = model(OBJ_MDLS[OBJ_MDL], 0);
|
||||
shader_bind(mdl.program);
|
||||
cubemap_sh_shader(&sky.cubemap);
|
||||
|
@ -167,7 +167,7 @@ int main(int argc, char** argv) {
|
|||
{
|
||||
for (int i = 0; i < array_count(lights); i++) {
|
||||
while (shadowmap_step(&sm)) {
|
||||
shadowmap_light(&sm, &lights[i], cam.fov, 2000.0f, cam.view);
|
||||
shadowmap_light(&sm, &lights[i], cam.proj, cam.view);
|
||||
model_render(mdl, cam.proj, cam.view, mdl.pivot, 0);
|
||||
}
|
||||
}
|
||||
|
|
633
demos/99-spot.c
633
demos/99-spot.c
|
@ -1,633 +0,0 @@
|
|||
// [ref] http://fabiensanglard.net/shadowmappingVSM/index.php
|
||||
// [ref] http://www.opengl-tutorial.org/es/intermediate-tutorials/tutorial-16-shadow-mapping/
|
||||
// [ref] https://github.com/cforfang/opengl-shadowmapping
|
||||
// [ref] https://learnopengl.com/Advanced-Lighting/Shadows/Shadow-Mapping
|
||||
|
||||
// @todo: spotlight (cone light)
|
||||
// @todo: pointlight (cubemap light)
|
||||
// @todo: area light (rect or circle light)
|
||||
// @todo: directional light (sunlight)
|
||||
|
||||
// further reading (in order):
|
||||
// DPSM [3] Brabec, Annen: Shadow mapping for hemispherical and omnidirectional light sources (2002)
|
||||
// DPSM* [4] Osman, Bukowski: Practical implementation of dual paraboloid shadow maps (2006)
|
||||
// IPSM [5] Vanek, Herout: High-quality Shadows with Improved Paraboloid Mapping (2011)
|
||||
// LiSPSMs
|
||||
// CSMs
|
||||
|
||||
// status: CUBE(0)+BLUR(0): ok
|
||||
// status: CUBE(0)+BLUR(1): ok
|
||||
// status: CUBE(1)+BLUR(1): ok
|
||||
// status: CUBE(1)+BLUR(0): ok
|
||||
// status: CUBE(?)+BLUR(?): no {
|
||||
// 003.470s|!cannot find uniform 'shadowMap' in shader program 21 |shader_uniform|fwk_render.c:772
|
||||
// 001: 00007FF7AF6A3FDA callstack (C:\prj\thread\FWK\fwk_system.c:250)
|
||||
// 002: 00007FF7AF8E7CBC shader_uniform (C:\prj\thread\FWK\fwk_render.c:772)
|
||||
// 003: 00007FF7AF691C27 shader_int (C:\prj\thread\FWK\fwk_render.c:777)
|
||||
// 004: 00007FF7AF8F54EF color_begin (C:\prj\thread\FWK\spot.c:525)
|
||||
// 005: 00007FF7AF8F5BF7 main (C:\prj\thread\FWK\spot.c:607)
|
||||
// }
|
||||
|
||||
#ifndef VSMCUBE
|
||||
#define VSMCUBE 0
|
||||
#endif
|
||||
#ifndef VSMBLUR
|
||||
#define VSMBLUR 1
|
||||
#endif
|
||||
|
||||
#include "v4k.h"
|
||||
|
||||
model_t sponza;
|
||||
|
||||
typedef struct Mesh
|
||||
{
|
||||
GLuint vao;
|
||||
GLuint vbo;
|
||||
} Mesh;
|
||||
|
||||
static float quadVertices[] = {
|
||||
// Front-face
|
||||
// Pos // Color //Tex // Norm
|
||||
-1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Top-left
|
||||
1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Top-right
|
||||
1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // Bottom-right
|
||||
|
||||
1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // Bottom-right
|
||||
-1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, //Bottom-left
|
||||
-1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Top-left
|
||||
};
|
||||
|
||||
static Mesh create_mesh(float* verts, int size) {
|
||||
Mesh mesh;
|
||||
|
||||
// Create VAO
|
||||
glGenVertexArrays(1, &mesh.vao);
|
||||
glBindVertexArray(mesh.vao);
|
||||
|
||||
// Create VBO and copy the vertex data to it
|
||||
glGenBuffers(1, &mesh.vbo);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, mesh.vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, size, verts, GL_STATIC_DRAW);
|
||||
|
||||
// Enable attribs
|
||||
// Position
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(float), 0);
|
||||
// Color
|
||||
glEnableVertexAttribArray(3);
|
||||
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(float), (void*)(3 * sizeof(float)));
|
||||
// Texcoords
|
||||
glEnableVertexAttribArray(2);
|
||||
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 11 * sizeof(float), (void*)(6 * sizeof(float)));
|
||||
// Normal
|
||||
glEnableVertexAttribArray(1);
|
||||
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(float), (void*)(8 * sizeof(float)));
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
Mesh create_quad() {
|
||||
return create_mesh(quadVertices, sizeof(quadVertices));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
#define Mesh model_t
|
||||
model_t create_cube() {
|
||||
model_t m = model("#meshes/cube.obj", 0); //MESH_TRIANGLE_STRIP);
|
||||
return m;
|
||||
}
|
||||
*/
|
||||
static const char* const vs_shadow_blur = "//" FILELINE "\n"
|
||||
"in vec3 position;\n"
|
||||
"in vec2 texcoord;\n"
|
||||
"out vec2 Texcoord;\n"
|
||||
|
||||
"void main() {\n"
|
||||
" gl_Position = vec4(position, 1.0);\n"
|
||||
" Texcoord = texcoord;\n"
|
||||
"}\n";
|
||||
|
||||
static const char* const fs_shadow_blur = "//" FILELINE "\n"
|
||||
"uniform sampler2D textureSource;\n"
|
||||
"uniform vec2 ScaleU;\n"
|
||||
|
||||
"in vec2 Texcoord;\n"
|
||||
"out vec4 outColor;\n"
|
||||
|
||||
"void main() {\n"
|
||||
" vec4 color = vec4(0.0);\n"
|
||||
" color += texture( textureSource, Texcoord.st + vec2( -3.0*ScaleU.x, -3.0*ScaleU.y ) ) * 0.015625;\n"
|
||||
" color += texture( textureSource, Texcoord.st + vec2( -2.0*ScaleU.x, -2.0*ScaleU.y ) )*0.09375;\n"
|
||||
" color += texture( textureSource, Texcoord.st + vec2( -1.0*ScaleU.x, -1.0*ScaleU.y ) )*0.234375;\n"
|
||||
" color += texture( textureSource, Texcoord.st + vec2( 0.0 , 0.0) )*0.3125;\n"
|
||||
" color += texture( textureSource, Texcoord.st + vec2( 1.0*ScaleU.x, 1.0*ScaleU.y ) )*0.234375;\n"
|
||||
" color += texture( textureSource, Texcoord.st + vec2( 2.0*ScaleU.x, 2.0*ScaleU.y ) )*0.09375;\n"
|
||||
" color += texture( textureSource, Texcoord.st + vec2( 3.0*ScaleU.x, -3.0*ScaleU.y ) ) * 0.015625;\n"
|
||||
" outColor = vec4(color.xyz, 1.0);\n"
|
||||
"}\n";
|
||||
|
||||
|
||||
|
||||
static const char* const vs_shadow_vsm = "//" FILELINE "\n"
|
||||
"uniform mat4 model;\n"
|
||||
"uniform mat4 cameraToShadowView;\n"
|
||||
"uniform mat4 cameraToShadowProjector;\n"
|
||||
|
||||
"in vec3 position;\n"
|
||||
"out vec4 v_position;\n"
|
||||
|
||||
"void main() {\n"
|
||||
" gl_Position = cameraToShadowProjector * model * vec4(position, 1.0);\n"
|
||||
#if VSMCUBE
|
||||
" v_position = cameraToShadowView * model * vec4(position, 1.0);\n"
|
||||
#else
|
||||
" v_position = gl_Position;\n"
|
||||
#endif
|
||||
"}\n";
|
||||
|
||||
static const char* const fs_shadow_vsm = "//" FILELINE "\n"
|
||||
"in vec4 v_position;\n"
|
||||
"out vec4 outColor;\n"
|
||||
|
||||
"void main() {\n"
|
||||
#if VSMCUBE
|
||||
" float depth = length( vec3(v_position) ) / 20;\n"
|
||||
#else
|
||||
" float depth = v_position.z / v_position.w;\n"
|
||||
" depth = depth * 0.5 + 0.5;\n"
|
||||
#endif
|
||||
|
||||
" float moment1 = depth;\n"
|
||||
" float moment2 = depth * depth;\n"
|
||||
|
||||
" float dx = dFdx(depth);\n"
|
||||
" float dy = dFdy(depth);\n"
|
||||
" moment2 += 0.25*(dx*dx+dy*dy);\n"
|
||||
" outColor = vec4( moment1, moment2, 0.0, 0.0);\n"
|
||||
"}\n";
|
||||
|
||||
|
||||
struct shadow {
|
||||
// Resources
|
||||
GLuint shadowProgram, blurProgram;
|
||||
Mesh quadMesh;
|
||||
GLuint shadowMapFBO, shadowMapTex, shadowMapTexDepth;
|
||||
GLuint blurFBO, blurTex;
|
||||
// Options
|
||||
bool do_blur;
|
||||
bool do_debugshadow;
|
||||
float BLUR_SCALE; // Amount of blurring [0..100]
|
||||
GLuint SHADOWMAP_WIDTH; // 256,512,1024,2048
|
||||
// State
|
||||
int shadow_active;
|
||||
vec3 lightPos;
|
||||
vec3 lightAimPos;
|
||||
|
||||
// VSM cubemap
|
||||
GLuint cubeTex, cubeDepthTex, cubeFBOs[6];
|
||||
GLuint currentSideTex, currentSideDepthTex;
|
||||
GLuint toCurrentSideFBO;
|
||||
} shadow;
|
||||
|
||||
#define shadowProgram shadow.shadowProgram
|
||||
#define blurProgram shadow.blurProgram
|
||||
#define quadMesh shadow.quadMesh
|
||||
#define shadowMapFBO shadow.shadowMapFBO
|
||||
#define shadowMapTex shadow.shadowMapTex
|
||||
#define shadowMapTexDepth shadow.shadowMapTexDepth
|
||||
#define blurFBO shadow.blurFBO
|
||||
#define blurTex shadow.blurTex
|
||||
#define do_blur shadow.do_blur
|
||||
#define do_debugshadow shadow.do_debugshadow
|
||||
#define BLUR_SCALE shadow.BLUR_SCALE
|
||||
#define SHADOWMAP_WIDTH shadow.SHADOWMAP_WIDTH
|
||||
#define shadow_active shadow.shadow_active
|
||||
#define lightPos shadow.lightPos
|
||||
#define lightAimPos shadow.lightAimPos
|
||||
// vsm cubemap
|
||||
#define cubeTex shadow.cubeTex
|
||||
#define cubeDepthTex shadow.cubeDepthTex
|
||||
#define cubeFBOs shadow.cubeFBOs
|
||||
#define currentSideTex shadow.currentSideTex
|
||||
#define currentSideDepthTex shadow.currentSideDepthTex
|
||||
#define toCurrentSideFBO shadow.toCurrentSideFBO
|
||||
|
||||
|
||||
|
||||
static GLuint cubemap_create(GLsizei size, int flags) {
|
||||
GLenum texel = flags & TEXTURE_DEPTH ? GL_DEPTH_COMPONENT : GL_RGB32F;
|
||||
GLenum pixel = flags & TEXTURE_DEPTH ? GL_DEPTH_COMPONENT : GL_RGB;
|
||||
GLenum storage = flags & TEXTURE_DEPTH ? GL_FLOAT : GL_UNSIGNED_BYTE; // swap?
|
||||
GLuint id;
|
||||
glGenTextures(1, &id);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, id);
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, texel, size, size, 0, pixel, storage, NULL);
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, texel, size, size, 0, pixel, storage, NULL);
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, texel, size, size, 0, pixel, storage, NULL);
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, texel, size, size, 0, pixel, storage, NULL);
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, texel, size, size, 0, pixel, storage, NULL);
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, texel, size, size, 0, pixel, storage, NULL);
|
||||
if( flags & TEXTURE_DEPTH ) {
|
||||
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);
|
||||
} else {
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0);
|
||||
}
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
return id;
|
||||
}
|
||||
static void framebuffer_cube_create(GLuint cube_fbo[6], GLuint cube_texture, GLuint cube_texture_depth) {
|
||||
glGenFramebuffers(6, cube_fbo);
|
||||
for (int i = 0; i < 6; i++) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, cube_fbo[i]);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, cube_texture, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, cube_texture_depth, 0);
|
||||
GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (GL_FRAMEBUFFER_COMPLETE != result) {
|
||||
printf("ERROR: Framebuffer is not complete.\n");
|
||||
}
|
||||
}
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
static void set_shadow_matrix_uniform(const GLuint program, int dir) {
|
||||
if(dir<0) return;
|
||||
mat44 P, V, PV;
|
||||
perspective44(P, 90.0f, 1.0f, 0.5f, 100.0f);
|
||||
|
||||
/**/ if(dir == 0) lookat44(V, lightPos, add3(lightPos, vec3(+1, 0, 0)), vec3(0, -1, 0)); // +X
|
||||
else if(dir == 1) lookat44(V, lightPos, add3(lightPos, vec3(-1, 0, 0)), vec3(0, -1, 0)); // -X
|
||||
else if(dir == 2) lookat44(V, lightPos, add3(lightPos, vec3( 0, +1, 0)), vec3(0, 0, +1)); // +Y
|
||||
else if(dir == 3) lookat44(V, lightPos, add3(lightPos, vec3( 0, -1, 0)), vec3(0, 0, -1)); // -Y
|
||||
else if(dir == 4) lookat44(V, lightPos, add3(lightPos, vec3( 0, 0, +1)), vec3(0, -1, 0)); // +Z
|
||||
else /*dir == 5*/ lookat44(V, lightPos, add3(lightPos, vec3( 0, 0, -1)), vec3(0, -1, 0)); // -Z
|
||||
multiply44x2(PV, P, V); // -Z
|
||||
|
||||
shader_bind(program); shader_mat44("cameraToShadowView", V);
|
||||
shader_bind(program); shader_mat44("cameraToShadowProjector", PV);
|
||||
}
|
||||
|
||||
void shadow_create(int RESOLUTION) {
|
||||
do_blur = 1;
|
||||
do_debugshadow = 0;
|
||||
BLUR_SCALE = 0.5; // Amount of blurring [0..1]
|
||||
SHADOWMAP_WIDTH = RESOLUTION; // 256,512,1024,2048
|
||||
lightPos = vec3(-2, 2.0, -2);
|
||||
lightAimPos = vec3(0.0, 0, -5.0);
|
||||
|
||||
// Create programs
|
||||
shadowProgram = shader(vs_shadow_vsm, fs_shadow_vsm, "position", "outColor", 0);
|
||||
blurProgram = shader(vs_shadow_blur, fs_shadow_blur, "position,,texcoord", "outColor", 0);
|
||||
|
||||
// ShadowMap-textures and FBO // @todo: GL_RG32F+GL_RG also GL_CLAMP to remove artifacts
|
||||
shadowMapTex = texture_create(SHADOWMAP_WIDTH, SHADOWMAP_WIDTH, 2, NULL, TEXTURE_FLOAT).id;
|
||||
shadowMapTexDepth = texture_create(SHADOWMAP_WIDTH, SHADOWMAP_WIDTH, 0, NULL, TEXTURE_DEPTH | TEXTURE_FLOAT).id;
|
||||
shadowMapFBO = fbo(shadowMapTex, shadowMapTexDepth, 0);
|
||||
|
||||
// Textures and FBO to perform blurring
|
||||
blurTex = texture_create(SHADOWMAP_WIDTH, SHADOWMAP_WIDTH, 2, NULL, TEXTURE_FLOAT).id;
|
||||
blurFBO = fbo(blurTex, 0, 0);
|
||||
|
||||
#if VSMCUBE
|
||||
// Create cubemap
|
||||
cubeTex = cubemap_create(SHADOWMAP_WIDTH, 0);
|
||||
cubeDepthTex = cubemap_create(SHADOWMAP_WIDTH, TEXTURE_DEPTH);
|
||||
framebuffer_cube_create(cubeFBOs, cubeTex, cubeDepthTex);
|
||||
// Temporary storage
|
||||
currentSideTex = texture_create(SHADOWMAP_WIDTH, SHADOWMAP_WIDTH, 2, NULL, TEXTURE_FLOAT /*| TEXTURE_EDGE*/ ).id;
|
||||
currentSideDepthTex = texture_create(SHADOWMAP_WIDTH, SHADOWMAP_WIDTH, 0, NULL, TEXTURE_DEPTH | TEXTURE_FLOAT).id;
|
||||
toCurrentSideFBO = fbo(currentSideTex, currentSideDepthTex, 0);
|
||||
#endif
|
||||
}
|
||||
void shadow_destroy() {
|
||||
glDeleteProgram(shadowProgram);
|
||||
glDeleteProgram(blurProgram);
|
||||
|
||||
glDeleteTextures(1, &blurTex);
|
||||
glDeleteFramebuffers(1, &blurFBO);
|
||||
|
||||
glDeleteTextures(1, &shadowMapTex);
|
||||
glDeleteTextures(1, &shadowMapTexDepth);
|
||||
glDeleteFramebuffers(1, &shadowMapFBO);
|
||||
}
|
||||
bool shadow_is_active() {
|
||||
return shadow_active;
|
||||
}
|
||||
void shadow_pv_matrix(mat44 PV) {
|
||||
mat44 P,V;
|
||||
// perspective44(P, 45.0f, 1.0f, 2.0f, 100.0f);
|
||||
perspective44(P, 45*2, window_width() / ((float)window_height()+!window_height()), 1.f, 100.f);
|
||||
|
||||
lookat44(V, lightPos, lightAimPos, vec3(0, 1, 0)); // Point toward object regardless of position
|
||||
multiply44x2(PV, P, V);
|
||||
}
|
||||
void shadow_position(vec3 p) {
|
||||
lightPos = p;
|
||||
}
|
||||
void shadow_target(vec3 p) {
|
||||
lightAimPos = p;
|
||||
}
|
||||
void shadow_begin() {
|
||||
shadow_active = 1;
|
||||
|
||||
// shadow_state() {
|
||||
glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS);
|
||||
glEnable(GL_CULL_FACE); glCullFace(GL_BACK);
|
||||
glFrontFace(GL_CW);
|
||||
glBlendFunc(1, 0);
|
||||
#if VSMCUBE
|
||||
glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
|
||||
#endif
|
||||
// }
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, shadowMapFBO);
|
||||
|
||||
glViewport(0, 0, SHADOWMAP_WIDTH, SHADOWMAP_WIDTH);
|
||||
//glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
mat44 PV; shadow_pv_matrix(PV);
|
||||
shader_bind(shadowProgram);shader_mat44("cameraToShadowProjector", PV);
|
||||
}
|
||||
static void draw_fullscreen_quad() {
|
||||
//delete_mesh(quadMesh);
|
||||
if(!quadMesh.vao) quadMesh = create_quad();
|
||||
|
||||
glBindVertexArray(quadMesh.vao);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
static void shadow_blur() {
|
||||
// remap 0(min)..1(max) -> 2(min)..epsilon(max)
|
||||
float blur_scale = 1.999 * (1 - BLUR_SCALE) + 0.001;
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
// Blur shadowMapTex (horizontally) to blurTex
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, blurFBO);
|
||||
glViewport(0, 0, SHADOWMAP_WIDTH, SHADOWMAP_WIDTH);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, shadowMapTex); //Input-texture
|
||||
shader_bind(blurProgram); shader_vec2("ScaleU", vec2(1.0 / (SHADOWMAP_WIDTH*blur_scale), 0));
|
||||
shader_int("textureSource",0);
|
||||
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
draw_fullscreen_quad();
|
||||
|
||||
// Blur blurTex vertically and write to shadowMapTex
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, shadowMapFBO);
|
||||
glViewport(0, 0, SHADOWMAP_WIDTH, SHADOWMAP_WIDTH);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, blurTex);
|
||||
shader_bind(blurProgram); shader_vec2("ScaleU", vec2(0, 1.0 / (SHADOWMAP_WIDTH*blur_scale)));
|
||||
shader_int("textureSource",0);
|
||||
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
draw_fullscreen_quad();
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
}
|
||||
void shadow_end() {
|
||||
// Reset
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
if(do_blur) shadow_blur();
|
||||
shadow_active = 0;
|
||||
|
||||
glViewport(0, 0, window_width(), window_height());
|
||||
}
|
||||
void shadow_ui() {
|
||||
// UI
|
||||
if( ui_panel("Shadow", 0) ) {
|
||||
if(ui_toggle("Debug", &do_debugshadow)) {}
|
||||
if(ui_toggle("Blur shadow", &do_blur)) {}
|
||||
if(ui_slider("Blur amount", &BLUR_SCALE)) {}
|
||||
ui_panel_end();
|
||||
}
|
||||
|
||||
if(do_debugshadow) {
|
||||
// Blur and draw to screen
|
||||
shader_bind(blurProgram); shader_vec2("ScaleU", vec2(0, 0)); // ... but make sure we don't actually blur
|
||||
glBindTexture(GL_TEXTURE_2D, shadowMapTex);
|
||||
draw_fullscreen_quad();
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#define USER_DRAWCALL(shader) do { \
|
||||
model_render(sponza, camera_get_active()->proj, camera_get_active()->view, sponza.pivot, shader); \
|
||||
} while(0)
|
||||
|
||||
|
||||
static void vsm_cube_draw()
|
||||
{
|
||||
glViewport(0, 0, SHADOWMAP_WIDTH, SHADOWMAP_WIDTH);
|
||||
|
||||
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
shader_bind(shadowProgram);
|
||||
|
||||
// For each side of cubemap
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
#if VSMBLUR
|
||||
// Draw to temp. storage
|
||||
shader_bind(shadowProgram);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, toCurrentSideFBO);
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
set_shadow_matrix_uniform(shadowProgram, i);
|
||||
USER_DRAWCALL(shadowProgram);
|
||||
|
||||
// Blur horizontally to blurTex
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
shader_bind(blurProgram);
|
||||
shader_vec2("ScaleU", vec2(1.0 / SHADOWMAP_WIDTH, 0));
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, blurFBO);
|
||||
glBindTexture(GL_TEXTURE_2D, currentSideTex);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
draw_fullscreen_quad();
|
||||
|
||||
// Blur vertically to actual cubemap
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, cubeFBOs[i]);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, blurTex);
|
||||
shader_bind(blurProgram);
|
||||
shader_vec2("ScaleU", vec2(0, 1.0 / SHADOWMAP_WIDTH));
|
||||
|
||||
draw_fullscreen_quad();
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
#else
|
||||
// Draw directly to cubemap
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, cubeFBOs[i]);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
set_shadow_matrix_uniform(shadowProgram, i);
|
||||
USER_DRAWCALL(shadowProgram);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Reset state
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
#undef shadowProgram
|
||||
#undef blurProgram
|
||||
#undef quadMesh
|
||||
#undef shadowMapFBO
|
||||
#undef shadowMapTex
|
||||
#undef shadowMapTexDepth
|
||||
#undef blurFBO
|
||||
#undef blurTex
|
||||
#undef do_blur
|
||||
#undef do_debugshadow
|
||||
#undef BLUR_SCALE
|
||||
#undef SHADOWMAP_WIDTH
|
||||
#undef shadow_active
|
||||
#undef lightPos
|
||||
#undef lightAimPos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Geometry (world coordinates)
|
||||
static bool do_animate = 1;
|
||||
|
||||
static void color_begin(const GLuint program) {
|
||||
glCullFace(GL_BACK);
|
||||
|
||||
#if 1 // VSMCUBE
|
||||
glViewport(0, 0, window_width(), window_height());
|
||||
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
#endif
|
||||
|
||||
// Upload uniforms
|
||||
shader_bind(program);
|
||||
shader_mat44("view", camera_get_active()->view);
|
||||
// shader_mat44("proj", camera_get_active()->proj);
|
||||
shader_vec3("lightPos", shadow.lightPos);
|
||||
|
||||
#if VSMCUBE
|
||||
set_shadow_matrix_uniform(program, -1);
|
||||
#else
|
||||
mat44 PV; shadow_pv_matrix(PV);
|
||||
shader_mat44("cameraToShadowProjector", PV);
|
||||
#endif
|
||||
|
||||
glActiveTexture(GL_TEXTURE0+1);
|
||||
#if VSMCUBE
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, cubeTex);
|
||||
#else
|
||||
glBindTexture(GL_TEXTURE_2D, shadow.shadowMapTex); //Input-texture
|
||||
#endif
|
||||
shader_int("shadowMap",1);
|
||||
}
|
||||
static void color_end() {
|
||||
#if VSMCUBE
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
|
||||
#else
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
window_create(0.75f, 0);
|
||||
|
||||
camera_t cam = camera();
|
||||
|
||||
// init shadowing 384x384 // 512x512
|
||||
shadow_create(argc > 1 ? atoi(argv[1]) : 384);
|
||||
|
||||
sponza = model("sponza.obj", 0);
|
||||
translation44(sponza.pivot, 0,-1,0);
|
||||
rotate44(sponza.pivot, -90,1,0,0);
|
||||
scale44(sponza.pivot, 10,10,10);
|
||||
|
||||
model_t suzanne = model("suzanne.obj", 0);
|
||||
|
||||
// create geometry
|
||||
GLuint vsm_program = sponza.iqm->program;
|
||||
#if 1
|
||||
const char *tpl[] = {
|
||||
"{{include-shadowmap}}", fs_0_0_shadowmap_lit,
|
||||
};
|
||||
vsm_program = shader(strlerp(1,tpl,vs_323444143_16_332_model), strlerp(1,tpl,fs_32_4_model), "att_position,att_texcoord,att_normal", "fragColor");
|
||||
#endif
|
||||
|
||||
while (window_swap())
|
||||
{
|
||||
// input
|
||||
if (input(KEY_ESC))
|
||||
break;
|
||||
|
||||
// fps camera
|
||||
bool active = ui_active() ? 0 : input(MOUSE_L) || input(MOUSE_M) || input(MOUSE_R);
|
||||
vec3 wasdec = scale3( vec3(input(KEY_D)-input(KEY_A),input(KEY_E)-input(KEY_C),input(KEY_W)-input(KEY_S)), 0.2f);
|
||||
vec2 mouse = scale2( vec2(input_diff(MOUSE_X), -input_diff(MOUSE_Y)), 0.2f * active);
|
||||
camera_move(&cam, wasdec.x,wasdec.y,wasdec.z);
|
||||
camera_fps(&cam, mouse.x,mouse.y);
|
||||
window_cursor( !active );
|
||||
|
||||
#if 1
|
||||
// animate light
|
||||
if( do_animate ) {
|
||||
static vec3 lightPos;
|
||||
do_once {
|
||||
lightPos = cam.position;
|
||||
};
|
||||
vec3 offs = vec3(sin(window_time()) * 15, 0, cos(window_time()) * 15);
|
||||
shadow_position(add3(lightPos, offs));
|
||||
// shadow_target(vec3(0,0,0)); // good for pointlight
|
||||
shadow_target(add3(add3(lightPos, offs), vec3(0,0,-1)));
|
||||
}
|
||||
#else
|
||||
shadow_position(cam.position);
|
||||
shadow_target(add3(cam.position, cam.look));
|
||||
#endif
|
||||
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
// render
|
||||
|
||||
#if VSMCUBE
|
||||
shadow_begin();
|
||||
vsm_cube_draw();
|
||||
shadow_end();
|
||||
#else
|
||||
shadow_begin();
|
||||
model_render(sponza, camera_get_active()->proj, camera_get_active()->view, sponza.pivot, shadow.shadowProgram); //< typo!, but works!
|
||||
shadow_end();
|
||||
#endif
|
||||
|
||||
color_begin(vsm_program);
|
||||
model_render(sponza, camera_get_active()->proj, camera_get_active()->view, sponza.pivot, vsm_program); // does not work without program
|
||||
color_end();
|
||||
|
||||
|
||||
// light bulb (suzanne)
|
||||
{
|
||||
mat44 M; scaling44(M, 10,10,10); relocate44(M, shadow.lightPos.x, shadow.lightPos.y, shadow.lightPos.z );
|
||||
model_render(suzanne, camera_get_active()->proj, camera_get_active()->view, M, 0);
|
||||
}
|
||||
|
||||
|
||||
if( ui_panel("App", 0) ) {
|
||||
if(ui_toggle("Animate light", &do_animate)) {}
|
||||
ui_panel_end();
|
||||
}
|
||||
|
||||
shadow_ui();
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
uniform int u_num_lights;
|
||||
|
||||
#define NUM_SHADOW_CASCADES 4
|
||||
#define NUM_SHADOW_CASCADES 6
|
||||
|
||||
struct light_t {
|
||||
int type;
|
||||
|
|
|
@ -1,118 +0,0 @@
|
|||
// WIP
|
||||
#ifndef SHADOWMAP_GLSL
|
||||
#define SHADOWMAP_GLSL
|
||||
|
||||
// uniform mat4 view = mat4(1.0);
|
||||
uniform vec3 lightPos; /// set:1,1,1
|
||||
uniform float doTexture; /// set:1
|
||||
#ifdef VSMCUBE
|
||||
uniform samplerCube shadowMap; // VSMCUBE
|
||||
#else
|
||||
uniform sampler2D shadowMap; // !VSMCUBE
|
||||
#endif
|
||||
|
||||
|
||||
struct light {
|
||||
vec3 position; // world-space
|
||||
vec4 diffuse;
|
||||
vec4 specular;
|
||||
float constantAttenuation, linearAttenuation, quadraticAttenuation;
|
||||
};
|
||||
|
||||
light light0 = light(
|
||||
vec3(1,1,1), // lightPos
|
||||
vec4(1,1,1,1), // diffuse
|
||||
vec4(1,1,1,1), // specular
|
||||
1.0, 0.0, 0.0 // attenuation (const, linear, quad)
|
||||
);
|
||||
|
||||
// From http://fabiensanglard.net/shadowmappingVSM/index.php
|
||||
#ifdef VSMCUBE
|
||||
float chebyshevUpperBound(float distance, vec3 dir) {
|
||||
distance = distance/20 ;
|
||||
vec2 moments = texture(shadowMap, dir).rg;
|
||||
#else
|
||||
float chebyshevUpperBound(float distance, vec4 scPostW) {
|
||||
vec2 moments = texture(shadowMap,scPostW.xy).rg;
|
||||
#endif
|
||||
// Surface is fully lit. as the current fragment is before the light occluder
|
||||
if (distance <= moments.x)
|
||||
return 1.0;
|
||||
|
||||
// The fragment is either in shadow or penumbra. We now use chebyshev's upperBound to check
|
||||
// How likely this pixel is to be lit (p_max)
|
||||
float variance = moments.y - (moments.x*moments.x);
|
||||
//variance = max(variance, 0.000002);
|
||||
variance = max(variance, 0.00002);
|
||||
|
||||
float d = distance - moments.x;
|
||||
float p_max = variance / (variance + d*d);
|
||||
|
||||
return p_max;
|
||||
}
|
||||
|
||||
|
||||
vec4 shadowmap(in vec4 vpeye, in vec4 vneye, in vec2 uv, in vec4 sc) {
|
||||
#ifndef VSMCUBE
|
||||
return vec4(1.);
|
||||
#else
|
||||
vec3 fragment = vec3(vpeye);
|
||||
vec3 normal = vec3(normalize(vneye));
|
||||
vec3 viewDir = normalize(-fragment);
|
||||
|
||||
// Lighting
|
||||
// Convert to eye-space
|
||||
vec3 light = vec3(view * vec4(light0.position, 1.0));
|
||||
|
||||
#ifdef VSMCUBE
|
||||
// Vectors
|
||||
vec3 fragmentToLight = light - fragment;
|
||||
vec3 fragmentToLightDir = normalize(fragmentToLight);
|
||||
|
||||
// Shadows
|
||||
vec4 fragmentToLight_world = inverse(view) * vec4(fragmentToLightDir, 0.0);
|
||||
float shadowFactor = chebyshevUpperBound(length(fragmentToLight), -fragmentToLight_world.xyz);
|
||||
#else
|
||||
// Shadows
|
||||
vec4 scPostW = sc / sc.w;
|
||||
scPostW = scPostW * 0.5 + 0.5;
|
||||
|
||||
float shadowFactor = 1.0; // Not in shadow
|
||||
|
||||
bool outsideShadowMap = sc.w <= 0.0f || (scPostW.x < 0 || scPostW.y < 0) || (scPostW.x >= 1 || scPostW.y >= 1);
|
||||
if (!outsideShadowMap) {
|
||||
shadowFactor = chebyshevUpperBound(scPostW.z, scPostW);
|
||||
}
|
||||
#endif
|
||||
|
||||
vec4 diffColor = vec4(1,1,1,1);
|
||||
#ifdef VSMCUBE
|
||||
if(doTexture != 0) diffColor = vec4(vec3(texture(shadowMap, -fragmentToLight_world.xyz).r), 1.0);
|
||||
#else
|
||||
if(doTexture != 0) diffColor = vec4(vec3(texture(shadowMap, vec2(uv.x, 1.0 - uv.y)).r), 1.0);
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
vec3 positionToLight = light - fragment;
|
||||
vec3 lightDir = normalize(positionToLight);
|
||||
|
||||
// Angle between fragment-normal and incoming light
|
||||
float cosAngIncidence = dot(lightDir, normal);
|
||||
cosAngIncidence = clamp(cosAngIncidence, 0, 1);
|
||||
|
||||
float attenuation = 1.0f;
|
||||
attenuation = 1.0 / (light0.constantAttenuation + light0.linearAttenuation * length(positionToLight) + light0.quadraticAttenuation * pow(length(positionToLight),2));
|
||||
|
||||
vec4 diffuse = diffColor * light0.diffuse * cosAngIncidence * attenuation;
|
||||
|
||||
vec4 total_lighting;
|
||||
total_lighting += vec4(0.1, 0.1, 0.1, 1.0) * diffColor; // Ambient
|
||||
total_lighting += diffuse * shadowFactor; // Diffuse
|
||||
#else
|
||||
vec4 total_lighting = diffColor;
|
||||
#endif
|
||||
return vec4(clamp(vec3(total_lighting), 0., 1.), 1.0);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,3 +1,5 @@
|
|||
#include "utils.glsl"
|
||||
|
||||
in vec4 vpeye;
|
||||
in vec4 vneye;
|
||||
uniform bool u_shadow_receiver;
|
||||
|
@ -6,6 +8,8 @@ uniform float u_cascade_distances[NUM_SHADOW_CASCADES];
|
|||
uniform samplerCube shadowMap[MAX_LIGHTS];
|
||||
uniform sampler2D shadowMap2D[MAX_LIGHTS * NUM_SHADOW_CASCADES];
|
||||
|
||||
const float bias_modifier[NUM_SHADOW_CASCADES] = float[NUM_SHADOW_CASCADES](0.95, 0.35, 0.20, 0.15, 0.15, 0.15);
|
||||
|
||||
//// From http://fabiensanglard.net/shadowmappingVSM/index.php
|
||||
float shadow_vsm(float distance, vec3 dir, int light_index) {
|
||||
distance = distance/20;
|
||||
|
@ -59,26 +63,33 @@ float shadow_pcf(float distance, vec3 lightDir, int light_index) {
|
|||
// Calculate bias
|
||||
vec3 normal = normalize(vneye.xyz);
|
||||
float bias = max(0.05 * (1.0 - dot(normal, lightDir)), 0.005);
|
||||
const float bias_modifier = 0.45;
|
||||
if (cascade_index == NUM_SHADOW_CASCADES-1) {
|
||||
bias *= 1 / (u_cascade_distances[NUM_SHADOW_CASCADES-1] * bias_modifier);
|
||||
} else {
|
||||
bias *= 1 / (u_cascade_distances[cascade_index] * bias_modifier);
|
||||
}
|
||||
|
||||
bias *= 1 / (u_cascade_distances[cascade_index] * bias_modifier[cascade_index]);
|
||||
|
||||
// PCF
|
||||
float shadow = 0.0;
|
||||
vec2 texelSize = 1.0 / textureSize(shadowMap2D[index], 0);
|
||||
|
||||
#if 1
|
||||
for(int x = -3; x <= 3; ++x)
|
||||
{
|
||||
for(int y = -3; y <= 3; ++y)
|
||||
{
|
||||
float pcfDepth = texture(shadowMap2D[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 /= 36.0;
|
||||
#else
|
||||
for(int x = -1; x <= 1; ++x)
|
||||
{
|
||||
for(int y = -1; y <= 1; ++y)
|
||||
{
|
||||
float pcfDepth = texture(shadowMap2D[index], projCoords.xy + vec2(x, y) * texelSize).r;
|
||||
shadow += currentDepth - bias > pcfDepth ? 1.0 : 0.0;
|
||||
}
|
||||
}
|
||||
shadow /= 36.0;
|
||||
|
||||
shadow /= 9.0;
|
||||
#endif
|
||||
return 1.0 - shadow;
|
||||
}
|
||||
|
||||
|
|
|
@ -17267,7 +17267,7 @@ enum SHADOW_TECHNIQUE {
|
|||
SHADOW_PCF,
|
||||
};
|
||||
|
||||
#define NUM_SHADOW_CASCADES 4
|
||||
#define NUM_SHADOW_CASCADES 6
|
||||
|
||||
typedef struct light_t {
|
||||
char type;
|
||||
|
@ -17351,7 +17351,7 @@ API void shadowmap_destroy(shadowmap_t *s);
|
|||
|
||||
API void shadowmap_begin(shadowmap_t *s);
|
||||
API bool shadowmap_step(shadowmap_t *s);
|
||||
API void shadowmap_light(shadowmap_t *s, light_t *l, float cam_fov, float cam_far, mat44 cam_view); //< can be called once per shadowmap_step
|
||||
API void shadowmap_light(shadowmap_t *s, light_t *l, mat44 cam_proj, mat44 cam_view); //< can be called once per shadowmap_step
|
||||
API void shadowmap_end(shadowmap_t *s);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -17971,6 +17971,7 @@ typedef struct camera_t {
|
|||
vec3 position, updir, lookdir;
|
||||
float yaw, pitch, roll; // mirror of (x,y) lookdir in deg;
|
||||
float speed, fov; // fov in deg(45)
|
||||
float near_clip, far_clip;
|
||||
|
||||
float move_friction, move_damping;
|
||||
float look_friction, look_damping;
|
||||
|
@ -383431,12 +383432,14 @@ shadowmap_t shadowmap(int vsm_texture_width, int pcf_texture_width) { // = 512,
|
|||
s.vsm_texture_width = vsm_texture_width;
|
||||
s.pcf_texture_width = pcf_texture_width;
|
||||
s.saved_fb = 0;
|
||||
s.blur_pcf = true;
|
||||
s.blur_pcf = false;
|
||||
s.blur_scale = 0.5f;
|
||||
s.cascade_splits[0] = 0.1f;
|
||||
s.cascade_splits[1] = 0.3f;
|
||||
s.cascade_splits[2] = 0.5f;
|
||||
s.cascade_splits[3] = 1.0f;
|
||||
s.cascade_splits[3] = 0.7f;
|
||||
s.cascade_splits[5] = 1.0f;
|
||||
s.cascade_splits[6] = 1.0f; /* sticks to camera far plane */
|
||||
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &s.saved_fb);
|
||||
|
||||
|
@ -383614,10 +383617,21 @@ static void shadowmap_light_directional(shadowmap_t *s, light_t *l, int dir, flo
|
|||
maxZ = max(maxZ, corner.z);
|
||||
}
|
||||
|
||||
#if 0
|
||||
float tmpZ = -minZ;
|
||||
minZ = -maxZ;
|
||||
maxZ = tmpZ;
|
||||
|
||||
float mid = (maxZ + minZ) * 0.5f;
|
||||
minZ -= mid * 5.0f;
|
||||
maxZ += mid * 5.0f;
|
||||
#endif
|
||||
|
||||
mat44 P, PV;
|
||||
ortho44(P,
|
||||
minX, maxX,
|
||||
minY, maxY,
|
||||
// minZ, maxZ);
|
||||
-maxZ, -minZ);
|
||||
|
||||
multiply44x2(PV, P, V);
|
||||
|
@ -383738,10 +383752,20 @@ void shadowmap_clear_fbo() {
|
|||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
void shadowmap_light(shadowmap_t *s, light_t *l, float cam_fov, float cam_far, mat44 cam_view) {
|
||||
void shadowmap_light(shadowmap_t *s, light_t *l, mat44 cam_proj, mat44 cam_view) {
|
||||
if (l->cast_shadows) {
|
||||
int step = s->step - 1;
|
||||
|
||||
float y_scale = cam_proj[5];
|
||||
float cam_fov = (2.0f * atan(1.0f / y_scale)) * TO_DEG;
|
||||
float cam_far = 0.0f; {
|
||||
float m22 = cam_proj[10];
|
||||
float m32 = cam_proj[14];
|
||||
float near_plane = -m32 / (m22 + 1.0f);
|
||||
cam_far = (2.0f * near_plane) / (m22 - 1.0f);
|
||||
cam_far *= 0.5f;
|
||||
}
|
||||
|
||||
if (l->type == LIGHT_POINT) {
|
||||
shadowmap_light_point(s, l, step);
|
||||
} else if (l->type == LIGHT_SPOT) {
|
||||
|
@ -386588,12 +386612,10 @@ void model_set_renderstates(model_t *m) {
|
|||
// Shadow pass
|
||||
renderstate_t *pcf_shadow_rs = &m->rs[RENDER_PASS_SHADOW_PCF];
|
||||
{
|
||||
pcf_shadow_rs->blend_enabled = 1;
|
||||
pcf_shadow_rs->blend_src = GL_SRC_ALPHA;
|
||||
pcf_shadow_rs->blend_dst = GL_ONE_MINUS_SRC_ALPHA;
|
||||
pcf_shadow_rs->blend_enabled = 0;
|
||||
pcf_shadow_rs->cull_face_enabled = 1;
|
||||
pcf_shadow_rs->cull_face_mode = GL_FRONT;
|
||||
pcf_shadow_rs->front_face = GL_CCW;
|
||||
pcf_shadow_rs->cull_face_mode = GL_BACK;
|
||||
pcf_shadow_rs->front_face = GL_CW;
|
||||
pcf_shadow_rs->depth_clamp_enabled = 1;
|
||||
}
|
||||
|
||||
|
@ -388714,6 +388736,8 @@ camera_t camera() {
|
|||
cam.fov = 45;
|
||||
cam.orthographic = false;
|
||||
cam.distance = 3; // len3(cam.position);
|
||||
cam.near_clip = 0.1f;
|
||||
cam.far_clip = 1000.f;
|
||||
|
||||
cam.damping = false;
|
||||
cam.move_friction = 0.09f;
|
||||
|
@ -388810,12 +388834,12 @@ void camera_fov(camera_t *cam, float fov) {
|
|||
cam->fov = fov;
|
||||
|
||||
if( cam->orthographic ) {
|
||||
ortho44(cam->proj, -cam->fov * aspect, cam->fov * aspect, -cam->fov, cam->fov, 0.01f, 2000);
|
||||
ortho44(cam->proj, -cam->fov * aspect, cam->fov * aspect, -cam->fov, cam->fov, cam->near_clip, cam->far_clip);
|
||||
// [ref] https://commons.wikimedia.org/wiki/File:Isometric_dimetric_camera_views.png
|
||||
// float pitch = cam->dimetric ? 30.000f : 35.264f; // dimetric or isometric
|
||||
// cam->pitch = -pitch; // quickly reorient towards origin
|
||||
} else {
|
||||
perspective44(cam->proj, cam->fov, aspect, 0.01f, 2000.f);
|
||||
perspective44(cam->proj, cam->fov, aspect, cam->near_clip, cam->far_clip);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1696,12 +1696,14 @@ shadowmap_t shadowmap(int vsm_texture_width, int pcf_texture_width) { // = 512,
|
|||
s.vsm_texture_width = vsm_texture_width;
|
||||
s.pcf_texture_width = pcf_texture_width;
|
||||
s.saved_fb = 0;
|
||||
s.blur_pcf = true;
|
||||
s.blur_pcf = false;
|
||||
s.blur_scale = 0.5f;
|
||||
s.cascade_splits[0] = 0.1f;
|
||||
s.cascade_splits[1] = 0.3f;
|
||||
s.cascade_splits[2] = 0.5f;
|
||||
s.cascade_splits[3] = 1.0f;
|
||||
s.cascade_splits[3] = 0.7f;
|
||||
s.cascade_splits[5] = 1.0f;
|
||||
s.cascade_splits[6] = 1.0f; /* sticks to camera far plane */
|
||||
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &s.saved_fb);
|
||||
|
||||
|
@ -1879,10 +1881,21 @@ static void shadowmap_light_directional(shadowmap_t *s, light_t *l, int dir, flo
|
|||
maxZ = max(maxZ, corner.z);
|
||||
}
|
||||
|
||||
#if 0
|
||||
float tmpZ = -minZ;
|
||||
minZ = -maxZ;
|
||||
maxZ = tmpZ;
|
||||
|
||||
float mid = (maxZ + minZ) * 0.5f;
|
||||
minZ -= mid * 5.0f;
|
||||
maxZ += mid * 5.0f;
|
||||
#endif
|
||||
|
||||
mat44 P, PV;
|
||||
ortho44(P,
|
||||
minX, maxX,
|
||||
minY, maxY,
|
||||
// minZ, maxZ);
|
||||
-maxZ, -minZ);
|
||||
|
||||
multiply44x2(PV, P, V);
|
||||
|
@ -2003,10 +2016,20 @@ void shadowmap_clear_fbo() {
|
|||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
void shadowmap_light(shadowmap_t *s, light_t *l, float cam_fov, float cam_far, mat44 cam_view) {
|
||||
void shadowmap_light(shadowmap_t *s, light_t *l, mat44 cam_proj, mat44 cam_view) {
|
||||
if (l->cast_shadows) {
|
||||
int step = s->step - 1;
|
||||
|
||||
float y_scale = cam_proj[5];
|
||||
float cam_fov = (2.0f * atan(1.0f / y_scale)) * TO_DEG;
|
||||
float cam_far = 0.0f; {
|
||||
float m22 = cam_proj[10];
|
||||
float m32 = cam_proj[14];
|
||||
float near_plane = -m32 / (m22 + 1.0f);
|
||||
cam_far = (2.0f * near_plane) / (m22 - 1.0f);
|
||||
cam_far *= 0.5f;
|
||||
}
|
||||
|
||||
if (l->type == LIGHT_POINT) {
|
||||
shadowmap_light_point(s, l, step);
|
||||
} else if (l->type == LIGHT_SPOT) {
|
||||
|
@ -4853,12 +4876,10 @@ void model_set_renderstates(model_t *m) {
|
|||
// Shadow pass
|
||||
renderstate_t *pcf_shadow_rs = &m->rs[RENDER_PASS_SHADOW_PCF];
|
||||
{
|
||||
pcf_shadow_rs->blend_enabled = 1;
|
||||
pcf_shadow_rs->blend_src = GL_SRC_ALPHA;
|
||||
pcf_shadow_rs->blend_dst = GL_ONE_MINUS_SRC_ALPHA;
|
||||
pcf_shadow_rs->blend_enabled = 0;
|
||||
pcf_shadow_rs->cull_face_enabled = 1;
|
||||
pcf_shadow_rs->cull_face_mode = GL_FRONT;
|
||||
pcf_shadow_rs->front_face = GL_CCW;
|
||||
pcf_shadow_rs->cull_face_mode = GL_BACK;
|
||||
pcf_shadow_rs->front_face = GL_CW;
|
||||
pcf_shadow_rs->depth_clamp_enabled = 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -299,7 +299,7 @@ enum SHADOW_TECHNIQUE {
|
|||
SHADOW_PCF,
|
||||
};
|
||||
|
||||
#define NUM_SHADOW_CASCADES 4
|
||||
#define NUM_SHADOW_CASCADES 6
|
||||
|
||||
typedef struct light_t {
|
||||
char type;
|
||||
|
@ -383,7 +383,7 @@ API void shadowmap_destroy(shadowmap_t *s);
|
|||
|
||||
API void shadowmap_begin(shadowmap_t *s);
|
||||
API bool shadowmap_step(shadowmap_t *s);
|
||||
API void shadowmap_light(shadowmap_t *s, light_t *l, float cam_fov, float cam_far, mat44 cam_view); //< can be called once per shadowmap_step
|
||||
API void shadowmap_light(shadowmap_t *s, light_t *l, mat44 cam_proj, mat44 cam_view); //< can be called once per shadowmap_step
|
||||
API void shadowmap_end(shadowmap_t *s);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -14,6 +14,8 @@ camera_t camera() {
|
|||
cam.fov = 45;
|
||||
cam.orthographic = false;
|
||||
cam.distance = 3; // len3(cam.position);
|
||||
cam.near_clip = 0.1f;
|
||||
cam.far_clip = 1000.f;
|
||||
|
||||
cam.damping = false;
|
||||
cam.move_friction = 0.09f;
|
||||
|
@ -110,12 +112,12 @@ void camera_fov(camera_t *cam, float fov) {
|
|||
cam->fov = fov;
|
||||
|
||||
if( cam->orthographic ) {
|
||||
ortho44(cam->proj, -cam->fov * aspect, cam->fov * aspect, -cam->fov, cam->fov, 0.01f, 2000);
|
||||
ortho44(cam->proj, -cam->fov * aspect, cam->fov * aspect, -cam->fov, cam->fov, cam->near_clip, cam->far_clip);
|
||||
// [ref] https://commons.wikimedia.org/wiki/File:Isometric_dimetric_camera_views.png
|
||||
// float pitch = cam->dimetric ? 30.000f : 35.264f; // dimetric or isometric
|
||||
// cam->pitch = -pitch; // quickly reorient towards origin
|
||||
} else {
|
||||
perspective44(cam->proj, cam->fov, aspect, 0.01f, 2000.f);
|
||||
perspective44(cam->proj, cam->fov, aspect, cam->near_clip, cam->far_clip);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ typedef struct camera_t {
|
|||
vec3 position, updir, lookdir;
|
||||
float yaw, pitch, roll; // mirror of (x,y) lookdir in deg;
|
||||
float speed, fov; // fov in deg(45)
|
||||
float near_clip, far_clip;
|
||||
|
||||
float move_friction, move_damping;
|
||||
float look_friction, look_damping;
|
||||
|
|
43
engine/v4k.c
43
engine/v4k.c
|
@ -18495,12 +18495,14 @@ shadowmap_t shadowmap(int vsm_texture_width, int pcf_texture_width) { // = 512,
|
|||
s.vsm_texture_width = vsm_texture_width;
|
||||
s.pcf_texture_width = pcf_texture_width;
|
||||
s.saved_fb = 0;
|
||||
s.blur_pcf = true;
|
||||
s.blur_pcf = false;
|
||||
s.blur_scale = 0.5f;
|
||||
s.cascade_splits[0] = 0.1f;
|
||||
s.cascade_splits[1] = 0.3f;
|
||||
s.cascade_splits[2] = 0.5f;
|
||||
s.cascade_splits[3] = 1.0f;
|
||||
s.cascade_splits[3] = 0.7f;
|
||||
s.cascade_splits[5] = 1.0f;
|
||||
s.cascade_splits[6] = 1.0f; /* sticks to camera far plane */
|
||||
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &s.saved_fb);
|
||||
|
||||
|
@ -18678,10 +18680,21 @@ static void shadowmap_light_directional(shadowmap_t *s, light_t *l, int dir, flo
|
|||
maxZ = max(maxZ, corner.z);
|
||||
}
|
||||
|
||||
#if 0
|
||||
float tmpZ = -minZ;
|
||||
minZ = -maxZ;
|
||||
maxZ = tmpZ;
|
||||
|
||||
float mid = (maxZ + minZ) * 0.5f;
|
||||
minZ -= mid * 5.0f;
|
||||
maxZ += mid * 5.0f;
|
||||
#endif
|
||||
|
||||
mat44 P, PV;
|
||||
ortho44(P,
|
||||
minX, maxX,
|
||||
minY, maxY,
|
||||
// minZ, maxZ);
|
||||
-maxZ, -minZ);
|
||||
|
||||
multiply44x2(PV, P, V);
|
||||
|
@ -18802,10 +18815,20 @@ void shadowmap_clear_fbo() {
|
|||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
void shadowmap_light(shadowmap_t *s, light_t *l, float cam_fov, float cam_far, mat44 cam_view) {
|
||||
void shadowmap_light(shadowmap_t *s, light_t *l, mat44 cam_proj, mat44 cam_view) {
|
||||
if (l->cast_shadows) {
|
||||
int step = s->step - 1;
|
||||
|
||||
float y_scale = cam_proj[5];
|
||||
float cam_fov = (2.0f * atan(1.0f / y_scale)) * TO_DEG;
|
||||
float cam_far = 0.0f; {
|
||||
float m22 = cam_proj[10];
|
||||
float m32 = cam_proj[14];
|
||||
float near_plane = -m32 / (m22 + 1.0f);
|
||||
cam_far = (2.0f * near_plane) / (m22 - 1.0f);
|
||||
cam_far *= 0.5f;
|
||||
}
|
||||
|
||||
if (l->type == LIGHT_POINT) {
|
||||
shadowmap_light_point(s, l, step);
|
||||
} else if (l->type == LIGHT_SPOT) {
|
||||
|
@ -21652,12 +21675,10 @@ void model_set_renderstates(model_t *m) {
|
|||
// Shadow pass
|
||||
renderstate_t *pcf_shadow_rs = &m->rs[RENDER_PASS_SHADOW_PCF];
|
||||
{
|
||||
pcf_shadow_rs->blend_enabled = 1;
|
||||
pcf_shadow_rs->blend_src = GL_SRC_ALPHA;
|
||||
pcf_shadow_rs->blend_dst = GL_ONE_MINUS_SRC_ALPHA;
|
||||
pcf_shadow_rs->blend_enabled = 0;
|
||||
pcf_shadow_rs->cull_face_enabled = 1;
|
||||
pcf_shadow_rs->cull_face_mode = GL_FRONT;
|
||||
pcf_shadow_rs->front_face = GL_CCW;
|
||||
pcf_shadow_rs->cull_face_mode = GL_BACK;
|
||||
pcf_shadow_rs->front_face = GL_CW;
|
||||
pcf_shadow_rs->depth_clamp_enabled = 1;
|
||||
}
|
||||
|
||||
|
@ -23778,6 +23799,8 @@ camera_t camera() {
|
|||
cam.fov = 45;
|
||||
cam.orthographic = false;
|
||||
cam.distance = 3; // len3(cam.position);
|
||||
cam.near_clip = 0.1f;
|
||||
cam.far_clip = 1000.f;
|
||||
|
||||
cam.damping = false;
|
||||
cam.move_friction = 0.09f;
|
||||
|
@ -23874,12 +23897,12 @@ void camera_fov(camera_t *cam, float fov) {
|
|||
cam->fov = fov;
|
||||
|
||||
if( cam->orthographic ) {
|
||||
ortho44(cam->proj, -cam->fov * aspect, cam->fov * aspect, -cam->fov, cam->fov, 0.01f, 2000);
|
||||
ortho44(cam->proj, -cam->fov * aspect, cam->fov * aspect, -cam->fov, cam->fov, cam->near_clip, cam->far_clip);
|
||||
// [ref] https://commons.wikimedia.org/wiki/File:Isometric_dimetric_camera_views.png
|
||||
// float pitch = cam->dimetric ? 30.000f : 35.264f; // dimetric or isometric
|
||||
// cam->pitch = -pitch; // quickly reorient towards origin
|
||||
} else {
|
||||
perspective44(cam->proj, cam->fov, aspect, 0.01f, 2000.f);
|
||||
perspective44(cam->proj, cam->fov, aspect, cam->near_clip, cam->far_clip);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3334,7 +3334,7 @@ enum SHADOW_TECHNIQUE {
|
|||
SHADOW_PCF,
|
||||
};
|
||||
|
||||
#define NUM_SHADOW_CASCADES 4
|
||||
#define NUM_SHADOW_CASCADES 6
|
||||
|
||||
typedef struct light_t {
|
||||
char type;
|
||||
|
@ -3418,7 +3418,7 @@ API void shadowmap_destroy(shadowmap_t *s);
|
|||
|
||||
API void shadowmap_begin(shadowmap_t *s);
|
||||
API bool shadowmap_step(shadowmap_t *s);
|
||||
API void shadowmap_light(shadowmap_t *s, light_t *l, float cam_fov, float cam_far, mat44 cam_view); //< can be called once per shadowmap_step
|
||||
API void shadowmap_light(shadowmap_t *s, light_t *l, mat44 cam_proj, mat44 cam_view); //< can be called once per shadowmap_step
|
||||
API void shadowmap_end(shadowmap_t *s);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -4038,6 +4038,7 @@ typedef struct camera_t {
|
|||
vec3 position, updir, lookdir;
|
||||
float yaw, pitch, roll; // mirror of (x,y) lookdir in deg;
|
||||
float speed, fov; // fov in deg(45)
|
||||
float near_clip, far_clip;
|
||||
|
||||
float move_friction, move_damping;
|
||||
float look_friction, look_damping;
|
||||
|
|
Loading…
Reference in New Issue