File: spot_light.cpp

package info (click to toggle)
embree 4.3.3%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 100,656 kB
  • sloc: cpp: 228,918; xml: 40,944; ansic: 2,685; python: 812; sh: 635; makefile: 228; csh: 42
file content (139 lines) | stat: -rw-r--r-- 4,677 bytes parent folder | download
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
// 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 SpotLight
{
  Light super;            //!< inherited light fields

  Vec3fa position;         //!< Position of the SpotLight
  LinearSpace3fa frame;         //!< coordinate frame, with vz == direction that the SpotLight is emitting
  Vec3fa power;            //!< RGB color and intensity of the SpotLight
  float cosAngleMax;      //!< Angular limit of the spot in an easier to use form: cosine of the half angle in radians
  float cosAngleScale;    //!< 1/(cos(border of the penumbra area) - cosAngleMax); positive
  float radius;           //!< defines the size of the (extended) SpotLight
  float diskPdf;          //!< pdf of disk with radius
};


// Implementation
//////////////////////////////////////////////////////////////////////////////

SYCL_EXTERNAL Light_SampleRes SpotLight_sample(const Light* super,
                                                              const DifferentialGeometry& dg,
                                                              const Vec2f& s)
{
  const SpotLight* self = (SpotLight*)super;
  Light_SampleRes res;

  // extant light vector from the hit point
  res.dir = self->position - dg.P;

  if (self->radius > 0.0f)
    res.dir = self->frame * uniformSampleDisk(self->radius, s) + res.dir;

  const float dist2 = dot(res.dir, res.dir);
  const float invdist = rsqrt(dist2);

  // normalized light vector
  res.dir = res.dir * invdist;
  res.dist = dist2 * invdist;

  // cosine of the negated light direction and light vector.
  const float cosAngle = -dot(self->frame.vz, res.dir);
  const float angularAttenuation = clamp((cosAngle - self->cosAngleMax) * self->cosAngleScale);

  if (self->radius > 0.0f)
    res.pdf = self->diskPdf * dist2 * abs(cosAngle);
  else
    res.pdf = inf; // we always take this res

  // convert from power to radiance by attenuating by distance^2; attenuate by angle
  res.weight = self->power * (sqr(invdist) * angularAttenuation);

  return res;
}

SYCL_EXTERNAL Light_EvalRes SpotLight_eval(const Light* super,
                                                          const DifferentialGeometry& dg,
                                                          const Vec3fa& dir)
{
  const SpotLight* self = (SpotLight*)super;
  Light_EvalRes res;
  res.value = Vec3fa(0.0f);
  res.dist = inf;
  res.pdf = 0.0f;

  if (self->radius > 0.0f) {
    // intersect disk
    const float cosAngle = -dot(dir, self->frame.vz);
    if (cosAngle > self->cosAngleMax) { // inside illuminated cone?
      const Vec3fa vp = dg.P - self->position;
      const float dp = dot(vp, self->frame.vz);
      if (dp > 0.0f) { // in front of light?
        const float t = dp*rcp(cosAngle);
        const Vec3fa vd = vp + t * dir;
        if (dot(vd, vd) < sqr(self->radius)) { // inside disk?
          const float angularAttenuation = min((cosAngle - self->cosAngleMax) * self->cosAngleScale, 1.f);
          const float pdf = self->diskPdf * cosAngle;
          res.value = self->power * (angularAttenuation * pdf); // *sqr(t)/sqr(t) cancels
          res.dist = t;
          res.pdf = pdf * sqr(t);
        }
      }
    }
  }

  return res;
}


// Exports (called from C++)
//////////////////////////////////////////////////////////////////////////////

//! Set the parameters of an ispc-side SpotLight object
extern "C" void SpotLight_set(void* super,
                          const Vec3fa& position,
                          const Vec3fa& direction,
                          const Vec3fa& power,
                          float cosAngleMax,
                          float cosAngleScale,
                          float radius)
{
  SpotLight* self = (SpotLight*)super;
  self->position      = position;
  self->frame         = frame(direction);
  self->power         = power;
  self->cosAngleMax   = cosAngleMax;
  self->cosAngleScale = cosAngleScale;
  self->radius        = radius;
  self->diskPdf       = uniformSampleDiskPDF(radius);
}

//! Create an ispc-side SpotLight object
extern "C" void* SpotLight_create()
{
  SpotLight* self = (SpotLight*) alignedUSMMalloc(sizeof(SpotLight),16);

  Light_Constructor(&self->super);
  //self->super.sample = GET_FUNCTION_POINTER(SpotLight_sample);
  //self->super.eval = GET_FUNCTION_POINTER(SpotLight_eval);
  self->super.type = LIGHT_SPOT;

  SpotLight_set(self,
                Vec3fa(0.f),
                Vec3fa(0.f, 0.f, 1.f),
                Vec3fa(1.f),
                0.f,
                100.f,
                0.f);

  return self;
}

} // namespace embree