555 lines
19 KiB
C
555 lines
19 KiB
C
// [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|v4k_render.c:772
|
|
// 001: 00007FF7AF6A3FDA callstack (C:\prj\thread\V4K\v4k_system.c:250)
|
|
// 002: 00007FF7AF8E7CBC shader_uniform (C:\prj\thread\V4K\v4k_render.c:772)
|
|
// 003: 00007FF7AF691C27 shader_int (C:\prj\thread\V4K\v4k_render.c:777)
|
|
// 004: 00007FF7AF8F54EF color_begin (C:\prj\thread\V4K\spot.c:525)
|
|
// 005: 00007FF7AF8F5BF7 main (C:\prj\thread\V4K\spot.c:607)
|
|
// }
|
|
|
|
#ifndef VSMCUBE
|
|
#define VSMCUBE 0
|
|
#endif
|
|
#ifndef VSMBLUR
|
|
#define VSMBLUR 1
|
|
#endif
|
|
|
|
#include "v4k.h"
|
|
#include "split/v4k_shaders.c"
|
|
|
|
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));
|
|
}
|
|
|
|
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");
|
|
blurProgram = shader(vs_shadow_blur, fs_shadow_blur, "position,,texcoord", "outColor");
|
|
|
|
// 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.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,att_tangent,att_instanced_matrix,,,,att_indexes,att_weights,att_vertexindex,att_color,att_bitangent", "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();
|
|
}
|
|
}
|