Add attenuated point lights

This commit is contained in:
Magnus Norddahl 2017-01-02 06:52:50 +01:00
commit c61e9c7fe2
9 changed files with 80 additions and 14 deletions

View file

@ -102,6 +102,7 @@ namespace swrenderer
uint8_t *dc_destorg;
int dc_destheight;
int dc_count;
FVector3 dc_normal;
FVector3 dc_viewpos;
FVector3 dc_viewpos_step;
TriLight *dc_lights;

View file

@ -66,6 +66,7 @@ namespace swrenderer
extern uint8_t *dc_destorg;
extern int dc_destheight;
extern int dc_count;
extern FVector3 dc_normal;
extern FVector3 dc_viewpos;
extern FVector3 dc_viewpos_step;
extern TriLight *dc_lights;

View file

@ -128,12 +128,21 @@ namespace swrenderer
// L = light-pos
// dist = sqrt(dot(L, L))
// attenuation = 1 - MIN(dist * (1/radius), 1)
// distance_attenuation = 1 - MIN(dist * (1/radius), 1)
float Lxy2 = lights[i].x; // L.x*L.x + L.y*L.y
float Lz = lights[i].z - viewpos_z;
float dist2 = Lxy2 + Lz * Lz;
float dist = dist2 * _mm_cvtss_f32(_mm_rsqrt_ss(_mm_load_ss(&dist2)));
uint32_t attenuation = (uint32_t)(256.0f - MIN(dist * lights[i].radius, 256.0f));
float rcp_dist = _mm_cvtss_f32(_mm_rsqrt_ss(_mm_load_ss(&dist2)));
float dist = dist2 * rcp_dist;
float distance_attenuation = (256.0f - MIN(dist * lights[i].radius, 256.0f));
// The simple light type
float simple_attenuation = distance_attenuation;
// The point light type
// diffuse = dot(N,L) * attenuation
float point_attenuation = lights[i].y * rcp_dist * distance_attenuation;
uint32_t attenuation = (uint32_t)(lights[i].y == 0.0f ? simple_attenuation : point_attenuation);
lit_r += (light_color_r * material_r * attenuation) >> 16;
lit_g += (light_color_g * material_g * attenuation) >> 16;
@ -1733,8 +1742,17 @@ namespace swrenderer
float Lyz2 = lights[i].y; // L.y*L.y + L.z*L.z
float Lx = lights[i].x - viewpos_x;
float dist2 = Lyz2 + Lx * Lx;
float dist = dist2 * _mm_cvtss_f32(_mm_rsqrt_ss(_mm_load_ss(&dist2)));
uint32_t attenuation = (uint32_t)(256.0f - MIN(dist * lights[i].radius, 256.0f));
float rcp_dist = _mm_cvtss_f32(_mm_rsqrt_ss(_mm_load_ss(&dist2)));
float dist = dist2 * rcp_dist;
float distance_attenuation = (256.0f - MIN(dist * lights[i].radius, 256.0f));
// The simple light type
float simple_attenuation = distance_attenuation;
// The point light type
// diffuse = dot(N,L) * attenuation
float point_attenuation = lights[i].z * rcp_dist * distance_attenuation;
uint32_t attenuation = (uint32_t)(lights[i].z == 0.0f ? simple_attenuation : point_attenuation);
lit_r += (light_color_r * material_r * attenuation) >> 16;
lit_g += (light_color_g * material_g * attenuation) >> 16;

View file

@ -227,11 +227,13 @@ namespace swrenderer
float lz = (float)lightZ;
// Precalculate the constant part of the dot here so the drawer doesn't have to.
bool is_point_light = (cur_node->lightsource->flags4 & MF4_ATTENUATE) != 0;
float lconstant = lx * lx + ly * ly;
float nlconstant = is_point_light ? lx * dc_normal.X + ly * dc_normal.Y : 0.0f;
// Include light only if it touches this column
float radius = cur_node->lightsource->GetRadius();
if (radius * radius >= lconstant)
if (radius * radius >= lconstant && nlconstant >= 0.0f)
{
uint32_t red = cur_node->lightsource->GetRed();
uint32_t green = cur_node->lightsource->GetGreen();
@ -240,6 +242,7 @@ namespace swrenderer
nextlightindex++;
auto &light = dc_lights[dc_num_lights++];
light.x = lconstant;
light.y = nlconstant;
light.z = lz;
light.radius = 256.0f / cur_node->lightsource->GetRadius();
light.color = (red << 16) | (green << 8) | blue;
@ -365,6 +368,13 @@ namespace swrenderer
else
R_SetColorMapLight(basecolormap, 0, 0);
float dx = WallC.tright.X - WallC.tleft.X;
float dy = WallC.tright.Y - WallC.tleft.Y;
float length = sqrt(dx * dx + dy * dy);
dc_normal.X = dy / length;
dc_normal.Y = -dx / length;
dc_normal.Z = 0.0f;
float light = rw_light;
double xmagnitude = 1.0;

View file

@ -255,8 +255,13 @@ namespace swrenderer
static TriLight lightbuffer[64 * 1024];
static int nextlightindex = 0;
// Plane normal
dc_normal.X = 0.0f;
dc_normal.Y = 0.0f;
dc_normal.Z = (y >= CenterY) ? 1.0f : -1.0f;
// Setup lights for column
// Setup lights for row
dc_num_lights = 0;
dc_lights = lightbuffer + nextlightindex;
visplane_light *cur_node = ds_light_list;
@ -271,11 +276,13 @@ namespace swrenderer
float lz = (float)lightZ - dc_viewpos.Z;
// Precalculate the constant part of the dot here so the drawer doesn't have to.
bool is_point_light = (cur_node->lightsource->flags4 & MF4_ATTENUATE) != 0;
float lconstant = ly * ly + lz * lz;
float nlconstant = is_point_light ? lz * dc_normal.Z : 0.0f;
// Include light only if it touches this row
float radius = cur_node->lightsource->GetRadius();
if (radius * radius >= lconstant)
if (radius * radius >= lconstant && nlconstant >= 0.0f)
{
uint32_t red = cur_node->lightsource->GetRed();
uint32_t green = cur_node->lightsource->GetGreen();
@ -285,6 +292,7 @@ namespace swrenderer
auto &light = dc_lights[dc_num_lights++];
light.x = lx;
light.y = lconstant;
light.z = nlconstant;
light.radius = 256.0f / radius;
light.color = (red << 16) | (green << 8) | blue;
}