2023-06-14 16:52:36 +10:00
|
|
|
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
|
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: Apache-2.0 */
|
2022-11-30 20:17:45 +01:00
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include "kernel/light/common.h"
|
|
|
|
|
|
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
|
|
|
|
|
|
/* Importance sampling.
|
|
|
|
|
*
|
|
|
|
|
* An Area-Preserving Parametrization for Spherical Rectangles.
|
|
|
|
|
* Carlos Urena et al.
|
|
|
|
|
*
|
|
|
|
|
* NOTE: light_p is modified when sample_coord is true. */
|
|
|
|
|
ccl_device_inline float area_light_rect_sample(float3 P,
|
|
|
|
|
ccl_private float3 *light_p,
|
2022-12-02 15:21:57 +01:00
|
|
|
const float3 axis_u,
|
|
|
|
|
const float len_u,
|
|
|
|
|
const float3 axis_v,
|
|
|
|
|
const float len_v,
|
2023-05-24 18:56:58 +02:00
|
|
|
const float2 rand,
|
2022-11-30 20:17:45 +01:00
|
|
|
bool sample_coord)
|
|
|
|
|
{
|
|
|
|
|
/* In our name system we're using P for the center, which is o in the paper. */
|
2022-12-02 15:21:57 +01:00
|
|
|
float3 corner = *light_p - axis_u * len_u * 0.5f - axis_v * len_v * 0.5f;
|
2022-11-30 20:17:45 +01:00
|
|
|
/* Compute local reference system R. */
|
2022-12-02 15:21:57 +01:00
|
|
|
float3 x = axis_u;
|
|
|
|
|
float3 y = axis_v;
|
2022-11-30 20:17:45 +01:00
|
|
|
float3 z = cross(x, y);
|
|
|
|
|
/* Compute rectangle coords in local reference system. */
|
|
|
|
|
float3 dir = corner - P;
|
|
|
|
|
float z0 = dot(dir, z);
|
|
|
|
|
/* Flip 'z' to make it point against Q. */
|
|
|
|
|
if (z0 > 0.0f) {
|
|
|
|
|
z *= -1.0f;
|
|
|
|
|
z0 *= -1.0f;
|
|
|
|
|
}
|
|
|
|
|
float x0 = dot(dir, x);
|
|
|
|
|
float y0 = dot(dir, y);
|
2022-12-02 15:21:57 +01:00
|
|
|
float x1 = x0 + len_u;
|
|
|
|
|
float y1 = y0 + len_v;
|
2023-10-05 22:53:05 +02:00
|
|
|
/* Compute predefined constants. */
|
2022-11-30 20:17:45 +01:00
|
|
|
float4 diff = make_float4(x0, y1, x1, y0) - make_float4(x1, y0, x0, y1);
|
|
|
|
|
float4 nz = make_float4(y0, x1, y1, x0) * diff;
|
|
|
|
|
nz = nz / sqrt(z0 * z0 * diff * diff + nz * nz);
|
2023-10-27 12:13:48 +11:00
|
|
|
/* The original paper uses `acos()` to compute the internal angles here, and then computes the
|
2023-10-05 22:53:05 +02:00
|
|
|
* solid angle as their sum minus 2*pi. However, for very small rectangles, this results in
|
|
|
|
|
* excessive cancellation error since the sum will be almost 2*pi as well.
|
2023-10-10 09:44:46 +11:00
|
|
|
* This can be avoided by using that `asin(x) = pi/2 - acos(x)`. */
|
2023-10-05 22:53:05 +02:00
|
|
|
float g0 = safe_asinf(-nz.x * nz.y);
|
|
|
|
|
float g1 = safe_asinf(-nz.y * nz.z);
|
|
|
|
|
float g2 = safe_asinf(-nz.z * nz.w);
|
|
|
|
|
float g3 = safe_asinf(-nz.w * nz.x);
|
|
|
|
|
float S = -(g0 + g1 + g2 + g3);
|
2022-11-30 20:17:45 +01:00
|
|
|
|
|
|
|
|
if (sample_coord) {
|
2023-10-05 22:53:05 +02:00
|
|
|
/* Compute predefined constants. */
|
|
|
|
|
float b0 = nz.x;
|
|
|
|
|
float b1 = nz.z;
|
|
|
|
|
float b0sq = b0 * b0;
|
|
|
|
|
/* Compute cu.
|
|
|
|
|
* In the original paper, an additional constant k is involved here. However, just like above,
|
2023-10-27 12:13:48 +11:00
|
|
|
* it causes cancellation issues. The same `asin()` terms from above can be used instead, and
|
|
|
|
|
* the extra +pi that would remain in the expression for au can be removed by flipping the sign
|
2023-10-05 22:53:05 +02:00
|
|
|
* of cos(au) and sin(au), which also cancels if we flip the sign of b1 in the fu term. */
|
|
|
|
|
float au = rand.x * S + g2 + g3;
|
|
|
|
|
float fu = (cosf(au) * b0 + b1) / sinf(au);
|
|
|
|
|
float cu = copysignf(1.0f / sqrtf(fu * fu + b0sq), fu);
|
2022-11-30 20:17:45 +01:00
|
|
|
cu = clamp(cu, -1.0f, 1.0f);
|
|
|
|
|
/* Compute xu. */
|
|
|
|
|
float xu = -(cu * z0) / max(sqrtf(1.0f - cu * cu), 1e-7f);
|
|
|
|
|
xu = clamp(xu, x0, x1);
|
|
|
|
|
/* Compute yv. */
|
|
|
|
|
float z0sq = z0 * z0;
|
|
|
|
|
float y0sq = y0 * y0;
|
|
|
|
|
float y1sq = y1 * y1;
|
|
|
|
|
float d = sqrtf(xu * xu + z0sq);
|
|
|
|
|
float h0 = y0 / sqrtf(d * d + y0sq);
|
|
|
|
|
float h1 = y1 / sqrtf(d * d + y1sq);
|
2023-05-24 18:56:58 +02:00
|
|
|
float hv = h0 + rand.y * (h1 - h0), hv2 = hv * hv;
|
2022-11-30 20:17:45 +01:00
|
|
|
float yv = (hv2 < 1.0f - 1e-6f) ? (hv * d) / sqrtf(1.0f - hv2) : y1;
|
|
|
|
|
|
|
|
|
|
/* Transform (xu, yv, z0) to world coords. */
|
|
|
|
|
*light_p = P + xu * x + yv * y + z0 * z;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* return pdf */
|
2023-09-24 14:52:38 +10:00
|
|
|
if (S != 0.0f) {
|
2022-11-30 20:17:45 +01:00
|
|
|
return 1.0f / S;
|
2023-09-24 14:52:38 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2022-11-30 20:17:45 +01:00
|
|
|
return 0.0f;
|
2023-09-24 14:52:38 +10:00
|
|
|
}
|
2022-11-30 20:17:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Light spread. */
|
|
|
|
|
|
|
|
|
|
ccl_device float area_light_spread_attenuation(const float3 D,
|
|
|
|
|
const float3 lightNg,
|
2022-12-07 18:51:26 +01:00
|
|
|
const float tan_half_spread,
|
2022-11-30 20:17:45 +01:00
|
|
|
const float normalize_spread)
|
|
|
|
|
{
|
|
|
|
|
/* Model a soft-box grid, computing the ratio of light not hidden by the
|
|
|
|
|
* slats of the grid at a given angle. (see D10594). */
|
2023-06-22 17:47:54 +02:00
|
|
|
const float tan_a = tan_angle(-D, lightNg);
|
|
|
|
|
|
2022-12-07 19:55:13 +01:00
|
|
|
if (tan_half_spread == 0.0f) {
|
|
|
|
|
/* The factor M_PI_F comes from integrating the radiance over the hemisphere */
|
2023-06-22 17:47:54 +02:00
|
|
|
return (tan_a > 1e-5f) ? 0.0f : M_PI_F;
|
2022-12-07 19:55:13 +01:00
|
|
|
}
|
2023-06-22 17:47:54 +02:00
|
|
|
|
2022-12-07 18:51:26 +01:00
|
|
|
return max((tan_half_spread - tan_a) * normalize_spread, 0.0f);
|
2022-11-30 20:17:45 +01:00
|
|
|
}
|
|
|
|
|
|
Cycles: improve sampling of ellipse area light with spread
**Problem**:
Area lights in Cycles have spread angle, in which case some part of the area light might be invisible to a shading point. The current implementation samples the whole area light, resulting some samples invisible and thus simply discarded. A technique is applied on rectangular light to sample a subset of the area light that is potentially visible (rB3f24cfb9582e1c826406301d37808df7ca6aa64c), however, ellipse (including disk) area lights remained untreated. The purpose of this patch is to apply a techniques to ellipse area light.
**Related Task**:
T87053
**Results**:
These are renderings before and after the patch:
|16spp|Disk light|Ellipse light|Square light (for reference, no changes)
|Before|{F13996789}|{F13996788}|{F13996822}
|After|{F13996759}|{F13996787}|{F13996852}
**Explanation**:
The visible region on an area light is found by drawing a cone from the shading point to the plane where the area light lies, with the aperture of the cone being the light spread.
{F13990078,height=200}
Ideally, we would like to draw samples only from the intersection of the area light and the projection of the cone onto the plane (forming a circle). However, the shape of the intersection is often irregular and thus hard to sample from directly.
{F13990104,height=200}
Instead, the current implementation draws samples from the bounding rectangle of the intersection. In this case, we still end up with some invalid samples outside of the circle, but already much less than sampling the original area light, and the bounding rectangle is easy to sample from.
{F13990125}
The above technique is only applied to rectangle area lights, ellipse area light still suffers from poor sampling. We could apply a similar technique to ellipse area lights, that is, find the
smallest regular shape (rectangle, circle, or ellipse) that covers the intersection (or maybe not the smallest but easy to compute).
For disk area light, we consider the relative position of both circles. Denoting `dist` as the distance between the centre of two circles, and `r1`, `r2` their radii. If `dist > r1 + r2`, the area light is completely invisible, we directly return `false`. If `dist < abs(r1 - r2)`, the smaller circle lies inside the larger one, and we sample whichever circle is smaller. Otherwise, the two circles intersect, we compute the bounding rectangle of the intersection, in which case `axis_u`, `len_u`, `axis_v`, `len_v` needs to be computed anew. Depending on the distance between the two circles, `len_v` is either the diameter of the smaller circle or the length of the common chord.
|{F13990211,height=195}|{F13990225,height=195}|{F13990274,height=195}|{F13990210,height=195}
|`dist > r1 + r2`|`dist < abs(r1 - r2)`|`dist^2 < abs(r1^2 - r2^2)`|`dist^2 > abs(r1^2 - r2^2)`
For ellipse area light, it's hard to find the smallest bounding shape of the intersection, therefore, we compute the bounding rectangle of the ellipse itself, then treat it as a rectangle light.
|{F13990386,height=195}|{F13990385,height=195}|{F13990387,height=195}
We also check the areas of the bounding rectangle of the intersection, the ellipse (disk) light, and the spread circle, then draw samples from the smallest shape of the three. For ellipse light, this also detects where one shape lies inside the other. I am not sure if we should add this measure to rectangle area light and sample from the spread circle when it has smaller area, as we seem to have a better sampling technique for rectangular (uniformly sample the solid angle). Maybe we could add [area-preserving parameterization for spherical
ellipse](https://arxiv.org/pdf/1805.09048.pdf) in the future.
**Limitation**:
At some point we switch from sampling the ellipse to sampling the rectangle, depending on the area of the both, and there seems to be a visible line (with |slope| =1) on the final rendering
which demonstrate at which point we switch between the two methods. We could see that the new sampling method clearly has lower variance near the boundaries, but close to that visible line,
the rectangle sampling method seems to have larger variance. I could not spot any bug in the implementation, and I am not sure if this happens because different sampling patterns for ellipse and rectangle are used.
|Before (256spp)|After (256spp)
|{F13996995}|{F13996998}
Differential Revision: https://developer.blender.org/D16694
2022-12-05 14:35:25 +01:00
|
|
|
/* Compute the minimal rectangle, circle or ellipse that covers the valid sample region, to reduce
|
|
|
|
|
* noise with low spread. */
|
|
|
|
|
ccl_device bool area_light_spread_clamp_light(const float3 P,
|
|
|
|
|
const float3 lightNg,
|
|
|
|
|
ccl_private float3 *lightP,
|
|
|
|
|
ccl_private float3 *axis_u,
|
|
|
|
|
ccl_private float *len_u,
|
|
|
|
|
ccl_private float3 *axis_v,
|
|
|
|
|
ccl_private float *len_v,
|
2022-12-07 18:51:26 +01:00
|
|
|
const float tan_half_spread,
|
Cycles: improve sampling of ellipse area light with spread
**Problem**:
Area lights in Cycles have spread angle, in which case some part of the area light might be invisible to a shading point. The current implementation samples the whole area light, resulting some samples invisible and thus simply discarded. A technique is applied on rectangular light to sample a subset of the area light that is potentially visible (rB3f24cfb9582e1c826406301d37808df7ca6aa64c), however, ellipse (including disk) area lights remained untreated. The purpose of this patch is to apply a techniques to ellipse area light.
**Related Task**:
T87053
**Results**:
These are renderings before and after the patch:
|16spp|Disk light|Ellipse light|Square light (for reference, no changes)
|Before|{F13996789}|{F13996788}|{F13996822}
|After|{F13996759}|{F13996787}|{F13996852}
**Explanation**:
The visible region on an area light is found by drawing a cone from the shading point to the plane where the area light lies, with the aperture of the cone being the light spread.
{F13990078,height=200}
Ideally, we would like to draw samples only from the intersection of the area light and the projection of the cone onto the plane (forming a circle). However, the shape of the intersection is often irregular and thus hard to sample from directly.
{F13990104,height=200}
Instead, the current implementation draws samples from the bounding rectangle of the intersection. In this case, we still end up with some invalid samples outside of the circle, but already much less than sampling the original area light, and the bounding rectangle is easy to sample from.
{F13990125}
The above technique is only applied to rectangle area lights, ellipse area light still suffers from poor sampling. We could apply a similar technique to ellipse area lights, that is, find the
smallest regular shape (rectangle, circle, or ellipse) that covers the intersection (or maybe not the smallest but easy to compute).
For disk area light, we consider the relative position of both circles. Denoting `dist` as the distance between the centre of two circles, and `r1`, `r2` their radii. If `dist > r1 + r2`, the area light is completely invisible, we directly return `false`. If `dist < abs(r1 - r2)`, the smaller circle lies inside the larger one, and we sample whichever circle is smaller. Otherwise, the two circles intersect, we compute the bounding rectangle of the intersection, in which case `axis_u`, `len_u`, `axis_v`, `len_v` needs to be computed anew. Depending on the distance between the two circles, `len_v` is either the diameter of the smaller circle or the length of the common chord.
|{F13990211,height=195}|{F13990225,height=195}|{F13990274,height=195}|{F13990210,height=195}
|`dist > r1 + r2`|`dist < abs(r1 - r2)`|`dist^2 < abs(r1^2 - r2^2)`|`dist^2 > abs(r1^2 - r2^2)`
For ellipse area light, it's hard to find the smallest bounding shape of the intersection, therefore, we compute the bounding rectangle of the ellipse itself, then treat it as a rectangle light.
|{F13990386,height=195}|{F13990385,height=195}|{F13990387,height=195}
We also check the areas of the bounding rectangle of the intersection, the ellipse (disk) light, and the spread circle, then draw samples from the smallest shape of the three. For ellipse light, this also detects where one shape lies inside the other. I am not sure if we should add this measure to rectangle area light and sample from the spread circle when it has smaller area, as we seem to have a better sampling technique for rectangular (uniformly sample the solid angle). Maybe we could add [area-preserving parameterization for spherical
ellipse](https://arxiv.org/pdf/1805.09048.pdf) in the future.
**Limitation**:
At some point we switch from sampling the ellipse to sampling the rectangle, depending on the area of the both, and there seems to be a visible line (with |slope| =1) on the final rendering
which demonstrate at which point we switch between the two methods. We could see that the new sampling method clearly has lower variance near the boundaries, but close to that visible line,
the rectangle sampling method seems to have larger variance. I could not spot any bug in the implementation, and I am not sure if this happens because different sampling patterns for ellipse and rectangle are used.
|Before (256spp)|After (256spp)
|{F13996995}|{F13996998}
Differential Revision: https://developer.blender.org/D16694
2022-12-05 14:35:25 +01:00
|
|
|
ccl_private bool *sample_rectangle)
|
2022-11-30 20:17:45 +01:00
|
|
|
{
|
2023-06-26 11:47:50 +02:00
|
|
|
/* Distance from shading point to area light plane and the closest point on that plane. */
|
|
|
|
|
const float t = dot(lightNg, P - *lightP);
|
|
|
|
|
const float3 closest_P = P - t * lightNg;
|
2022-11-30 20:17:45 +01:00
|
|
|
|
|
|
|
|
/* Radius of circle on area light that actually affects the shading point. */
|
2022-12-07 18:51:26 +01:00
|
|
|
const float r_spread = t * tan_half_spread;
|
2022-11-30 20:17:45 +01:00
|
|
|
|
|
|
|
|
/* Local uv coordinates of closest point. */
|
Cycles: improve sampling of ellipse area light with spread
**Problem**:
Area lights in Cycles have spread angle, in which case some part of the area light might be invisible to a shading point. The current implementation samples the whole area light, resulting some samples invisible and thus simply discarded. A technique is applied on rectangular light to sample a subset of the area light that is potentially visible (rB3f24cfb9582e1c826406301d37808df7ca6aa64c), however, ellipse (including disk) area lights remained untreated. The purpose of this patch is to apply a techniques to ellipse area light.
**Related Task**:
T87053
**Results**:
These are renderings before and after the patch:
|16spp|Disk light|Ellipse light|Square light (for reference, no changes)
|Before|{F13996789}|{F13996788}|{F13996822}
|After|{F13996759}|{F13996787}|{F13996852}
**Explanation**:
The visible region on an area light is found by drawing a cone from the shading point to the plane where the area light lies, with the aperture of the cone being the light spread.
{F13990078,height=200}
Ideally, we would like to draw samples only from the intersection of the area light and the projection of the cone onto the plane (forming a circle). However, the shape of the intersection is often irregular and thus hard to sample from directly.
{F13990104,height=200}
Instead, the current implementation draws samples from the bounding rectangle of the intersection. In this case, we still end up with some invalid samples outside of the circle, but already much less than sampling the original area light, and the bounding rectangle is easy to sample from.
{F13990125}
The above technique is only applied to rectangle area lights, ellipse area light still suffers from poor sampling. We could apply a similar technique to ellipse area lights, that is, find the
smallest regular shape (rectangle, circle, or ellipse) that covers the intersection (or maybe not the smallest but easy to compute).
For disk area light, we consider the relative position of both circles. Denoting `dist` as the distance between the centre of two circles, and `r1`, `r2` their radii. If `dist > r1 + r2`, the area light is completely invisible, we directly return `false`. If `dist < abs(r1 - r2)`, the smaller circle lies inside the larger one, and we sample whichever circle is smaller. Otherwise, the two circles intersect, we compute the bounding rectangle of the intersection, in which case `axis_u`, `len_u`, `axis_v`, `len_v` needs to be computed anew. Depending on the distance between the two circles, `len_v` is either the diameter of the smaller circle or the length of the common chord.
|{F13990211,height=195}|{F13990225,height=195}|{F13990274,height=195}|{F13990210,height=195}
|`dist > r1 + r2`|`dist < abs(r1 - r2)`|`dist^2 < abs(r1^2 - r2^2)`|`dist^2 > abs(r1^2 - r2^2)`
For ellipse area light, it's hard to find the smallest bounding shape of the intersection, therefore, we compute the bounding rectangle of the ellipse itself, then treat it as a rectangle light.
|{F13990386,height=195}|{F13990385,height=195}|{F13990387,height=195}
We also check the areas of the bounding rectangle of the intersection, the ellipse (disk) light, and the spread circle, then draw samples from the smallest shape of the three. For ellipse light, this also detects where one shape lies inside the other. I am not sure if we should add this measure to rectangle area light and sample from the spread circle when it has smaller area, as we seem to have a better sampling technique for rectangular (uniformly sample the solid angle). Maybe we could add [area-preserving parameterization for spherical
ellipse](https://arxiv.org/pdf/1805.09048.pdf) in the future.
**Limitation**:
At some point we switch from sampling the ellipse to sampling the rectangle, depending on the area of the both, and there seems to be a visible line (with |slope| =1) on the final rendering
which demonstrate at which point we switch between the two methods. We could see that the new sampling method clearly has lower variance near the boundaries, but close to that visible line,
the rectangle sampling method seems to have larger variance. I could not spot any bug in the implementation, and I am not sure if this happens because different sampling patterns for ellipse and rectangle are used.
|Before (256spp)|After (256spp)
|{F13996995}|{F13996998}
Differential Revision: https://developer.blender.org/D16694
2022-12-05 14:35:25 +01:00
|
|
|
const float spread_u = dot(*axis_u, closest_P - *lightP);
|
|
|
|
|
const float spread_v = dot(*axis_v, closest_P - *lightP);
|
|
|
|
|
|
|
|
|
|
const bool is_round = !(*sample_rectangle) && (*len_u == *len_v);
|
|
|
|
|
|
|
|
|
|
/* Whether we should sample the spread circle. */
|
2022-12-07 19:55:13 +01:00
|
|
|
bool sample_spread = (r_spread == 0.0f);
|
|
|
|
|
if (is_round && !sample_spread) {
|
Cycles: improve sampling of ellipse area light with spread
**Problem**:
Area lights in Cycles have spread angle, in which case some part of the area light might be invisible to a shading point. The current implementation samples the whole area light, resulting some samples invisible and thus simply discarded. A technique is applied on rectangular light to sample a subset of the area light that is potentially visible (rB3f24cfb9582e1c826406301d37808df7ca6aa64c), however, ellipse (including disk) area lights remained untreated. The purpose of this patch is to apply a techniques to ellipse area light.
**Related Task**:
T87053
**Results**:
These are renderings before and after the patch:
|16spp|Disk light|Ellipse light|Square light (for reference, no changes)
|Before|{F13996789}|{F13996788}|{F13996822}
|After|{F13996759}|{F13996787}|{F13996852}
**Explanation**:
The visible region on an area light is found by drawing a cone from the shading point to the plane where the area light lies, with the aperture of the cone being the light spread.
{F13990078,height=200}
Ideally, we would like to draw samples only from the intersection of the area light and the projection of the cone onto the plane (forming a circle). However, the shape of the intersection is often irregular and thus hard to sample from directly.
{F13990104,height=200}
Instead, the current implementation draws samples from the bounding rectangle of the intersection. In this case, we still end up with some invalid samples outside of the circle, but already much less than sampling the original area light, and the bounding rectangle is easy to sample from.
{F13990125}
The above technique is only applied to rectangle area lights, ellipse area light still suffers from poor sampling. We could apply a similar technique to ellipse area lights, that is, find the
smallest regular shape (rectangle, circle, or ellipse) that covers the intersection (or maybe not the smallest but easy to compute).
For disk area light, we consider the relative position of both circles. Denoting `dist` as the distance between the centre of two circles, and `r1`, `r2` their radii. If `dist > r1 + r2`, the area light is completely invisible, we directly return `false`. If `dist < abs(r1 - r2)`, the smaller circle lies inside the larger one, and we sample whichever circle is smaller. Otherwise, the two circles intersect, we compute the bounding rectangle of the intersection, in which case `axis_u`, `len_u`, `axis_v`, `len_v` needs to be computed anew. Depending on the distance between the two circles, `len_v` is either the diameter of the smaller circle or the length of the common chord.
|{F13990211,height=195}|{F13990225,height=195}|{F13990274,height=195}|{F13990210,height=195}
|`dist > r1 + r2`|`dist < abs(r1 - r2)`|`dist^2 < abs(r1^2 - r2^2)`|`dist^2 > abs(r1^2 - r2^2)`
For ellipse area light, it's hard to find the smallest bounding shape of the intersection, therefore, we compute the bounding rectangle of the ellipse itself, then treat it as a rectangle light.
|{F13990386,height=195}|{F13990385,height=195}|{F13990387,height=195}
We also check the areas of the bounding rectangle of the intersection, the ellipse (disk) light, and the spread circle, then draw samples from the smallest shape of the three. For ellipse light, this also detects where one shape lies inside the other. I am not sure if we should add this measure to rectangle area light and sample from the spread circle when it has smaller area, as we seem to have a better sampling technique for rectangular (uniformly sample the solid angle). Maybe we could add [area-preserving parameterization for spherical
ellipse](https://arxiv.org/pdf/1805.09048.pdf) in the future.
**Limitation**:
At some point we switch from sampling the ellipse to sampling the rectangle, depending on the area of the both, and there seems to be a visible line (with |slope| =1) on the final rendering
which demonstrate at which point we switch between the two methods. We could see that the new sampling method clearly has lower variance near the boundaries, but close to that visible line,
the rectangle sampling method seems to have larger variance. I could not spot any bug in the implementation, and I am not sure if this happens because different sampling patterns for ellipse and rectangle are used.
|Before (256spp)|After (256spp)
|{F13996995}|{F13996998}
Differential Revision: https://developer.blender.org/D16694
2022-12-05 14:35:25 +01:00
|
|
|
/* Distance between the centers of the disk light and the valid region circle. */
|
|
|
|
|
const float dist = len(make_float2(spread_u, spread_v));
|
|
|
|
|
|
|
|
|
|
/* Radius of the disk light. */
|
|
|
|
|
const float r = *len_u * 0.5f;
|
|
|
|
|
|
|
|
|
|
if (dist >= r + r_spread) {
|
|
|
|
|
/* Two circles are outside each other or touch externally. */
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sample_spread = (dist <= fabsf(r - r_spread)) && (r_spread < r);
|
|
|
|
|
if (dist > fabsf(r - r_spread)) {
|
|
|
|
|
/* Two circles intersect. Find the smallest rectangle that covers the intersection */
|
|
|
|
|
const float len_u_ = r + r_spread - dist;
|
|
|
|
|
const float len_v_ = (fabsf(sqr(r) - sqr(r_spread)) >= sqr(dist)) ?
|
|
|
|
|
2.0f * fminf(r, r_spread) :
|
|
|
|
|
sqrtf(sqr(2.0f * r_spread) -
|
|
|
|
|
sqr(dist + (sqr(r_spread) - sqr(r)) / dist));
|
|
|
|
|
|
|
|
|
|
const float rect_area = len_u_ * len_v_;
|
|
|
|
|
const float circle_area = M_PI_F * sqr(r);
|
|
|
|
|
const float spread_area = M_PI_F * sqr(r_spread);
|
|
|
|
|
|
|
|
|
|
/* Sample the shape with minimal area. */
|
|
|
|
|
if (rect_area < fminf(circle_area, spread_area)) {
|
|
|
|
|
*sample_rectangle = true;
|
|
|
|
|
*axis_u = normalize(*lightP - closest_P);
|
|
|
|
|
*axis_v = rotate_around_axis(*axis_u, lightNg, M_PI_2_F);
|
|
|
|
|
*len_u = len_u_;
|
|
|
|
|
*len_v = len_v_;
|
|
|
|
|
*lightP = 0.5f * (*lightP + closest_P + *axis_u * (r_spread - r));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sample_spread = (spread_area < circle_area);
|
|
|
|
|
}
|
2022-11-30 20:17:45 +01:00
|
|
|
}
|
2022-12-07 19:55:13 +01:00
|
|
|
else if (!is_round && !sample_spread) {
|
Cycles: improve sampling of ellipse area light with spread
**Problem**:
Area lights in Cycles have spread angle, in which case some part of the area light might be invisible to a shading point. The current implementation samples the whole area light, resulting some samples invisible and thus simply discarded. A technique is applied on rectangular light to sample a subset of the area light that is potentially visible (rB3f24cfb9582e1c826406301d37808df7ca6aa64c), however, ellipse (including disk) area lights remained untreated. The purpose of this patch is to apply a techniques to ellipse area light.
**Related Task**:
T87053
**Results**:
These are renderings before and after the patch:
|16spp|Disk light|Ellipse light|Square light (for reference, no changes)
|Before|{F13996789}|{F13996788}|{F13996822}
|After|{F13996759}|{F13996787}|{F13996852}
**Explanation**:
The visible region on an area light is found by drawing a cone from the shading point to the plane where the area light lies, with the aperture of the cone being the light spread.
{F13990078,height=200}
Ideally, we would like to draw samples only from the intersection of the area light and the projection of the cone onto the plane (forming a circle). However, the shape of the intersection is often irregular and thus hard to sample from directly.
{F13990104,height=200}
Instead, the current implementation draws samples from the bounding rectangle of the intersection. In this case, we still end up with some invalid samples outside of the circle, but already much less than sampling the original area light, and the bounding rectangle is easy to sample from.
{F13990125}
The above technique is only applied to rectangle area lights, ellipse area light still suffers from poor sampling. We could apply a similar technique to ellipse area lights, that is, find the
smallest regular shape (rectangle, circle, or ellipse) that covers the intersection (or maybe not the smallest but easy to compute).
For disk area light, we consider the relative position of both circles. Denoting `dist` as the distance between the centre of two circles, and `r1`, `r2` their radii. If `dist > r1 + r2`, the area light is completely invisible, we directly return `false`. If `dist < abs(r1 - r2)`, the smaller circle lies inside the larger one, and we sample whichever circle is smaller. Otherwise, the two circles intersect, we compute the bounding rectangle of the intersection, in which case `axis_u`, `len_u`, `axis_v`, `len_v` needs to be computed anew. Depending on the distance between the two circles, `len_v` is either the diameter of the smaller circle or the length of the common chord.
|{F13990211,height=195}|{F13990225,height=195}|{F13990274,height=195}|{F13990210,height=195}
|`dist > r1 + r2`|`dist < abs(r1 - r2)`|`dist^2 < abs(r1^2 - r2^2)`|`dist^2 > abs(r1^2 - r2^2)`
For ellipse area light, it's hard to find the smallest bounding shape of the intersection, therefore, we compute the bounding rectangle of the ellipse itself, then treat it as a rectangle light.
|{F13990386,height=195}|{F13990385,height=195}|{F13990387,height=195}
We also check the areas of the bounding rectangle of the intersection, the ellipse (disk) light, and the spread circle, then draw samples from the smallest shape of the three. For ellipse light, this also detects where one shape lies inside the other. I am not sure if we should add this measure to rectangle area light and sample from the spread circle when it has smaller area, as we seem to have a better sampling technique for rectangular (uniformly sample the solid angle). Maybe we could add [area-preserving parameterization for spherical
ellipse](https://arxiv.org/pdf/1805.09048.pdf) in the future.
**Limitation**:
At some point we switch from sampling the ellipse to sampling the rectangle, depending on the area of the both, and there seems to be a visible line (with |slope| =1) on the final rendering
which demonstrate at which point we switch between the two methods. We could see that the new sampling method clearly has lower variance near the boundaries, but close to that visible line,
the rectangle sampling method seems to have larger variance. I could not spot any bug in the implementation, and I am not sure if this happens because different sampling patterns for ellipse and rectangle are used.
|Before (256spp)|After (256spp)
|{F13996995}|{F13996998}
Differential Revision: https://developer.blender.org/D16694
2022-12-05 14:35:25 +01:00
|
|
|
/* Compute rectangle encompassing the circle that affects the shading point,
|
|
|
|
|
* clamped to the bounds of the area light. */
|
|
|
|
|
const float min_u = max(spread_u - r_spread, -*len_u * 0.5f);
|
|
|
|
|
const float max_u = min(spread_u + r_spread, *len_u * 0.5f);
|
|
|
|
|
const float min_v = max(spread_v - r_spread, -*len_v * 0.5f);
|
|
|
|
|
const float max_v = min(spread_v + r_spread, *len_v * 0.5f);
|
|
|
|
|
|
|
|
|
|
/* Skip if rectangle is empty. */
|
|
|
|
|
if (min_u >= max_u || min_v >= max_v) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2022-11-30 20:17:45 +01:00
|
|
|
|
Cycles: improve sampling of ellipse area light with spread
**Problem**:
Area lights in Cycles have spread angle, in which case some part of the area light might be invisible to a shading point. The current implementation samples the whole area light, resulting some samples invisible and thus simply discarded. A technique is applied on rectangular light to sample a subset of the area light that is potentially visible (rB3f24cfb9582e1c826406301d37808df7ca6aa64c), however, ellipse (including disk) area lights remained untreated. The purpose of this patch is to apply a techniques to ellipse area light.
**Related Task**:
T87053
**Results**:
These are renderings before and after the patch:
|16spp|Disk light|Ellipse light|Square light (for reference, no changes)
|Before|{F13996789}|{F13996788}|{F13996822}
|After|{F13996759}|{F13996787}|{F13996852}
**Explanation**:
The visible region on an area light is found by drawing a cone from the shading point to the plane where the area light lies, with the aperture of the cone being the light spread.
{F13990078,height=200}
Ideally, we would like to draw samples only from the intersection of the area light and the projection of the cone onto the plane (forming a circle). However, the shape of the intersection is often irregular and thus hard to sample from directly.
{F13990104,height=200}
Instead, the current implementation draws samples from the bounding rectangle of the intersection. In this case, we still end up with some invalid samples outside of the circle, but already much less than sampling the original area light, and the bounding rectangle is easy to sample from.
{F13990125}
The above technique is only applied to rectangle area lights, ellipse area light still suffers from poor sampling. We could apply a similar technique to ellipse area lights, that is, find the
smallest regular shape (rectangle, circle, or ellipse) that covers the intersection (or maybe not the smallest but easy to compute).
For disk area light, we consider the relative position of both circles. Denoting `dist` as the distance between the centre of two circles, and `r1`, `r2` their radii. If `dist > r1 + r2`, the area light is completely invisible, we directly return `false`. If `dist < abs(r1 - r2)`, the smaller circle lies inside the larger one, and we sample whichever circle is smaller. Otherwise, the two circles intersect, we compute the bounding rectangle of the intersection, in which case `axis_u`, `len_u`, `axis_v`, `len_v` needs to be computed anew. Depending on the distance between the two circles, `len_v` is either the diameter of the smaller circle or the length of the common chord.
|{F13990211,height=195}|{F13990225,height=195}|{F13990274,height=195}|{F13990210,height=195}
|`dist > r1 + r2`|`dist < abs(r1 - r2)`|`dist^2 < abs(r1^2 - r2^2)`|`dist^2 > abs(r1^2 - r2^2)`
For ellipse area light, it's hard to find the smallest bounding shape of the intersection, therefore, we compute the bounding rectangle of the ellipse itself, then treat it as a rectangle light.
|{F13990386,height=195}|{F13990385,height=195}|{F13990387,height=195}
We also check the areas of the bounding rectangle of the intersection, the ellipse (disk) light, and the spread circle, then draw samples from the smallest shape of the three. For ellipse light, this also detects where one shape lies inside the other. I am not sure if we should add this measure to rectangle area light and sample from the spread circle when it has smaller area, as we seem to have a better sampling technique for rectangular (uniformly sample the solid angle). Maybe we could add [area-preserving parameterization for spherical
ellipse](https://arxiv.org/pdf/1805.09048.pdf) in the future.
**Limitation**:
At some point we switch from sampling the ellipse to sampling the rectangle, depending on the area of the both, and there seems to be a visible line (with |slope| =1) on the final rendering
which demonstrate at which point we switch between the two methods. We could see that the new sampling method clearly has lower variance near the boundaries, but close to that visible line,
the rectangle sampling method seems to have larger variance. I could not spot any bug in the implementation, and I am not sure if this happens because different sampling patterns for ellipse and rectangle are used.
|Before (256spp)|After (256spp)
|{F13996995}|{F13996998}
Differential Revision: https://developer.blender.org/D16694
2022-12-05 14:35:25 +01:00
|
|
|
const float rect_len_u = max_u - min_u;
|
|
|
|
|
const float rect_len_v = max_v - min_v;
|
|
|
|
|
|
|
|
|
|
const float rect_area = rect_len_u * rect_len_v;
|
|
|
|
|
const float ellipse_area = (*sample_rectangle) ? FLT_MAX : M_PI_4_F * (*len_u) * (*len_v);
|
|
|
|
|
const float spread_area = M_PI_F * sqr(r_spread);
|
|
|
|
|
|
|
|
|
|
/* Sample the shape with minimal area. */
|
|
|
|
|
/* NOTE: we don't switch to spread circle sampling for rectangle light because rectangle light
|
|
|
|
|
* supports solid angle sampling, which has less variance than sampling the area. If ellipse
|
|
|
|
|
* area light also supports solid angle sampling, `*sample_rectangle ||` could be deleted. */
|
|
|
|
|
if (*sample_rectangle || rect_area < fminf(ellipse_area, spread_area)) {
|
|
|
|
|
*sample_rectangle = true;
|
|
|
|
|
|
|
|
|
|
/* Compute new area light center position and axes from rectangle in local
|
|
|
|
|
* uv coordinates. */
|
|
|
|
|
const float new_center_u = 0.5f * (min_u + max_u);
|
|
|
|
|
const float new_center_v = 0.5f * (min_v + max_v);
|
|
|
|
|
|
|
|
|
|
*len_u = rect_len_u;
|
|
|
|
|
*len_v = rect_len_v;
|
|
|
|
|
*lightP = *lightP + *axis_u * new_center_u + *axis_v * new_center_v;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
*sample_rectangle = false;
|
|
|
|
|
sample_spread = (spread_area < ellipse_area);
|
|
|
|
|
}
|
2022-11-30 20:17:45 +01:00
|
|
|
|
Cycles: improve sampling of ellipse area light with spread
**Problem**:
Area lights in Cycles have spread angle, in which case some part of the area light might be invisible to a shading point. The current implementation samples the whole area light, resulting some samples invisible and thus simply discarded. A technique is applied on rectangular light to sample a subset of the area light that is potentially visible (rB3f24cfb9582e1c826406301d37808df7ca6aa64c), however, ellipse (including disk) area lights remained untreated. The purpose of this patch is to apply a techniques to ellipse area light.
**Related Task**:
T87053
**Results**:
These are renderings before and after the patch:
|16spp|Disk light|Ellipse light|Square light (for reference, no changes)
|Before|{F13996789}|{F13996788}|{F13996822}
|After|{F13996759}|{F13996787}|{F13996852}
**Explanation**:
The visible region on an area light is found by drawing a cone from the shading point to the plane where the area light lies, with the aperture of the cone being the light spread.
{F13990078,height=200}
Ideally, we would like to draw samples only from the intersection of the area light and the projection of the cone onto the plane (forming a circle). However, the shape of the intersection is often irregular and thus hard to sample from directly.
{F13990104,height=200}
Instead, the current implementation draws samples from the bounding rectangle of the intersection. In this case, we still end up with some invalid samples outside of the circle, but already much less than sampling the original area light, and the bounding rectangle is easy to sample from.
{F13990125}
The above technique is only applied to rectangle area lights, ellipse area light still suffers from poor sampling. We could apply a similar technique to ellipse area lights, that is, find the
smallest regular shape (rectangle, circle, or ellipse) that covers the intersection (or maybe not the smallest but easy to compute).
For disk area light, we consider the relative position of both circles. Denoting `dist` as the distance between the centre of two circles, and `r1`, `r2` their radii. If `dist > r1 + r2`, the area light is completely invisible, we directly return `false`. If `dist < abs(r1 - r2)`, the smaller circle lies inside the larger one, and we sample whichever circle is smaller. Otherwise, the two circles intersect, we compute the bounding rectangle of the intersection, in which case `axis_u`, `len_u`, `axis_v`, `len_v` needs to be computed anew. Depending on the distance between the two circles, `len_v` is either the diameter of the smaller circle or the length of the common chord.
|{F13990211,height=195}|{F13990225,height=195}|{F13990274,height=195}|{F13990210,height=195}
|`dist > r1 + r2`|`dist < abs(r1 - r2)`|`dist^2 < abs(r1^2 - r2^2)`|`dist^2 > abs(r1^2 - r2^2)`
For ellipse area light, it's hard to find the smallest bounding shape of the intersection, therefore, we compute the bounding rectangle of the ellipse itself, then treat it as a rectangle light.
|{F13990386,height=195}|{F13990385,height=195}|{F13990387,height=195}
We also check the areas of the bounding rectangle of the intersection, the ellipse (disk) light, and the spread circle, then draw samples from the smallest shape of the three. For ellipse light, this also detects where one shape lies inside the other. I am not sure if we should add this measure to rectangle area light and sample from the spread circle when it has smaller area, as we seem to have a better sampling technique for rectangular (uniformly sample the solid angle). Maybe we could add [area-preserving parameterization for spherical
ellipse](https://arxiv.org/pdf/1805.09048.pdf) in the future.
**Limitation**:
At some point we switch from sampling the ellipse to sampling the rectangle, depending on the area of the both, and there seems to be a visible line (with |slope| =1) on the final rendering
which demonstrate at which point we switch between the two methods. We could see that the new sampling method clearly has lower variance near the boundaries, but close to that visible line,
the rectangle sampling method seems to have larger variance. I could not spot any bug in the implementation, and I am not sure if this happens because different sampling patterns for ellipse and rectangle are used.
|Before (256spp)|After (256spp)
|{F13996995}|{F13996998}
Differential Revision: https://developer.blender.org/D16694
2022-12-05 14:35:25 +01:00
|
|
|
if (sample_spread) {
|
2022-12-07 19:55:13 +01:00
|
|
|
*sample_rectangle = false;
|
Cycles: improve sampling of ellipse area light with spread
**Problem**:
Area lights in Cycles have spread angle, in which case some part of the area light might be invisible to a shading point. The current implementation samples the whole area light, resulting some samples invisible and thus simply discarded. A technique is applied on rectangular light to sample a subset of the area light that is potentially visible (rB3f24cfb9582e1c826406301d37808df7ca6aa64c), however, ellipse (including disk) area lights remained untreated. The purpose of this patch is to apply a techniques to ellipse area light.
**Related Task**:
T87053
**Results**:
These are renderings before and after the patch:
|16spp|Disk light|Ellipse light|Square light (for reference, no changes)
|Before|{F13996789}|{F13996788}|{F13996822}
|After|{F13996759}|{F13996787}|{F13996852}
**Explanation**:
The visible region on an area light is found by drawing a cone from the shading point to the plane where the area light lies, with the aperture of the cone being the light spread.
{F13990078,height=200}
Ideally, we would like to draw samples only from the intersection of the area light and the projection of the cone onto the plane (forming a circle). However, the shape of the intersection is often irregular and thus hard to sample from directly.
{F13990104,height=200}
Instead, the current implementation draws samples from the bounding rectangle of the intersection. In this case, we still end up with some invalid samples outside of the circle, but already much less than sampling the original area light, and the bounding rectangle is easy to sample from.
{F13990125}
The above technique is only applied to rectangle area lights, ellipse area light still suffers from poor sampling. We could apply a similar technique to ellipse area lights, that is, find the
smallest regular shape (rectangle, circle, or ellipse) that covers the intersection (or maybe not the smallest but easy to compute).
For disk area light, we consider the relative position of both circles. Denoting `dist` as the distance between the centre of two circles, and `r1`, `r2` their radii. If `dist > r1 + r2`, the area light is completely invisible, we directly return `false`. If `dist < abs(r1 - r2)`, the smaller circle lies inside the larger one, and we sample whichever circle is smaller. Otherwise, the two circles intersect, we compute the bounding rectangle of the intersection, in which case `axis_u`, `len_u`, `axis_v`, `len_v` needs to be computed anew. Depending on the distance between the two circles, `len_v` is either the diameter of the smaller circle or the length of the common chord.
|{F13990211,height=195}|{F13990225,height=195}|{F13990274,height=195}|{F13990210,height=195}
|`dist > r1 + r2`|`dist < abs(r1 - r2)`|`dist^2 < abs(r1^2 - r2^2)`|`dist^2 > abs(r1^2 - r2^2)`
For ellipse area light, it's hard to find the smallest bounding shape of the intersection, therefore, we compute the bounding rectangle of the ellipse itself, then treat it as a rectangle light.
|{F13990386,height=195}|{F13990385,height=195}|{F13990387,height=195}
We also check the areas of the bounding rectangle of the intersection, the ellipse (disk) light, and the spread circle, then draw samples from the smallest shape of the three. For ellipse light, this also detects where one shape lies inside the other. I am not sure if we should add this measure to rectangle area light and sample from the spread circle when it has smaller area, as we seem to have a better sampling technique for rectangular (uniformly sample the solid angle). Maybe we could add [area-preserving parameterization for spherical
ellipse](https://arxiv.org/pdf/1805.09048.pdf) in the future.
**Limitation**:
At some point we switch from sampling the ellipse to sampling the rectangle, depending on the area of the both, and there seems to be a visible line (with |slope| =1) on the final rendering
which demonstrate at which point we switch between the two methods. We could see that the new sampling method clearly has lower variance near the boundaries, but close to that visible line,
the rectangle sampling method seems to have larger variance. I could not spot any bug in the implementation, and I am not sure if this happens because different sampling patterns for ellipse and rectangle are used.
|Before (256spp)|After (256spp)
|{F13996995}|{F13996998}
Differential Revision: https://developer.blender.org/D16694
2022-12-05 14:35:25 +01:00
|
|
|
*lightP = *lightP + *axis_u * spread_u + *axis_v * spread_v;
|
|
|
|
|
*len_u = r_spread * 2.0f;
|
|
|
|
|
*len_v = r_spread * 2.0f;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2022-11-30 20:17:45 +01:00
|
|
|
|
Cycles: improve sampling of ellipse area light with spread
**Problem**:
Area lights in Cycles have spread angle, in which case some part of the area light might be invisible to a shading point. The current implementation samples the whole area light, resulting some samples invisible and thus simply discarded. A technique is applied on rectangular light to sample a subset of the area light that is potentially visible (rB3f24cfb9582e1c826406301d37808df7ca6aa64c), however, ellipse (including disk) area lights remained untreated. The purpose of this patch is to apply a techniques to ellipse area light.
**Related Task**:
T87053
**Results**:
These are renderings before and after the patch:
|16spp|Disk light|Ellipse light|Square light (for reference, no changes)
|Before|{F13996789}|{F13996788}|{F13996822}
|After|{F13996759}|{F13996787}|{F13996852}
**Explanation**:
The visible region on an area light is found by drawing a cone from the shading point to the plane where the area light lies, with the aperture of the cone being the light spread.
{F13990078,height=200}
Ideally, we would like to draw samples only from the intersection of the area light and the projection of the cone onto the plane (forming a circle). However, the shape of the intersection is often irregular and thus hard to sample from directly.
{F13990104,height=200}
Instead, the current implementation draws samples from the bounding rectangle of the intersection. In this case, we still end up with some invalid samples outside of the circle, but already much less than sampling the original area light, and the bounding rectangle is easy to sample from.
{F13990125}
The above technique is only applied to rectangle area lights, ellipse area light still suffers from poor sampling. We could apply a similar technique to ellipse area lights, that is, find the
smallest regular shape (rectangle, circle, or ellipse) that covers the intersection (or maybe not the smallest but easy to compute).
For disk area light, we consider the relative position of both circles. Denoting `dist` as the distance between the centre of two circles, and `r1`, `r2` their radii. If `dist > r1 + r2`, the area light is completely invisible, we directly return `false`. If `dist < abs(r1 - r2)`, the smaller circle lies inside the larger one, and we sample whichever circle is smaller. Otherwise, the two circles intersect, we compute the bounding rectangle of the intersection, in which case `axis_u`, `len_u`, `axis_v`, `len_v` needs to be computed anew. Depending on the distance between the two circles, `len_v` is either the diameter of the smaller circle or the length of the common chord.
|{F13990211,height=195}|{F13990225,height=195}|{F13990274,height=195}|{F13990210,height=195}
|`dist > r1 + r2`|`dist < abs(r1 - r2)`|`dist^2 < abs(r1^2 - r2^2)`|`dist^2 > abs(r1^2 - r2^2)`
For ellipse area light, it's hard to find the smallest bounding shape of the intersection, therefore, we compute the bounding rectangle of the ellipse itself, then treat it as a rectangle light.
|{F13990386,height=195}|{F13990385,height=195}|{F13990387,height=195}
We also check the areas of the bounding rectangle of the intersection, the ellipse (disk) light, and the spread circle, then draw samples from the smallest shape of the three. For ellipse light, this also detects where one shape lies inside the other. I am not sure if we should add this measure to rectangle area light and sample from the spread circle when it has smaller area, as we seem to have a better sampling technique for rectangular (uniformly sample the solid angle). Maybe we could add [area-preserving parameterization for spherical
ellipse](https://arxiv.org/pdf/1805.09048.pdf) in the future.
**Limitation**:
At some point we switch from sampling the ellipse to sampling the rectangle, depending on the area of the both, and there seems to be a visible line (with |slope| =1) on the final rendering
which demonstrate at which point we switch between the two methods. We could see that the new sampling method clearly has lower variance near the boundaries, but close to that visible line,
the rectangle sampling method seems to have larger variance. I could not spot any bug in the implementation, and I am not sure if this happens because different sampling patterns for ellipse and rectangle are used.
|Before (256spp)|After (256spp)
|{F13996995}|{F13996998}
Differential Revision: https://developer.blender.org/D16694
2022-12-05 14:35:25 +01:00
|
|
|
/* Don't clamp. */
|
2022-11-30 20:17:45 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Common API. */
|
2023-05-12 23:07:28 +02:00
|
|
|
/* Compute `eval_fac` and `pdf`. Also sample a new position on the light if `sample_coord`. */
|
2022-11-30 20:17:45 +01:00
|
|
|
template<bool in_volume_segment>
|
2023-05-12 23:07:28 +02:00
|
|
|
ccl_device_inline bool area_light_eval(const ccl_global KernelLight *klight,
|
|
|
|
|
const float3 ray_P,
|
|
|
|
|
ccl_private float3 *light_P,
|
|
|
|
|
ccl_private LightSample *ccl_restrict ls,
|
2023-05-24 18:56:58 +02:00
|
|
|
const float2 rand,
|
2023-05-12 23:07:28 +02:00
|
|
|
bool sample_coord)
|
2022-11-30 20:17:45 +01:00
|
|
|
{
|
2023-05-12 23:07:28 +02:00
|
|
|
float3 axis_u = klight->area.axis_u;
|
|
|
|
|
float3 axis_v = klight->area.axis_v;
|
|
|
|
|
float len_u = klight->area.len_u;
|
|
|
|
|
float len_v = klight->area.len_v;
|
2022-11-30 20:17:45 +01:00
|
|
|
|
2023-05-12 23:07:28 +02:00
|
|
|
const float3 Ng = klight->area.dir;
|
|
|
|
|
const float invarea = fabsf(klight->area.invarea);
|
|
|
|
|
bool sample_rectangle = (klight->area.invarea > 0.0f);
|
2022-11-30 20:17:45 +01:00
|
|
|
|
2023-05-12 23:07:28 +02:00
|
|
|
float3 light_P_new = *light_P;
|
2022-11-30 20:17:45 +01:00
|
|
|
|
Cycles: improve sampling of ellipse area light with spread
**Problem**:
Area lights in Cycles have spread angle, in which case some part of the area light might be invisible to a shading point. The current implementation samples the whole area light, resulting some samples invisible and thus simply discarded. A technique is applied on rectangular light to sample a subset of the area light that is potentially visible (rB3f24cfb9582e1c826406301d37808df7ca6aa64c), however, ellipse (including disk) area lights remained untreated. The purpose of this patch is to apply a techniques to ellipse area light.
**Related Task**:
T87053
**Results**:
These are renderings before and after the patch:
|16spp|Disk light|Ellipse light|Square light (for reference, no changes)
|Before|{F13996789}|{F13996788}|{F13996822}
|After|{F13996759}|{F13996787}|{F13996852}
**Explanation**:
The visible region on an area light is found by drawing a cone from the shading point to the plane where the area light lies, with the aperture of the cone being the light spread.
{F13990078,height=200}
Ideally, we would like to draw samples only from the intersection of the area light and the projection of the cone onto the plane (forming a circle). However, the shape of the intersection is often irregular and thus hard to sample from directly.
{F13990104,height=200}
Instead, the current implementation draws samples from the bounding rectangle of the intersection. In this case, we still end up with some invalid samples outside of the circle, but already much less than sampling the original area light, and the bounding rectangle is easy to sample from.
{F13990125}
The above technique is only applied to rectangle area lights, ellipse area light still suffers from poor sampling. We could apply a similar technique to ellipse area lights, that is, find the
smallest regular shape (rectangle, circle, or ellipse) that covers the intersection (or maybe not the smallest but easy to compute).
For disk area light, we consider the relative position of both circles. Denoting `dist` as the distance between the centre of two circles, and `r1`, `r2` their radii. If `dist > r1 + r2`, the area light is completely invisible, we directly return `false`. If `dist < abs(r1 - r2)`, the smaller circle lies inside the larger one, and we sample whichever circle is smaller. Otherwise, the two circles intersect, we compute the bounding rectangle of the intersection, in which case `axis_u`, `len_u`, `axis_v`, `len_v` needs to be computed anew. Depending on the distance between the two circles, `len_v` is either the diameter of the smaller circle or the length of the common chord.
|{F13990211,height=195}|{F13990225,height=195}|{F13990274,height=195}|{F13990210,height=195}
|`dist > r1 + r2`|`dist < abs(r1 - r2)`|`dist^2 < abs(r1^2 - r2^2)`|`dist^2 > abs(r1^2 - r2^2)`
For ellipse area light, it's hard to find the smallest bounding shape of the intersection, therefore, we compute the bounding rectangle of the ellipse itself, then treat it as a rectangle light.
|{F13990386,height=195}|{F13990385,height=195}|{F13990387,height=195}
We also check the areas of the bounding rectangle of the intersection, the ellipse (disk) light, and the spread circle, then draw samples from the smallest shape of the three. For ellipse light, this also detects where one shape lies inside the other. I am not sure if we should add this measure to rectangle area light and sample from the spread circle when it has smaller area, as we seem to have a better sampling technique for rectangular (uniformly sample the solid angle). Maybe we could add [area-preserving parameterization for spherical
ellipse](https://arxiv.org/pdf/1805.09048.pdf) in the future.
**Limitation**:
At some point we switch from sampling the ellipse to sampling the rectangle, depending on the area of the both, and there seems to be a visible line (with |slope| =1) on the final rendering
which demonstrate at which point we switch between the two methods. We could see that the new sampling method clearly has lower variance near the boundaries, but close to that visible line,
the rectangle sampling method seems to have larger variance. I could not spot any bug in the implementation, and I am not sure if this happens because different sampling patterns for ellipse and rectangle are used.
|Before (256spp)|After (256spp)
|{F13996995}|{F13996998}
Differential Revision: https://developer.blender.org/D16694
2022-12-05 14:35:25 +01:00
|
|
|
if (in_volume_segment) {
|
2023-05-12 23:07:28 +02:00
|
|
|
light_P_new += sample_rectangle ?
|
2023-05-24 18:56:58 +02:00
|
|
|
rectangle_sample(axis_u * len_u * 0.5f, axis_v * len_v * 0.5f, rand) :
|
|
|
|
|
ellipse_sample(axis_u * len_u * 0.5f, axis_v * len_v * 0.5f, rand);
|
2022-11-30 20:17:45 +01:00
|
|
|
ls->pdf = invarea;
|
|
|
|
|
}
|
|
|
|
|
else {
|
2022-12-07 18:51:26 +01:00
|
|
|
if (klight->area.normalize_spread > 0) {
|
2023-05-12 23:07:28 +02:00
|
|
|
if (!area_light_spread_clamp_light(ray_P,
|
Cycles: improve sampling of ellipse area light with spread
**Problem**:
Area lights in Cycles have spread angle, in which case some part of the area light might be invisible to a shading point. The current implementation samples the whole area light, resulting some samples invisible and thus simply discarded. A technique is applied on rectangular light to sample a subset of the area light that is potentially visible (rB3f24cfb9582e1c826406301d37808df7ca6aa64c), however, ellipse (including disk) area lights remained untreated. The purpose of this patch is to apply a techniques to ellipse area light.
**Related Task**:
T87053
**Results**:
These are renderings before and after the patch:
|16spp|Disk light|Ellipse light|Square light (for reference, no changes)
|Before|{F13996789}|{F13996788}|{F13996822}
|After|{F13996759}|{F13996787}|{F13996852}
**Explanation**:
The visible region on an area light is found by drawing a cone from the shading point to the plane where the area light lies, with the aperture of the cone being the light spread.
{F13990078,height=200}
Ideally, we would like to draw samples only from the intersection of the area light and the projection of the cone onto the plane (forming a circle). However, the shape of the intersection is often irregular and thus hard to sample from directly.
{F13990104,height=200}
Instead, the current implementation draws samples from the bounding rectangle of the intersection. In this case, we still end up with some invalid samples outside of the circle, but already much less than sampling the original area light, and the bounding rectangle is easy to sample from.
{F13990125}
The above technique is only applied to rectangle area lights, ellipse area light still suffers from poor sampling. We could apply a similar technique to ellipse area lights, that is, find the
smallest regular shape (rectangle, circle, or ellipse) that covers the intersection (or maybe not the smallest but easy to compute).
For disk area light, we consider the relative position of both circles. Denoting `dist` as the distance between the centre of two circles, and `r1`, `r2` their radii. If `dist > r1 + r2`, the area light is completely invisible, we directly return `false`. If `dist < abs(r1 - r2)`, the smaller circle lies inside the larger one, and we sample whichever circle is smaller. Otherwise, the two circles intersect, we compute the bounding rectangle of the intersection, in which case `axis_u`, `len_u`, `axis_v`, `len_v` needs to be computed anew. Depending on the distance between the two circles, `len_v` is either the diameter of the smaller circle or the length of the common chord.
|{F13990211,height=195}|{F13990225,height=195}|{F13990274,height=195}|{F13990210,height=195}
|`dist > r1 + r2`|`dist < abs(r1 - r2)`|`dist^2 < abs(r1^2 - r2^2)`|`dist^2 > abs(r1^2 - r2^2)`
For ellipse area light, it's hard to find the smallest bounding shape of the intersection, therefore, we compute the bounding rectangle of the ellipse itself, then treat it as a rectangle light.
|{F13990386,height=195}|{F13990385,height=195}|{F13990387,height=195}
We also check the areas of the bounding rectangle of the intersection, the ellipse (disk) light, and the spread circle, then draw samples from the smallest shape of the three. For ellipse light, this also detects where one shape lies inside the other. I am not sure if we should add this measure to rectangle area light and sample from the spread circle when it has smaller area, as we seem to have a better sampling technique for rectangular (uniformly sample the solid angle). Maybe we could add [area-preserving parameterization for spherical
ellipse](https://arxiv.org/pdf/1805.09048.pdf) in the future.
**Limitation**:
At some point we switch from sampling the ellipse to sampling the rectangle, depending on the area of the both, and there seems to be a visible line (with |slope| =1) on the final rendering
which demonstrate at which point we switch between the two methods. We could see that the new sampling method clearly has lower variance near the boundaries, but close to that visible line,
the rectangle sampling method seems to have larger variance. I could not spot any bug in the implementation, and I am not sure if this happens because different sampling patterns for ellipse and rectangle are used.
|Before (256spp)|After (256spp)
|{F13996995}|{F13996998}
Differential Revision: https://developer.blender.org/D16694
2022-12-05 14:35:25 +01:00
|
|
|
Ng,
|
2023-05-12 23:07:28 +02:00
|
|
|
&light_P_new,
|
|
|
|
|
&axis_u,
|
|
|
|
|
&len_u,
|
|
|
|
|
&axis_v,
|
|
|
|
|
&len_v,
|
2022-12-07 18:51:26 +01:00
|
|
|
klight->area.tan_half_spread,
|
Cycles: improve sampling of ellipse area light with spread
**Problem**:
Area lights in Cycles have spread angle, in which case some part of the area light might be invisible to a shading point. The current implementation samples the whole area light, resulting some samples invisible and thus simply discarded. A technique is applied on rectangular light to sample a subset of the area light that is potentially visible (rB3f24cfb9582e1c826406301d37808df7ca6aa64c), however, ellipse (including disk) area lights remained untreated. The purpose of this patch is to apply a techniques to ellipse area light.
**Related Task**:
T87053
**Results**:
These are renderings before and after the patch:
|16spp|Disk light|Ellipse light|Square light (for reference, no changes)
|Before|{F13996789}|{F13996788}|{F13996822}
|After|{F13996759}|{F13996787}|{F13996852}
**Explanation**:
The visible region on an area light is found by drawing a cone from the shading point to the plane where the area light lies, with the aperture of the cone being the light spread.
{F13990078,height=200}
Ideally, we would like to draw samples only from the intersection of the area light and the projection of the cone onto the plane (forming a circle). However, the shape of the intersection is often irregular and thus hard to sample from directly.
{F13990104,height=200}
Instead, the current implementation draws samples from the bounding rectangle of the intersection. In this case, we still end up with some invalid samples outside of the circle, but already much less than sampling the original area light, and the bounding rectangle is easy to sample from.
{F13990125}
The above technique is only applied to rectangle area lights, ellipse area light still suffers from poor sampling. We could apply a similar technique to ellipse area lights, that is, find the
smallest regular shape (rectangle, circle, or ellipse) that covers the intersection (or maybe not the smallest but easy to compute).
For disk area light, we consider the relative position of both circles. Denoting `dist` as the distance between the centre of two circles, and `r1`, `r2` their radii. If `dist > r1 + r2`, the area light is completely invisible, we directly return `false`. If `dist < abs(r1 - r2)`, the smaller circle lies inside the larger one, and we sample whichever circle is smaller. Otherwise, the two circles intersect, we compute the bounding rectangle of the intersection, in which case `axis_u`, `len_u`, `axis_v`, `len_v` needs to be computed anew. Depending on the distance between the two circles, `len_v` is either the diameter of the smaller circle or the length of the common chord.
|{F13990211,height=195}|{F13990225,height=195}|{F13990274,height=195}|{F13990210,height=195}
|`dist > r1 + r2`|`dist < abs(r1 - r2)`|`dist^2 < abs(r1^2 - r2^2)`|`dist^2 > abs(r1^2 - r2^2)`
For ellipse area light, it's hard to find the smallest bounding shape of the intersection, therefore, we compute the bounding rectangle of the ellipse itself, then treat it as a rectangle light.
|{F13990386,height=195}|{F13990385,height=195}|{F13990387,height=195}
We also check the areas of the bounding rectangle of the intersection, the ellipse (disk) light, and the spread circle, then draw samples from the smallest shape of the three. For ellipse light, this also detects where one shape lies inside the other. I am not sure if we should add this measure to rectangle area light and sample from the spread circle when it has smaller area, as we seem to have a better sampling technique for rectangular (uniformly sample the solid angle). Maybe we could add [area-preserving parameterization for spherical
ellipse](https://arxiv.org/pdf/1805.09048.pdf) in the future.
**Limitation**:
At some point we switch from sampling the ellipse to sampling the rectangle, depending on the area of the both, and there seems to be a visible line (with |slope| =1) on the final rendering
which demonstrate at which point we switch between the two methods. We could see that the new sampling method clearly has lower variance near the boundaries, but close to that visible line,
the rectangle sampling method seems to have larger variance. I could not spot any bug in the implementation, and I am not sure if this happens because different sampling patterns for ellipse and rectangle are used.
|Before (256spp)|After (256spp)
|{F13996995}|{F13996998}
Differential Revision: https://developer.blender.org/D16694
2022-12-05 14:35:25 +01:00
|
|
|
&sample_rectangle))
|
|
|
|
|
{
|
2022-11-30 20:17:45 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
Cycles: improve sampling of ellipse area light with spread
**Problem**:
Area lights in Cycles have spread angle, in which case some part of the area light might be invisible to a shading point. The current implementation samples the whole area light, resulting some samples invisible and thus simply discarded. A technique is applied on rectangular light to sample a subset of the area light that is potentially visible (rB3f24cfb9582e1c826406301d37808df7ca6aa64c), however, ellipse (including disk) area lights remained untreated. The purpose of this patch is to apply a techniques to ellipse area light.
**Related Task**:
T87053
**Results**:
These are renderings before and after the patch:
|16spp|Disk light|Ellipse light|Square light (for reference, no changes)
|Before|{F13996789}|{F13996788}|{F13996822}
|After|{F13996759}|{F13996787}|{F13996852}
**Explanation**:
The visible region on an area light is found by drawing a cone from the shading point to the plane where the area light lies, with the aperture of the cone being the light spread.
{F13990078,height=200}
Ideally, we would like to draw samples only from the intersection of the area light and the projection of the cone onto the plane (forming a circle). However, the shape of the intersection is often irregular and thus hard to sample from directly.
{F13990104,height=200}
Instead, the current implementation draws samples from the bounding rectangle of the intersection. In this case, we still end up with some invalid samples outside of the circle, but already much less than sampling the original area light, and the bounding rectangle is easy to sample from.
{F13990125}
The above technique is only applied to rectangle area lights, ellipse area light still suffers from poor sampling. We could apply a similar technique to ellipse area lights, that is, find the
smallest regular shape (rectangle, circle, or ellipse) that covers the intersection (or maybe not the smallest but easy to compute).
For disk area light, we consider the relative position of both circles. Denoting `dist` as the distance between the centre of two circles, and `r1`, `r2` their radii. If `dist > r1 + r2`, the area light is completely invisible, we directly return `false`. If `dist < abs(r1 - r2)`, the smaller circle lies inside the larger one, and we sample whichever circle is smaller. Otherwise, the two circles intersect, we compute the bounding rectangle of the intersection, in which case `axis_u`, `len_u`, `axis_v`, `len_v` needs to be computed anew. Depending on the distance between the two circles, `len_v` is either the diameter of the smaller circle or the length of the common chord.
|{F13990211,height=195}|{F13990225,height=195}|{F13990274,height=195}|{F13990210,height=195}
|`dist > r1 + r2`|`dist < abs(r1 - r2)`|`dist^2 < abs(r1^2 - r2^2)`|`dist^2 > abs(r1^2 - r2^2)`
For ellipse area light, it's hard to find the smallest bounding shape of the intersection, therefore, we compute the bounding rectangle of the ellipse itself, then treat it as a rectangle light.
|{F13990386,height=195}|{F13990385,height=195}|{F13990387,height=195}
We also check the areas of the bounding rectangle of the intersection, the ellipse (disk) light, and the spread circle, then draw samples from the smallest shape of the three. For ellipse light, this also detects where one shape lies inside the other. I am not sure if we should add this measure to rectangle area light and sample from the spread circle when it has smaller area, as we seem to have a better sampling technique for rectangular (uniformly sample the solid angle). Maybe we could add [area-preserving parameterization for spherical
ellipse](https://arxiv.org/pdf/1805.09048.pdf) in the future.
**Limitation**:
At some point we switch from sampling the ellipse to sampling the rectangle, depending on the area of the both, and there seems to be a visible line (with |slope| =1) on the final rendering
which demonstrate at which point we switch between the two methods. We could see that the new sampling method clearly has lower variance near the boundaries, but close to that visible line,
the rectangle sampling method seems to have larger variance. I could not spot any bug in the implementation, and I am not sure if this happens because different sampling patterns for ellipse and rectangle are used.
|Before (256spp)|After (256spp)
|{F13996995}|{F13996998}
Differential Revision: https://developer.blender.org/D16694
2022-12-05 14:35:25 +01:00
|
|
|
if (sample_rectangle) {
|
|
|
|
|
ls->pdf = area_light_rect_sample(
|
2023-05-24 18:56:58 +02:00
|
|
|
ray_P, &light_P_new, axis_u, len_u, axis_v, len_v, rand, sample_coord);
|
Cycles: improve sampling of ellipse area light with spread
**Problem**:
Area lights in Cycles have spread angle, in which case some part of the area light might be invisible to a shading point. The current implementation samples the whole area light, resulting some samples invisible and thus simply discarded. A technique is applied on rectangular light to sample a subset of the area light that is potentially visible (rB3f24cfb9582e1c826406301d37808df7ca6aa64c), however, ellipse (including disk) area lights remained untreated. The purpose of this patch is to apply a techniques to ellipse area light.
**Related Task**:
T87053
**Results**:
These are renderings before and after the patch:
|16spp|Disk light|Ellipse light|Square light (for reference, no changes)
|Before|{F13996789}|{F13996788}|{F13996822}
|After|{F13996759}|{F13996787}|{F13996852}
**Explanation**:
The visible region on an area light is found by drawing a cone from the shading point to the plane where the area light lies, with the aperture of the cone being the light spread.
{F13990078,height=200}
Ideally, we would like to draw samples only from the intersection of the area light and the projection of the cone onto the plane (forming a circle). However, the shape of the intersection is often irregular and thus hard to sample from directly.
{F13990104,height=200}
Instead, the current implementation draws samples from the bounding rectangle of the intersection. In this case, we still end up with some invalid samples outside of the circle, but already much less than sampling the original area light, and the bounding rectangle is easy to sample from.
{F13990125}
The above technique is only applied to rectangle area lights, ellipse area light still suffers from poor sampling. We could apply a similar technique to ellipse area lights, that is, find the
smallest regular shape (rectangle, circle, or ellipse) that covers the intersection (or maybe not the smallest but easy to compute).
For disk area light, we consider the relative position of both circles. Denoting `dist` as the distance between the centre of two circles, and `r1`, `r2` their radii. If `dist > r1 + r2`, the area light is completely invisible, we directly return `false`. If `dist < abs(r1 - r2)`, the smaller circle lies inside the larger one, and we sample whichever circle is smaller. Otherwise, the two circles intersect, we compute the bounding rectangle of the intersection, in which case `axis_u`, `len_u`, `axis_v`, `len_v` needs to be computed anew. Depending on the distance between the two circles, `len_v` is either the diameter of the smaller circle or the length of the common chord.
|{F13990211,height=195}|{F13990225,height=195}|{F13990274,height=195}|{F13990210,height=195}
|`dist > r1 + r2`|`dist < abs(r1 - r2)`|`dist^2 < abs(r1^2 - r2^2)`|`dist^2 > abs(r1^2 - r2^2)`
For ellipse area light, it's hard to find the smallest bounding shape of the intersection, therefore, we compute the bounding rectangle of the ellipse itself, then treat it as a rectangle light.
|{F13990386,height=195}|{F13990385,height=195}|{F13990387,height=195}
We also check the areas of the bounding rectangle of the intersection, the ellipse (disk) light, and the spread circle, then draw samples from the smallest shape of the three. For ellipse light, this also detects where one shape lies inside the other. I am not sure if we should add this measure to rectangle area light and sample from the spread circle when it has smaller area, as we seem to have a better sampling technique for rectangular (uniformly sample the solid angle). Maybe we could add [area-preserving parameterization for spherical
ellipse](https://arxiv.org/pdf/1805.09048.pdf) in the future.
**Limitation**:
At some point we switch from sampling the ellipse to sampling the rectangle, depending on the area of the both, and there seems to be a visible line (with |slope| =1) on the final rendering
which demonstrate at which point we switch between the two methods. We could see that the new sampling method clearly has lower variance near the boundaries, but close to that visible line,
the rectangle sampling method seems to have larger variance. I could not spot any bug in the implementation, and I am not sure if this happens because different sampling patterns for ellipse and rectangle are used.
|Before (256spp)|After (256spp)
|{F13996995}|{F13996998}
Differential Revision: https://developer.blender.org/D16694
2022-12-05 14:35:25 +01:00
|
|
|
}
|
|
|
|
|
else {
|
2022-12-07 19:55:13 +01:00
|
|
|
if (klight->area.tan_half_spread == 0.0f) {
|
|
|
|
|
ls->pdf = 1.0f;
|
|
|
|
|
}
|
|
|
|
|
else {
|
2023-05-12 23:07:28 +02:00
|
|
|
if (sample_coord) {
|
2023-05-24 18:56:58 +02:00
|
|
|
light_P_new += ellipse_sample(axis_u * len_u * 0.5f, axis_v * len_v * 0.5f, rand);
|
2023-05-12 23:07:28 +02:00
|
|
|
}
|
|
|
|
|
ls->pdf = 4.0f * M_1_PI_F / (len_u * len_v);
|
2022-12-07 19:55:13 +01:00
|
|
|
}
|
Cycles: improve sampling of ellipse area light with spread
**Problem**:
Area lights in Cycles have spread angle, in which case some part of the area light might be invisible to a shading point. The current implementation samples the whole area light, resulting some samples invisible and thus simply discarded. A technique is applied on rectangular light to sample a subset of the area light that is potentially visible (rB3f24cfb9582e1c826406301d37808df7ca6aa64c), however, ellipse (including disk) area lights remained untreated. The purpose of this patch is to apply a techniques to ellipse area light.
**Related Task**:
T87053
**Results**:
These are renderings before and after the patch:
|16spp|Disk light|Ellipse light|Square light (for reference, no changes)
|Before|{F13996789}|{F13996788}|{F13996822}
|After|{F13996759}|{F13996787}|{F13996852}
**Explanation**:
The visible region on an area light is found by drawing a cone from the shading point to the plane where the area light lies, with the aperture of the cone being the light spread.
{F13990078,height=200}
Ideally, we would like to draw samples only from the intersection of the area light and the projection of the cone onto the plane (forming a circle). However, the shape of the intersection is often irregular and thus hard to sample from directly.
{F13990104,height=200}
Instead, the current implementation draws samples from the bounding rectangle of the intersection. In this case, we still end up with some invalid samples outside of the circle, but already much less than sampling the original area light, and the bounding rectangle is easy to sample from.
{F13990125}
The above technique is only applied to rectangle area lights, ellipse area light still suffers from poor sampling. We could apply a similar technique to ellipse area lights, that is, find the
smallest regular shape (rectangle, circle, or ellipse) that covers the intersection (or maybe not the smallest but easy to compute).
For disk area light, we consider the relative position of both circles. Denoting `dist` as the distance between the centre of two circles, and `r1`, `r2` their radii. If `dist > r1 + r2`, the area light is completely invisible, we directly return `false`. If `dist < abs(r1 - r2)`, the smaller circle lies inside the larger one, and we sample whichever circle is smaller. Otherwise, the two circles intersect, we compute the bounding rectangle of the intersection, in which case `axis_u`, `len_u`, `axis_v`, `len_v` needs to be computed anew. Depending on the distance between the two circles, `len_v` is either the diameter of the smaller circle or the length of the common chord.
|{F13990211,height=195}|{F13990225,height=195}|{F13990274,height=195}|{F13990210,height=195}
|`dist > r1 + r2`|`dist < abs(r1 - r2)`|`dist^2 < abs(r1^2 - r2^2)`|`dist^2 > abs(r1^2 - r2^2)`
For ellipse area light, it's hard to find the smallest bounding shape of the intersection, therefore, we compute the bounding rectangle of the ellipse itself, then treat it as a rectangle light.
|{F13990386,height=195}|{F13990385,height=195}|{F13990387,height=195}
We also check the areas of the bounding rectangle of the intersection, the ellipse (disk) light, and the spread circle, then draw samples from the smallest shape of the three. For ellipse light, this also detects where one shape lies inside the other. I am not sure if we should add this measure to rectangle area light and sample from the spread circle when it has smaller area, as we seem to have a better sampling technique for rectangular (uniformly sample the solid angle). Maybe we could add [area-preserving parameterization for spherical
ellipse](https://arxiv.org/pdf/1805.09048.pdf) in the future.
**Limitation**:
At some point we switch from sampling the ellipse to sampling the rectangle, depending on the area of the both, and there seems to be a visible line (with |slope| =1) on the final rendering
which demonstrate at which point we switch between the two methods. We could see that the new sampling method clearly has lower variance near the boundaries, but close to that visible line,
the rectangle sampling method seems to have larger variance. I could not spot any bug in the implementation, and I am not sure if this happens because different sampling patterns for ellipse and rectangle are used.
|Before (256spp)|After (256spp)
|{F13996995}|{F13996998}
Differential Revision: https://developer.blender.org/D16694
2022-12-05 14:35:25 +01:00
|
|
|
}
|
2022-11-30 20:17:45 +01:00
|
|
|
}
|
|
|
|
|
|
2023-05-12 23:07:28 +02:00
|
|
|
if (sample_coord) {
|
|
|
|
|
*light_P = light_P_new;
|
|
|
|
|
ls->D = normalize_len(*light_P - ray_P, &ls->t);
|
Cycles: improve sampling of ellipse area light with spread
**Problem**:
Area lights in Cycles have spread angle, in which case some part of the area light might be invisible to a shading point. The current implementation samples the whole area light, resulting some samples invisible and thus simply discarded. A technique is applied on rectangular light to sample a subset of the area light that is potentially visible (rB3f24cfb9582e1c826406301d37808df7ca6aa64c), however, ellipse (including disk) area lights remained untreated. The purpose of this patch is to apply a techniques to ellipse area light.
**Related Task**:
T87053
**Results**:
These are renderings before and after the patch:
|16spp|Disk light|Ellipse light|Square light (for reference, no changes)
|Before|{F13996789}|{F13996788}|{F13996822}
|After|{F13996759}|{F13996787}|{F13996852}
**Explanation**:
The visible region on an area light is found by drawing a cone from the shading point to the plane where the area light lies, with the aperture of the cone being the light spread.
{F13990078,height=200}
Ideally, we would like to draw samples only from the intersection of the area light and the projection of the cone onto the plane (forming a circle). However, the shape of the intersection is often irregular and thus hard to sample from directly.
{F13990104,height=200}
Instead, the current implementation draws samples from the bounding rectangle of the intersection. In this case, we still end up with some invalid samples outside of the circle, but already much less than sampling the original area light, and the bounding rectangle is easy to sample from.
{F13990125}
The above technique is only applied to rectangle area lights, ellipse area light still suffers from poor sampling. We could apply a similar technique to ellipse area lights, that is, find the
smallest regular shape (rectangle, circle, or ellipse) that covers the intersection (or maybe not the smallest but easy to compute).
For disk area light, we consider the relative position of both circles. Denoting `dist` as the distance between the centre of two circles, and `r1`, `r2` their radii. If `dist > r1 + r2`, the area light is completely invisible, we directly return `false`. If `dist < abs(r1 - r2)`, the smaller circle lies inside the larger one, and we sample whichever circle is smaller. Otherwise, the two circles intersect, we compute the bounding rectangle of the intersection, in which case `axis_u`, `len_u`, `axis_v`, `len_v` needs to be computed anew. Depending on the distance between the two circles, `len_v` is either the diameter of the smaller circle or the length of the common chord.
|{F13990211,height=195}|{F13990225,height=195}|{F13990274,height=195}|{F13990210,height=195}
|`dist > r1 + r2`|`dist < abs(r1 - r2)`|`dist^2 < abs(r1^2 - r2^2)`|`dist^2 > abs(r1^2 - r2^2)`
For ellipse area light, it's hard to find the smallest bounding shape of the intersection, therefore, we compute the bounding rectangle of the ellipse itself, then treat it as a rectangle light.
|{F13990386,height=195}|{F13990385,height=195}|{F13990387,height=195}
We also check the areas of the bounding rectangle of the intersection, the ellipse (disk) light, and the spread circle, then draw samples from the smallest shape of the three. For ellipse light, this also detects where one shape lies inside the other. I am not sure if we should add this measure to rectangle area light and sample from the spread circle when it has smaller area, as we seem to have a better sampling technique for rectangular (uniformly sample the solid angle). Maybe we could add [area-preserving parameterization for spherical
ellipse](https://arxiv.org/pdf/1805.09048.pdf) in the future.
**Limitation**:
At some point we switch from sampling the ellipse to sampling the rectangle, depending on the area of the both, and there seems to be a visible line (with |slope| =1) on the final rendering
which demonstrate at which point we switch between the two methods. We could see that the new sampling method clearly has lower variance near the boundaries, but close to that visible line,
the rectangle sampling method seems to have larger variance. I could not spot any bug in the implementation, and I am not sure if this happens because different sampling patterns for ellipse and rectangle are used.
|Before (256spp)|After (256spp)
|{F13996995}|{F13996998}
Differential Revision: https://developer.blender.org/D16694
2022-12-05 14:35:25 +01:00
|
|
|
}
|
|
|
|
|
|
2023-07-07 17:03:02 +02:00
|
|
|
/* Convert radiant flux to radiance. */
|
|
|
|
|
ls->eval_fac = M_1_PI_F * invarea;
|
2022-11-30 20:17:45 +01:00
|
|
|
|
2022-12-07 18:51:26 +01:00
|
|
|
if (klight->area.normalize_spread > 0) {
|
2022-11-30 20:17:45 +01:00
|
|
|
/* Area Light spread angle attenuation */
|
|
|
|
|
ls->eval_fac *= area_light_spread_attenuation(
|
2023-05-12 23:07:28 +02:00
|
|
|
ls->D, Ng, klight->area.tan_half_spread, klight->area.normalize_spread);
|
2022-11-30 20:17:45 +01:00
|
|
|
}
|
|
|
|
|
|
2023-05-12 22:40:02 +02:00
|
|
|
if (in_volume_segment || (!sample_rectangle && klight->area.tan_half_spread > 0)) {
|
2022-11-30 20:17:45 +01:00
|
|
|
ls->pdf *= lamp_light_pdf(Ng, -ls->D, ls->t);
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-12 23:07:28 +02:00
|
|
|
return ls->eval_fac > 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<bool in_volume_segment>
|
|
|
|
|
ccl_device_inline bool area_light_sample(const ccl_global KernelLight *klight,
|
2023-05-24 18:56:58 +02:00
|
|
|
const float2 rand,
|
2023-05-12 23:07:28 +02:00
|
|
|
const float3 P,
|
|
|
|
|
ccl_private LightSample *ls)
|
|
|
|
|
{
|
|
|
|
|
ls->P = klight->co;
|
|
|
|
|
ls->Ng = klight->area.dir;
|
|
|
|
|
|
|
|
|
|
if (!in_volume_segment) {
|
|
|
|
|
if (dot(ls->P - P, ls->Ng) > 0.0f) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-24 18:56:58 +02:00
|
|
|
if (!area_light_eval<in_volume_segment>(klight, P, &ls->P, ls, rand, true)) {
|
2023-05-12 23:07:28 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const float3 inplane = ls->P - klight->co;
|
|
|
|
|
const float light_u = dot(inplane, klight->area.axis_u) / klight->area.len_u;
|
|
|
|
|
const float light_v = dot(inplane, klight->area.axis_v) / klight->area.len_v;
|
|
|
|
|
|
|
|
|
|
if (!in_volume_segment) {
|
|
|
|
|
const bool is_ellipse = (klight->area.invarea < 0.0f);
|
|
|
|
|
|
|
|
|
|
/* Sampled point lies outside of the area light. */
|
|
|
|
|
if (is_ellipse && (sqr(light_u) + sqr(light_v) > 0.25f)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!is_ellipse && (fabsf(light_u) > 0.5f || fabsf(light_v) > 0.5f)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* NOTE: Return barycentric coordinates in the same notation as Embree and OptiX. */
|
|
|
|
|
ls->u = light_v + 0.5f;
|
|
|
|
|
ls->v = -light_u - light_v;
|
|
|
|
|
|
2022-11-30 20:17:45 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-25 12:22:25 +02:00
|
|
|
ccl_device_forceinline void area_light_mnee_sample_update(const ccl_global KernelLight *klight,
|
|
|
|
|
ccl_private LightSample *ls,
|
|
|
|
|
const float3 P)
|
2022-11-30 20:17:45 +01:00
|
|
|
{
|
2023-05-11 16:32:05 +02:00
|
|
|
if (klight->area.tan_half_spread == 0) {
|
|
|
|
|
/* Update position on the light to keep the direction fixed. */
|
2023-05-24 18:56:58 +02:00
|
|
|
area_light_eval<false>(klight, P, &ls->P, ls, zero_float2(), true);
|
2023-05-11 16:32:05 +02:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
ls->D = normalize_len(ls->P - P, &ls->t);
|
2023-05-24 18:56:58 +02:00
|
|
|
area_light_eval<false>(klight, P, &ls->P, ls, zero_float2(), false);
|
2023-05-12 23:07:28 +02:00
|
|
|
/* Convert pdf to be in area measure. */
|
|
|
|
|
ls->pdf /= lamp_light_pdf(ls->Ng, -ls->D, ls->t);
|
2022-11-30 20:17:45 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ccl_device_inline bool area_light_intersect(const ccl_global KernelLight *klight,
|
|
|
|
|
const ccl_private Ray *ccl_restrict ray,
|
|
|
|
|
ccl_private float *t,
|
|
|
|
|
ccl_private float *u,
|
|
|
|
|
ccl_private float *v)
|
|
|
|
|
{
|
|
|
|
|
/* Area light. */
|
|
|
|
|
const float invarea = fabsf(klight->area.invarea);
|
Cycles: improve sampling of ellipse area light with spread
**Problem**:
Area lights in Cycles have spread angle, in which case some part of the area light might be invisible to a shading point. The current implementation samples the whole area light, resulting some samples invisible and thus simply discarded. A technique is applied on rectangular light to sample a subset of the area light that is potentially visible (rB3f24cfb9582e1c826406301d37808df7ca6aa64c), however, ellipse (including disk) area lights remained untreated. The purpose of this patch is to apply a techniques to ellipse area light.
**Related Task**:
T87053
**Results**:
These are renderings before and after the patch:
|16spp|Disk light|Ellipse light|Square light (for reference, no changes)
|Before|{F13996789}|{F13996788}|{F13996822}
|After|{F13996759}|{F13996787}|{F13996852}
**Explanation**:
The visible region on an area light is found by drawing a cone from the shading point to the plane where the area light lies, with the aperture of the cone being the light spread.
{F13990078,height=200}
Ideally, we would like to draw samples only from the intersection of the area light and the projection of the cone onto the plane (forming a circle). However, the shape of the intersection is often irregular and thus hard to sample from directly.
{F13990104,height=200}
Instead, the current implementation draws samples from the bounding rectangle of the intersection. In this case, we still end up with some invalid samples outside of the circle, but already much less than sampling the original area light, and the bounding rectangle is easy to sample from.
{F13990125}
The above technique is only applied to rectangle area lights, ellipse area light still suffers from poor sampling. We could apply a similar technique to ellipse area lights, that is, find the
smallest regular shape (rectangle, circle, or ellipse) that covers the intersection (or maybe not the smallest but easy to compute).
For disk area light, we consider the relative position of both circles. Denoting `dist` as the distance between the centre of two circles, and `r1`, `r2` their radii. If `dist > r1 + r2`, the area light is completely invisible, we directly return `false`. If `dist < abs(r1 - r2)`, the smaller circle lies inside the larger one, and we sample whichever circle is smaller. Otherwise, the two circles intersect, we compute the bounding rectangle of the intersection, in which case `axis_u`, `len_u`, `axis_v`, `len_v` needs to be computed anew. Depending on the distance between the two circles, `len_v` is either the diameter of the smaller circle or the length of the common chord.
|{F13990211,height=195}|{F13990225,height=195}|{F13990274,height=195}|{F13990210,height=195}
|`dist > r1 + r2`|`dist < abs(r1 - r2)`|`dist^2 < abs(r1^2 - r2^2)`|`dist^2 > abs(r1^2 - r2^2)`
For ellipse area light, it's hard to find the smallest bounding shape of the intersection, therefore, we compute the bounding rectangle of the ellipse itself, then treat it as a rectangle light.
|{F13990386,height=195}|{F13990385,height=195}|{F13990387,height=195}
We also check the areas of the bounding rectangle of the intersection, the ellipse (disk) light, and the spread circle, then draw samples from the smallest shape of the three. For ellipse light, this also detects where one shape lies inside the other. I am not sure if we should add this measure to rectangle area light and sample from the spread circle when it has smaller area, as we seem to have a better sampling technique for rectangular (uniformly sample the solid angle). Maybe we could add [area-preserving parameterization for spherical
ellipse](https://arxiv.org/pdf/1805.09048.pdf) in the future.
**Limitation**:
At some point we switch from sampling the ellipse to sampling the rectangle, depending on the area of the both, and there seems to be a visible line (with |slope| =1) on the final rendering
which demonstrate at which point we switch between the two methods. We could see that the new sampling method clearly has lower variance near the boundaries, but close to that visible line,
the rectangle sampling method seems to have larger variance. I could not spot any bug in the implementation, and I am not sure if this happens because different sampling patterns for ellipse and rectangle are used.
|Before (256spp)|After (256spp)
|{F13996995}|{F13996998}
Differential Revision: https://developer.blender.org/D16694
2022-12-05 14:35:25 +01:00
|
|
|
const bool is_ellipse = (klight->area.invarea < 0.0f);
|
2022-11-30 20:17:45 +01:00
|
|
|
if (invarea == 0.0f) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-02 15:21:57 +01:00
|
|
|
const float3 inv_extent_u = klight->area.axis_u / klight->area.len_u;
|
|
|
|
|
const float3 inv_extent_v = klight->area.axis_v / klight->area.len_v;
|
2022-11-30 20:17:45 +01:00
|
|
|
const float3 Ng = klight->area.dir;
|
|
|
|
|
|
|
|
|
|
/* One sided. */
|
|
|
|
|
if (dot(ray->D, Ng) >= 0.0f) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const float3 light_P = klight->co;
|
|
|
|
|
|
|
|
|
|
float3 P;
|
2022-12-02 15:21:57 +01:00
|
|
|
return ray_quad_intersect(ray->P,
|
|
|
|
|
ray->D,
|
|
|
|
|
ray->tmin,
|
|
|
|
|
ray->tmax,
|
|
|
|
|
light_P,
|
|
|
|
|
inv_extent_u,
|
|
|
|
|
inv_extent_v,
|
|
|
|
|
Ng,
|
|
|
|
|
&P,
|
|
|
|
|
t,
|
|
|
|
|
u,
|
|
|
|
|
v,
|
Cycles: improve sampling of ellipse area light with spread
**Problem**:
Area lights in Cycles have spread angle, in which case some part of the area light might be invisible to a shading point. The current implementation samples the whole area light, resulting some samples invisible and thus simply discarded. A technique is applied on rectangular light to sample a subset of the area light that is potentially visible (rB3f24cfb9582e1c826406301d37808df7ca6aa64c), however, ellipse (including disk) area lights remained untreated. The purpose of this patch is to apply a techniques to ellipse area light.
**Related Task**:
T87053
**Results**:
These are renderings before and after the patch:
|16spp|Disk light|Ellipse light|Square light (for reference, no changes)
|Before|{F13996789}|{F13996788}|{F13996822}
|After|{F13996759}|{F13996787}|{F13996852}
**Explanation**:
The visible region on an area light is found by drawing a cone from the shading point to the plane where the area light lies, with the aperture of the cone being the light spread.
{F13990078,height=200}
Ideally, we would like to draw samples only from the intersection of the area light and the projection of the cone onto the plane (forming a circle). However, the shape of the intersection is often irregular and thus hard to sample from directly.
{F13990104,height=200}
Instead, the current implementation draws samples from the bounding rectangle of the intersection. In this case, we still end up with some invalid samples outside of the circle, but already much less than sampling the original area light, and the bounding rectangle is easy to sample from.
{F13990125}
The above technique is only applied to rectangle area lights, ellipse area light still suffers from poor sampling. We could apply a similar technique to ellipse area lights, that is, find the
smallest regular shape (rectangle, circle, or ellipse) that covers the intersection (or maybe not the smallest but easy to compute).
For disk area light, we consider the relative position of both circles. Denoting `dist` as the distance between the centre of two circles, and `r1`, `r2` their radii. If `dist > r1 + r2`, the area light is completely invisible, we directly return `false`. If `dist < abs(r1 - r2)`, the smaller circle lies inside the larger one, and we sample whichever circle is smaller. Otherwise, the two circles intersect, we compute the bounding rectangle of the intersection, in which case `axis_u`, `len_u`, `axis_v`, `len_v` needs to be computed anew. Depending on the distance between the two circles, `len_v` is either the diameter of the smaller circle or the length of the common chord.
|{F13990211,height=195}|{F13990225,height=195}|{F13990274,height=195}|{F13990210,height=195}
|`dist > r1 + r2`|`dist < abs(r1 - r2)`|`dist^2 < abs(r1^2 - r2^2)`|`dist^2 > abs(r1^2 - r2^2)`
For ellipse area light, it's hard to find the smallest bounding shape of the intersection, therefore, we compute the bounding rectangle of the ellipse itself, then treat it as a rectangle light.
|{F13990386,height=195}|{F13990385,height=195}|{F13990387,height=195}
We also check the areas of the bounding rectangle of the intersection, the ellipse (disk) light, and the spread circle, then draw samples from the smallest shape of the three. For ellipse light, this also detects where one shape lies inside the other. I am not sure if we should add this measure to rectangle area light and sample from the spread circle when it has smaller area, as we seem to have a better sampling technique for rectangular (uniformly sample the solid angle). Maybe we could add [area-preserving parameterization for spherical
ellipse](https://arxiv.org/pdf/1805.09048.pdf) in the future.
**Limitation**:
At some point we switch from sampling the ellipse to sampling the rectangle, depending on the area of the both, and there seems to be a visible line (with |slope| =1) on the final rendering
which demonstrate at which point we switch between the two methods. We could see that the new sampling method clearly has lower variance near the boundaries, but close to that visible line,
the rectangle sampling method seems to have larger variance. I could not spot any bug in the implementation, and I am not sure if this happens because different sampling patterns for ellipse and rectangle are used.
|Before (256spp)|After (256spp)
|{F13996995}|{F13996998}
Differential Revision: https://developer.blender.org/D16694
2022-12-05 14:35:25 +01:00
|
|
|
is_ellipse);
|
2022-11-30 20:17:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ccl_device_inline bool area_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)
|
|
|
|
|
{
|
|
|
|
|
ls->u = isect->u;
|
|
|
|
|
ls->v = isect->v;
|
|
|
|
|
ls->D = ray_D;
|
2023-05-12 23:07:28 +02:00
|
|
|
ls->Ng = klight->area.dir;
|
2022-11-30 20:17:45 +01:00
|
|
|
|
2023-05-12 23:07:28 +02:00
|
|
|
float3 light_P = klight->co;
|
2023-05-24 18:56:58 +02:00
|
|
|
return area_light_eval<false>(klight, ray_P, &light_P, ls, zero_float2(), false);
|
2022-11-30 20:17:45 +01:00
|
|
|
}
|
2022-12-02 19:04:00 +01:00
|
|
|
|
|
|
|
|
template<bool in_volume_segment>
|
|
|
|
|
ccl_device_forceinline bool area_light_tree_parameters(const ccl_global KernelLight *klight,
|
|
|
|
|
const float3 centroid,
|
|
|
|
|
const float3 P,
|
|
|
|
|
const float3 N,
|
|
|
|
|
const float3 bcone_axis,
|
|
|
|
|
ccl_private float &cos_theta_u,
|
|
|
|
|
ccl_private float2 &distance,
|
|
|
|
|
ccl_private float3 &point_to_centroid)
|
|
|
|
|
{
|
|
|
|
|
if (!in_volume_segment) {
|
|
|
|
|
/* TODO: a cheap substitute for minimal distance between point and primitive. Does it
|
|
|
|
|
* worth the overhead to compute the accurate minimal distance? */
|
|
|
|
|
float min_distance;
|
|
|
|
|
point_to_centroid = safe_normalize_len(centroid - P, &min_distance);
|
|
|
|
|
distance = make_float2(min_distance, min_distance);
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-05 20:16:10 +01:00
|
|
|
cos_theta_u = FLT_MAX;
|
|
|
|
|
|
2022-12-02 19:04:00 +01:00
|
|
|
const float3 extentu = klight->area.axis_u * klight->area.len_u;
|
|
|
|
|
const float3 extentv = klight->area.axis_v * klight->area.len_v;
|
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
|
const float3 corner = ((i & 1) - 0.5f) * extentu + 0.5f * ((i & 2) - 1) * extentv + centroid;
|
|
|
|
|
float distance_point_to_corner;
|
|
|
|
|
const float3 point_to_corner = safe_normalize_len(corner - P, &distance_point_to_corner);
|
|
|
|
|
cos_theta_u = fminf(cos_theta_u, dot(point_to_centroid, point_to_corner));
|
|
|
|
|
if (!in_volume_segment) {
|
|
|
|
|
distance.x = fmaxf(distance.x, distance_point_to_corner);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const bool front_facing = dot(bcone_axis, point_to_centroid) < 0;
|
|
|
|
|
const bool shape_above_surface = dot(N, centroid - P) + fabsf(dot(N, extentu)) +
|
|
|
|
|
fabsf(dot(N, extentv)) >
|
|
|
|
|
0;
|
|
|
|
|
const bool in_volume = is_zero(N);
|
|
|
|
|
|
|
|
|
|
return (front_facing && shape_above_surface) || in_volume;
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-30 20:17:45 +01:00
|
|
|
CCL_NAMESPACE_END
|