mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-25 05:21:02 +00:00
Add attenuated point lights
This commit is contained in:
parent
c0e91086ce
commit
c61e9c7fe2
9 changed files with 80 additions and 14 deletions
|
@ -102,6 +102,7 @@ namespace swrenderer
|
||||||
uint8_t *dc_destorg;
|
uint8_t *dc_destorg;
|
||||||
int dc_destheight;
|
int dc_destheight;
|
||||||
int dc_count;
|
int dc_count;
|
||||||
|
FVector3 dc_normal;
|
||||||
FVector3 dc_viewpos;
|
FVector3 dc_viewpos;
|
||||||
FVector3 dc_viewpos_step;
|
FVector3 dc_viewpos_step;
|
||||||
TriLight *dc_lights;
|
TriLight *dc_lights;
|
||||||
|
|
|
@ -66,6 +66,7 @@ namespace swrenderer
|
||||||
extern uint8_t *dc_destorg;
|
extern uint8_t *dc_destorg;
|
||||||
extern int dc_destheight;
|
extern int dc_destheight;
|
||||||
extern int dc_count;
|
extern int dc_count;
|
||||||
|
extern FVector3 dc_normal;
|
||||||
extern FVector3 dc_viewpos;
|
extern FVector3 dc_viewpos;
|
||||||
extern FVector3 dc_viewpos_step;
|
extern FVector3 dc_viewpos_step;
|
||||||
extern TriLight *dc_lights;
|
extern TriLight *dc_lights;
|
||||||
|
|
|
@ -128,12 +128,21 @@ namespace swrenderer
|
||||||
|
|
||||||
// L = light-pos
|
// L = light-pos
|
||||||
// dist = sqrt(dot(L, L))
|
// 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 Lxy2 = lights[i].x; // L.x*L.x + L.y*L.y
|
||||||
float Lz = lights[i].z - viewpos_z;
|
float Lz = lights[i].z - viewpos_z;
|
||||||
float dist2 = Lxy2 + Lz * Lz;
|
float dist2 = Lxy2 + Lz * Lz;
|
||||||
float dist = dist2 * _mm_cvtss_f32(_mm_rsqrt_ss(_mm_load_ss(&dist2)));
|
float rcp_dist = _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 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_r += (light_color_r * material_r * attenuation) >> 16;
|
||||||
lit_g += (light_color_g * material_g * 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 Lyz2 = lights[i].y; // L.y*L.y + L.z*L.z
|
||||||
float Lx = lights[i].x - viewpos_x;
|
float Lx = lights[i].x - viewpos_x;
|
||||||
float dist2 = Lyz2 + Lx * Lx;
|
float dist2 = Lyz2 + Lx * Lx;
|
||||||
float dist = dist2 * _mm_cvtss_f32(_mm_rsqrt_ss(_mm_load_ss(&dist2)));
|
float rcp_dist = _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 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_r += (light_color_r * material_r * attenuation) >> 16;
|
||||||
lit_g += (light_color_g * material_g * attenuation) >> 16;
|
lit_g += (light_color_g * material_g * attenuation) >> 16;
|
||||||
|
|
|
@ -227,11 +227,13 @@ namespace swrenderer
|
||||||
float lz = (float)lightZ;
|
float lz = (float)lightZ;
|
||||||
|
|
||||||
// Precalculate the constant part of the dot here so the drawer doesn't have to.
|
// 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 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
|
// Include light only if it touches this column
|
||||||
float radius = cur_node->lightsource->GetRadius();
|
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 red = cur_node->lightsource->GetRed();
|
||||||
uint32_t green = cur_node->lightsource->GetGreen();
|
uint32_t green = cur_node->lightsource->GetGreen();
|
||||||
|
@ -240,6 +242,7 @@ namespace swrenderer
|
||||||
nextlightindex++;
|
nextlightindex++;
|
||||||
auto &light = dc_lights[dc_num_lights++];
|
auto &light = dc_lights[dc_num_lights++];
|
||||||
light.x = lconstant;
|
light.x = lconstant;
|
||||||
|
light.y = nlconstant;
|
||||||
light.z = lz;
|
light.z = lz;
|
||||||
light.radius = 256.0f / cur_node->lightsource->GetRadius();
|
light.radius = 256.0f / cur_node->lightsource->GetRadius();
|
||||||
light.color = (red << 16) | (green << 8) | blue;
|
light.color = (red << 16) | (green << 8) | blue;
|
||||||
|
@ -365,6 +368,13 @@ namespace swrenderer
|
||||||
else
|
else
|
||||||
R_SetColorMapLight(basecolormap, 0, 0);
|
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;
|
float light = rw_light;
|
||||||
|
|
||||||
double xmagnitude = 1.0;
|
double xmagnitude = 1.0;
|
||||||
|
|
|
@ -256,7 +256,12 @@ namespace swrenderer
|
||||||
static TriLight lightbuffer[64 * 1024];
|
static TriLight lightbuffer[64 * 1024];
|
||||||
static int nextlightindex = 0;
|
static int nextlightindex = 0;
|
||||||
|
|
||||||
// Setup lights for column
|
// Plane normal
|
||||||
|
dc_normal.X = 0.0f;
|
||||||
|
dc_normal.Y = 0.0f;
|
||||||
|
dc_normal.Z = (y >= CenterY) ? 1.0f : -1.0f;
|
||||||
|
|
||||||
|
// Setup lights for row
|
||||||
dc_num_lights = 0;
|
dc_num_lights = 0;
|
||||||
dc_lights = lightbuffer + nextlightindex;
|
dc_lights = lightbuffer + nextlightindex;
|
||||||
visplane_light *cur_node = ds_light_list;
|
visplane_light *cur_node = ds_light_list;
|
||||||
|
@ -271,11 +276,13 @@ namespace swrenderer
|
||||||
float lz = (float)lightZ - dc_viewpos.Z;
|
float lz = (float)lightZ - dc_viewpos.Z;
|
||||||
|
|
||||||
// Precalculate the constant part of the dot here so the drawer doesn't have to.
|
// 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 lconstant = ly * ly + lz * lz;
|
||||||
|
float nlconstant = is_point_light ? lz * dc_normal.Z : 0.0f;
|
||||||
|
|
||||||
// Include light only if it touches this row
|
// Include light only if it touches this row
|
||||||
float radius = cur_node->lightsource->GetRadius();
|
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 red = cur_node->lightsource->GetRed();
|
||||||
uint32_t green = cur_node->lightsource->GetGreen();
|
uint32_t green = cur_node->lightsource->GetGreen();
|
||||||
|
@ -285,6 +292,7 @@ namespace swrenderer
|
||||||
auto &light = dc_lights[dc_num_lights++];
|
auto &light = dc_lights[dc_num_lights++];
|
||||||
light.x = lx;
|
light.x = lx;
|
||||||
light.y = lconstant;
|
light.y = lconstant;
|
||||||
|
light.z = nlconstant;
|
||||||
light.radius = 256.0f / radius;
|
light.radius = 256.0f / radius;
|
||||||
light.color = (red << 16) | (green << 8) | blue;
|
light.color = (red << 16) | (green << 8) | blue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -248,7 +248,7 @@ SSAVec4i DrawSpanCodegen::Shade(SSAVec4i fg, bool isSimpleShade)
|
||||||
SSAVec4i light_color = SSAUBytePtr(SSAValue(dynlights[light_index][0]).v).load_vec4ub(true);
|
SSAVec4i light_color = SSAUBytePtr(SSAValue(dynlights[light_index][0]).v).load_vec4ub(true);
|
||||||
SSAFloat light_x = dynlights[light_index][1].load(true);
|
SSAFloat light_x = dynlights[light_index][1].load(true);
|
||||||
SSAFloat light_y = dynlights[light_index][2].load(true);
|
SSAFloat light_y = dynlights[light_index][2].load(true);
|
||||||
//SSAFloat light_z = dynlights[light_index][3].load(true);
|
SSAFloat light_z = dynlights[light_index][3].load(true);
|
||||||
SSAFloat light_rcp_radius = dynlights[light_index][4].load(true);
|
SSAFloat light_rcp_radius = dynlights[light_index][4].load(true);
|
||||||
|
|
||||||
// L = light-pos
|
// L = light-pos
|
||||||
|
@ -256,8 +256,19 @@ SSAVec4i DrawSpanCodegen::Shade(SSAVec4i fg, bool isSimpleShade)
|
||||||
// attenuation = 1 - MIN(dist * (1/radius), 1)
|
// attenuation = 1 - MIN(dist * (1/radius), 1)
|
||||||
SSAFloat Lyz2 = light_y; // L.y*L.y + L.z*L.z
|
SSAFloat Lyz2 = light_y; // L.y*L.y + L.z*L.z
|
||||||
SSAFloat Lx = light_x - viewpos_x;
|
SSAFloat Lx = light_x - viewpos_x;
|
||||||
SSAFloat dist = SSAFloat::fastsqrt(Lyz2 + Lx * Lx);
|
SSAFloat dist2 = Lyz2 + Lx * Lx;
|
||||||
SSAInt attenuation = SSAInt(SSAFloat(256.0f) - SSAFloat::MIN(dist * light_rcp_radius, SSAFloat(256.0f)), true);
|
SSAFloat rcp_dist = SSAFloat::rsqrt(dist2);
|
||||||
|
SSAFloat dist = dist2 * rcp_dist;
|
||||||
|
SSAFloat distance_attenuation = SSAFloat(256.0f) - SSAFloat::MIN(dist * light_rcp_radius, SSAFloat(256.0f));
|
||||||
|
|
||||||
|
// The simple light type
|
||||||
|
SSAFloat simple_attenuation = distance_attenuation;
|
||||||
|
|
||||||
|
// The point light type
|
||||||
|
// diffuse = dot(N,L) * attenuation
|
||||||
|
SSAFloat point_attenuation = light_z * rcp_dist * distance_attenuation;
|
||||||
|
|
||||||
|
SSAInt attenuation = SSAInt((light_z == SSAFloat(0.0f)).select(simple_attenuation, point_attenuation), true);
|
||||||
SSAVec4i contribution = (light_color * fg * attenuation) >> 16;
|
SSAVec4i contribution = (light_color * fg * attenuation) >> 16;
|
||||||
|
|
||||||
stack_lit_color.store(lit_color + contribution);
|
stack_lit_color.store(lit_color + contribution);
|
||||||
|
|
|
@ -179,7 +179,7 @@ SSAVec4i DrawWallCodegen::Shade(SSAVec4i fg, bool isSimpleShade)
|
||||||
{
|
{
|
||||||
SSAVec4i light_color = SSAUBytePtr(SSAValue(dynlights[light_index][0]).v).load_vec4ub(true);
|
SSAVec4i light_color = SSAUBytePtr(SSAValue(dynlights[light_index][0]).v).load_vec4ub(true);
|
||||||
SSAFloat light_x = dynlights[light_index][1].load(true);
|
SSAFloat light_x = dynlights[light_index][1].load(true);
|
||||||
//SSAFloat light_y = dynlights[light_index][2].load(true);
|
SSAFloat light_y = dynlights[light_index][2].load(true);
|
||||||
SSAFloat light_z = dynlights[light_index][3].load(true);
|
SSAFloat light_z = dynlights[light_index][3].load(true);
|
||||||
SSAFloat light_rcp_radius = dynlights[light_index][4].load(true);
|
SSAFloat light_rcp_radius = dynlights[light_index][4].load(true);
|
||||||
|
|
||||||
|
@ -188,8 +188,19 @@ SSAVec4i DrawWallCodegen::Shade(SSAVec4i fg, bool isSimpleShade)
|
||||||
// attenuation = 1 - MIN(dist * (1/radius), 1)
|
// attenuation = 1 - MIN(dist * (1/radius), 1)
|
||||||
SSAFloat Lxy2 = light_x; // L.x*L.x + L.y*L.y
|
SSAFloat Lxy2 = light_x; // L.x*L.x + L.y*L.y
|
||||||
SSAFloat Lz = light_z - z;
|
SSAFloat Lz = light_z - z;
|
||||||
SSAFloat dist = SSAFloat::fastsqrt(Lxy2 + Lz * Lz);
|
SSAFloat dist2 = Lxy2 + Lz * Lz;
|
||||||
SSAInt attenuation = SSAInt(SSAFloat(256.0f) - SSAFloat::MIN(dist * light_rcp_radius, SSAFloat(256.0f)), true);
|
SSAFloat rcp_dist = SSAFloat::rsqrt(dist2);
|
||||||
|
SSAFloat dist = dist2 * rcp_dist;
|
||||||
|
SSAFloat distance_attenuation = SSAFloat(256.0f) - SSAFloat::MIN(dist * light_rcp_radius, SSAFloat(256.0f));
|
||||||
|
|
||||||
|
// The simple light type
|
||||||
|
SSAFloat simple_attenuation = distance_attenuation;
|
||||||
|
|
||||||
|
// The point light type
|
||||||
|
// diffuse = dot(N,L) * attenuation
|
||||||
|
SSAFloat point_attenuation = light_y * rcp_dist * distance_attenuation;
|
||||||
|
|
||||||
|
SSAInt attenuation = SSAInt((light_y == SSAFloat(0.0f)).select(simple_attenuation, point_attenuation), true);
|
||||||
SSAVec4i contribution = (light_color * fg * attenuation) >> 16;
|
SSAVec4i contribution = (light_color * fg * attenuation) >> 16;
|
||||||
|
|
||||||
stack_lit_color.store(lit_color + contribution);
|
stack_lit_color.store(lit_color + contribution);
|
||||||
|
|
|
@ -58,6 +58,11 @@ SSAInt SSABool::select(SSAInt a, SSAInt b)
|
||||||
return SSAValue::from_llvm(SSAScope::builder().CreateSelect(v, a.v, b.v, SSAScope::hint()));
|
return SSAValue::from_llvm(SSAScope::builder().CreateSelect(v, a.v, b.v, SSAScope::hint()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SSAFloat SSABool::select(SSAFloat a, SSAFloat b)
|
||||||
|
{
|
||||||
|
return SSAValue::from_llvm(SSAScope::builder().CreateSelect(v, a.v, b.v, SSAScope::hint()));
|
||||||
|
}
|
||||||
|
|
||||||
SSAUByte SSABool::select(SSAUByte a, SSAUByte b)
|
SSAUByte SSABool::select(SSAUByte a, SSAUByte b)
|
||||||
{
|
{
|
||||||
return SSAValue::from_llvm(SSAScope::builder().CreateSelect(v, a.v, b.v, SSAScope::hint()));
|
return SSAValue::from_llvm(SSAScope::builder().CreateSelect(v, a.v, b.v, SSAScope::hint()));
|
||||||
|
|
|
@ -42,6 +42,7 @@ public:
|
||||||
|
|
||||||
SSAInt zext_int();
|
SSAInt zext_int();
|
||||||
SSAInt select(SSAInt a, SSAInt b);
|
SSAInt select(SSAInt a, SSAInt b);
|
||||||
|
SSAFloat select(SSAFloat a, SSAFloat b);
|
||||||
SSAUByte select(SSAUByte a, SSAUByte b);
|
SSAUByte select(SSAUByte a, SSAUByte b);
|
||||||
SSAVec4i select(SSAVec4i a, SSAVec4i b);
|
SSAVec4i select(SSAVec4i a, SSAVec4i b);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue