From 6e996d145b9dee8a01d64d8db320bfb92a4dc4e1 Mon Sep 17 00:00:00 2001 From: Vincent Pelletier Date: Sun, 15 Mar 2015 22:02:26 +0100 Subject: [PATCH 1/8] GRIM: Disable specular lighting. My initial idea that GRIM would use specular likely came from a difference between DirectX and OpenGL lighting for spotlights: DirectX allows for an extra penumbra angle, allowing stronger center spots while maintaining a smooth fade (which I emulated with a fixed 2.0 exponent). Also, specular involves an extra light color value and material definition for specular reflection, which are not visible in game data files. All this making the use of specular very unlikely to match original renderer. --- engines/grim/gfx_opengl.cpp | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/engines/grim/gfx_opengl.cpp b/engines/grim/gfx_opengl.cpp index ad7d7cbcccf..b9de9d0ae5e 100644 --- a/engines/grim/gfx_opengl.cpp +++ b/engines/grim/gfx_opengl.cpp @@ -158,8 +158,6 @@ byte *GfxOpenGL::setupScreen(int screenW, int screenH, bool fullscreen) { GLfloat ambientSource[] = { 0.0f, 0.0f, 0.0f, 1.0f }; glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientSource); - GLfloat specularReflectance[] = { 0.3f, 0.3f, 0.3f, 1.0f }; - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specularReflectance); if (g_grim->getGameType() == GType_GRIM) { glPolygonOffset(-6.0, -6.0); @@ -970,17 +968,16 @@ void GfxOpenGL::setupLight(Light *light, int lightId) { } glEnable(GL_LIGHTING); - GLfloat diffuse[] = { 0.0f, 0.0f, 0.0f, 1.0f }; - GLfloat specular[] = { 0.0f, 0.0f, 0.0f, 1.0f }; + GLfloat lightColor[] = { 0.0f, 0.0f, 0.0f, 1.0f }; GLfloat lightPos[] = { 0.0f, 0.0f, 0.0f, 1.0f }; GLfloat lightDir[] = { 0.0f, 0.0f, -1.0f }; GLfloat cutoff = 180.0f; GLfloat spot_exp = 0.0f; GLfloat intensity = light->_intensity; - diffuse[0] = ((GLfloat)light->_color.getRed() / 15.0f) * intensity; - diffuse[1] = ((GLfloat)light->_color.getGreen() / 15.0f) * intensity; - diffuse[2] = ((GLfloat)light->_color.getBlue() / 15.0f) * intensity; + lightColor[0] = ((GLfloat)light->_color.getRed() / 15.0f) * intensity; + lightColor[1] = ((GLfloat)light->_color.getGreen() / 15.0f) * intensity; + lightColor[2] = ((GLfloat)light->_color.getBlue() / 15.0f) * intensity; if (light->_type == Light::Omni) { lightPos[0] = light->_pos.x(); @@ -998,16 +995,12 @@ void GfxOpenGL::setupLight(Light *light, int lightId) { lightDir[0] = light->_dir.x(); lightDir[1] = light->_dir.y(); lightDir[2] = light->_dir.z(); - specular[0] = diffuse[0]; - specular[1] = diffuse[1]; - specular[2] = diffuse[2]; spot_exp = 2.0f; cutoff = light->_penumbraangle; } glDisable(GL_LIGHT0 + lightId); - glLightfv(GL_LIGHT0 + lightId, GL_DIFFUSE, diffuse); - glLightfv(GL_LIGHT0 + lightId, GL_SPECULAR, specular); + glLightfv(GL_LIGHT0 + lightId, GL_DIFFUSE, lightColor); glLightfv(GL_LIGHT0 + lightId, GL_POSITION, lightPos); glLightfv(GL_LIGHT0 + lightId, GL_SPOT_DIRECTION, lightDir); glLightf(GL_LIGHT0 + lightId, GL_SPOT_EXPONENT, spot_exp); From ce5af40a0b198ebb1ac24756ad1ebc6834d439ea Mon Sep 17 00:00:00 2001 From: Vincent Pelletier Date: Wed, 6 May 2015 19:49:35 +0200 Subject: [PATCH 2/8] TinyGL: Store spot direction in eye coordinates. As per OpenGL specifications: The spot direction is transformed by the upper 3x3 of the modelview matrix when glLight is called, and it is stored in eye coordinates. --- graphics/tinygl/light.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphics/tinygl/light.cpp b/graphics/tinygl/light.cpp index 7887333c5a2..d370a325b7e 100644 --- a/graphics/tinygl/light.cpp +++ b/graphics/tinygl/light.cpp @@ -118,7 +118,7 @@ void glopLight(GLContext *c, GLParam *p) { l->spot_direction.X = v.X; l->spot_direction.Y = v.Y; l->spot_direction.Z = v.Z; - l->norm_spot_direction = l->spot_direction; + c->matrix_stack_ptr[0]->transform3x3(l->spot_direction, l->norm_spot_direction); l->norm_spot_direction.normalize(); break; case TGL_SPOT_EXPONENT: From 5c0d8ae30e37c0e23abc1de72c6fd48ffb8ca4b8 Mon Sep 17 00:00:00 2001 From: Vincent Pelletier Date: Sun, 15 Mar 2015 19:55:49 +0100 Subject: [PATCH 3/8] GRIM: Set correct cutoff angle now that TinyGL renders spots correctly. Also, set (T)GL_SPOT_EXPONENT as in OpenGL renderer. --- engines/grim/gfx_tinygl.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/engines/grim/gfx_tinygl.cpp b/engines/grim/gfx_tinygl.cpp index d53550b77a4..4601d31a500 100644 --- a/engines/grim/gfx_tinygl.cpp +++ b/engines/grim/gfx_tinygl.cpp @@ -894,6 +894,7 @@ void GfxTinyGL::setupLight(Light *light, int lightId) { float lightPos[] = { 0.0f, 0.0f, 0.0f, 1.0f }; float lightDir[] = { 0.0f, 0.0f, -1.0f }; float cutoff = 180.0f; + float spot_exp = 0.0f; float intensity = light->_intensity / 1.3f; lightColor[0] = ((float)light->_color.getRed() / 15.0f) * intensity; @@ -916,17 +917,15 @@ void GfxTinyGL::setupLight(Light *light, int lightId) { lightDir[0] = light->_dir.x(); lightDir[1] = light->_dir.y(); lightDir[2] = light->_dir.z(); - /* FIXME: TGL_SPOT_CUTOFF should be light->_penumbraangle, but there - seems to be a bug in tinygl as it renders differently from OpenGL. - Reproducing: turn off all lights (comment out), go to scene "al", - and walk along left wall under the lamp. */ - cutoff = 90.0f; + spot_exp = 2.0f; + cutoff = light->_penumbraangle; } tglDisable(TGL_LIGHT0 + lightId); tglLightfv(TGL_LIGHT0 + lightId, TGL_DIFFUSE, lightColor); tglLightfv(TGL_LIGHT0 + lightId, TGL_POSITION, lightPos); tglLightfv(TGL_LIGHT0 + lightId, TGL_SPOT_DIRECTION, lightDir); + tglLightf(TGL_LIGHT0 + lightId, TGL_SPOT_EXPONENT, spot_exp); tglLightf(TGL_LIGHT0 + lightId, TGL_SPOT_CUTOFF, cutoff); tglEnable(TGL_LIGHT0 + lightId); } From f36d2b62f837856866a5735c85db8f380348ff03 Mon Sep 17 00:00:00 2001 From: Vincent Pelletier Date: Sun, 8 Jun 2014 09:51:28 +0200 Subject: [PATCH 4/8] GRIM: Drop TinyGL-only intensity divisor. Also, divide intensity once instead of once per component. --- engines/grim/gfx_opengl.cpp | 8 ++++---- engines/grim/gfx_tinygl.cpp | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/engines/grim/gfx_opengl.cpp b/engines/grim/gfx_opengl.cpp index b9de9d0ae5e..d3e8d70bdb1 100644 --- a/engines/grim/gfx_opengl.cpp +++ b/engines/grim/gfx_opengl.cpp @@ -974,10 +974,10 @@ void GfxOpenGL::setupLight(Light *light, int lightId) { GLfloat cutoff = 180.0f; GLfloat spot_exp = 0.0f; - GLfloat intensity = light->_intensity; - lightColor[0] = ((GLfloat)light->_color.getRed() / 15.0f) * intensity; - lightColor[1] = ((GLfloat)light->_color.getGreen() / 15.0f) * intensity; - lightColor[2] = ((GLfloat)light->_color.getBlue() / 15.0f) * intensity; + GLfloat intensity = light->_intensity / 15.0f; + lightColor[0] = (GLfloat)light->_color.getRed() * intensity; + lightColor[1] = (GLfloat)light->_color.getGreen() * intensity; + lightColor[2] = (GLfloat)light->_color.getBlue() * intensity; if (light->_type == Light::Omni) { lightPos[0] = light->_pos.x(); diff --git a/engines/grim/gfx_tinygl.cpp b/engines/grim/gfx_tinygl.cpp index 4601d31a500..9fc81907f4a 100644 --- a/engines/grim/gfx_tinygl.cpp +++ b/engines/grim/gfx_tinygl.cpp @@ -896,10 +896,10 @@ void GfxTinyGL::setupLight(Light *light, int lightId) { float cutoff = 180.0f; float spot_exp = 0.0f; - float intensity = light->_intensity / 1.3f; - lightColor[0] = ((float)light->_color.getRed() / 15.0f) * intensity; - lightColor[1] = ((float)light->_color.getGreen() / 15.0f) * intensity; - lightColor[2] = ((float)light->_color.getBlue() / 15.0f) * intensity; + float intensity = light->_intensity / 15.0f; + lightColor[0] = (float)light->_color.getRed() * intensity; + lightColor[1] = (float)light->_color.getGreen() * intensity; + lightColor[2] = (float)light->_color.getBlue() * intensity; if (light->_type == Light::Omni) { lightPos[0] = light->_pos.x(); From 06e7aa68b0c9430f59810064d9f67e1afdba6f4d Mon Sep 17 00:00:00 2001 From: Vincent Pelletier Date: Mon, 16 Mar 2015 22:53:52 +0100 Subject: [PATCH 5/8] GRIM: Correct diffuse reflectance. Determined by keping a single directional light source enabled, as they are not subject to attenuation (having no position), and comparing with original software renderer. Default DirectX material reflects all diffuse light, so 1.0f coefficient is likely correct. --- engines/grim/gfx_opengl.cpp | 2 ++ engines/grim/gfx_tinygl.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/engines/grim/gfx_opengl.cpp b/engines/grim/gfx_opengl.cpp index d3e8d70bdb1..fab0496a20f 100644 --- a/engines/grim/gfx_opengl.cpp +++ b/engines/grim/gfx_opengl.cpp @@ -158,6 +158,8 @@ byte *GfxOpenGL::setupScreen(int screenW, int screenH, bool fullscreen) { GLfloat ambientSource[] = { 0.0f, 0.0f, 0.0f, 1.0f }; glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientSource); + GLfloat diffuseReflectance[] = { 1.0f, 1.0f, 1.0f, 1.0f }; + glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuseReflectance); if (g_grim->getGameType() == GType_GRIM) { glPolygonOffset(-6.0, -6.0); diff --git a/engines/grim/gfx_tinygl.cpp b/engines/grim/gfx_tinygl.cpp index 9fc81907f4a..df45510ecd5 100644 --- a/engines/grim/gfx_tinygl.cpp +++ b/engines/grim/gfx_tinygl.cpp @@ -103,6 +103,8 @@ byte *GfxTinyGL::setupScreen(int screenW, int screenH, bool fullscreen) { TGLfloat ambientSource[] = { 0.0f, 0.0f, 0.0f, 1.0f }; tglLightModelfv(TGL_LIGHT_MODEL_AMBIENT, ambientSource); + TGLfloat diffuseReflectance[] = { 1.0f, 1.0f, 1.0f, 1.0f }; + tglMaterialfv(TGL_FRONT, TGL_DIFFUSE, diffuseReflectance); // we now generate a buffer (id 1), which we will use as a backing buffer, where the actors' clean buffers // will blit to. everu frame this will be blitted to screen, but the actors' buffers will be blitted to From 351a4efa8a64b2810bb4d79fc10b1904d6d180fe Mon Sep 17 00:00:00 2001 From: Vincent Pelletier Date: Mon, 16 Mar 2015 23:33:42 +0100 Subject: [PATCH 6/8] GRIM: Tweak attenuation. Determined by enabling a single omnidirectional light (newlight9 in set "ce", which stands at set entrance toward elevator) and comparing luminosity level on Manny at several locations in that scene with original software renderer. This set is quite convenient for this comparison, as Manny position can be easily controlled: stick to the wall with the red arrow pointing at the stairs, making movements one-dimensional. For spotlight, set "tu" was used with the single spotlight on, walking from the fire extinguisher to server door, confirming similar attenuation. From these tests, it seems only quadratic attenuation is used, which makes sense as it gives a realistic effect. --- engines/grim/gfx_opengl.cpp | 2 +- engines/grim/gfx_tinygl.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/engines/grim/gfx_opengl.cpp b/engines/grim/gfx_opengl.cpp index fab0496a20f..ebe3aa0c101 100644 --- a/engines/grim/gfx_opengl.cpp +++ b/engines/grim/gfx_opengl.cpp @@ -1007,7 +1007,7 @@ void GfxOpenGL::setupLight(Light *light, int lightId) { glLightfv(GL_LIGHT0 + lightId, GL_SPOT_DIRECTION, lightDir); glLightf(GL_LIGHT0 + lightId, GL_SPOT_EXPONENT, spot_exp); glLightf(GL_LIGHT0 + lightId, GL_SPOT_CUTOFF, cutoff); - glLightf(GL_LIGHT0 + lightId, GL_QUADRATIC_ATTENUATION, 0.2f); + glLightf(GL_LIGHT0 + lightId, GL_QUADRATIC_ATTENUATION, 1.0f); glEnable(GL_LIGHT0 + lightId); } diff --git a/engines/grim/gfx_tinygl.cpp b/engines/grim/gfx_tinygl.cpp index df45510ecd5..d0bfae5cb35 100644 --- a/engines/grim/gfx_tinygl.cpp +++ b/engines/grim/gfx_tinygl.cpp @@ -929,6 +929,7 @@ void GfxTinyGL::setupLight(Light *light, int lightId) { tglLightfv(TGL_LIGHT0 + lightId, TGL_SPOT_DIRECTION, lightDir); tglLightf(TGL_LIGHT0 + lightId, TGL_SPOT_EXPONENT, spot_exp); tglLightf(TGL_LIGHT0 + lightId, TGL_SPOT_CUTOFF, cutoff); + tglLightf(TGL_LIGHT0 + lightId, TGL_QUADRATIC_ATTENUATION, 1.0f); tglEnable(TGL_LIGHT0 + lightId); } From faad6a1fe35239bacf6bd1fbc1b0f77e54204dc3 Mon Sep 17 00:00:00 2001 From: Vincent Pelletier Date: Tue, 17 Mar 2015 00:17:30 +0100 Subject: [PATCH 7/8] GRIM: Disable quadratic attenuation for spotlights. Enabling quadratic atenuation, even with values as low as 0.1, reduces spot lighting too much in (at least) sets "do" (see Domino), "al" (see Manny when walking along the garage door), "hq" (see Salvador). Disabling is not perfect either, as attenuation can be seen (at least) in set "tu" (see fire extinguisher), but it should be overall better. Also, it should be noted that perfect fidelity cannot be achieved with openGL fixed pipeline, as DirectX spotlight have two angles (0 <= phi <= theta <= pi), atenuation being null below phi, full above theta, transitioning with a configurable exponent between both (defaults to angle-linear). OpenGL would correspond to phi=0 and theta=pi (ie, transition is always done between fixed angles), plus a configurable hard cutoff. --- engines/grim/gfx_opengl.cpp | 4 +++- engines/grim/gfx_tinygl.cpp | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/engines/grim/gfx_opengl.cpp b/engines/grim/gfx_opengl.cpp index ebe3aa0c101..1e10a0c22ec 100644 --- a/engines/grim/gfx_opengl.cpp +++ b/engines/grim/gfx_opengl.cpp @@ -975,6 +975,7 @@ void GfxOpenGL::setupLight(Light *light, int lightId) { GLfloat lightDir[] = { 0.0f, 0.0f, -1.0f }; GLfloat cutoff = 180.0f; GLfloat spot_exp = 0.0f; + GLfloat q_attenuation = 1.0f; GLfloat intensity = light->_intensity / 15.0f; lightColor[0] = (GLfloat)light->_color.getRed() * intensity; @@ -999,6 +1000,7 @@ void GfxOpenGL::setupLight(Light *light, int lightId) { lightDir[2] = light->_dir.z(); spot_exp = 2.0f; cutoff = light->_penumbraangle; + q_attenuation = 0.0f; } glDisable(GL_LIGHT0 + lightId); @@ -1007,7 +1009,7 @@ void GfxOpenGL::setupLight(Light *light, int lightId) { glLightfv(GL_LIGHT0 + lightId, GL_SPOT_DIRECTION, lightDir); glLightf(GL_LIGHT0 + lightId, GL_SPOT_EXPONENT, spot_exp); glLightf(GL_LIGHT0 + lightId, GL_SPOT_CUTOFF, cutoff); - glLightf(GL_LIGHT0 + lightId, GL_QUADRATIC_ATTENUATION, 1.0f); + glLightf(GL_LIGHT0 + lightId, GL_QUADRATIC_ATTENUATION, q_attenuation); glEnable(GL_LIGHT0 + lightId); } diff --git a/engines/grim/gfx_tinygl.cpp b/engines/grim/gfx_tinygl.cpp index d0bfae5cb35..3f75ebb468a 100644 --- a/engines/grim/gfx_tinygl.cpp +++ b/engines/grim/gfx_tinygl.cpp @@ -897,6 +897,7 @@ void GfxTinyGL::setupLight(Light *light, int lightId) { float lightDir[] = { 0.0f, 0.0f, -1.0f }; float cutoff = 180.0f; float spot_exp = 0.0f; + float q_attenuation = 1.0f; float intensity = light->_intensity / 15.0f; lightColor[0] = (float)light->_color.getRed() * intensity; @@ -921,6 +922,7 @@ void GfxTinyGL::setupLight(Light *light, int lightId) { lightDir[2] = light->_dir.z(); spot_exp = 2.0f; cutoff = light->_penumbraangle; + q_attenuation = 0.0f; } tglDisable(TGL_LIGHT0 + lightId); @@ -929,7 +931,7 @@ void GfxTinyGL::setupLight(Light *light, int lightId) { tglLightfv(TGL_LIGHT0 + lightId, TGL_SPOT_DIRECTION, lightDir); tglLightf(TGL_LIGHT0 + lightId, TGL_SPOT_EXPONENT, spot_exp); tglLightf(TGL_LIGHT0 + lightId, TGL_SPOT_CUTOFF, cutoff); - tglLightf(TGL_LIGHT0 + lightId, TGL_QUADRATIC_ATTENUATION, 1.0f); + tglLightf(TGL_LIGHT0 + lightId, TGL_QUADRATIC_ATTENUATION, q_attenuation); tglEnable(TGL_LIGHT0 + lightId); } From 4239446a70c46715295951873afb477e3ce93ee8 Mon Sep 17 00:00:00 2001 From: Vincent Pelletier Date: Sun, 29 Mar 2015 13:40:09 +0200 Subject: [PATCH 8/8] GRIM: SHADERS: Use non-zero constant attenuation. This is consistent with OpenGL default value for GL_CONSTANT_ATTENUATION. --- engines/grim/shaders/grim_actor.vertex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/grim/shaders/grim_actor.vertex b/engines/grim/shaders/grim_actor.vertex index b8bbaf93995..239bcf407a8 100644 --- a/engines/grim/shaders/grim_actor.vertex +++ b/engines/grim/shaders/grim_actor.vertex @@ -1,4 +1,4 @@ -const float CONSTANT_ATTENUATION = 0.0; +const float CONSTANT_ATTENUATION = 1.0; const float LINEAR_ATTENUATION = 0.0; const float QUADRATIC_ATTENUATION = 1.0;