Skip to content

Commit 773733d

Browse files
committed
refactor NEE to use templated light types and sampling
1 parent b483aa6 commit 773733d

File tree

6 files changed

+413
-683
lines changed

6 files changed

+413
-683
lines changed

31_HLSLPathTracer/app_resources/hlsl/common.hlsl

Lines changed: 1 addition & 271 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ struct Payload
3535

3636
enum ProceduralShapeType : uint16_t
3737
{
38+
PST_NONE = 0,
3839
PST_SPHERE,
3940
PST_TRIANGLE,
4041
PST_RECTANGLE
@@ -173,54 +174,13 @@ enum PTPolygonMethod : uint16_t
173174
PPM_APPROX_PROJECTED_SOLID_ANGLE
174175
};
175176

176-
// namespace Intersector
177-
// {
178-
// // ray query method
179-
// // ray query struct holds AS info
180-
// // pass in address to vertex/index buffers?
181-
182-
// // ray tracing pipeline method
183-
184-
// // procedural data store: [obj count] [intersect type] [obj1] [obj2] [...]
185-
186-
// struct IntersectData
187-
// {
188-
// enum Mode : uint32_t // enum class?
189-
// {
190-
// RAY_QUERY,
191-
// RAY_TRACING,
192-
// PROCEDURAL
193-
// };
194-
195-
// NBL_CONSTEXPR_STATIC_INLINE uint32_t DataSize = 128;
196-
197-
// uint32_t mode : 2;
198-
// uint32_t unused : 30; // possible space for flags
199-
// uint32_t data[DataSize];
200-
// };
201-
// }
202-
203177
enum IntersectMode : uint32_t
204178
{
205179
IM_RAY_QUERY,
206180
IM_RAY_TRACING,
207181
IM_PROCEDURAL
208182
};
209183

210-
namespace NextEventEstimator
211-
{
212-
// procedural data store: [light count] [event type] [obj]
213-
214-
struct Event
215-
{
216-
NBL_CONSTEXPR_STATIC_INLINE uint32_t DataSize = 16;
217-
218-
uint32_t mode : 2;
219-
uint32_t unused : 30; // possible space for flags
220-
uint32_t data[DataSize];
221-
};
222-
}
223-
224184
template<ProceduralShapeType type>
225185
struct Shape;
226186

@@ -269,45 +229,6 @@ struct Shape<PST_SPHERE>
269229
return 2.0 * numbers::pi<float> * (1.0 - cosThetaMax);
270230
}
271231

272-
template<typename Ray>
273-
float deferredPdf(NBL_CONST_REF_ARG(Ray) ray)
274-
{
275-
return 1.0 / getSolidAngle(ray.origin);
276-
}
277-
278-
template<class Aniso>
279-
float32_t3 generate_and_pdf(NBL_REF_ARG(float32_t) pdf, NBL_REF_ARG(float32_t) newRayMaxT, NBL_CONST_REF_ARG(float32_t3) origin, NBL_CONST_REF_ARG(Aniso) interaction, bool isBSDF, NBL_CONST_REF_ARG(float32_t3) xi)
280-
{
281-
float32_t3 Z = position - origin;
282-
const float distanceSQ = hlsl::dot<float32_t3>(Z,Z);
283-
const float cosThetaMax2 = 1.0 - radius2 / distanceSQ;
284-
if (cosThetaMax2 > 0.0)
285-
{
286-
const float rcpDistance = 1.0 / hlsl::sqrt<float32_t>(distanceSQ);
287-
Z *= rcpDistance;
288-
289-
const float cosThetaMax = hlsl::sqrt<float32_t>(cosThetaMax2);
290-
const float cosTheta = hlsl::mix<float>(1.0, cosThetaMax, xi.x);
291-
292-
float32_t3 L = Z * cosTheta;
293-
294-
const float cosTheta2 = cosTheta * cosTheta;
295-
const float sinTheta = hlsl::sqrt<float32_t>(1.0 - cosTheta2);
296-
float sinPhi, cosPhi;
297-
math::sincos<float>(2.0 * numbers::pi<float> * xi.y - numbers::pi<float>, sinPhi, cosPhi);
298-
float32_t3 X, Y;
299-
math::frisvad<float32_t3>(Z, X, Y);
300-
301-
L += (X * cosPhi + Y * sinPhi) * sinTheta;
302-
303-
newRayMaxT = (cosTheta - hlsl::sqrt<float32_t>(cosTheta2 - cosThetaMax2)) / rcpDistance;
304-
pdf = 1.0 / (2.0 * numbers::pi<float> * (1.0 - cosThetaMax));
305-
return L;
306-
}
307-
pdf = 0.0;
308-
return float32_t3(0.0,0.0,0.0);
309-
}
310-
311232
NBL_CONSTEXPR_STATIC_INLINE uint32_t ObjSize = 5;
312233

313234
float32_t3 position;
@@ -361,100 +282,6 @@ struct Shape<PST_TRIANGLE>
361282
return hlsl::cross<float32_t3>(edges[0], edges[1]) * 0.5f;
362283
}
363284

