From 06d1b8c63ae63035fc95c350da8f1879eca7fc25 Mon Sep 17 00:00:00 2001 From: NanoByte011 Date: Sat, 7 Feb 2015 10:40:21 -0700 Subject: [PATCH 1/2] VideoSW: rewrite lighting attenuation - Fixes remaining lighting issues (Mario Tennis, etc) - Apply same fixes to Software Renderer - Corrected zero length light direction vector to resolve with normal direction (essentially becomes LIGHTDIF_NONE which was what I was after) --- .../VideoBackends/Software/TransformUnit.cpp | 210 +++++++----------- Source/Core/VideoCommon/LightingShaderGen.h | 4 +- 2 files changed, 88 insertions(+), 126 deletions(-) diff --git a/Source/Core/VideoBackends/Software/TransformUnit.cpp b/Source/Core/VideoBackends/Software/TransformUnit.cpp index f170e7d9c4..73eab84440 100644 --- a/Source/Core/VideoBackends/Software/TransformUnit.cpp +++ b/Source/Core/VideoBackends/Software/TransformUnit.cpp @@ -212,38 +212,33 @@ static void LightColor(const Vec3 &pos, const Vec3 &normal, u8 lightNum, const L { const LightPointer *light = (const LightPointer*)&xfmem.lights[lightNum]; - if (!(chan.attnfunc & 1)) - { - // atten disabled - switch (chan.diffusefunc) - { - case LIGHTDIF_NONE: - AddIntegerColor(light->color, lightCol); - break; - case LIGHTDIF_SIGN: - { - Vec3 ldir = (light->pos - pos).Normalized(); - float diffuse = ldir * normal; - AddScaledIntegerColor(light->color, diffuse, lightCol); - } - break; - case LIGHTDIF_CLAMP: - { - Vec3 ldir = (light->pos - pos).Normalized(); - float diffuse = std::max(0.0f, ldir * normal); - AddScaledIntegerColor(light->color, diffuse, lightCol); - } - break; - default: _assert_(0); - } - } - else // spec and spot - { - // not sure about divide by zero checks - Vec3 ldir = light->pos - pos; - float attn; + Vec3 ldir = light->pos - pos; + float attn = 1.0f; - if (chan.attnfunc == 3) // spot + switch (chan.attnfunc) + { + case LIGHTATTN_NONE: + case LIGHTATTN_DIR: + { + ldir = ldir.Normalized(); + if (ldir == Vec3(0, 0, 0)) + ldir = Vec3(1, 1, 1); + break; + } + case LIGHTATTN_SPEC: + { + ldir = ldir.Normalized(); + attn = (ldir * normal) >= 0.0 ? std::max(0.0f, light->dir * normal) : 0; + Vec3 attLen = Vec3(1.0, attn, attn*attn); + Vec3 cosAttn = light->cosatt; + Vec3 distAttn = light->distatt; + if (chan.diffusefunc != LIGHTDIF_NONE) + distAttn = distAttn.Normalized(); + + attn = SafeDivide(std::max(0.0f, attLen * cosAttn), attLen * distAttn); + break; + } + case LIGHTATTN_SPOT: { float dist2 = ldir.Length2(); float dist = sqrtf(dist2); @@ -253,43 +248,26 @@ static void LightColor(const Vec3 &pos, const Vec3 &normal, u8 lightNum, const L float cosAtt = light->cosatt.x + (light->cosatt.y * attn) + (light->cosatt.z * attn * attn); float distAtt = light->distatt.x + (light->distatt.y * dist) + (light->distatt.z * dist2); attn = SafeDivide(std::max(0.0f, cosAtt), distAtt); + break; } - else if (chan.attnfunc == 1) // specular - { - // donko - what is going on here? 655.36 is a guess but seems about right. - attn = (light->pos * normal) > -655.36 ? std::max(0.0f, (light->dir * normal)) : 0; - ldir.set(1.0f, attn, attn * attn); - - float cosAtt = std::max(0.0f, light->cosatt * ldir); - float distAtt = light->distatt * ldir; - attn = SafeDivide(std::max(0.0f, cosAtt), distAtt); - } - else - { + default: PanicAlert("LightColor"); - return; - } + } - switch (chan.diffusefunc) - { - case LIGHTDIF_NONE: - AddScaledIntegerColor(light->color, attn, lightCol); - break; - case LIGHTDIF_SIGN: - { - float difAttn = ldir * normal; - AddScaledIntegerColor(light->color, attn * difAttn, lightCol); - } - break; - - case LIGHTDIF_CLAMP: - { - float difAttn = std::max(0.0f, ldir * normal); - AddScaledIntegerColor(light->color, attn * difAttn, lightCol); - } - break; - default: _assert_(0); - } + float difAttn = ldir * normal; + switch (chan.diffusefunc) + { + case LIGHTDIF_NONE: + AddScaledIntegerColor(light->color, attn, lightCol); + break; + case LIGHTDIF_SIGN: + AddScaledIntegerColor(light->color, attn * difAttn, lightCol); + break; + case LIGHTDIF_CLAMP: + difAttn = std::max(0.0f, difAttn); + AddScaledIntegerColor(light->color, attn * difAttn, lightCol); + break; + default: _assert_(0); } } @@ -297,37 +275,31 @@ static void LightAlpha(const Vec3 &pos, const Vec3 &normal, u8 lightNum, const L { const LightPointer *light = (const LightPointer*)&xfmem.lights[lightNum]; - if (!(chan.attnfunc & 1)) - { - // atten disabled - switch (chan.diffusefunc) - { - case LIGHTDIF_NONE: - lightCol += light->color[0]; - break; - case LIGHTDIF_SIGN: - { - Vec3 ldir = (light->pos - pos).Normalized(); - float diffuse = ldir * normal; - lightCol += light->color[0] * diffuse; - } - break; - case LIGHTDIF_CLAMP: - { - Vec3 ldir = (light->pos - pos).Normalized(); - float diffuse = std::max(0.0f, ldir * normal); - lightCol += light->color[0] * diffuse; - } - break; - default: _assert_(0); - } - } - else // spec and spot - { - Vec3 ldir = light->pos - pos; - float attn; + Vec3 ldir = light->pos - pos; + float attn = 1.0f; - if (chan.attnfunc == 3) // spot + switch (chan.attnfunc) + { + case LIGHTATTN_NONE: + case LIGHTATTN_DIR: + { + ldir = ldir.Normalized(); + break; + } + case LIGHTATTN_SPEC: + { + ldir = ldir.Normalized(); + attn = (ldir * normal) >= 0.0 ? std::max(0.0f, light->dir * normal) : 0; + Vec3 attLen = Vec3(1.0, attn, attn*attn); + Vec3 cosAttn = light->cosatt; + Vec3 distAttn = light->distatt; + if (chan.diffusefunc != LIGHTDIF_NONE) + distAttn = distAttn.Normalized(); + + attn = SafeDivide(std::max(0.0f, attLen * cosAttn), attLen * distAttn); + break; + } + case LIGHTATTN_SPOT: { float dist2 = ldir.Length2(); float dist = sqrtf(dist2); @@ -337,38 +309,26 @@ static void LightAlpha(const Vec3 &pos, const Vec3 &normal, u8 lightNum, const L float cosAtt = light->cosatt.x + (light->cosatt.y * attn) + (light->cosatt.z * attn * attn); float distAtt = light->distatt.x + (light->distatt.y * dist) + (light->distatt.z * dist2); attn = SafeDivide(std::max(0.0f, cosAtt), distAtt); + break; } - else /* if (chan.attnfunc == 1) */ // specular - { - // donko - what is going on here? 655.36 is a guess but seems about right. - attn = (light->pos * normal) > -655.36 ? std::max(0.0f, (light->dir * normal)) : 0; - ldir.set(1.0f, attn, attn * attn); + default: + PanicAlert("LightColor"); + } - float cosAtt = light->cosatt * ldir; - float distAtt = light->distatt * ldir; - attn = SafeDivide(std::max(0.0f, cosAtt), distAtt); - } - - switch (chan.diffusefunc) - { - case LIGHTDIF_NONE: - lightCol += light->color[0] * attn; - break; - case LIGHTDIF_SIGN: - { - float difAttn = ldir * normal; - lightCol += light->color[0] * attn * difAttn; - } - break; - - case LIGHTDIF_CLAMP: - { - float difAttn = std::max(0.0f, ldir * normal); - lightCol += light->color[0] * attn * difAttn; - } - break; - default: _assert_(0); - } + float difAttn = ldir * normal; + switch (chan.diffusefunc) + { + case LIGHTDIF_NONE: + lightCol += light->color[0] * attn; + break; + case LIGHTDIF_SIGN: + lightCol += light->color[0] * attn * difAttn; + break; + case LIGHTDIF_CLAMP: + difAttn = std::max(0.0f, difAttn); + lightCol += light->color[0] * attn * difAttn; + break; + default: _assert_(0); } } diff --git a/Source/Core/VideoCommon/LightingShaderGen.h b/Source/Core/VideoCommon/LightingShaderGen.h index 2714ae66a0..83ecfb4174 100644 --- a/Source/Core/VideoCommon/LightingShaderGen.h +++ b/Source/Core/VideoCommon/LightingShaderGen.h @@ -63,7 +63,8 @@ static void GenerateLightShader(T& object, LightingUidData& uid_data, int index, case LIGHTATTN_NONE: case LIGHTATTN_DIR: object.Write("ldir = normalize(" LIGHT_POS".xyz - pos.xyz);\n", LIGHT_POS_PARAMS(index)); - object.Write("attn = 1.0f;\n"); + object.Write("attn = 1.0;\n"); + object.Write("if (length(ldir) == 0.0)\n\t ldir = _norm0;\n"); break; case LIGHTATTN_SPEC: object.Write("ldir = normalize(" LIGHT_POS".xyz - pos.xyz);\n", LIGHT_POS_PARAMS(index)); @@ -82,6 +83,7 @@ static void GenerateLightShader(T& object, LightingUidData& uid_data, int index, object.Write("attn = max(0.0, " LIGHT_COSATT".x + " LIGHT_COSATT".y*attn + " LIGHT_COSATT".z*attn*attn) / dot(" LIGHT_DISTATT".xyz, float3(1.0,dist,dist2));\n", LIGHT_COSATT_PARAMS(index), LIGHT_COSATT_PARAMS(index), LIGHT_COSATT_PARAMS(index), LIGHT_DISTATT_PARAMS(index)); break; + default: _assert_(0); } switch (chan.diffusefunc) From 59f273696ab3c2b1965106e9e4145e5b62a6ccd5 Mon Sep 17 00:00:00 2001 From: NanoByte011 Date: Sat, 7 Feb 2015 17:16:04 -0700 Subject: [PATCH 2/2] VideoSW: refactor shared lighting attenuation function - Refactored Light Attenuation into inline function in Software Renderer - Corrected zero length light direction vector to resolve with normal direction (essentially becomes LIGHTDIF_NONE which was what I was after) - Change the API of this shared function to use points for output variables (degasus) --- .../VideoBackends/Software/TransformUnit.cpp | 59 +++++-------------- 1 file changed, 15 insertions(+), 44 deletions(-) diff --git a/Source/Core/VideoBackends/Software/TransformUnit.cpp b/Source/Core/VideoBackends/Software/TransformUnit.cpp index 73eab84440..e7e46691fd 100644 --- a/Source/Core/VideoBackends/Software/TransformUnit.cpp +++ b/Source/Core/VideoBackends/Software/TransformUnit.cpp @@ -208,12 +208,10 @@ static inline float SafeDivide(float n, float d) return (d==0) ? (n>0?1:0) : n/d; } -static void LightColor(const Vec3 &pos, const Vec3 &normal, u8 lightNum, const LitChannel &chan, Vec3 &lightCol) +static float CalculateLightAttn(const LightPointer *light, Vec3* _ldir, const Vec3 &normal, const LitChannel &chan) { - const LightPointer *light = (const LightPointer*)&xfmem.lights[lightNum]; - - Vec3 ldir = light->pos - pos; float attn = 1.0f; + Vec3& ldir = *_ldir; switch (chan.attnfunc) { @@ -221,8 +219,8 @@ static void LightColor(const Vec3 &pos, const Vec3 &normal, u8 lightNum, const L case LIGHTATTN_DIR: { ldir = ldir.Normalized(); - if (ldir == Vec3(0, 0, 0)) - ldir = Vec3(1, 1, 1); + if (ldir == Vec3(0.0f, 0.0f, 0.0f)) + ldir = normal; break; } case LIGHTATTN_SPEC: @@ -254,6 +252,16 @@ static void LightColor(const Vec3 &pos, const Vec3 &normal, u8 lightNum, const L PanicAlert("LightColor"); } + return attn; +} + +static void LightColor(const Vec3 &pos, const Vec3 &normal, u8 lightNum, LitChannel &chan, Vec3 &lightCol) +{ + const LightPointer *light = (const LightPointer*)&xfmem.lights[lightNum]; + + Vec3 ldir = light->pos - pos; + float attn = CalculateLightAttn(light, &ldir, normal, chan); + float difAttn = ldir * normal; switch (chan.diffusefunc) { @@ -276,44 +284,7 @@ static void LightAlpha(const Vec3 &pos, const Vec3 &normal, u8 lightNum, const L const LightPointer *light = (const LightPointer*)&xfmem.lights[lightNum]; Vec3 ldir = light->pos - pos; - float attn = 1.0f; - - switch (chan.attnfunc) - { - case LIGHTATTN_NONE: - case LIGHTATTN_DIR: - { - ldir = ldir.Normalized(); - break; - } - case LIGHTATTN_SPEC: - { - ldir = ldir.Normalized(); - attn = (ldir * normal) >= 0.0 ? std::max(0.0f, light->dir * normal) : 0; - Vec3 attLen = Vec3(1.0, attn, attn*attn); - Vec3 cosAttn = light->cosatt; - Vec3 distAttn = light->distatt; - if (chan.diffusefunc != LIGHTDIF_NONE) - distAttn = distAttn.Normalized(); - - attn = SafeDivide(std::max(0.0f, attLen * cosAttn), attLen * distAttn); - break; - } - case LIGHTATTN_SPOT: - { - float dist2 = ldir.Length2(); - float dist = sqrtf(dist2); - ldir = ldir / dist; - attn = std::max(0.0f, ldir * light->dir); - - float cosAtt = light->cosatt.x + (light->cosatt.y * attn) + (light->cosatt.z * attn * attn); - float distAtt = light->distatt.x + (light->distatt.y * dist) + (light->distatt.z * dist2); - attn = SafeDivide(std::max(0.0f, cosAtt), distAtt); - break; - } - default: - PanicAlert("LightColor"); - } + float attn = CalculateLightAttn(light, &ldir, normal, chan); float difAttn = ldir * normal; switch (chan.diffusefunc)