chrono_batch_render/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
1 / 1
100.0%
Branches:
-
-%
Functions:
-
-%

scene/records/lights.h
Line Branch Exec Source
1 // SPDX-License-Identifier: BSD-3-Clause
2 #pragma once
3
4 #include "chrono_batch_render/io/kernels/ies.h"
5 #include "chrono_batch_render/scene/records/instances.h"
6 #include "chrono_batch_render/scene/records/textures.h"
7 #include "chrono_batch_render/stage/schema/ids.h"
8
9 namespace chrono::batch_render {
10
11 CHRONO_BATCH_RENDER_ENUM(LightType) {
12 Distant,
13 Sphere,
14 Rect,
15 Disk,
16 Cylinder,
17 Dome,
18 Portal,
19 Unsupported,
20 };
21
22 static const uint kLightTreatAsPoint = 1u << 0;
23 static const uint kLightTreatAsLine = 1u << 1;
24 static const uint kLightNormalize = 1u << 2;
25
26 static const uint kLightShaped = 1u << 3;
27 static const uint kLightVisible = 1u << 4;
28 static const uint kLightShadowless = 1u << 5;
29
30 struct LightRecord {
31 Float3 position;
32 uint prim;
33 Float3 axisX;
34 uint type;
35 Float3 axisY;
36 uint flags;
37 Float3 axisZ;
38 float power;
39 Float3 radiance;
40 float radius;
41 Float3 focusTint;
42 float focus;
43 float width;
44 float height;
45 float length;
46 float cosAngle;
47 float diffuse;
48 float specular;
49 float coneAngle;
50 float coneSoftness;
51 uint forwardAxis;
52 float spread;
53 uint lightLink;
54 uint shadowLink;
55 Float3 shadowColor;
56 float shadowDistance;
57 float shadowFalloff;
58 float shadowFalloffGamma;
59 uint textures;
60 uint textureFormat;
61 Ptr<float> map;
62 uint portals;
63 uint ies;
64 float iesAngleScale;
65 float iesScale;
66 uint instancer;
67 uint copyOffset;
68 uint64_t portalPrims;
69 };
70
71 CHRONO_BATCH_RENDER_CHECK_SIZE(LightRecord, 216);
72
73 struct LightLayout {
74 Ptr<LightRecord> records;
75 Ptr<uint> firstLights;
76 Ptr<uint> prims;
77 Ptr<float> cdf;
78 Ptr<float> maps;
79 Ptr<uint> domePrims;
80 Ptr<uint> domeSlots;
81 Ptr<uint> offsetBases;
82 Ptr<Float3> offsets;
83 Ptr<uint> copies;
84 uint worldCount;
85 uint domeCount;
86 };
87
88 CHRONO_BATCH_RENDER_CHECK_SIZE(LightLayout, 88);
89
90 11 struct MinimalLightRecord {
91 Float3 direction;
92 uint headlight;
93 Float3 radiance;
94 float diffuse;
95 float specular;
96 uint padding0;
97 uint padding1;
98 uint padding2;
99 };
100
101 CHRONO_BATCH_RENDER_CHECK_SIZE(MinimalLightRecord, 48);
102
103 static const uint kDomeMapWidth = 256;
104 static const uint kDomeMapHeight = 128;
105 static const uint kDomeMapCells = kDomeMapWidth * kDomeMapHeight;
106 static const uint kDomeMapFloats = kDomeMapCells + kDomeMapHeight + 1;
107
108 static const uint kSpectralRows = 95;
109 static const float kSpectralFirstNm = 360;
110 static const float kSpectralStepNm = 5;
111 static const uint kTemperatureRows = 256;
112 static const float kMaxMired = 1000;
113 static const uint kBlackbodyRow = kSpectralRows;
114 static const uint kDaylightRow = kBlackbodyRow + kTemperatureRows;
115 static const uint kWhiteRow = kDaylightRow + kTemperatureRows;
116
117 #ifndef __SLANG__
118
119 struct SpectralTables {
120 Float3 cmf[kSpectralRows];
121 Float3 blackbody[kTemperatureRows];
122 Float3 daylight[kTemperatureRows];
123 Float3 white;
124 uint padding;
125 };
126
127 CHRONO_BATCH_RENDER_CHECK_SIZE(SpectralTables, 7300);
128
129 #endif
130
131 struct CollectionRecord {
132 ArrayRef includes;
133 ArrayRef excludes;
134 uint includeRoot;
135 uint explicitOnly;
136 uint padding0;
137 uint padding1;
138 };
139
140 CHRONO_BATCH_RENDER_CHECK_SIZE(CollectionRecord, 48);
141
142 struct LightShapeRecord {
143 float radius;
144 float width;
145 float height;
146 float length;
147 uint treatAsPoint;
148 uint padding0;
149 uint padding1;
150 uint padding2;
151 };
152
153 CHRONO_BATCH_RENDER_CHECK_SIZE(LightShapeRecord, 32);
154
155 static const uint kLoopedLights = 8;
156
157 #ifdef __SLANG__
158
159 bool Lists(ArrayRef targets, uint prim) {
160 Ptr<uint> items = Ptr<uint>(targets.address);
161 for (uint i = 0; i < targets.count; ++i) {
162 if (items[i] == prim) {
163 return true;
164 }
165 }
166 return false;
167 }
168
169 float3 ShapingWeight(LightRecord light, float cosine) {
170 if ((light.flags & kLightShaped) == 0) {
171 return float3(1);
172 }
173 const float angle = acos(clamp(cosine, -1.0f, 1.0f));
174 float cone = angle <= light.coneAngle ? 1 : 0;
175 const float inner = light.coneAngle * (1 - light.coneSoftness);
176 if (light.coneSoftness > 0 && angle > inner && angle <= light.coneAngle) {
177 cone = smoothstep(light.coneAngle, inner, angle);
178 }
179 const float focused = light.focus > 0 ? pow(max(cosine, 0.0f), light.focus) : 1;
180 const float3 tint = light.focusTint.Vector();
181 return cone * (tint + (1 - tint) * focused);
182 }
183
184 float3 ForwardAxis(LightRecord light) {
185 switch (ShapingAxis(light.forwardAxis)) {
186 case ShapingAxis::PlusZ:
187 return light.axisZ.Vector();
188 case ShapingAxis::MinusY:
189 return -light.axisY.Vector();
190 case ShapingAxis::PlusY:
191 return light.axisY.Vector();
192 case ShapingAxis::MinusX:
193 return -light.axisX.Vector();
194 case ShapingAxis::PlusX:
195 return light.axisX.Vector();
196 default:
197 return -light.axisZ.Vector();
198 }
199 }
200
201 float3 EmissionAcross(LightRecord light) {
202 const ShapingAxis axis = ShapingAxis(light.forwardAxis);
203 return axis == ShapingAxis::MinusX || axis == ShapingAxis::PlusX ? light.axisY.Vector()
204 : light.axisX.Vector();
205 }
206
207 float2 IesSt(LightRecord light, float3 emitted) {
208 const float3 forward = ForwardAxis(light);
209 const float3 across = EmissionAcross(light);
210 const float polar =
211 acos(clamp(dot(emitted, forward), -1.0f, 1.0f)) / max(1 + light.iesAngleScale, 1e-3f);
212 if (polar > kPi) {
213 return float2(-1);
214 }
215 float around = atan2(dot(emitted, cross(forward, across)), dot(emitted, across)) / (2 * kPi);
216 around -= floor(around);
217 return float2((around * (kIesColumns - 1) + 0.5f) / kIesColumns,
218 1 - (polar / kPi * (kIesRows - 1) + 0.5f) / kIesRows);
219 }
220
221 float2 CrossFace(uint column, uint row, float a, float b) {
222 const float edge = 1 - 1e-4f;
223 const float2 at = float2(clamp(a, -edge, edge), clamp(b, -edge, edge));
224 return float2((column + 0.5f * (at.x + 1)) / 3, 1 - (row + 0.5f * (1 - at.y)) / 4);
225 }
226
227 float2 DomeTextureSt(DomeTextureFormat format, float3 n) {
228 switch (format) {
229 case DomeTextureFormat::MirroredBall: {
230 const float3 h = n + float3(0, 0, 1);
231 const float size = length(h);
232 const float2 xy = size > 1e-6f ? h.xy / size : float2(1, 0);
233 return 0.5f + 0.5f * xy;
234 }
235 case DomeTextureFormat::Angular: {
236 const float side = length(n.xy);
237 const float radius = side > 1e-6f ? acos(clamp(n.z, -1.0f, 1.0f)) / (kPi * side) : 0;
238 return 0.5f + 0.5f * radius * n.xy;
239 }
240 case DomeTextureFormat::CubeMapVerticalCross: {
241 const float3 a = abs(n);
242 if (a.x >= a.y && a.x >= a.z) {
243 return n.x > 0 ? CrossFace(2, 1, n.z / a.x, n.y / a.x)
244 : CrossFace(0, 1, -n.z / a.x, n.y / a.x);
245 }
246 if (a.y >= a.z) {
247 return n.y > 0 ? CrossFace(1, 0, n.x / a.y, n.z / a.y)
248 : CrossFace(1, 2, n.x / a.y, -n.z / a.y);
249 }
250 return n.z < 0 ? CrossFace(1, 1, n.x / a.z, n.y / a.z)
251 : CrossFace(1, 3, n.x / a.z, -n.y / a.z);
252 }
253 default: {
254 const float u = (atan2(n.z, n.x) + 0.5f * kPi) / (2 * kPi);
255 return float2(u - floor(u), 1 - acos(clamp(n.y, -1.0f, 1.0f)) / kPi);
256 }
257 }
258 }
259
260 float3 DomeMapDirection(float2 uv) {
261 const float phi = 2 * kPi * uv.x;
262 const float theta = kPi * uv.y;
263 return float3(sin(theta) * cos(phi), cos(theta), sin(theta) * sin(phi));
264 }
265
266 #endif
267
268 }
269