364-
template<typename Ray>
365-
float deferredPdf(NBL_CONST_REF_ARG(Ray) ray)
366-
{
367-
const float32_t3 L = ray.direction;
368-
switch (polygonMethod)
369-
{
370-
case PPM_AREA:
371-
{
372-
const float dist = ray.intersectionT;
373-
const float32_t3 L = ray.direction;
374-
return dist * dist / hlsl::abs<float32_t>(hlsl::dot<float32_t3>(getNormalTimesArea(), L));
375-
}
376-
break;
377-
case PPM_SOLID_ANGLE:
378-
{
379-
shapes::SphericalTriangle<float> st = shapes::SphericalTriangle<float>::create(vertex0, vertex1, vertex2, ray.origin);
380-
const float rcpProb = st.solidAngleOfTriangle();
381-
// if `rcpProb` is NAN then the triangle's solid angle was close to 0.0
382-
return rcpProb > numeric_limits<float>::min ? (1.0 / rcpProb) : numeric_limits<float>::max;
383-
}
384-
break;
385-
case PPM_APPROX_PROJECTED_SOLID_ANGLE:
386-
{
387-
shapes::SphericalTriangle<float> st = shapes::SphericalTriangle<float>::create(vertex0, vertex1, vertex2, ray.origin);
388-
sampling::ProjectedSphericalTriangle<float> pst = sampling::ProjectedSphericalTriangle<float>::create(st);
389-
const float pdf = pst.pdf(ray.normalAtOrigin, ray.wasBSDFAtOrigin, L);
390-
// if `pdf` is NAN then the triangle's projected solid angle was close to 0.0, if its close to INF then the triangle was very small
391-
return pdf < numeric_limits<float>::max ? pdf : numeric_limits<float>::max;
392-
}
393-
break;
394-
default:
395-
return 0.0;
396-
}
397-
}
398-
399-
template<class Aniso>
400-
float32_t3 generate_and_pdf(NBL_REF_ARG(float32_t) pdf, NBL_REF_ARG(float32_t) newRayMaxT, NBL_CONST_REF_ARG(float32_t3) origin, NBL_CONST_REF_ARG(Aniso) interaction, bool isBSDF, float32_t3 xi)
401-
{
402-
switch(polygonMethod)
403-
{
404-
case PPM_AREA:
405-
{
406-
const float32_t3 edge0 = vertex1 - vertex0;
407-
const float32_t3 edge1 = vertex2 - vertex0;
408-
const float sqrtU = hlsl::sqrt<float32_t>(xi.x);
409-
float32_t3 pnt = vertex0 + edge0 * (1.0 - sqrtU) + edge1 * sqrtU * xi.y;
410-
float32_t3 L = pnt - origin;
411-
412-
const float distanceSq = hlsl::dot<float32_t3>(L,L);
413-
const float rcpDistance = 1.0 / hlsl::sqrt<float32_t>(distanceSq);
414-
L *= rcpDistance;
415-
416-
pdf = distanceSq / hlsl::abs<float32_t>(hlsl::dot<float32_t3>(hlsl::cross<float32_t3>(edge0, edge1) * 0.5f, L));
417-
newRayMaxT = 1.0 / rcpDistance;
418-
return L;
419-
}
420-
break;
421-
case PPM_SOLID_ANGLE:
422-
{
423-
float rcpPdf;
424-
425-
shapes::SphericalTriangle<float> st = shapes::SphericalTriangle<float>::create(vertex0, vertex1, vertex2, origin);
426-
sampling::SphericalTriangle<float> sst = sampling::SphericalTriangle<float>::create(st);
427-
428-
const float32_t3 L = sst.generate(rcpPdf, xi.xy);
429-
430-
pdf = rcpPdf > numeric_limits<float>::min ? (1.0 / rcpPdf) : numeric_limits<float>::max;
431-
432-
const float32_t3 N = getNormalTimesArea();
433-
newRayMaxT = hlsl::dot<float32_t3>(N, vertex0 - origin) / hlsl::dot<float32_t3>(N, L);
434-
return L;
435-
}
436-
break;
437-
case PPM_APPROX_PROJECTED_SOLID_ANGLE:
438-
{
439-
float rcpPdf;
440-
441-
shapes::SphericalTriangle<float> st = shapes::SphericalTriangle<float>::create(vertex0, vertex1, vertex2, origin);
442-
sampling::ProjectedSphericalTriangle<float> sst = sampling::ProjectedSphericalTriangle<float>::create(st);
443-
444-
const float32_t3 L = sst.generate(rcpPdf, interaction.isotropic.N, isBSDF, xi.xy);
445-
446-
pdf = rcpPdf > numeric_limits<float>::min ? (1.0 / rcpPdf) : numeric_limits<float>::max;
447-
448-
const float32_t3 N = getNormalTimesArea();
449-
newRayMaxT = hlsl::dot<float32_t3>(N, vertex0 - origin) / hlsl::dot<float32_t3>(N, L);
450-
return L;
451-
}
452-
break;
453-
default:
454-
return (float32_t3)0.0;
455-
}
456-
}
457-
458285
NBL_CONSTEXPR_STATIC_INLINE uint32_t ObjSize = 10;
459286

