File: spot_light.ispc

package info (click to toggle)
embree 3.12.1%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 27,412 kB
  • sloc: cpp: 173,822; xml: 3,737; ansic: 2,955; python: 1,628; sh: 480; makefile: 193; csh: 42
file content (134 lines) | stat: -rw-r--r-- 4,563 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
// Copyright 2009-2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0

#include "light.isph"
#include "../math/sampling.isph"
#include "../math/linearspace.isph"

struct SpotLight
{
  Light super;            //!< inherited light fields

  Vec3f position;         //!< Position of the SpotLight
  LinearSpace3f frame;         //!< coordinate frame, with vz == direction that the SpotLight is emitting
  Vec3f 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
//////////////////////////////////////////////////////////////////////////////

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

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

  if (self->radius > 0.)
    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.)
    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;
}

Light_EvalRes SpotLight_eval(const uniform Light* uniform super,
                             const DifferentialGeometry& dg,
                             const Vec3f& dir)
{
  const SpotLight* uniform self = (SpotLight* uniform)super;
  Light_EvalRes res;
  res.value = make_Vec3f(0.f);
  res.dist = inf;
  res.pdf = 0.f;

  if (self->radius > 0.f) {
    // intersect disk
    const float cosAngle = -dot(dir, self->frame.vz);
    if (cosAngle > self->cosAngleMax) { // inside illuminated cone?
      const Vec3f vp = dg.P - self->position;
      const float dp = dot(vp, self->frame.vz);
      if (dp > 0.f) { // in front of light?
        const float t = dp*rcp(cosAngle);
        const Vec3f 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
export void SpotLight_set(void* uniform super,
                          const uniform Vec3f& position,
                          const uniform Vec3f& direction,
                          const uniform Vec3f& power,
                          uniform float cosAngleMax,
                          uniform float cosAngleScale,
                          uniform float radius)
{
  uniform SpotLight* uniform self = (uniform SpotLight* uniform)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
export void* uniform SpotLight_create()
{
  uniform SpotLight* uniform self = uniform new uniform SpotLight;

  Light_Constructor(&self->super);
  self->super.sample = SpotLight_sample;
  self->super.eval = SpotLight_eval;

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

  return self;
}