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
|
// Copyright 2009-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
#include "light.h"
#include "../math/sampling.h"
#include "../math/linearspace.h"
namespace embree {
struct PointLight
{
Light super; //!< inherited light fields
Vec3fa position; //!< light position
Vec3fa power; //!< RGB color and intensity of light
float radius; //!< defines the size of the SphereLight
};
// Implementation
//////////////////////////////////////////////////////////////////////////////
SYCL_EXTERNAL Light_SampleRes PointLight_sample(const Light* super,
const DifferentialGeometry& dg,
const Vec2f& s)
{
const PointLight* self = (PointLight*)super;
Light_SampleRes res;
// extant light vector from the hit point
const Vec3fa dir = self->position - dg.P;
const float dist2 = dot(dir, dir);
const float invdist = rsqrt(dist2);
// normalized light vector
res.dir = dir * invdist;
res.dist = dist2 * invdist;
res.pdf = inf; // per default we always take this res
// convert from power to radiance by attenuating by distance^2
res.weight = self->power * sqr(invdist);
const float sinTheta = self->radius * invdist;
if ((self->radius > 0.f) & (sinTheta > 0.005f)) {
// res surface of sphere as seen by hit point -> cone of directions
// for very small cones treat as point light, because float precision is not good enough
if (sinTheta < 1.f) {
const float cosTheta = sqrt(1.f - sinTheta * sinTheta);
const Vec3fa localDir = uniformSampleCone(cosTheta, s);
res.dir = frame(res.dir) * localDir;
res.pdf = uniformSampleConePDF(cosTheta);
const float c = localDir.z;
res.dist = c*res.dist - sqrt(sqr(self->radius) - (1.f - c*c) * dist2);
// TODO scale radiance by actual distance
} else { // inside sphere
const Vec3fa localDir = cosineSampleHemisphere(s);
res.dir = frame(dg.Ns) * localDir;
res.pdf = cosineSampleHemispherePDF(localDir);
// TODO:
res.weight = self->power * rcp(sqr(self->radius));
res.dist = self->radius;
}
}
return res;
}
SYCL_EXTERNAL Light_EvalRes PointLight_eval(const Light* super,
const DifferentialGeometry& dg,
const Vec3fa& dir)
{
const PointLight* self = (PointLight*)super;
Light_EvalRes res;
res.value = Vec3fa(0.f);
res.dist = inf;
res.pdf = 0.f;
if (self->radius > 0.f) {
const Vec3fa A = self->position - dg.P;
const float a = dot(dir, dir);
const float b = 2.f * dot(dir, A);
const float centerDist2 = dot(A, A);
const float c = centerDist2 - sqr(self->radius);
const float radical = sqr(b) - 4.f*a*c;
if (radical > 0.f) {
const float t_near = (b - sqrt(radical)) / (2.f*a);
const float t_far = (b + sqrt(radical)) / (2.f*a);
if (t_far > 0.0f) {
// TODO: handle interior case
res.dist = t_near;
const float sinTheta2 = sqr(self->radius) * rcp(centerDist2);
const float cosTheta = sqrt(1.f - sinTheta2);
res.pdf = uniformSampleConePDF(cosTheta);
const float invdist = rcp(t_near);
res.value = self->power * res.pdf * sqr(invdist);
}
}
}
return res;
}
// Exports (called from C++)
//////////////////////////////////////////////////////////////////////////////
//! Set the parameters of an ispc-side PointLight object
extern "C" void PointLight_set(void* super,
const Vec3fa& position,
const Vec3fa& power,
float radius)
{
PointLight* self = (PointLight*)super;
self->position = position;
self->power = power;
self->radius = radius;
}
//! Create an ispc-side PointLight object
extern "C" void* PointLight_create()
{
PointLight* self = (PointLight*) alignedUSMMalloc(sizeof(PointLight),16);
Light_Constructor(&self->super);
//self->super.sample = GET_FUNCTION_POINTER(PointLight_sample);
//self->super.eval = GET_FUNCTION_POINTER(PointLight_eval);
self->super.type = LIGHT_POINT;
PointLight_set(self, Vec3fa(0.f), Vec3fa(1.f), 0.f);
return self;
}
} // namespace embree
|