diff options
author | Kae <80987908+Novaenia@users.noreply.github.com> | 2024-03-20 01:53:34 +1100 |
---|---|---|
committer | Kae <80987908+Novaenia@users.noreply.github.com> | 2024-03-20 01:53:34 +1100 |
commit | 6d76a11e256cd96c9cdd7ae5a10c0276e6347277 (patch) | |
tree | d52459889408115d1e0eb657a05dc58e098e50eb /source/base/StarCellularLightArray.cpp | |
parent | 58a346e563df12af9194c198c7ffe974411abb28 (diff) |
experiment: unclamped lighting
Diffstat (limited to 'source/base/StarCellularLightArray.cpp')
-rw-r--r-- | source/base/StarCellularLightArray.cpp | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/source/base/StarCellularLightArray.cpp b/source/base/StarCellularLightArray.cpp new file mode 100644 index 0000000..60a6d95 --- /dev/null +++ b/source/base/StarCellularLightArray.cpp @@ -0,0 +1,130 @@ +#include "StarCellularLightArray.hpp" +// just specializing these in a cpp file so I can iterate on them without recompiling like 40 files!! + +namespace Star { + +template <> +void CellularLightArray<ScalarLightTraits>::calculatePointLighting(size_t xmin, size_t ymin, size_t xmax, size_t ymax) { + float perBlockObstacleAttenuation = 1.0f / m_pointMaxObstacle; + float perBlockAirAttenuation = 1.0f / m_pointMaxAir; + + for (PointLight light : m_pointLights) { + if (light.position[0] < 0 || light.position[0] > m_width - 1 || light.position[1] < 0 || light.position[1] > m_height - 1) + continue; + + float maxIntensity = ScalarLightTraits::maxIntensity(light.value); + Vec2F beamDirection = Vec2F(1, 0).rotate(light.beamAngle); + + float maxRange = maxIntensity * m_pointMaxAir; + // The min / max considering the radius of the light + size_t lxmin = std::floor(std::max<float>(xmin, light.position[0] - maxRange)); + size_t lymin = std::floor(std::max<float>(ymin, light.position[1] - maxRange)); + size_t lxmax = std::ceil(std::min<float>(xmax, light.position[0] + maxRange)); + size_t lymax = std::ceil(std::min<float>(ymax, light.position[1] + maxRange)); + + for (size_t x = lxmin; x < lxmax; ++x) { + for (size_t y = lymin; y < lymax; ++y) { + LightValue lvalue = getLight(x, y); + // + 0.5f to correct block position to center + Vec2F blockPos = Vec2F(x + 0.5f, y + 0.5f); + + Vec2F relativeLightPosition = blockPos - light.position; + float distance = relativeLightPosition.magnitude(); + if (distance == 0.0f) { + setLight(x, y, light.value + lvalue); + continue; + } + + float attenuation = distance * perBlockAirAttenuation; + if (attenuation >= 1.0f) + continue; + + Vec2F direction = relativeLightPosition / distance; + if (light.beam > 0.0f) { + attenuation += (1.0f - light.beamAmbience) * clamp(light.beam * (1.0f - direction * beamDirection), 0.0f, 1.0f); + if (attenuation >= 1.0f) + continue; + } + + float remainingAttenuation = maxIntensity - attenuation; + if (remainingAttenuation <= 0.0f) + continue; + + // Need to circularize manhattan attenuation here + float circularizedPerBlockObstacleAttenuation = perBlockObstacleAttenuation / max(fabs(direction[0]), fabs(direction[1])); + float blockAttenuation = lineAttenuation(blockPos, light.position, circularizedPerBlockObstacleAttenuation, remainingAttenuation); + + // Apply single obstacle boost (determine single obstacle by one + // block unit of attenuation). + attenuation += blockAttenuation + min(blockAttenuation, circularizedPerBlockObstacleAttenuation) * m_pointObstacleBoost; + + if (attenuation < 1.0f) + setLight(x, y, lvalue + ScalarLightTraits::subtract(light.value, attenuation)); + } + } + } +} + +template <> +void CellularLightArray<ColoredLightTraits>::calculatePointLighting(size_t xmin, size_t ymin, size_t xmax, size_t ymax) { + float perBlockObstacleAttenuation = 1.0f / m_pointMaxObstacle; + float perBlockAirAttenuation = 1.0f / m_pointMaxAir; + + for (PointLight light : m_pointLights) { + if (light.position[0] < 0 || light.position[0] > m_width - 1 || light.position[1] < 0 || light.position[1] > m_height - 1) + continue; + + float maxIntensity = ColoredLightTraits::maxIntensity(light.value); + Vec2F beamDirection = Vec2F(1, 0).rotate(light.beamAngle); + + float maxRange = maxIntensity * m_pointMaxAir; + // The min / max considering the radius of the light + size_t lxmin = std::floor(std::max<float>(xmin, light.position[0] - maxRange)); + size_t lymin = std::floor(std::max<float>(ymin, light.position[1] - maxRange)); + size_t lxmax = std::ceil(std::min<float>(xmax, light.position[0] + maxRange)); + size_t lymax = std::ceil(std::min<float>(ymax, light.position[1] + maxRange)); + + for (size_t x = lxmin; x < lxmax; ++x) { + for (size_t y = lymin; y < lymax; ++y) { + LightValue lvalue = getLight(x, y); + // + 0.5f to correct block position to center + Vec2F blockPos = Vec2F(x + 0.5f, y + 0.5f); + + Vec2F relativeLightPosition = blockPos - light.position; + float distance = relativeLightPosition.magnitude(); + if (distance == 0.0f) { + setLight(x, y, light.value + lvalue); + continue; + } + + float attenuation = distance * perBlockAirAttenuation; + if (attenuation >= 1.0f) + continue; + + Vec2F direction = relativeLightPosition / distance; + if (light.beam > 0.0f) { + attenuation += (1.0f - light.beamAmbience) * clamp(light.beam * (1.0f - direction * beamDirection), 0.0f, 1.0f); + if (attenuation >= 1.0f) + continue; + } + + float remainingAttenuation = maxIntensity - attenuation; + if (remainingAttenuation <= 0.0f) + continue; + + // Need to circularize manhattan attenuation here + float circularizedPerBlockObstacleAttenuation = perBlockObstacleAttenuation / max(fabs(direction[0]), fabs(direction[1])); + float blockAttenuation = lineAttenuation(blockPos, light.position, circularizedPerBlockObstacleAttenuation, remainingAttenuation); + + // Apply single obstacle boost (determine single obstacle by one + // block unit of attenuation). + attenuation += blockAttenuation + min(blockAttenuation, circularizedPerBlockObstacleAttenuation) * m_pointObstacleBoost; + + if (attenuation < 1.0f) + setLight(x, y, lvalue + ColoredLightTraits::subtract(light.value, attenuation)); + } + } + } +} + +}
\ No newline at end of file |