460287
float32_t3 vertex0;
@@ -515,103 +342,6 @@ struct Shape<PST_RECTANGLE>
515342
basis[2] = normalize(cross(basis[0],basis[1]));
516343
}
517344

518-
template<typename Ray>
519-
float deferredPdf(NBL_CONST_REF_ARG(Ray) ray)
520-
{
521-
switch (polygonMethod)
522-
{
523-
case PPM_AREA:
524-
{
525-
const float dist = ray.intersectionT;
526-
const float32_t3 L = ray.direction;
527-
return dist * dist / hlsl::abs<float32_t>(hlsl::dot<float32_t3>(getNormalTimesArea(), L));
528-
}
529-
break;
530-
// #ifdef TRIANGLE_REFERENCE ?
531-
case PPM_SOLID_ANGLE:
532-
{
533-
float pdf;
534-
float32_t3x3 rectNormalBasis;
535-
float32_t2 rectExtents;
536-
getNormalBasis(rectNormalBasis, rectExtents);
537-
shapes::SphericalRectangle<float> sphR0 = shapes::SphericalRectangle<float>::create(ray.origin, offset, rectNormalBasis);
538-
float solidAngle = sphR0.solidAngleOfRectangle(rectExtents);
539-
if (solidAngle > numeric_limits<float>::min)
540-
pdf = 1.f / solidAngle;
541-
else
542-
pdf = bit_cast<float>(numeric_limits<float>::infinity);
543-
return pdf;
544-
}
545-
break;
546-
case PPM_APPROX_PROJECTED_SOLID_ANGLE:
547-
{
548-
// currently broken
549-
return bit_cast<float>(numeric_limits<float>::infinity);
550-
}
551-
break;
552-
default:
553-
return bit_cast<float>(numeric_limits<float>::infinity);
554-
}
555-
}
556-
557-
template<class Aniso>
558-
float32_t3 generate_and_pdf(NBL_REF_ARG(float32_t) pdf, NBL_REF_ARG(float32_t) newRayMaxT, NBL_CONST_REF_ARG(float32_t3) origin, NBL_CONST_REF_ARG(Aniso) interaction, bool isBSDF, float32_t3 xi)
559-
{
560-
const float32_t3 N = getNormalTimesArea();
561-
const float32_t3 origin2origin = offset - origin;
562-
563-
switch (polygonMethod)
564-
{
565-
case PPM_AREA:
566-
{
567-
float32_t3 L = origin2origin + edge0 * xi.x + edge1 * xi.y;
568-
const float distSq = hlsl::dot<float32_t3>(L, L);
569-
const float rcpDist = 1.0 / hlsl::sqrt<float32_t>(distSq);
570-
L *= rcpDist;
571-
pdf = distSq / hlsl::abs<float32_t>(hlsl::dot<float32_t3>(N, L));
572-
newRayMaxT = 1.0 / rcpDist;
573-
return L;
574-
}
575-
break;
576-
// #ifdef TRIANGLE_REFERENCE ?
577-
case PPM_SOLID_ANGLE:
578-
{
579-
float32_t3x3 rectNormalBasis;
580-
float32_t2 rectExtents;
581-
getNormalBasis(rectNormalBasis, rectExtents);
582-
shapes::SphericalRectangle<float> sphR0 = shapes::SphericalRectangle<float>::create(origin, offset, rectNormalBasis);
583-
float32_t3 L = (float32_t3)0.0;
584-
float solidAngle = sphR0.solidAngleOfRectangle(rectExtents);
585-
586-
sampling::SphericalRectangle<float> ssph = sampling::SphericalRectangle<float>::create(sphR0);
587-
float32_t2 sphUv = ssph.generate(rectExtents, xi.xy, solidAngle);
588-
if (solidAngle > numeric_limits<float>::min)
589-
{
590-
float32_t3 sph_sample = sphUv[0] * edge0 + sphUv[1] * edge1 + offset;
591-
L = sph_sample - origin;
592-
L = hlsl::mix<float32_t3>(nbl::hlsl::normalize(L), (float32_t3)0.0, hlsl::abs<float32_t3>(L) > (float32_t3)numeric_limits<float>::min); // TODO? sometimes L is vec3(0), find cause
593-
pdf = 1.f / solidAngle;
594-
}
595-
else
596-
pdf = bit_cast<float>(numeric_limits<float>::infinity);
597-
598-
newRayMaxT = hlsl::dot<float32_t3>(N, origin2origin) / hlsl::dot<float32_t3>(N, L);
599-
return L;
600-
}
601-
break;
602-
case PPM_APPROX_PROJECTED_SOLID_ANGLE:
603-
{
604-
// currently broken
605-
pdf = bit_cast<float>(numeric_limits<float>::infinity);
606-
return (float32_t3)0.0;
607-
}
608-
break;
609-
default:
610-
pdf = bit_cast<float>(numeric_limits<float>::infinity);
611-
return (float32_t3)0.0;
612-
}
613-
}
614-
615345
NBL_CONSTEXPR_STATIC_INLINE uint32_t ObjSize = 10;
616346

617347
float32_t3 offset;

0 commit comments

Comments
 (0)