Cycles/EEVEE: change point light to double-sided sphere light #108506

Merged
Weizhen Huang merged 18 commits from weizhen/blender:point_light_to_sphere_light into main 2023-06-20 12:23:12 +02:00
2 changed files with 54 additions and 4 deletions
Showing only changes of commit 9e816b8cef - Show all commits

View File

@ -325,6 +325,20 @@ float light_diffuse(LightData ld, vec3 N, vec3 V, vec4 l_vector)
return ltc_evaluate_disk(N, V, mat3(1.0), points);
}
else if (ld.l_type == POINT) {
if (l_vector.w < ld.l_radius) {
/* Inside, treat as hemispherical light. */
return 1.0;
}
else {
/* Outside, treat as disk light spanning the same solid angle. */
/* The result is the same as passing the scaled radius to #ltc_evaluate_disk_simple (see
* #light_specular), using simplified math here. */
float r_sqr = sqr(ld.l_radius / l_vector.w);
vec3 L = l_vector.xyz / l_vector.w;
return r_sqr * diffuse_sphere_integral(dot(N, L), r_sqr);
}
}
else {
float radius = ld.l_radius;
radius /= (ld.l_type == SUN) ? 1.0 : l_vector.w;
@ -347,11 +361,21 @@ float light_specular(LightData ld, vec4 ltc_mat, vec3 N, vec3 V, vec4 l_vector)
return ltc_evaluate_quad(corners, vec3(0.0, 0.0, 1.0));
}
else if (ld.l_type == POINT && l_vector.w < ld.l_radius) {
/* Inside the sphere light, integrate over the hemisphere. */
return 1.0;
}
else {
bool is_ellipse = (ld.l_type == AREA_ELLIPSE);
float radius_x = is_ellipse ? ld.l_sizex : ld.l_radius;
float radius_y = is_ellipse ? ld.l_sizey : ld.l_radius;
if (ld.l_type == POINT) {
/* Sphere light spans a larger angle than a disk light with the same radius (sin -> tan). */
radius_x *= inversesqrt(1.0 - sqr(radius_x / l_vector.w));
radius_y *= inversesqrt(1.0 - sqr(radius_y / l_vector.w));
}
vec3 L = (ld.l_type == SUN) ? -ld.l_forward : l_vector.xyz;
vec3 Px = ld.l_right;
vec3 Py = ld.l_up;

View File

@ -106,7 +106,20 @@ float light_diffuse(sampler2DArray utility_tx,
vec3 L,
float dist)
{
if (is_directional || !is_area_light(ld.type)) {
if (ld.type == LIGHT_POINT) {
if (dist < ld._radius) {
/* Inside, treat as hemispherical light. */
return 1.0;
}
else {
/* Outside, treat as disk light spanning the same solid angle. */
/* The result is the same as passing the scaled radius to #ltc_evaluate_disk_simple (see
* #light_ltc), using simplified math here. */
float r_sqr = sqr(ld._radius / dist);
return r_sqr * ltc_diffuse_sphere_integral(utility_tx, dot(N, L), r_sqr);
}
}
else if (is_directional || ld.type == LIGHT_SPOT) {
float radius = ld._radius / dist;
return ltc_evaluate_disk_simple(utility_tx, radius, dot(N, L));
}
@ -147,7 +160,11 @@ float light_ltc(sampler2DArray utility_tx,
float dist,
vec4 ltc_mat)
{
if (is_directional || ld.type != LIGHT_RECT) {
if (ld.type == LIGHT_POINT && dist < ld._radius) {
/* Inside the sphere light, integrate over the hemisphere. */
return 1.0;
}
else if (is_directional || ld.type != LIGHT_RECT) {
vec3 Px = ld._right;
vec3 Py = ld._up;
@ -156,8 +173,17 @@ float light_ltc(sampler2DArray utility_tx,
}
vec3 points[3];
points[0] = Px * -ld._area_size_x + Py * -ld._area_size_y;
points[1] = Px * ld._area_size_x + Py * -ld._area_size_y;
if (ld.type == LIGHT_POINT) {
/* Sphere light spans a larger angle than a disk light with the same radius (sin -> tan). */
weizhen marked this conversation as resolved Outdated

This sin -> tan is a bit cryptic. It could help if it was a full sentence.

This `sin -> tan` is a bit cryptic. It could help if it was a full sentence.
float radius = ld._radius * inversesqrt(1.0 - sqr(ld._radius / dist));
points[0] = Px * -radius + Py * -radius;
points[1] = Px * radius + Py * -radius;
}
else {
points[0] = Px * -ld._area_size_x + Py * -ld._area_size_y;
points[1] = Px * ld._area_size_x + Py * -ld._area_size_y;
}
points[2] = -points[0];
points[0] += L * dist;