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

View file

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

View file

@ -158,6 +158,8 @@ fixed_t CheckFixed(const char *key)
void FProcessor::ParseThing(IntThing *th) void FProcessor::ParseThing(IntThing *th)
{ {
th->pitch = 0;
SC_MustGetStringName("{"); SC_MustGetStringName("{");
while (!SC_CheckString("}")) while (!SC_CheckString("}"))
{ {
@ -179,6 +181,10 @@ void FProcessor::ParseThing(IntThing *th)
{ {
th->angle = (short)CheckInt(key); th->angle = (short)CheckInt(key);
} }
if (!stricmp(key, "pitch"))
{
th->pitch = (short)CheckInt(key);
}
if (!stricmp(key, "type")) if (!stricmp(key, "type"))
{ {
th->type = (short)CheckInt(key); 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 // 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 kexLightmapBuilder::LightTexelSample(kexTrace &trace, const kexVec3 &origin, surface_t *surface)
{ {
kexVec3 lightOrigin; kexPlane plane = surface->plane;
kexVec3 dir; kexVec3 color(0.0f, 0.0f, 0.0f);
kexVec3 color;
kexPlane plane;
float dist;
float radius;
float intensity;
float colorAdd;
plane = surface->plane;
color.Clear();
// check all thing lights // check all thing lights
for(unsigned int i = 0; i < map->thingLights.Size(); i++) for(unsigned int i = 0; i < map->thingLights.Size(); i++)
@ -263,11 +266,13 @@ kexVec3 kexLightmapBuilder::LightTexelSample(kexTrace &trace, const kexVec3 &ori
continue; continue;
} }
lightOrigin.Set(tl->origin.x, float originZ;
tl->origin.y, if (!tl->bCeiling)
!tl->bCeiling ? originZ = tl->sector->floorplane.zAt(tl->origin.x, tl->origin.y) + tl->height;
tl->sector->data.floorheight + tl->height : else
tl->sector->data.ceilingheight - tl->height); 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) if(plane.Distance(lightOrigin) - plane.d < 0)
{ {
@ -275,8 +280,8 @@ kexVec3 kexLightmapBuilder::LightTexelSample(kexTrace &trace, const kexVec3 &ori
continue; continue;
} }
radius = tl->radius; float radius = tl->radius;
intensity = tl->intensity; float intensity = tl->intensity;
if(origin.DistanceSq(lightOrigin) > (radius*radius)) if(origin.DistanceSq(lightOrigin) > (radius*radius))
{ {
@ -284,6 +289,28 @@ kexVec3 kexLightmapBuilder::LightTexelSample(kexTrace &trace, const kexVec3 &ori
continue; 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); trace.Trace(lightOrigin, origin);
if(trace.fraction != 1) if(trace.fraction != 1)
@ -292,23 +319,13 @@ kexVec3 kexLightmapBuilder::LightTexelSample(kexTrace &trace, const kexVec3 &ori
continue; continue;
} }
dir = (lightOrigin - origin); float attenuation = 1.0f - (dist / radius);
dist = dir.Unit(); attenuation *= spotAttenuation;
attenuation *= plane.Normal().Dot(dir);
dir.Normalize(); attenuation *= intensity;
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);
}
// accumulate results // accumulate results
color += tl->rgb * colorAdd; color += tl->rgb * attenuation;
tracedTexels++; tracedTexels++;
} }
@ -331,9 +348,10 @@ kexVec3 kexLightmapBuilder::LightTexelSample(kexTrace &trace, const kexVec3 &ori
continue; 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++; tracedTexels++;
} }

View file

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

View file

@ -450,6 +450,8 @@ void FLevel::CreateLights()
uint32_t lightcolor = 0xffffff; uint32_t lightcolor = 0xffffff;
float lightintensity = 1.0f; float lightintensity = 1.0f;
float lightdistance = 0.0f; float lightdistance = 0.0f;
float innerAngleCos = -1.0f;
float outerAngleCos = -1.0f;
for (unsigned int propIndex = 0; propIndex < thing->props.Size(); propIndex++) for (unsigned int propIndex = 0; propIndex < thing->props.Size(); propIndex++)
{ {
@ -466,6 +468,14 @@ void FLevel::CreateLights()
{ {
lightdistance = atof(key.value); 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) 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.y = ((lightcolor >> 8) & 0xff) / 255.0f;
thingLight->rgb.z = (lightcolor & 0xff) / 255.0f; thingLight->rgb.z = (lightcolor & 0xff) / 255.0f;
thingLight->intensity = lightintensity; thingLight->intensity = lightintensity;
thingLight->falloff = 1.0f; thingLight->innerAngleCos = max(innerAngleCos, outerAngleCos);
thingLight->outerAngleCos = outerAngleCos;
thingLight->radius = lightdistance; thingLight->radius = lightdistance;
thingLight->height = thing->height; thingLight->height = thing->height;
thingLight->bCeiling = false; thingLight->bCeiling = false;