Merge pull request #2471 from degasus/lighting_attn

Lighting Attenuation
This commit is contained in:
Jules Blok 2015-06-09 00:16:02 +02:00
commit 58f9b05e7e
2 changed files with 68 additions and 135 deletions

View File

@ -208,42 +208,35 @@ static inline float SafeDivide(float n, float d)
return (d==0) ? (n>0?1:0) : n/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]; float attn = 1.0f;
Vec3& ldir = *_ldir;
if (!(chan.attnfunc & 1)) switch (chan.attnfunc)
{ {
// atten disabled case LIGHTATTN_NONE:
switch (chan.diffusefunc) case LIGHTATTN_DIR:
{ {
case LIGHTDIF_NONE: ldir = ldir.Normalized();
AddIntegerColor(light->color, lightCol); if (ldir == Vec3(0.0f, 0.0f, 0.0f))
break; ldir = normal;
case LIGHTDIF_SIGN: break;
{
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);
} }
} case LIGHTATTN_SPEC:
else // spec and spot {
{ ldir = ldir.Normalized();
// not sure about divide by zero checks attn = (ldir * normal) >= 0.0 ? std::max(0.0f, light->dir * normal) : 0;
Vec3 ldir = light->pos - pos; Vec3 attLen = Vec3(1.0, attn, attn*attn);
float attn; Vec3 cosAttn = light->cosatt;
Vec3 distAttn = light->distatt;
if (chan.diffusefunc != LIGHTDIF_NONE)
distAttn = distAttn.Normalized();
if (chan.attnfunc == 3) // spot attn = SafeDivide(std::max(0.0f, attLen * cosAttn), attLen * distAttn);
break;
}
case LIGHTATTN_SPOT:
{ {
float dist2 = ldir.Length2(); float dist2 = ldir.Length2();
float dist = sqrtf(dist2); float dist = sqrtf(dist2);
@ -253,43 +246,36 @@ 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 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); float distAtt = light->distatt.x + (light->distatt.y * dist) + (light->distatt.z * dist2);
attn = SafeDivide(std::max(0.0f, cosAtt), distAtt); attn = SafeDivide(std::max(0.0f, cosAtt), distAtt);
break;
} }
else if (chan.attnfunc == 1) // specular default:
{
// 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
{
PanicAlert("LightColor"); PanicAlert("LightColor");
return; }
}
switch (chan.diffusefunc) return attn;
{ }
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: static void LightColor(const Vec3 &pos, const Vec3 &normal, u8 lightNum, LitChannel &chan, Vec3 &lightCol)
{ {
float difAttn = std::max(0.0f, ldir * normal); const LightPointer *light = (const LightPointer*)&xfmem.lights[lightNum];
AddScaledIntegerColor(light->color, attn * difAttn, lightCol);
} Vec3 ldir = light->pos - pos;
break; float attn = CalculateLightAttn(light, &ldir, normal, chan);
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,78 +283,23 @@ static void LightAlpha(const Vec3 &pos, const Vec3 &normal, u8 lightNum, const L
{ {
const LightPointer *light = (const LightPointer*)&xfmem.lights[lightNum]; const LightPointer *light = (const LightPointer*)&xfmem.lights[lightNum];
if (!(chan.attnfunc & 1)) Vec3 ldir = light->pos - pos;
float attn = CalculateLightAttn(light, &ldir, normal, chan);
float difAttn = ldir * normal;
switch (chan.diffusefunc)
{ {
// atten disabled case LIGHTDIF_NONE:
switch (chan.diffusefunc) lightCol += light->color[0] * attn;
{ break;
case LIGHTDIF_NONE: case LIGHTDIF_SIGN:
lightCol += light->color[0]; lightCol += light->color[0] * attn * difAttn;
break; break;
case LIGHTDIF_SIGN: case LIGHTDIF_CLAMP:
{ difAttn = std::max(0.0f, difAttn);
Vec3 ldir = (light->pos - pos).Normalized(); lightCol += light->color[0] * attn * difAttn;
float diffuse = ldir * normal; break;
lightCol += light->color[0] * diffuse; default: _assert_(0);
}
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;
if (chan.attnfunc == 3) // 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);
}
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 = 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);
}
} }
} }

View File

@ -63,7 +63,8 @@ static void GenerateLightShader(T& object, LightingUidData& uid_data, int index,
case LIGHTATTN_NONE: case LIGHTATTN_NONE:
case LIGHTATTN_DIR: case LIGHTATTN_DIR:
object.Write("ldir = normalize(" LIGHT_POS".xyz - pos.xyz);\n", LIGHT_POS_PARAMS(index)); 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; break;
case LIGHTATTN_SPEC: case LIGHTATTN_SPEC:
object.Write("ldir = normalize(" LIGHT_POS".xyz - pos.xyz);\n", LIGHT_POS_PARAMS(index)); 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", 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)); LIGHT_COSATT_PARAMS(index), LIGHT_COSATT_PARAMS(index), LIGHT_COSATT_PARAMS(index), LIGHT_DISTATT_PARAMS(index));
break; break;
default: _assert_(0);
} }
switch (chan.diffusefunc) switch (chan.diffusefunc)