19 const auto fail = [](
const char*
message) {
23 if (!std::isfinite(
radius) || radius <= 0.f || radius > 1.f || !std::isfinite(
opacity) ||
opacity < 0.f ||
24 opacity > 1.f || !std::isfinite(fadeSeconds) || fadeSeconds <= 0.f || fadeSeconds > 86400.f)
25 return fail(
"Invalid diffuse rendering settings");
29 color_.size() != depth_.size() * 4)
30 return fail(
"Invalid reconstructed frame size");
31 const int renderWidth = std::max(1, (
width + foamDownsample_ - 1) / foamDownsample_);
32 const int renderHeight = std::max(1, (
height + foamDownsample_ - 1) / foamDownsample_);
33 const float tangent = std::tan(glm::radians(params_.
fovYDeg) * .5f);
34 if (!std::isfinite(
tangent) ||
tangent <= 0.f)
return fail(
"Invalid diffuse camera projection");
35 const auto view = glm::lookAtRH(params_.
eye, params_.
target, params_.
up);
37 diffuseSplats_.clear();
38 diffuseSplats_.reserve(diffuseParticles_.size());
40 for (
const auto p : diffuseParticles_) {
41 const auto v =
view * glm::vec4(glm::vec3(
p), 1.f);
42 if (!std::isfinite(
v.x) || !std::isfinite(
v.y) || !std::isfinite(
v.z))
43 return fail(
"Invalid diffuse camera transform");
46 if (
s.z <= params_.
nearZ ||
s.z >= params_.
farZ)
continue;
47 s.r = std::max(1.f,
radius *
float(renderHeight) / (2.f *
s.z *
tangent));
48 s.x = (.5f + .5f *
v.x / (
s.z *
tangent * float(renderWidth) / float(renderHeight))) * float(renderWidth);
49 s.y = (.5f - .5f *
v.y / (
s.z *
tangent)) * float(renderHeight);
50 if (!std::isfinite(
s.r) || !std::isfinite(
s.x) || !std::isfinite(
s.y))
51 return fail(
"Invalid diffuse projection");
52 if (
s.x +
s.r < 0.f ||
s.y +
s.r < 0.f ||
s.x -
s.r >=
float(renderWidth) ||
s.y -
s.r >=
float(renderHeight))
55 s.x0 = int(std::floor(std::clamp(
s.x -
s.r, 0.f,
float(renderWidth - 1))));
56 s.x1 = int(std::ceil(std::clamp(
s.x +
s.r, 0.f,
float(renderWidth - 1))));
57 s.y0 = int(std::floor(std::clamp(
s.y -
s.r, 0.f,
float(renderHeight - 1))));
58 s.y1 = int(std::ceil(std::clamp(
s.y +
s.r, 0.f,
float(renderHeight - 1))));
59 s.alpha =
opacity * std::min(1.f,
p.w / fadeSeconds);
60 visits += uint64_t(
s.x1 -
s.x0 + 1) * uint64_t(
s.y1 -
s.y0 + 1);
61 if (visits > 4000000)
return fail(
"Diffuse rendering exceeds 4M pixel visits");
62 diffuseSplats_.push_back(
s);
64 if (foamDownsample_ > 1) foamCoverageScratch_.assign(
size_t(renderWidth) *
size_t(renderHeight), 0.f);
65 for (
const auto&
s : diffuseSplats_) {
66 for (
int y =
s.y0;
y <=
s.y1; ++
y)
67 for (
int x =
s.x0;
x <=
s.x1; ++
x) {
68 const float dx = (float(
x) + .5f -
s.x) /
s.r,
dy = (
float(
y) + .5f -
s.y) /
s.r;
70 if (
q <= 0.f)
continue;
71 const size_t reducedAt = size_t(
y) * size_t(renderWidth) + size_t(
x);
72 const int fullX = std::min(
width - 1,
x *
width / renderWidth);
73 const int fullY = std::min(
height - 1,
y *
height / renderHeight);
74 const size_t at = size_t(fullY) * size_t(
width) + size_t(fullX);
75 const float front =
s.z -
radius * std::sqrt(
q);
76 const float visibility = std::clamp(1.f + (depth_[
at] - front) /
radius, 0.f, 1.f);
77 const float alpha =
s.alpha *
q *
q * visibility;
78 if (alpha <= 0.f)
continue;
79 if (foamDownsample_ > 1) {
80 foamCoverageScratch_[reducedAt] = alpha + foamCoverageScratch_[reducedAt] * (1.f - alpha);
83 const float oldAlpha = float(color_[
at * 4 + 3]) / 255.f;
84 const float retained = oldAlpha * (1.f - alpha), combined = alpha + retained;
85 for (
size_t c = 0;
c < 3; ++
c) {
86 const float color = (alpha + float(color_[
at * 4 +
c]) / 255.f * retained) / combined;
87 color_[
at * 4 +
c] = uint8_t(std::clamp(
color, 0.f, 1.f) * 255.f + .5f);
89 color_[
at * 4 + 3] = uint8_t(std::clamp(combined, 0.f, 1.f) * 255.f + .5f);
92 if (foamDownsample_ > 1) {
95 const int sx = std::min(renderWidth - 1,
x * renderWidth /
width);
96 const int sy = std::min(renderHeight - 1,
y * renderHeight /
height);
97 const float alpha = foamCoverageScratch_[size_t(
sy) * size_t(renderWidth) + size_t(
sx)];
98 if (alpha <= 0.f)
continue;
99 const size_t at = size_t(
y) * size_t(
width) + size_t(
x);
100 const float oldAlpha = float(color_[
at * 4u + 3u]) / 255.f;
101 const float retained = oldAlpha * (1.f - alpha), combined = alpha + retained;
102 for (
size_t c = 0;
c < 3; ++
c) {
103 const float value = (alpha + float(color_[
at * 4u +
c]) / 255.f * retained) / combined;
104 color_[
at * 4u +
c] = uint8_t(std::clamp(
value, 0.f, 1.f) * 255.f + .5f);
106 color_[
at * 4u + 3u] = uint8_t(std::clamp(combined, 0.f, 1.f) * 255.f + .5f);
109 residentColorCurrent_ =
false;
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.