- add spotlight support

This commit is contained in:
Magnus Norddahl 2018-10-31 20:08:01 +01:00
parent 8bea68f6af
commit 8b290752c6
6 changed files with 79 additions and 39 deletions

View file

@ -223,6 +223,7 @@ struct IntThing
char special;
char args[5];
short pitch; // UDMF
float height; // UDMF
TArray<UDMFKey> props;
@ -278,7 +279,8 @@ struct thingLight_t
kexVec2 origin;
kexVec3 rgb;
float intensity;
float falloff;
float innerAngleCos;
float outerAngleCos;
float height;
float radius;
bool bCeiling;

View file

@ -130,6 +130,7 @@ void FProcessor::LoadThings ()
Level.Things[i].args[2] = Things[i].args[2];
Level.Things[i].args[3] = Things[i].args[3];
Level.Things[i].args[4] = Things[i].args[4];
Level.Things[i].pitch = 0;
}
delete[] Things;
}
@ -153,6 +154,7 @@ void FProcessor::LoadThings ()
Level.Things[i].args[2] = 0;
Level.Things[i].args[3] = 0;
Level.Things[i].args[4] = 0;
Level.Things[i].pitch = 0;
}
delete[] mt;
}

View file

@ -158,6 +158,8 @@ fixed_t CheckFixed(const char *key)
void FProcessor::ParseThing(IntThing *th)
{
th->pitch = 0;
SC_MustGetStringName("{");
while (!SC_CheckString("}"))
{
@ -179,6 +181,10 @@ void FProcessor::ParseThing(IntThing *th)
{
th->angle = (short)CheckInt(key);
}
if (!stricmp(key, "pitch"))
{
th->pitch = (short)CheckInt(key);
}
if (!stricmp(key, "type"))
{
th->type = (short)CheckInt(key);

View file

@ -238,19 +238,22 @@ bool kexLightmapBuilder::EmitFromCeiling(kexTrace &trace, const surface_t *surfa
// and against all nearby thing lights
//
template<class T>
T smoothstep(const T edge0, const T edge1, const T x)
{
auto t = clamp<T>((x - edge0) / (edge1 - edge0), 0.0, 1.0);
return t * t * (3.0 - 2.0 * t);
}
static float radians(float degrees)
{
return degrees * 3.14159265359f / 180.0f;
}
kexVec3 kexLightmapBuilder::LightTexelSample(kexTrace &trace, const kexVec3 &origin, surface_t *surface)
{
kexVec3 lightOrigin;
kexVec3 dir;
kexVec3 color;
kexPlane plane;
float dist;
float radius;
float intensity;
float colorAdd;
plane = surface->plane;
color.Clear();
kexPlane plane = surface->plane;
kexVec3 color(0.0f, 0.0f, 0.0f);
// check all thing lights
for(unsigned int i = 0; i < map->thingLights.Size(); i++)
@ -263,11 +266,13 @@ kexVec3 kexLightmapBuilder::LightTexelSample(kexTrace &trace, const kexVec3 &ori
continue;
}
lightOrigin.Set(tl->origin.x,
tl->origin.y,
!tl->bCeiling ?
tl->sector->data.floorheight + tl->height :
tl->sector->data.ceilingheight - tl->height);
float originZ;
if (!tl->bCeiling)
originZ = tl->sector->floorplane.zAt(tl->origin.x, tl->origin.y) + tl->height;
else
originZ = tl->sector->ceilingplane.zAt(tl->origin.x, tl->origin.y) - tl->height;
kexVec3 lightOrigin(tl->origin.x, tl->origin.y, originZ);
if(plane.Distance(lightOrigin) - plane.d < 0)
{
@ -275,8 +280,8 @@ kexVec3 kexLightmapBuilder::LightTexelSample(kexTrace &trace, const kexVec3 &ori
continue;
}
radius = tl->radius;
intensity = tl->intensity;
float radius = tl->radius;
float intensity = tl->intensity;
if(origin.DistanceSq(lightOrigin) > (radius*radius))
{
@ -284,6 +289,28 @@ kexVec3 kexLightmapBuilder::LightTexelSample(kexTrace &trace, const kexVec3 &ori
continue;
}
kexVec3 dir = (lightOrigin - origin);
float dist = dir.Unit();
dir.Normalize();
float spotAttenuation = 1.0f;
if (tl->outerAngleCos > -1.0f)
{
float negPitch = -radians(tl->mapThing->pitch);
float xyLen = std::cosf(negPitch);
kexVec3 spotDir;
spotDir.x = std::sinf(radians(tl->mapThing->angle)) * xyLen;
spotDir.y = std::cosf(radians(tl->mapThing->angle)) * xyLen;
spotDir.z = -std::sinf(negPitch);
float cosDir = kexVec3::Dot(dir, spotDir);
spotAttenuation = smoothstep(tl->outerAngleCos, tl->innerAngleCos, cosDir);
if (spotAttenuation <= 0.0f)
{
// outside spot light
continue;
}
}
trace.Trace(lightOrigin, origin);
if(trace.fraction != 1)
@ -292,23 +319,13 @@ kexVec3 kexLightmapBuilder::LightTexelSample(kexTrace &trace, const kexVec3 &ori
continue;
}
dir = (lightOrigin - origin);
dist = dir.Unit();
dir.Normalize();
float r = MAX(radius - dist, 0.0f);
colorAdd = ((r * plane.Normal().Dot(dir)) / radius) * intensity;
kexMath::Clamp(colorAdd, 0, 1);
if(tl->falloff != 1)
{
colorAdd = kexMath::Pow(colorAdd, tl->falloff);
}
float attenuation = 1.0f - (dist / radius);
attenuation *= spotAttenuation;
attenuation *= plane.Normal().Dot(dir);
attenuation *= intensity;
// accumulate results
color += tl->rgb * colorAdd;
color += tl->rgb * attenuation;
tracedTexels++;
}
@ -331,9 +348,10 @@ kexVec3 kexLightmapBuilder::LightTexelSample(kexTrace &trace, const kexVec3 &ori
continue;
}
if(surfaceLight->TraceSurface(map, trace, surface, origin, &dist))
float attenuation;
if(surfaceLight->TraceSurface(map, trace, surface, origin, &attenuation))
{
color += surfaceLight->GetRGB() * kexMath::Pow(dist * surfaceLight->Intensity(), surfaceLight->FallOff());
color += surfaceLight->GetRGB() * attenuation;
tracedTexels++;
}

View file

@ -302,7 +302,7 @@ bool kexLightSurface::TraceSurface(FLevel *doomMap, kexTrace &trace, const surfa
// light surface will always be fullbright
if(surf == surface)
{
*dist = 1;
*dist = Intensity();
return true;
}
@ -426,7 +426,7 @@ bool kexLightSurface::TraceSurface(FLevel *doomMap, kexTrace &trace, const surfa
if(!bWall)
{
*dist = 1;
return true;
break;
}
}
@ -451,5 +451,6 @@ bool kexLightSurface::TraceSurface(FLevel *doomMap, kexTrace &trace, const surfa
}
}
*dist *= Intensity();
return *dist > 0;
}

View file

@ -450,6 +450,8 @@ void FLevel::CreateLights()
uint32_t lightcolor = 0xffffff;
float lightintensity = 1.0f;
float lightdistance = 0.0f;
float innerAngleCos = -1.0f;
float outerAngleCos = -1.0f;
for (unsigned int propIndex = 0; propIndex < thing->props.Size(); propIndex++)
{
@ -466,6 +468,14 @@ void FLevel::CreateLights()
{
lightdistance = atof(key.value);
}
else if (!stricmp(key.key, "lightinnerangle"))
{
innerAngleCos = std::cosf(atof(key.value) * 3.14159265359f / 180.0f);
}
else if (!stricmp(key.key, "lightouterangle"))
{
outerAngleCos = std::cosf(atof(key.value) * 3.14159265359f / 180.0f);
}
}
if (lightdistance > 0.0f && lightintensity > 0.0f && lightcolor != 0)
@ -480,7 +490,8 @@ void FLevel::CreateLights()
thingLight->rgb.y = ((lightcolor >> 8) & 0xff) / 255.0f;
thingLight->rgb.z = (lightcolor & 0xff) / 255.0f;
thingLight->intensity = lightintensity;
thingLight->falloff = 1.0f;
thingLight->innerAngleCos = max(innerAngleCos, outerAngleCos);
thingLight->outerAngleCos = outerAngleCos;
thingLight->radius = lightdistance;
thingLight->height = thing->height;
thingLight->bCeiling = false;