Welcome to mirror list, hosted at ThFree Co, Russian Federation.

spot.h « light « kernel « cycles « intern - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 8f1eff7c8b9be61d62cb8ce9bb5283267b1271cd (plain)
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
/* SPDX-License-Identifier: Apache-2.0
 * Copyright 2011-2022 Blender Foundation */

#pragma once

#include "kernel/light/common.h"

CCL_NAMESPACE_BEGIN

ccl_device float spot_light_attenuation(float3 dir,
                                        float cos_half_spot_angle,
                                        float spot_smooth,
                                        float3 N)
{
  float attenuation = dot(dir, N);

  if (attenuation <= cos_half_spot_angle) {
    attenuation = 0.0f;
  }
  else {
    float t = attenuation - cos_half_spot_angle;

    if (t < spot_smooth && spot_smooth != 0.0f)
      attenuation *= smoothstepf(t / spot_smooth);
  }

  return attenuation;
}

template<bool in_volume_segment>
ccl_device_inline bool spot_light_sample(const ccl_global KernelLight *klight,
                                         const float randu,
                                         const float randv,
                                         const float3 P,
                                         ccl_private LightSample *ls)
{
  ls->P = make_float3(klight->co[0], klight->co[1], klight->co[2]);

  const float3 center = make_float3(klight->co[0], klight->co[1], klight->co[2]);
  const float radius = klight->spot.radius;
  const float3 dir = make_float3(klight->spot.dir[0], klight->spot.dir[1], klight->spot.dir[2]);
  /* disk oriented normal */
  const float3 lightN = normalize(P - center);
  ls->P = center;

  if (radius > 0.0f) {
    /* disk light */
    ls->P += disk_light_sample(lightN, randu, randv) * radius;
  }

  const float invarea = klight->spot.invarea;
  ls->pdf = invarea;

  ls->D = normalize_len(ls->P - P, &ls->t);
  /* we set the light normal to the outgoing direction to support texturing */
  ls->Ng = -ls->D;

  ls->eval_fac = (0.25f * M_1_PI_F) * invarea;

  /* spot light attenuation */
  ls->eval_fac *= spot_light_attenuation(
      dir, klight->spot.cos_half_spot_angle, klight->spot.spot_smooth, -ls->D);
  if (!in_volume_segment && ls->eval_fac == 0.0f) {
    return false;
  }

  float2 uv = map_to_sphere(ls->Ng);
  ls->u = uv.x;
  ls->v = uv.y;

  ls->pdf *= lamp_light_pdf(lightN, -ls->D, ls->t);
  return true;
}

ccl_device_forceinline void spot_light_update_position(const ccl_global KernelLight *klight,
                                                       ccl_private LightSample *ls,
                                                       const float3 P)
{
  ls->D = normalize_len(ls->P - P, &ls->t);
  ls->Ng = -ls->D;

  float2 uv = map_to_sphere(ls->Ng);
  ls->u = uv.x;
  ls->v = uv.y;

  float invarea = klight->spot.invarea;
  ls->eval_fac = (0.25f * M_1_PI_F) * invarea;
  ls->pdf = invarea;

  /* spot light attenuation */
  float3 dir = make_float3(klight->spot.dir[0], klight->spot.dir[1], klight->spot.dir[2]);
  ls->eval_fac *= spot_light_attenuation(
      dir, klight->spot.cos_half_spot_angle, klight->spot.spot_smooth, ls->Ng);
}

ccl_device_inline bool spot_light_intersect(const ccl_global KernelLight *klight,
                                            const ccl_private Ray *ccl_restrict ray,
                                            ccl_private float *t)
{
  /* Spot/Disk light. */
  const float3 lightP = make_float3(klight->co[0], klight->co[1], klight->co[2]);
  const float radius = klight->spot.radius;
  if (radius == 0.0f) {
    return false;
  }
  /* disk oriented normal */
  const float3 lightN = normalize(ray->P - lightP);
  /* One sided. */
  if (dot(ray->D, lightN) >= 0.0f) {
    return false;
  }

  float3 P;
  return ray_disk_intersect(ray->P, ray->D, ray->tmin, ray->tmax, lightP, lightN, radius, &P, t);
}

ccl_device_inline bool spot_light_sample_from_intersection(
    const ccl_global KernelLight *klight,
    ccl_private const Intersection *ccl_restrict isect,
    const float3 ray_P,
    const float3 ray_D,
    ccl_private LightSample *ccl_restrict ls)
{
  const float3 center = make_float3(klight->co[0], klight->co[1], klight->co[2]);
  const float3 dir = make_float3(klight->spot.dir[0], klight->spot.dir[1], klight->spot.dir[2]);
  /* the normal of the oriented disk */
  const float3 lightN = normalize(ray_P - center);
  /* We set the light normal to the outgoing direction to support texturing. */
  ls->Ng = -ls->D;

  float invarea = klight->spot.invarea;
  ls->eval_fac = (0.25f * M_1_PI_F) * invarea;
  ls->pdf = invarea;

  /* spot light attenuation */
  ls->eval_fac *= spot_light_attenuation(
      dir, klight->spot.cos_half_spot_angle, klight->spot.spot_smooth, -ls->D);

  if (ls->eval_fac == 0.0f) {
    return false;
  }

  float2 uv = map_to_sphere(ls->Ng);
  ls->u = uv.x;
  ls->v = uv.y;

  /* compute pdf */
  if (ls->t != FLT_MAX) {
    ls->pdf *= lamp_light_pdf(lightN, -ls->D, ls->t);
  }
  else {
    ls->pdf = 0.f;
  }

  return true;
}

ccl_device_inline float spot_light_tree_weight(const ccl_global KernelLight *klight,
                                               const float3 P,
                                               const float3 N)
{
  const float3 light_P = make_float3(klight->co[0], klight->co[1], klight->co[2]);

  const float radius = klight->spot.radius;
  const float cos_theta = klight->spot.cos_half_spot_angle;
  const float theta = fast_acosf(cos_theta);
  const float3 light_dir = make_float3(
      klight->spot.dir[0], klight->spot.dir[1], klight->spot.dir[2]);

  const float h1 = radius * fast_sinf(theta);
  const float d1 = radius * cos_theta;
  const float h2 = d1 / fast_tanf(theta);

  const float3 apex = light_P - (h1 + h2) * light_dir;
  const float3 apex_to_point = normalize(P - apex);

  return (dot(apex_to_point, light_dir) < cos_theta) ? 0.0f : 1.0f;
}

CCL_NAMESPACE_END