-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRayTracerTypes.cppm
More file actions
263 lines (238 loc) · 8.82 KB
/
Copy pathRayTracerTypes.cppm
File metadata and controls
263 lines (238 loc) · 8.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
module;
#include <algorithm>
#include <cmath>
#include <cstdint>
#include <limits>
#include <stdexcept>
#include <string>
export module Kairo.Foundation.RayTracer.Types;
import Kairo.Foundation.Math.Vector;
import Kairo.Foundation.RayTracer.Color;
export namespace kairo::foundation::raytracer
{
using namespace kairo::foundation::math;
enum class RenderMode : std::uint8_t
{
Normal,
Depth,
Whitted,
ShadowMask,
BVHHeatmap,
Albedo,
PrimitiveID,
UV,
Barycentric,
AccelerationDifference,
PBR,
Path
};
enum class AccelerationMode : std::uint8_t
{
BruteForce,
BVHSAH,
BVHMorton
};
// Matches the authored EngineCore environment contract. Fog is applied to
// primary beauty rays at the renderer boundary so every beauty integrator
// observes identical distance semantics without modifying recursive bounces.
enum class FogMode : std::uint8_t
{
Disabled,
Linear,
Exponential
};
struct RenderSettings final
{
std::uint32_t Width = 800;
std::uint32_t Height = 600;
std::uint32_t SamplesPerPixel = 1;
std::uint32_t MaxDepth = 4;
std::uint32_t TileSize = 16;
std::uint32_t ThreadCount = 0;
std::uint32_t SampleSeed = 0;
float DepthNear = 0.1f;
float DepthFar = 25.0f;
float RayBiasAbsolute = 1.0e-4f;
float RayBiasRelative = 1.0e-4f;
float MinimumLightDistanceSquared = 0.35f;
RenderMode Mode = RenderMode::Whitted;
AccelerationMode Acceleration = AccelerationMode::BVHSAH;
Color3f Background = { 0.02f, 0.03f, 0.05f };
FogMode Fog = FogMode::Disabled;
Color3f FogColor = { 0.5f, 0.5f, 0.5f };
float FogDensity = 0.01f;
float FogNear = 0.0f;
float FogFar = 100.0f;
};
inline void ValidateRenderSettings(
const RenderSettings& settings)
{
if (settings.Width == 0)
throw std::invalid_argument("Render width must be greater than zero.");
if (settings.Height == 0)
throw std::invalid_argument("Render height must be greater than zero.");
if (settings.SamplesPerPixel == 0)
throw std::invalid_argument("SamplesPerPixel must be greater than zero.");
if (settings.TileSize == 0)
throw std::invalid_argument("TileSize must be greater than zero.");
if (settings.DepthFar <= settings.DepthNear)
throw std::invalid_argument("DepthFar must be greater than DepthNear.");
if (settings.Width > 32768u || settings.Height > 32768u)
throw std::invalid_argument("Render dimensions are too large; maximum supported width/height is 32768.");
if (settings.SamplesPerPixel > 4096u)
throw std::invalid_argument("SamplesPerPixel is too large; maximum supported value is 4096.");
if (settings.TileSize > 4096u)
throw std::invalid_argument("TileSize is too large; maximum supported value is 4096.");
if (settings.MaxDepth > 64u)
throw std::invalid_argument("MaxDepth is too large; maximum supported value is 64.");
if (settings.ThreadCount > 1024u)
throw std::invalid_argument("ThreadCount is too large; maximum supported value is 1024.");
if (!std::isfinite(settings.FogDensity) || settings.FogDensity < 0.0f)
throw std::invalid_argument("FogDensity must be finite and non-negative.");
if (!std::isfinite(settings.FogNear) || !std::isfinite(settings.FogFar))
throw std::invalid_argument("FogNear and FogFar must be finite.");
if (settings.Fog == FogMode::Linear && settings.FogFar <= settings.FogNear)
throw std::invalid_argument("Linear fog requires FogFar greater than FogNear.");
}
[[nodiscard]]
inline float FogAmount(
const RenderSettings& settings,
float distance) noexcept
{
if (settings.Fog == FogMode::Disabled)
return 0.0f;
if (!std::isfinite(distance))
return 1.0f;
const float clampedDistance = std::max(distance, 0.0f);
if (settings.Fog == FogMode::Linear)
{
const float span = std::max(settings.FogFar - settings.FogNear, 1.0e-6f);
return std::clamp((clampedDistance - settings.FogNear) / span, 0.0f, 1.0f);
}
return std::clamp(
1.0f - std::exp(-settings.FogDensity * clampedDistance),
0.0f,
1.0f);
}
[[nodiscard]]
inline Color3f ApplyFog(
const RenderSettings& settings,
const Color3f& surface,
float distance) noexcept
{
const float amount = FogAmount(settings, distance);
return surface * (1.0f - amount) + settings.FogColor * amount;
}
struct RenderStats final
{
std::uint64_t PrimaryRays = 0;
std::uint64_t ShadowRays = 0;
std::uint64_t ReflectionRays = 0;
std::uint64_t HitCount = 0;
std::uint64_t MissCount = 0;
std::uint64_t BVHVisitedNodes = 0;
std::uint64_t BVHTestedPrimitives = 0;
std::uint32_t MaxRecursionDepthReached = 0;
double RenderMilliseconds = 0.0;
double RaysPerSecond = 0.0;
double PrimitiveTestsPerRay = 0.0;
double NodesVisitedPerRay = 0.0;
};
[[nodiscard]]
inline std::uint64_t TotalRays(
const RenderStats& stats) noexcept
{
return stats.PrimaryRays + stats.ShadowRays + stats.ReflectionRays;
}
inline void Accumulate(
RenderStats& target,
const RenderStats& source) noexcept
{
target.PrimaryRays += source.PrimaryRays;
target.ShadowRays += source.ShadowRays;
target.ReflectionRays += source.ReflectionRays;
target.HitCount += source.HitCount;
target.MissCount += source.MissCount;
target.BVHVisitedNodes += source.BVHVisitedNodes;
target.BVHTestedPrimitives += source.BVHTestedPrimitives;
target.MaxRecursionDepthReached =
target.MaxRecursionDepthReached > source.MaxRecursionDepthReached
? target.MaxRecursionDepthReached
: source.MaxRecursionDepthReached;
}
inline void FinalizeDerivedStats(
RenderStats& stats) noexcept
{
const double totalRays = static_cast<double>(TotalRays(stats));
const double seconds = stats.RenderMilliseconds / 1000.0;
stats.RaysPerSecond = seconds > 0.0 ? totalRays / seconds : 0.0;
stats.PrimitiveTestsPerRay =
totalRays > 0.0
? static_cast<double>(stats.BVHTestedPrimitives) / totalRays
: 0.0;
stats.NodesVisitedPerRay =
totalRays > 0.0
? static_cast<double>(stats.BVHVisitedNodes) / totalRays
: 0.0;
}
[[nodiscard]]
inline float RayBiasForHit(
const RenderSettings& settings,
float hitDistance) noexcept
{
const float relative =
settings.RayBiasRelative * (hitDistance > 0.0f ? hitDistance : 1.0f);
return settings.RayBiasAbsolute > relative
? settings.RayBiasAbsolute
: relative;
}
[[nodiscard]]
inline const char* ToString(
AccelerationMode mode) noexcept
{
switch (mode)
{
case AccelerationMode::BruteForce: return "brute";
case AccelerationMode::BVHSAH: return "sah";
case AccelerationMode::BVHMorton: return "morton";
}
return "unknown";
}
struct SurfaceHit final
{
bool Hit = false;
float Distance = std::numeric_limits<float>::infinity();
Vec3f Position = Vec3f::Zero();
Vec3f Normal = Vec3f::Up();
Vec2f UV = Vec2f::Zero();
std::uint32_t PrimitiveIndex = std::numeric_limits<std::uint32_t>::max();
std::uint32_t MaterialIndex = std::numeric_limits<std::uint32_t>::max();
};
struct SceneParseError final
{
std::uint32_t Line = 0;
std::uint32_t Column = 0;
std::string Message;
};
[[nodiscard]]
inline const char* ToString(
RenderMode mode) noexcept
{
switch (mode)
{
case RenderMode::Normal: return "normal";
case RenderMode::Depth: return "depth";
case RenderMode::Whitted: return "whitted";
case RenderMode::ShadowMask: return "shadow_mask";
case RenderMode::BVHHeatmap: return "bvh_heatmap";
case RenderMode::Albedo: return "albedo";
case RenderMode::PrimitiveID: return "primitive_id";
case RenderMode::UV: return "uv";
case RenderMode::Barycentric: return "barycentric";
case RenderMode::AccelerationDifference: return "accel_diff";
case RenderMode::PBR: return "pbr";
case RenderMode::Path: return "path";
}
return "unknown";
}
}