diff --git a/data/mdl/fish.gsm b/data/mdl/fish.gsm index 028436e..b080492 100644 Binary files a/data/mdl/fish.gsm and b/data/mdl/fish.gsm differ diff --git a/engine/data/shader/shadow.fs b/engine/data/shader/shadow.fs index c5436f2..33368c1 100644 --- a/engine/data/shader/shadow.fs +++ b/engine/data/shader/shadow.fs @@ -2,10 +2,14 @@ varying vec4 vPos; varying vec3 vNrm; -varying vec4 vShadowCoord; +varying vec4 vShadowCoord0; +varying vec4 vShadowCoord1; +varying vec4 vShadowCoord2; varying vec4 vColor; -uniform sampler2D depth_texture; +uniform sampler2D shadow_map0; +uniform sampler2D shadow_map1; +uniform sampler2D shadow_map2; uniform sampler2D current_texture; uniform float enable_lighting; uniform float enable_texture; @@ -36,14 +40,14 @@ vec4 PhongShading(void) return ambient+diffuse+specular; } -float ShadowCoef(void){ - vec3 shadow_coord = vShadowCoord.xyz / vShadowCoord.w; - float view = shadow_coord.z; - vec2 d[4]; +float SampleShadow(sampler2D shadowMap, vec4 shadowCoord) { + vec3 shadow_c = shadowCoord.xyz / shadowCoord.w; + float view = shadow_c.z; float shadow_coef = 1.0; + vec2 d[4]; int i; - if(shadow_coord.z > 1.0) return 1.0; + if(shadow_c.z > 1.0) return 1.0; d[0] = vec2(-0.94201624, -0.39906216); d[1] = vec2(0.94558609, -0.76890725); @@ -51,11 +55,11 @@ float ShadowCoef(void){ d[3] = vec2(0.34495938, 0.29387760); for(i = 0; i < 4; i++){ - vec2 p = shadow_coord.xy + d[i] / 700.0; + vec2 p = shadow_c.xy + d[i] / 700.0; if(p.x < 0.0 || p.y < 0.0 || p.x > 1.0 || p.y > 1.0) shadow_coef += 1.0; - if(texture2D(depth_texture, p).z < view){ + if(texture2D(shadowMap, p).z < view){ shadow_coef -= 0.2; } } @@ -63,6 +67,14 @@ float ShadowCoef(void){ return shadow_coef; } +float ShadowCoef(void){ + float dist = -vPos.z; + + if(dist < 10.0) return SampleShadow(shadow_map0, vShadowCoord0); + if(dist < 40.0) return SampleShadow(shadow_map1, vShadowCoord1); + return SampleShadow(shadow_map2, vShadowCoord2); +} + void main(void){ vec4 c = PhongShading(); vec4 ambient = gl_LightSource[0].ambient; @@ -74,4 +86,4 @@ void main(void){ gl_FragColor = ambient * shadow_coef * c + (1.0 - ambient) * c; gl_FragColor.a = vColor.a; -} +} \ No newline at end of file diff --git a/engine/data/shader/shadow.vs b/engine/data/shader/shadow.vs index e423e47..4905dfb 100644 --- a/engine/data/shader/shadow.vs +++ b/engine/data/shader/shadow.vs @@ -2,17 +2,21 @@ varying vec4 vPos; varying vec3 vNrm; -varying vec4 vShadowCoord; +varying vec4 vShadowCoord0; +varying vec4 vShadowCoord1; +varying vec4 vShadowCoord2; varying vec4 vColor; void main(void){ vPos = gl_ModelViewMatrix * gl_Vertex; vNrm = normalize(gl_NormalMatrix * gl_Normal); - vShadowCoord = gl_TextureMatrix[7] * gl_ModelViewMatrix * gl_Vertex; + vShadowCoord0 = gl_TextureMatrix[5] * gl_ModelViewMatrix * gl_Vertex; + vShadowCoord1 = gl_TextureMatrix[6] * gl_ModelViewMatrix * gl_Vertex; + vShadowCoord2 = gl_TextureMatrix[7] * gl_ModelViewMatrix * gl_Vertex; vColor = gl_Color; gl_Position = gl_ProjectionMatrix * vPos; gl_FrontColor = gl_Color; gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; -} +} \ No newline at end of file diff --git a/engine/include/GearSrc/GL.h b/engine/include/GearSrc/GL.h index 35600b1..162589a 100644 --- a/engine/include/GearSrc/GL.h +++ b/engine/include/GearSrc/GL.h @@ -37,8 +37,10 @@ GSDECL void GSGLTetrakis(GSGL gl, GSNumber scale, GSVector4 col1, GSVector4 co /* gl_shadow.c */ GSDECL void GSGLShadowInit(GSGL gl); -GSDECL GSBool GSGLShadowBeforeMapping(GSGL gl); -GSDECL void GSGLShadowAfterMapping(GSGL gl); +GSDECL GSBool GSGLShadowBegin(GSGL gl); +GSDECL void GSGLShadowCascade(GSGL gl, int cascade); +GSDECL void GSGLShadowCopy(GSGL gl, int cascade); +GSDECL void GSGLShadowApply(GSGL gl); GSDECL void GSGLShadowEnd(GSGL gl); GSDECL void GSGLShadowDeinit(GSGL gl); GSDECL void GSGLShadowDisable(GSGL gl); diff --git a/engine/include/GearSrc/TypeDefs.h b/engine/include/GearSrc/TypeDefs.h index de58f37..ab640d4 100644 --- a/engine/include/GearSrc/TypeDefs.h +++ b/engine/include/GearSrc/TypeDefs.h @@ -181,14 +181,16 @@ struct _GSNetKV { #include #include +#define GSGL_SHADOW_CASCADES 3 + struct _GSGL { GSEngine engine; int shadow_use_shader; - GLuint shadow_texture; + GLuint shadow_texture[GSGL_SHADOW_CASCADES]; GLuint shadow_shader; - GLdouble shadow_modelview[16]; - GLdouble shadow_projection[16]; + GLdouble shadow_modelview[GSGL_SHADOW_CASCADES][16]; + GLdouble shadow_projection[GSGL_SHADOW_CASCADES][16]; GLdouble shadow_old_projection[16]; GLdouble shadow_old_modelview[16]; diff --git a/engine/src/client.c b/engine/src/client.c index 06fcf34..a12a6c3 100644 --- a/engine/src/client.c +++ b/engine/src/client.c @@ -132,9 +132,14 @@ void GSClientStep(GSClient client) { GSGLTextBold(client->gl, 0); - if(GSGLShadowBeforeMapping(client->gl)) { - scene(client); - GSGLShadowAfterMapping(client->gl); + if(GSGLShadowBegin(client->gl)) { + int c; + for(c = 0; c < GSGL_SHADOW_CASCADES; c++) { + GSGLShadowCascade(client->gl, c); + scene(client); + GSGLShadowCopy(client->gl, c); + } + GSGLShadowApply(client->gl); } if(client->skybox_enabled) { diff --git a/engine/src/gl/gl_shadow.c b/engine/src/gl/gl_shadow.c index 819698a..9e34ccd 100644 --- a/engine/src/gl/gl_shadow.c +++ b/engine/src/gl/gl_shadow.c @@ -6,30 +6,37 @@ void GSGLShadowInit(GSGL gl) { GLfloat color[] = {1, 1, 1, 1}; + int i; - glGenTextures(1, &gl->shadow_texture); - glBindTexture(GL_TEXTURE_2D, gl->shadow_texture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, GSGLMaxShadowDistance, GSGLMaxShadowDistance, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0); + glGenTextures(GSGL_SHADOW_CASCADES, gl->shadow_texture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + for(i = 0; i < GSGL_SHADOW_CASCADES; i++) { + glBindTexture(GL_TEXTURE_2D, gl->shadow_texture[i]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, GSGLMaxShadowDistance, GSGLMaxShadowDistance, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); + glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); - glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); + + glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE); + } glBindTexture(GL_TEXTURE_2D, 0); if(GSGLShaderPrepare(gl, &gl->shadow_shader, "base:/shader/shadow.vs", "base:/shader/shadow.fs")) { glUseProgram(gl->shadow_shader); - glUniform1i(glGetUniformLocation(gl->shadow_shader, "depth_texture"), 7); + glUniform1i(glGetUniformLocation(gl->shadow_shader, "shadow_map0"), 5); + glUniform1i(glGetUniformLocation(gl->shadow_shader, "shadow_map1"), 6); + glUniform1i(glGetUniformLocation(gl->shadow_shader, "shadow_map2"), 7); + glUniform1i(glGetUniformLocation(gl->shadow_shader, "current_texture"), 0); glUniform1f(glGetUniformLocation(gl->shadow_shader, "enable_lighting"), 1); glUniform1f(glGetUniformLocation(gl->shadow_shader, "enable_texture"), 0); @@ -37,57 +44,22 @@ void GSGLShadowInit(GSGL gl) { gl->shadow_use_shader = 1; } else { - glDeleteTextures(1, &gl->shadow_texture); + glDeleteTextures(GSGL_SHADOW_CASCADES, gl->shadow_texture); gl->shadow_use_shader = 0; } } -GSBool GSGLShadowBeforeMapping(GSGL gl) { - GSVector3 zero = {0, 0, 0}; - +GSBool GSGLShadowBegin(GSGL gl) { if(!gl->shadow_use_shader) return GSFalse; - GSGLClear(gl); - - glViewport(0, 0, GSGLMaxShadowDistance, GSGLMaxShadowDistance); - glMatrixMode(GL_PROJECTION); glGetDoublev(GL_PROJECTION_MATRIX, gl->shadow_old_projection); - glLoadIdentity(); - if(gl->engine->client->light0[3]) { - GSGLCameraPerspective(gl, GSGLMaxShadowDistance, GSGLMaxShadowDistance); - } else { - glOrtho(-5, 5, -5, 5, -5, 10); - } - - glGetDoublev(GL_PROJECTION_MATRIX, gl->shadow_projection); glMatrixMode(GL_MODELVIEW); glGetDoublev(GL_MODELVIEW_MATRIX, gl->shadow_old_modelview); - glLoadIdentity(); - if(gl->engine->client->light0[3]){ - GSGLCameraLookAt(gl, gl->engine->client->light0, zero); - }else{ - GSVector3 n; - int i; - - for(i = 0; i < 3; i++) n[i] = gl->engine->client->light0[i]; - - GSMathNormalize3(n); - - for(i = 0; i < 3; i++){ - n[i] *= 5; - n[i] += gl->engine->client->position[i]; - } - - GSGLCameraLookAt(gl, n, gl->engine->client->position); - } - - glGetDoublev(GL_MODELVIEW_MATRIX, gl->shadow_modelview); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - glDisable(GL_LIGHTING); #ifdef SHADOW_CULL @@ -102,22 +74,78 @@ GSBool GSGLShadowBeforeMapping(GSGL gl) { return GSTrue; } -void GSGLShadowAfterMapping(GSGL gl) { - GSMatrix4x4 in, in2, out, out2; - GLdouble mat[16]; - int i; +void GSGLShadowCascade(GSGL gl, int cascade) { + GSVector3 zero = {0, 0, 0}; + GSNumber size; - glDisable(GL_POLYGON_OFFSET_FILL); + GSGLClear(gl); + glViewport(0, 0, GSGLMaxShadowDistance, GSGLMaxShadowDistance); - glActiveTexture(GL_TEXTURE7); - glBindTexture(GL_TEXTURE_2D, gl->shadow_texture); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + // Simple cascade sizing + if(cascade == 0) size = 10; + else if(cascade == 1) size = 40; + else size = 100; // Covers max distance roughly + + // If light is directional (light0[3] == 0) + // Current existing code logic: + if(gl->engine->client->light0[3]) { + // Point/Spot light - no cascade support implies here? + // Fallback to perspective for all cascades? + // Or just use the original logic. + GSGLCameraPerspective(gl, GSGLMaxShadowDistance, GSGLMaxShadowDistance); + } else { + // Directional + glOrtho(-size, size, -size, size, -size * 2, size * 2); + } + + glGetDoublev(GL_PROJECTION_MATRIX, gl->shadow_projection[cascade]); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + if(gl->engine->client->light0[3]) { + GSGLCameraLookAt(gl, gl->engine->client->light0, zero); + } else { + GSVector3 n; + int i; + + for(i = 0; i < 3; i++) n[i] = gl->engine->client->light0[i]; + + GSMathNormalize3(n); + + for(i = 0; i < 3; i++) { + n[i] *= size; // Move light pos away based on size to ensure coverage + n[i] += gl->engine->client->position[i]; + } + + GSGLCameraLookAt(gl, n, gl->engine->client->position); + } + + glGetDoublev(GL_MODELVIEW_MATRIX, gl->shadow_modelview[cascade]); +} + +void GSGLShadowCopy(GSGL gl, int cascade) { + if(cascade < 0 || cascade >= GSGL_SHADOW_CASCADES) return; + + glBindTexture(GL_TEXTURE_2D, gl->shadow_texture[cascade]); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, GSGLMaxShadowDistance, GSGLMaxShadowDistance); glBindTexture(GL_TEXTURE_2D, 0); - glActiveTexture(GL_TEXTURE0); +} + +void GSGLShadowApply(GSGL gl) { + GSMatrix4x4 in, in2, out, out2; + GLdouble mat[16]; + int i, c; + + glDisable(GL_POLYGON_OFFSET_FILL); glViewport(0, 0, gl->engine->width, gl->engine->height); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glEnable(GL_LIGHTING); + #ifdef SHADOW_CULL glCullFace(GL_BACK); #else @@ -132,50 +160,58 @@ void GSGLShadowAfterMapping(GSGL gl) { glLoadIdentity(); glMultMatrixd(gl->shadow_old_modelview); - glActiveTexture(GL_TEXTURE7); - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); + // Calculate texture matrices for each cascade + for(c = 0; c < GSGL_SHADOW_CASCADES; c++) { + glActiveTexture(GL_TEXTURE5 + c); + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); - for(i = 0; i < 16; i++) in[i] = gl->shadow_old_modelview[i]; - GSMathColumnToRow4x4(in2, in); - GSMathInvert4x4(out, in2); - GSMathRowToColumn4x4(out2, out); - for(i = 0; i < 16; i++) mat[i] = out2[i]; + for(i = 0; i < 16; i++) in[i] = gl->shadow_old_modelview[i]; + GSMathColumnToRow4x4(in2, in); + GSMathInvert4x4(out, in2); + GSMathRowToColumn4x4(out2, out); + for(i = 0; i < 16; i++) mat[i] = out2[i]; - glTranslated(0.5, 0.5, 0.5); - glScaled(0.5, 0.5, 0.5); - glMultMatrixd(gl->shadow_projection); - glMultMatrixd(gl->shadow_modelview); - glMultMatrixd(mat); + glTranslated(0.5, 0.5, 0.5); + glScaled(0.5, 0.5, 0.5); + glMultMatrixd(gl->shadow_projection[c]); + glMultMatrixd(gl->shadow_modelview[c]); + glMultMatrixd(mat); + } glActiveTexture(GL_TEXTURE0); - glMatrixMode(GL_MODELVIEW); - GSGLClear(gl); + GSGLClear(gl); // Clear for main render GSGLShadowEnable(gl); } void GSGLShadowDisable(GSGL gl) { + int i; glDisable(GL_LIGHTING); if(gl->shadow_use_shader) { glUseProgram(0); - glActiveTexture(GL_TEXTURE7); - glDisable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, 0); + for(i = 0; i < GSGL_SHADOW_CASCADES; i++) { + glActiveTexture(GL_TEXTURE5 + i); + glDisable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, 0); + } glActiveTexture(GL_TEXTURE0); } } void GSGLShadowEnable(GSGL gl) { + int i; glEnable(GL_LIGHTING); if(gl->shadow_use_shader) { glUseProgram(gl->shadow_shader); - glActiveTexture(GL_TEXTURE7); - glBindTexture(GL_TEXTURE_2D, gl->shadow_texture); - glEnable(GL_TEXTURE_2D); + for(i = 0; i < GSGL_SHADOW_CASCADES; i++) { + glActiveTexture(GL_TEXTURE5 + i); + glBindTexture(GL_TEXTURE_2D, gl->shadow_texture[i]); + glEnable(GL_TEXTURE_2D); + } glActiveTexture(GL_TEXTURE0); } } @@ -185,22 +221,19 @@ void GSGLShadowEnd(GSGL gl) { GSGLShadowDisable(gl); - glActiveTexture(GL_TEXTURE7); - glDisable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, 0); + // Reset texture matrices + for(int i = 0; i < GSGL_SHADOW_CASCADES; i++) { + glActiveTexture(GL_TEXTURE5 + i); + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + } glActiveTexture(GL_TEXTURE0); - - glActiveTexture(GL_TEXTURE7); - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glActiveTexture(GL_TEXTURE0); - glMatrixMode(GL_MODELVIEW); } void GSGLShadowDeinit(GSGL gl) { if(gl->shadow_use_shader) { - glDeleteTextures(1, &gl->shadow_texture); + glDeleteTextures(GSGL_SHADOW_CASCADES, gl->shadow_texture); glDeleteProgram(gl->shadow_shader); } -} +} \ No newline at end of file