-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathLightSource.cpp
More file actions
121 lines (111 loc) · 4.33 KB
/
LightSource.cpp
File metadata and controls
121 lines (111 loc) · 4.33 KB
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
// This is a personal academic project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: https://pvs-studio.com
#include "template.h"
#include "scene.h"
#include "ray.h"
#include "LightSource.h"
#include "Noise.h"
#include "camera.h"
float2 MapRectToCircle(float2 rect)
{
const float radius = sqrt(rect.x);
const float angle = rect.y * 2.0f * PI;
return float2(radius * std::cosf(angle), radius * std::sinf(angle));
}
float3 SphericalDirectionalLightRayDirection(float2 rect, float3 direction, float radius)
{
constexpr float3 WORLD_UP(0, 1, 0);
const float2 point = MapRectToCircle(rect) * radius;
const float3 tangent = normalize(cross(direction, WORLD_UP));
const float3 bitangent = normalize(cross(tangent, direction));
return normalize(direction + point.x * tangent + point.y * bitangent);
}
static bool UseBluenoise(const Scene* const scene, const Context& context)
{
return context.IsFirstSPP() && scene->GetSettingsR().m_denoiser.m_type == Settings::Denoiser::Noise::BlueNoise;
}
bool Light::IsVisible(const Scene* scene, const Ray& ray, bool ignoreTransparent, const Context& context) const
{
float3 bias = 0;
if (m_softness > 0 && scene->GetSettingsR().m_lightSampler.m_enableSoftLights)
{
if (UseBluenoise(scene, context))
{
const int2 scrpos = context.XY();
bias = Noise::Blue::GetFloat3(scrpos.x, scrpos.y);
}
else // use white noise otherwise
{
bias = float3(RandomFloat(), RandomFloat(), RandomFloat());
}
const float angle = bias.x * 2.0f * PI;
const float radius = sqrt(bias.y) * (m_softness / 10.f); // sqrt ensures uniform distribution
const float3 diskBias = float3(cos(angle) * radius, sin(angle) * radius, 0);
bias = (diskBias * m_softness);
}
const float3 origin = ray.IntersectionPoint() + ray.GetNormal() * 0.001f;
switch (m_type)
{
case Type::Point:
{
float3 direction = (m_position + bias - origin);
const float maxLength = length(direction) + 1e-4f;
direction /= maxLength;
Ray shadowRay(origin, direction, maxLength);
return !scene->IsOccluded(shadowRay, ignoreTransparent);
}
case Type::Directional:
{
const float3 direction = normalize(-m_direction + bias);
// no division by length, since rays have to be infinite
Ray shadowRay(origin, direction);
return !scene->IsOccluded(shadowRay, ignoreTransparent);
}
case Type::Spot:
{
float3 direction = m_position + bias - origin;
const float maxLength = length(direction) + 1e-4f;
direction /= maxLength;
if (dot(direction, -m_direction) < m_angleCos) return false;
Ray shadowRay(origin, direction, maxLength);
return !scene->IsOccluded(shadowRay, ignoreTransparent);
}
}
return false;
}
mat4 Light::GetMatrix(float scale) const
{
float3 right = cross(float3(0, 1, 0), m_direction);
if (dot(right, right) < 0.0001f)
right = cross(float3(1, 0, 0), m_direction);
right = normalize(right);
float3 up = normalize(cross(m_direction, right));
mat4 result = mat4::Identity();
result = mat4::Scale(m_radius * scale) * result;
result = mat4::Translate(m_position) * result;
return result;
}
float Light::GetImpact(float3 sample, float3 surfaceNormal) const
{
const float distanceSqr = sqrLength(m_position - sample);
float3 dir;
if (m_type == Type::Directional) dir = -m_direction;
else dir = (m_position - sample) / sqrtf(distanceSqr);
float result = 0;
switch (m_type)
{
case Type::Point: result = m_intensity * m_radius / (distanceSqr); break;
case Type::Spot:
{
const float cosTheta = dot(dir, -m_direction);
if (cosTheta < m_angleCos) return 0.0f; // point is outside the spotlight cone
const float innerCos = m_angleCos + m_softness;
float falloff = clamp((cosTheta - m_angleCos) / (innerCos - m_angleCos), 0.0f, 1.0f);
falloff = falloff * falloff;
result = m_intensity * m_radius / distanceSqr * falloff;
} break;
case Type::Directional: result = m_intensity; break;
}
result = result * std::max(0.0f, dot(dir, surfaceNormal));
return result;
}