2023-06-14 06:52:36 +00:00
|
|
|
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0 */
|
2011-04-27 11:58:34 +00:00
|
|
|
|
Cycles: Make all #include statements relative to cycles source directory
The idea is to make include statements more explicit and obvious where the
file is coming from, additionally reducing chance of wrong header being
picked up.
For example, it was not obvious whether bvh.h was refferring to builder
or traversal, whenter node.h is a generic graph node or a shader node
and cases like that.
Surely this might look obvious for the active developers, but after some
time of not touching the code it becomes less obvious where file is coming
from.
This was briefly mentioned in T50824 and seems @brecht is fine with such
explicitness, but need to agree with all active developers before committing
this.
Please note that this patch is lacking changes related on GPU/OpenCL
support. This will be solved if/when we all agree this is a good idea to move
forward.
Reviewers: brecht, lukasstockner97, maiself, nirved, dingto, juicyfruit, swerner
Reviewed By: lukasstockner97, maiself, nirved, dingto
Subscribers: brecht
Differential Revision: https://developer.blender.org/D2586
2017-03-28 18:39:14 +00:00
|
|
|
#include "device/device.h"
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 15:59:20 +00:00
|
|
|
|
2021-10-24 12:19:19 +00:00
|
|
|
#include "scene/background.h"
|
|
|
|
#include "scene/film.h"
|
|
|
|
#include "scene/integrator.h"
|
|
|
|
#include "scene/light.h"
|
2023-03-20 17:02:11 +00:00
|
|
|
#include "scene/light_tree.h"
|
2021-10-24 12:19:19 +00:00
|
|
|
#include "scene/mesh.h"
|
|
|
|
#include "scene/object.h"
|
|
|
|
#include "scene/scene.h"
|
|
|
|
#include "scene/shader.h"
|
|
|
|
#include "scene/shader_graph.h"
|
|
|
|
#include "scene/shader_nodes.h"
|
|
|
|
#include "scene/stats.h"
|
2011-04-27 11:58:34 +00:00
|
|
|
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 15:59:20 +00:00
|
|
|
#include "integrator/shader_eval.h"
|
|
|
|
|
2021-10-24 12:19:19 +00:00
|
|
|
#include "util/foreach.h"
|
|
|
|
#include "util/hash.h"
|
|
|
|
#include "util/log.h"
|
|
|
|
#include "util/path.h"
|
|
|
|
#include "util/progress.h"
|
|
|
|
#include "util/task.h"
|
2023-04-14 16:52:12 +00:00
|
|
|
#include <stack>
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
|
2019-04-17 04:17:24 +00:00
|
|
|
static void shade_background_pixels(Device *device,
|
|
|
|
DeviceScene *dscene,
|
|
|
|
int width,
|
|
|
|
int height,
|
|
|
|
vector<float3> &pixels,
|
|
|
|
Progress &progress)
|
2012-01-20 17:49:17 +00:00
|
|
|
{
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 15:59:20 +00:00
|
|
|
/* Needs to be up to data for attribute access. */
|
2022-06-17 15:16:37 +00:00
|
|
|
device->const_copy_to("data", &dscene->data, sizeof(dscene->data));
|
2019-04-17 04:17:24 +00:00
|
|
|
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 15:59:20 +00:00
|
|
|
const int size = width * height;
|
2021-10-13 17:13:35 +00:00
|
|
|
const int num_channels = 3;
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 15:59:20 +00:00
|
|
|
pixels.resize(size);
|
|
|
|
|
|
|
|
/* Evaluate shader on device. */
|
|
|
|
ShaderEval shader_eval(device, progress);
|
|
|
|
shader_eval.eval(
|
|
|
|
SHADER_EVAL_BACKGROUND,
|
|
|
|
size,
|
2021-10-13 17:13:35 +00:00
|
|
|
num_channels,
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 15:59:20 +00:00
|
|
|
[&](device_vector<KernelShaderEvalInput> &d_input) {
|
|
|
|
/* Fill coordinates for shading. */
|
|
|
|
KernelShaderEvalInput *d_input_data = d_input.data();
|
|
|
|
|
|
|
|
for (int y = 0; y < height; y++) {
|
|
|
|
for (int x = 0; x < width; x++) {
|
|
|
|
float u = (x + 0.5f) / width;
|
|
|
|
float v = (y + 0.5f) / height;
|
|
|
|
|
|
|
|
KernelShaderEvalInput in;
|
|
|
|
in.object = OBJECT_NONE;
|
|
|
|
in.prim = PRIM_NONE;
|
|
|
|
in.u = u;
|
|
|
|
in.v = v;
|
|
|
|
d_input_data[x + y * width] = in;
|
|
|
|
}
|
|
|
|
}
|
2019-04-17 04:17:24 +00:00
|
|
|
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 15:59:20 +00:00
|
|
|
return size;
|
|
|
|
},
|
2021-10-13 17:13:35 +00:00
|
|
|
[&](device_vector<float> &d_output) {
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 15:59:20 +00:00
|
|
|
/* Copy output to pixel buffer. */
|
2021-10-13 17:13:35 +00:00
|
|
|
float *d_output_data = d_output.data();
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 15:59:20 +00:00
|
|
|
|
|
|
|
for (int y = 0; y < height; y++) {
|
|
|
|
for (int x = 0; x < width; x++) {
|
2021-10-13 17:13:35 +00:00
|
|
|
pixels[y * width + x].x = d_output_data[(y * width + x) * num_channels + 0];
|
|
|
|
pixels[y * width + x].y = d_output_data[(y * width + x) * num_channels + 1];
|
|
|
|
pixels[y * width + x].z = d_output_data[(y * width + x) * num_channels + 2];
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 15:59:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2012-01-20 17:49:17 +00:00
|
|
|
}
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* Light */
|
|
|
|
|
2016-05-07 22:18:32 +00:00
|
|
|
NODE_DEFINE(Light)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2019-04-17 04:17:24 +00:00
|
|
|
NodeType *type = NodeType::add("light", create);
|
2016-05-07 22:18:32 +00:00
|
|
|
|
2019-04-17 04:17:24 +00:00
|
|
|
static NodeEnum type_enum;
|
|
|
|
type_enum.insert("point", LIGHT_POINT);
|
|
|
|
type_enum.insert("distant", LIGHT_DISTANT);
|
|
|
|
type_enum.insert("background", LIGHT_BACKGROUND);
|
|
|
|
type_enum.insert("area", LIGHT_AREA);
|
|
|
|
type_enum.insert("spot", LIGHT_SPOT);
|
2020-11-04 10:17:38 +00:00
|
|
|
SOCKET_ENUM(light_type, "Type", type_enum, LIGHT_POINT);
|
2016-05-07 22:18:32 +00:00
|
|
|
|
2021-02-17 00:47:18 +00:00
|
|
|
SOCKET_COLOR(strength, "Strength", one_float3());
|
2019-05-12 11:41:23 +00:00
|
|
|
|
2021-02-17 00:47:18 +00:00
|
|
|
SOCKET_POINT(co, "Co", zero_float3());
|
2016-05-07 22:18:32 +00:00
|
|
|
|
2021-02-17 00:47:18 +00:00
|
|
|
SOCKET_VECTOR(dir, "Dir", zero_float3());
|
2019-04-17 04:17:24 +00:00
|
|
|
SOCKET_FLOAT(size, "Size", 0.0f);
|
2020-06-02 05:14:25 +00:00
|
|
|
SOCKET_FLOAT(angle, "Angle", 0.0f);
|
2011-09-27 20:37:24 +00:00
|
|
|
|
2021-02-17 00:47:18 +00:00
|
|
|
SOCKET_VECTOR(axisu, "Axis U", zero_float3());
|
2019-04-17 04:17:24 +00:00
|
|
|
SOCKET_FLOAT(sizeu, "Size U", 1.0f);
|
2021-02-17 00:47:18 +00:00
|
|
|
SOCKET_VECTOR(axisv, "Axis V", zero_float3());
|
2019-04-17 04:17:24 +00:00
|
|
|
SOCKET_FLOAT(sizev, "Size V", 1.0f);
|
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 13:35:25 +00:00
|
|
|
SOCKET_BOOLEAN(ellipse, "Ellipse", false);
|
2021-04-01 03:35:56 +00:00
|
|
|
SOCKET_FLOAT(spread, "Spread", M_PI_F);
|
2011-09-27 20:37:24 +00:00
|
|
|
|
2019-04-17 04:17:24 +00:00
|
|
|
SOCKET_INT(map_resolution, "Map Resolution", 0);
|
2022-12-02 18:04:00 +00:00
|
|
|
SOCKET_FLOAT(average_radiance, "Average Radiance", 0.0f);
|
2011-09-27 20:37:24 +00:00
|
|
|
|
2019-04-17 04:17:24 +00:00
|
|
|
SOCKET_FLOAT(spot_angle, "Spot Angle", M_PI_4_F);
|
|
|
|
SOCKET_FLOAT(spot_smooth, "Spot Smooth", 0.0f);
|
2011-09-27 20:37:24 +00:00
|
|
|
|
2019-04-17 04:17:24 +00:00
|
|
|
SOCKET_TRANSFORM(tfm, "Transform", transform_identity());
|
2016-10-29 16:54:42 +00:00
|
|
|
|
2019-04-17 04:17:24 +00:00
|
|
|
SOCKET_BOOLEAN(cast_shadow, "Cast Shadow", true);
|
|
|
|
SOCKET_BOOLEAN(use_mis, "Use Mis", false);
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 15:59:20 +00:00
|
|
|
SOCKET_BOOLEAN(use_camera, "Use Camera", true);
|
2019-04-17 04:17:24 +00:00
|
|
|
SOCKET_BOOLEAN(use_diffuse, "Use Diffuse", true);
|
|
|
|
SOCKET_BOOLEAN(use_glossy, "Use Glossy", true);
|
|
|
|
SOCKET_BOOLEAN(use_transmission, "Use Transmission", true);
|
|
|
|
SOCKET_BOOLEAN(use_scatter, "Use Scatter", true);
|
Cycles: approximate shadow caustics using manifold next event estimation
This adds support for selective rendering of caustics in shadows of refractive
objects. Example uses are rendering of underwater caustics and eye caustics.
This is based on "Manifold Next Event Estimation", a method developed for
production rendering. The idea is to selectively enable shadow caustics on a
few objects in the scene where they have a big visual impact, without impacting
render performance for the rest of the scene.
The Shadow Caustic option must be manually enabled on light, caustic receiver
and caster objects. For such light paths, the Filter Glossy option will be
ignored and replaced by sharp caustics.
Currently this method has a various limitations:
* Only caustics in shadows of refractive objects work, which means no caustics
from reflection or caustics that outside shadows. Only up to 4 refractive
caustic bounces are supported.
* Caustic caster objects should have smooth normals.
* Not currently support for Metal GPU rendering.
In the future this method may be extended for more general caustics.
TECHNICAL DETAILS
This code adds manifold next event estimation through refractive surface(s) as a
new sampling technique for direct lighting, i.e. finding the point on the
refractive surface(s) along the path to a light sample, which satisfies Fermat's
principle for a given microfacet normal and the path's end points. This
technique involves walking on the "specular manifold" using a pseudo newton
solver. Such a manifold is defined by the specular constraint matrix from the
manifold exploration framework [2]. For each refractive interface, this
constraint is defined by enforcing that the generalized half-vector projection
onto the interface local tangent plane is null. The newton solver guides the
walk by linearizing the manifold locally before reprojecting the linear solution
onto the refractive surface. See paper [1] for more details about the technique
itself and [3] for the half-vector light transport formulation, from which it is
derived.
[1] Manifold Next Event Estimation
Johannes Hanika, Marc Droske, and Luca Fascione. 2015.
Comput. Graph. Forum 34, 4 (July 2015), 87–97.
https://jo.dreggn.org/home/2015_mnee.pdf
[2] Manifold exploration: a Markov Chain Monte Carlo technique for rendering
scenes with difficult specular transport Wenzel Jakob and Steve Marschner.
2012. ACM Trans. Graph. 31, 4, Article 58 (July 2012), 13 pages.
https://www.cs.cornell.edu/projects/manifolds-sg12/
[3] The Natural-Constraint Representation of the Path Space for Efficient
Light Transport Simulation. Anton S. Kaplanyan, Johannes Hanika, and Carsten
Dachsbacher. 2014. ACM Trans. Graph. 33, 4, Article 102 (July 2014), 13 pages.
https://cg.ivd.kit.edu/english/HSLT.php
The code for this samping technique was inserted at the light sampling stage
(direct lighting). If the walk is successful, it turns off path regularization
using a specialized flag in the path state (PATH_MNEE_SUCCESS). This flag tells
the integrator not to blur the brdf roughness further down the path (in a child
ray created from BSDF sampling). In addition, using a cascading mechanism of
flag values, we cull connections to caustic lights for this and children rays,
which should be resolved through MNEE.
This mechanism also cancels the MIS bsdf counter part at the casutic receiver
depth, in essence leaving MNEE as the only sampling technique from receivers
through refractive casters to caustic lights. This choice might not be optimal
when the light gets large wrt to the receiver, though this is usually not when
you want to use MNEE.
This connection culling strategy removes a fair amount of fireflies, at the cost
of introducing a slight bias. Because of the selective nature of the culling
mechanism, reflective caustics still benefit from the native path
regularization, which further removes fireflies on other surfaces (bouncing
light off casters).
Differential Revision: https://developer.blender.org/D13533
2022-04-01 13:44:24 +00:00
|
|
|
SOCKET_BOOLEAN(use_caustics, "Shadow Caustics", false);
|
2012-01-20 17:49:17 +00:00
|
|
|
|
2019-04-17 04:17:24 +00:00
|
|
|
SOCKET_INT(max_bounces, "Max Bounces", 1024);
|
|
|
|
SOCKET_UINT(random_id, "Random ID", 0);
|
2012-06-04 17:17:10 +00:00
|
|
|
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 15:59:20 +00:00
|
|
|
SOCKET_BOOLEAN(is_shadow_catcher, "Shadow Catcher", true);
|
2019-04-17 04:17:24 +00:00
|
|
|
SOCKET_BOOLEAN(is_portal, "Is Portal", false);
|
|
|
|
SOCKET_BOOLEAN(is_enabled, "Is Enabled", true);
|
2013-01-30 15:57:15 +00:00
|
|
|
|
2021-03-15 15:11:12 +00:00
|
|
|
SOCKET_NODE(shader, "Shader", Shader::get_node_type());
|
Cycles: Added support for light portals
This patch adds support for light portals: objects that help sampling the
environment light, therefore improving convergence. Using them tor other
lights in a unidirectional pathtracer is virtually useless.
The sampling is done with the area-preserving code already used for area lamps.
MIS is used both for combination of different portals and for combining portal-
and envmap-sampling.
The direction of portals is considered, they aren't used if the sampling point
is behind them.
Reviewers: sergey, dingto, #cycles
Reviewed By: dingto, #cycles
Subscribers: Lapineige, nutel, jtheninja, dsisco11, januz, vitorbalbio, candreacchio, TARDISMaker, lichtwerk, ace_dragon, marcog, mib2berlin, Tunge, lopataasdf, lordodin, sergey, dingto
Differential Revision: https://developer.blender.org/D1133
2015-04-27 19:51:55 +00:00
|
|
|
|
2022-04-01 22:11:11 +00:00
|
|
|
SOCKET_STRING(lightgroup, "Light Group", ustring());
|
2023-05-24 11:36:13 +00:00
|
|
|
SOCKET_UINT64(light_set_membership, "Light Set Membership", LIGHT_LINK_MASK_ALL);
|
|
|
|
SOCKET_UINT64(shadow_set_membership, "Shadow Set Membership", LIGHT_LINK_MASK_ALL);
|
2022-04-01 22:11:11 +00:00
|
|
|
|
2023-01-04 12:38:32 +00:00
|
|
|
SOCKET_BOOLEAN(normalize, "Normalize", true);
|
|
|
|
|
2019-04-17 04:17:24 +00:00
|
|
|
return type;
|
2016-05-07 22:18:32 +00:00
|
|
|
}
|
|
|
|
|
2021-03-15 15:11:12 +00:00
|
|
|
Light::Light() : Node(get_node_type())
|
2016-05-07 22:18:32 +00:00
|
|
|
{
|
2021-05-02 00:23:34 +00:00
|
|
|
dereference_all_used_nodes();
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Light::tag_update(Scene *scene)
|
|
|
|
{
|
Cycles: optimize device updates
This optimizes device updates (during user edits or frame changes in
the viewport) by avoiding unnecessary computations. To achieve this,
we use a combination of the sockets' update flags as well as some new
flags passed to the various managers when tagging for an update to tell
exactly what the tagging is for (e.g. shader was modified, object was
removed, etc.).
Besides avoiding recomputations, we also avoid resending to the devices
unmodified data arrays, thus reducing bandwidth usage. For OptiX and
Embree, BVH packing was also multithreaded.
The performance improvements may vary depending on the used device (CPU
or GPU), and the content of the scene. Simple scenes (e.g. with no adaptive
subdivision or volumes) rendered using OptiX will benefit from this work
the most.
On average, for a variety of animated scenes, this gives a 3x speedup.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79174
Differential Revision: https://developer.blender.org/D9555
2021-01-22 14:01:26 +00:00
|
|
|
if (is_modified()) {
|
|
|
|
scene->light_manager->tag_update(scene, LightManager::LIGHT_MODIFIED);
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
2015-06-25 15:00:32 +00:00
|
|
|
bool Light::has_contribution(Scene *scene)
|
|
|
|
{
|
2021-02-17 00:47:18 +00:00
|
|
|
if (strength == zero_float3()) {
|
2019-05-12 11:41:23 +00:00
|
|
|
return false;
|
|
|
|
}
|
2019-04-17 04:17:24 +00:00
|
|
|
if (is_portal) {
|
|
|
|
return false;
|
|
|
|
}
|
2020-11-04 10:17:38 +00:00
|
|
|
if (light_type == LIGHT_BACKGROUND) {
|
2019-04-17 04:17:24 +00:00
|
|
|
return true;
|
|
|
|
}
|
2022-11-30 19:50:11 +00:00
|
|
|
|
|
|
|
const Shader *effective_shader = (shader) ? shader : scene->default_light;
|
|
|
|
return !is_zero(effective_shader->emission_estimate);
|
2015-06-25 15:00:32 +00:00
|
|
|
}
|
|
|
|
|
2023-05-26 10:21:44 +00:00
|
|
|
bool Light::has_light_linking() const
|
|
|
|
{
|
|
|
|
if (get_light_set_membership() != LIGHT_LINK_MASK_ALL) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Light::has_shadow_linking() const
|
|
|
|
{
|
|
|
|
if (get_shadow_set_membership() != LIGHT_LINK_MASK_ALL) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* Light Manager */
|
|
|
|
|
|
|
|
LightManager::LightManager()
|
|
|
|
{
|
Cycles: optimize device updates
This optimizes device updates (during user edits or frame changes in
the viewport) by avoiding unnecessary computations. To achieve this,
we use a combination of the sockets' update flags as well as some new
flags passed to the various managers when tagging for an update to tell
exactly what the tagging is for (e.g. shader was modified, object was
removed, etc.).
Besides avoiding recomputations, we also avoid resending to the devices
unmodified data arrays, thus reducing bandwidth usage. For OptiX and
Embree, BVH packing was also multithreaded.
The performance improvements may vary depending on the used device (CPU
or GPU), and the content of the scene. Simple scenes (e.g. with no adaptive
subdivision or volumes) rendered using OptiX will benefit from this work
the most.
On average, for a variety of animated scenes, this gives a 3x speedup.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79174
Differential Revision: https://developer.blender.org/D9555
2021-01-22 14:01:26 +00:00
|
|
|
update_flags = UPDATE_ALL;
|
2020-05-14 15:41:37 +00:00
|
|
|
need_update_background = true;
|
|
|
|
last_background_enabled = false;
|
|
|
|
last_background_resolution = 0;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
LightManager::~LightManager()
|
|
|
|
{
|
2019-04-17 04:17:24 +00:00
|
|
|
foreach (IESSlot *slot, ies_slots) {
|
|
|
|
delete slot;
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
2016-09-02 07:58:41 +00:00
|
|
|
bool LightManager::has_background_light(Scene *scene)
|
|
|
|
{
|
2019-04-17 04:17:24 +00:00
|
|
|
foreach (Light *light, scene->lights) {
|
2020-11-04 10:17:38 +00:00
|
|
|
if (light->light_type == LIGHT_BACKGROUND && light->is_enabled) {
|
2019-04-17 04:17:24 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
2016-09-02 07:58:41 +00:00
|
|
|
}
|
|
|
|
|
2020-05-14 15:41:37 +00:00
|
|
|
void LightManager::test_enabled_lights(Scene *scene)
|
2016-02-06 19:43:44 +00:00
|
|
|
{
|
2019-04-17 04:17:24 +00:00
|
|
|
/* Make all lights enabled by default, and perform some preliminary checks
|
|
|
|
* needed for finer-tuning of settings (for example, check whether we've
|
|
|
|
* got portals or not).
|
|
|
|
*/
|
|
|
|
bool has_portal = false, has_background = false;
|
|
|
|
foreach (Light *light, scene->lights) {
|
|
|
|
light->is_enabled = light->has_contribution(scene);
|
|
|
|
has_portal |= light->is_portal;
|
2020-11-04 10:17:38 +00:00
|
|
|
has_background |= light->light_type == LIGHT_BACKGROUND;
|
2019-04-17 04:17:24 +00:00
|
|
|
}
|
|
|
|
|
2020-05-14 15:41:37 +00:00
|
|
|
bool background_enabled = false;
|
|
|
|
int background_resolution = 0;
|
|
|
|
|
2019-04-17 04:17:24 +00:00
|
|
|
if (has_background) {
|
|
|
|
/* Ignore background light if:
|
|
|
|
* - If unsupported on a device
|
|
|
|
* - If we don't need it (no HDRs etc.)
|
|
|
|
*/
|
2020-01-20 12:42:26 +00:00
|
|
|
Shader *shader = scene->background->get_shader(scene);
|
2019-10-29 15:32:53 +00:00
|
|
|
const bool disable_mis = !(has_portal || shader->has_surface_spatial_varying);
|
2022-06-16 17:39:13 +00:00
|
|
|
if (disable_mis) {
|
|
|
|
VLOG_INFO << "Background MIS has been disabled.\n";
|
|
|
|
}
|
2019-10-29 15:32:53 +00:00
|
|
|
foreach (Light *light, scene->lights) {
|
2020-11-04 10:17:38 +00:00
|
|
|
if (light->light_type == LIGHT_BACKGROUND) {
|
2019-10-29 15:32:53 +00:00
|
|
|
light->is_enabled = !disable_mis;
|
2020-05-14 15:41:37 +00:00
|
|
|
background_enabled = !disable_mis;
|
|
|
|
background_resolution = light->map_resolution;
|
2019-04-17 04:17:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-05-14 15:41:37 +00:00
|
|
|
|
|
|
|
if (last_background_enabled != background_enabled ||
|
2023-05-01 22:42:26 +00:00
|
|
|
last_background_resolution != background_resolution)
|
|
|
|
{
|
2020-05-14 15:41:37 +00:00
|
|
|
last_background_enabled = background_enabled;
|
|
|
|
last_background_resolution = background_resolution;
|
|
|
|
need_update_background = true;
|
|
|
|
}
|
2016-02-06 19:43:44 +00:00
|
|
|
}
|
|
|
|
|
2022-12-02 18:08:56 +00:00
|
|
|
void LightManager::device_update_distribution(Device *,
|
2019-04-17 04:17:24 +00:00
|
|
|
DeviceScene *dscene,
|
|
|
|
Scene *scene,
|
|
|
|
Progress &progress)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2022-11-30 19:17:45 +00:00
|
|
|
KernelIntegrator *kintegrator = &dscene->data.integrator;
|
|
|
|
|
|
|
|
/* Update CDF over lights. */
|
2019-04-17 04:17:24 +00:00
|
|
|
progress.set_status("Updating Lights", "Computing distribution");
|
|
|
|
|
2022-11-30 19:17:45 +00:00
|
|
|
/* Counts emissive triangles in the scene. */
|
2019-04-17 04:17:24 +00:00
|
|
|
size_t num_triangles = 0;
|
|
|
|
|
|
|
|
foreach (Object *object, scene->objects) {
|
|
|
|
if (progress.get_cancel())
|
|
|
|
return;
|
|
|
|
|
2023-04-03 08:54:17 +00:00
|
|
|
if (!object->usable_as_light()) {
|
2019-04-17 04:17:24 +00:00
|
|
|
continue;
|
|
|
|
}
|
2020-02-02 11:04:19 +00:00
|
|
|
|
2022-11-30 19:17:45 +00:00
|
|
|
/* Count emissive triangles. */
|
2020-11-04 10:17:38 +00:00
|
|
|
Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
|
2023-04-04 18:00:56 +00:00
|
|
|
int mesh_num_triangles = static_cast<int>(mesh->num_triangles());
|
2022-11-30 19:17:45 +00:00
|
|
|
|
2023-04-04 18:00:56 +00:00
|
|
|
for (int i = 0; i < mesh_num_triangles; i++) {
|
2020-11-04 10:17:38 +00:00
|
|
|
int shader_index = mesh->get_shader()[i];
|
|
|
|
Shader *shader = (shader_index < mesh->get_used_shaders().size()) ?
|
|
|
|
static_cast<Shader *>(mesh->get_used_shaders()[shader_index]) :
|
2019-04-17 04:17:24 +00:00
|
|
|
scene->default_surface;
|
|
|
|
|
2022-11-30 19:50:11 +00:00
|
|
|
if (shader->emission_sampling != EMISSION_SAMPLING_NONE) {
|
2019-04-17 04:17:24 +00:00
|
|
|
num_triangles++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-30 19:17:45 +00:00
|
|
|
const size_t num_lights = kintegrator->num_lights;
|
|
|
|
const size_t num_distribution = num_triangles + num_lights;
|
|
|
|
|
|
|
|
/* Distribution size. */
|
|
|
|
kintegrator->num_distribution = num_distribution;
|
|
|
|
|
2022-12-02 18:04:00 +00:00
|
|
|
if (kintegrator->use_light_tree) {
|
|
|
|
dscene->light_distribution.free();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-05-05 14:32:59 +00:00
|
|
|
VLOG_INFO << "Use light distribution with " << num_distribution << " emitters.";
|
|
|
|
|
2022-11-30 19:17:45 +00:00
|
|
|
/* Emission area. */
|
2019-04-17 04:17:24 +00:00
|
|
|
KernelLightDistribution *distribution = dscene->light_distribution.alloc(num_distribution + 1);
|
|
|
|
float totarea = 0.0f;
|
|
|
|
|
2022-11-30 19:17:45 +00:00
|
|
|
/* Triangles. */
|
2019-04-17 04:17:24 +00:00
|
|
|
size_t offset = 0;
|
|
|
|
int j = 0;
|
|
|
|
|
|
|
|
foreach (Object *object, scene->objects) {
|
|
|
|
if (progress.get_cancel())
|
|
|
|
return;
|
|
|
|
|
2023-04-03 08:54:17 +00:00
|
|
|
if (!object->usable_as_light()) {
|
2019-04-17 04:17:24 +00:00
|
|
|
j++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/* Sum area. */
|
2020-11-04 10:17:38 +00:00
|
|
|
Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
|
2019-04-17 04:17:24 +00:00
|
|
|
bool transform_applied = mesh->transform_applied;
|
2020-11-04 10:17:38 +00:00
|
|
|
Transform tfm = object->get_tfm();
|
2019-04-17 04:17:24 +00:00
|
|
|
int object_id = j;
|
|
|
|
int shader_flag = 0;
|
|
|
|
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 15:59:20 +00:00
|
|
|
if (!(object->get_visibility() & PATH_RAY_CAMERA)) {
|
|
|
|
shader_flag |= SHADER_EXCLUDE_CAMERA;
|
|
|
|
}
|
2020-11-04 10:17:38 +00:00
|
|
|
if (!(object->get_visibility() & PATH_RAY_DIFFUSE)) {
|
2019-04-17 04:17:24 +00:00
|
|
|
shader_flag |= SHADER_EXCLUDE_DIFFUSE;
|
|
|
|
}
|
2020-11-04 10:17:38 +00:00
|
|
|
if (!(object->get_visibility() & PATH_RAY_GLOSSY)) {
|
2019-04-17 04:17:24 +00:00
|
|
|
shader_flag |= SHADER_EXCLUDE_GLOSSY;
|
|
|
|
}
|
2020-11-04 10:17:38 +00:00
|
|
|
if (!(object->get_visibility() & PATH_RAY_TRANSMIT)) {
|
2019-04-17 04:17:24 +00:00
|
|
|
shader_flag |= SHADER_EXCLUDE_TRANSMIT;
|
|
|
|
}
|
2020-11-04 10:17:38 +00:00
|
|
|
if (!(object->get_visibility() & PATH_RAY_VOLUME_SCATTER)) {
|
2019-04-17 04:17:24 +00:00
|
|
|
shader_flag |= SHADER_EXCLUDE_SCATTER;
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 15:59:20 +00:00
|
|
|
}
|
|
|
|
if (!(object->get_is_shadow_catcher())) {
|
|
|
|
shader_flag |= SHADER_EXCLUDE_SHADOW_CATCHER;
|
2019-04-17 04:17:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t mesh_num_triangles = mesh->num_triangles();
|
|
|
|
for (size_t i = 0; i < mesh_num_triangles; i++) {
|
2020-11-04 10:17:38 +00:00
|
|
|
int shader_index = mesh->get_shader()[i];
|
|
|
|
Shader *shader = (shader_index < mesh->get_used_shaders().size()) ?
|
|
|
|
static_cast<Shader *>(mesh->get_used_shaders()[shader_index]) :
|
2019-04-17 04:17:24 +00:00
|
|
|
scene->default_surface;
|
|
|
|
|
2022-11-30 19:50:11 +00:00
|
|
|
if (shader->emission_sampling != EMISSION_SAMPLING_NONE) {
|
2019-04-17 04:17:24 +00:00
|
|
|
distribution[offset].totarea = totarea;
|
2020-02-02 11:04:19 +00:00
|
|
|
distribution[offset].prim = i + mesh->prim_offset;
|
2019-04-17 04:17:24 +00:00
|
|
|
distribution[offset].mesh_light.shader_flag = shader_flag;
|
|
|
|
distribution[offset].mesh_light.object_id = object_id;
|
|
|
|
offset++;
|
|
|
|
|
|
|
|
Mesh::Triangle t = mesh->get_triangle(i);
|
2020-11-04 10:17:38 +00:00
|
|
|
if (!t.valid(&mesh->get_verts()[0])) {
|
2019-04-17 04:17:24 +00:00
|
|
|
continue;
|
|
|
|
}
|
2020-11-04 10:17:38 +00:00
|
|
|
float3 p1 = mesh->get_verts()[t.v[0]];
|
|
|
|
float3 p2 = mesh->get_verts()[t.v[1]];
|
|
|
|
float3 p3 = mesh->get_verts()[t.v[2]];
|
2019-04-17 04:17:24 +00:00
|
|
|
|
|
|
|
if (!transform_applied) {
|
|
|
|
p1 = transform_point(&tfm, p1);
|
|
|
|
p2 = transform_point(&tfm, p2);
|
|
|
|
p3 = transform_point(&tfm, p3);
|
|
|
|
}
|
|
|
|
|
|
|
|
totarea += triangle_area(p1, p2, p3);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
|
2022-11-30 19:17:45 +00:00
|
|
|
const float trianglearea = totarea;
|
|
|
|
|
|
|
|
/* Lights. */
|
2019-04-17 04:17:24 +00:00
|
|
|
int light_index = 0;
|
2021-09-13 07:50:02 +00:00
|
|
|
|
2021-09-06 11:08:41 +00:00
|
|
|
if (num_lights > 0) {
|
|
|
|
float lightarea = (totarea > 0.0f) ? totarea / num_lights : 1.0f;
|
|
|
|
foreach (Light *light, scene->lights) {
|
|
|
|
if (!light->is_enabled)
|
|
|
|
continue;
|
2019-04-17 04:17:24 +00:00
|
|
|
|
2021-09-06 11:08:41 +00:00
|
|
|
distribution[offset].totarea = totarea;
|
|
|
|
distribution[offset].prim = ~light_index;
|
2022-12-02 18:04:00 +00:00
|
|
|
distribution[offset].mesh_light.object_id = OBJECT_NONE;
|
|
|
|
distribution[offset].mesh_light.shader_flag = 0;
|
2021-09-06 11:08:41 +00:00
|
|
|
totarea += lightarea;
|
2019-04-17 04:17:24 +00:00
|
|
|
|
2021-09-06 11:08:41 +00:00
|
|
|
light_index++;
|
|
|
|
offset++;
|
|
|
|
}
|
2019-04-17 04:17:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* normalize cumulative distribution functions */
|
|
|
|
distribution[num_distribution].totarea = totarea;
|
2022-12-02 18:04:00 +00:00
|
|
|
distribution[num_distribution].prim = 0;
|
|
|
|
distribution[num_distribution].mesh_light.object_id = OBJECT_NONE;
|
|
|
|
distribution[num_distribution].mesh_light.shader_flag = 0;
|
2019-04-17 04:17:24 +00:00
|
|
|
|
|
|
|
if (totarea > 0.0f) {
|
|
|
|
for (size_t i = 0; i < num_distribution; i++)
|
|
|
|
distribution[i].totarea /= totarea;
|
|
|
|
distribution[num_distribution].totarea = 1.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (progress.get_cancel())
|
|
|
|
return;
|
|
|
|
|
2022-11-30 19:17:45 +00:00
|
|
|
/* Update integrator state. */
|
2019-04-17 04:17:24 +00:00
|
|
|
kintegrator->use_direct_light = (totarea > 0.0f);
|
|
|
|
|
2022-11-30 19:17:45 +00:00
|
|
|
/* Precompute pdfs for distribution sampling.
|
|
|
|
* Sample one, with 0.5 probability of light or triangle. */
|
|
|
|
kintegrator->distribution_pdf_triangles = 0.0f;
|
|
|
|
kintegrator->distribution_pdf_lights = 0.0f;
|
2019-04-17 04:17:24 +00:00
|
|
|
|
2022-11-30 19:17:45 +00:00
|
|
|
if (trianglearea > 0.0f) {
|
|
|
|
kintegrator->distribution_pdf_triangles = 1.0f / trianglearea;
|
2019-04-17 04:17:24 +00:00
|
|
|
if (num_lights) {
|
2022-11-30 19:17:45 +00:00
|
|
|
kintegrator->distribution_pdf_triangles *= 0.5f;
|
2019-04-17 04:17:24 +00:00
|
|
|
}
|
2022-11-30 19:17:45 +00:00
|
|
|
}
|
2019-04-17 04:17:24 +00:00
|
|
|
|
2022-11-30 19:17:45 +00:00
|
|
|
if (num_lights) {
|
|
|
|
kintegrator->distribution_pdf_lights = 1.0f / num_lights;
|
|
|
|
if (trianglearea > 0.0f) {
|
|
|
|
kintegrator->distribution_pdf_lights *= 0.5f;
|
2019-04-17 04:17:24 +00:00
|
|
|
}
|
2022-11-30 19:17:45 +00:00
|
|
|
}
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 18:27:10 +00:00
|
|
|
|
2022-11-30 19:17:45 +00:00
|
|
|
/* Copy distribution to device. */
|
|
|
|
dscene->light_distribution.copy_to_device();
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
2023-05-05 14:32:59 +00:00
|
|
|
/* Arguments for functions to convert the light tree to the kernel representation. */
|
|
|
|
struct LightTreeFlatten {
|
|
|
|
const Scene *scene;
|
|
|
|
const LightTreeEmitter *emitters;
|
|
|
|
const uint *object_lookup_offset;
|
|
|
|
uint *light_array;
|
|
|
|
uint *mesh_array;
|
|
|
|
uint *triangle_array;
|
|
|
|
|
|
|
|
/* Map from instance node to its node index. */
|
|
|
|
std::unordered_map<LightTreeNode *, int> instances;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void light_tree_node_copy_to_device(KernelLightTreeNode &knode,
|
|
|
|
const LightTreeNode &node,
|
2023-05-24 11:36:13 +00:00
|
|
|
const int left_child,
|
|
|
|
const int right_child)
|
2023-05-05 14:32:59 +00:00
|
|
|
{
|
|
|
|
/* Convert node to kernel representation. */
|
|
|
|
knode.energy = node.measure.energy;
|
|
|
|
|
|
|
|
knode.bbox.min = node.measure.bbox.min;
|
|
|
|
knode.bbox.max = node.measure.bbox.max;
|
|
|
|
|
|
|
|
knode.bcone.axis = node.measure.bcone.axis;
|
|
|
|
knode.bcone.theta_o = node.measure.bcone.theta_o;
|
|
|
|
knode.bcone.theta_e = node.measure.bcone.theta_e;
|
|
|
|
|
|
|
|
knode.bit_trail = node.bit_trail;
|
2023-05-24 11:36:13 +00:00
|
|
|
knode.bit_skip = 0;
|
2023-05-05 14:32:59 +00:00
|
|
|
knode.type = static_cast<LightTreeNodeType>(node.type);
|
|
|
|
|
|
|
|
if (node.is_leaf() || node.is_distant()) {
|
|
|
|
knode.num_emitters = node.get_leaf().num_emitters;
|
|
|
|
knode.leaf.first_emitter = node.get_leaf().first_emitter_index;
|
|
|
|
}
|
|
|
|
else if (node.is_inner()) {
|
|
|
|
knode.num_emitters = -1;
|
2023-05-24 11:36:13 +00:00
|
|
|
knode.inner.left_child = left_child;
|
|
|
|
knode.inner.right_child = right_child;
|
2023-05-05 14:32:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int light_tree_flatten(LightTreeFlatten &flatten,
|
|
|
|
const LightTreeNode *node,
|
|
|
|
KernelLightTreeNode *knodes,
|
|
|
|
KernelLightTreeEmitter *kemitters,
|
|
|
|
int &next_node_index);
|
|
|
|
|
|
|
|
static void light_tree_leaf_emitters_copy_and_flatten(LightTreeFlatten &flatten,
|
|
|
|
const LightTreeNode &node,
|
|
|
|
KernelLightTreeNode *knodes,
|
|
|
|
KernelLightTreeEmitter *kemitters,
|
|
|
|
int &next_node_index)
|
|
|
|
{
|
|
|
|
/* Convert emitters to kernel representation. */
|
|
|
|
for (int i = 0; i < node.get_leaf().num_emitters; i++) {
|
|
|
|
int emitter_index = i + node.get_leaf().first_emitter_index;
|
|
|
|
const LightTreeEmitter &emitter = flatten.emitters[emitter_index];
|
|
|
|
KernelLightTreeEmitter &kemitter = kemitters[emitter_index];
|
|
|
|
|
|
|
|
kemitter.energy = emitter.measure.energy;
|
|
|
|
kemitter.theta_o = emitter.measure.bcone.theta_o;
|
|
|
|
kemitter.theta_e = emitter.measure.bcone.theta_e;
|
|
|
|
|
|
|
|
if (emitter.is_triangle()) {
|
|
|
|
/* Triangle. */
|
|
|
|
int shader_flag = 0;
|
|
|
|
Object *object = flatten.scene->objects[emitter.object_id];
|
|
|
|
Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
|
|
|
|
Shader *shader = static_cast<Shader *>(
|
|
|
|
mesh->get_used_shaders()[mesh->get_shader()[emitter.prim_id]]);
|
|
|
|
|
|
|
|
if (!(object->get_visibility() & PATH_RAY_CAMERA)) {
|
|
|
|
shader_flag |= SHADER_EXCLUDE_CAMERA;
|
|
|
|
}
|
|
|
|
if (!(object->get_visibility() & PATH_RAY_DIFFUSE)) {
|
|
|
|
shader_flag |= SHADER_EXCLUDE_DIFFUSE;
|
|
|
|
}
|
|
|
|
if (!(object->get_visibility() & PATH_RAY_GLOSSY)) {
|
|
|
|
shader_flag |= SHADER_EXCLUDE_GLOSSY;
|
|
|
|
}
|
|
|
|
if (!(object->get_visibility() & PATH_RAY_TRANSMIT)) {
|
|
|
|
shader_flag |= SHADER_EXCLUDE_TRANSMIT;
|
|
|
|
}
|
|
|
|
if (!(object->get_visibility() & PATH_RAY_VOLUME_SCATTER)) {
|
|
|
|
shader_flag |= SHADER_EXCLUDE_SCATTER;
|
|
|
|
}
|
|
|
|
if (!(object->get_is_shadow_catcher())) {
|
|
|
|
shader_flag |= SHADER_EXCLUDE_SHADOW_CATCHER;
|
|
|
|
}
|
|
|
|
|
|
|
|
kemitter.triangle.id = emitter.prim_id + mesh->prim_offset;
|
|
|
|
kemitter.mesh_light.shader_flag = shader_flag;
|
|
|
|
kemitter.mesh_light.object_id = emitter.object_id;
|
|
|
|
kemitter.triangle.emission_sampling = shader->emission_sampling;
|
|
|
|
flatten.triangle_array[emitter.prim_id + flatten.object_lookup_offset[emitter.object_id]] =
|
|
|
|
emitter_index;
|
|
|
|
}
|
|
|
|
else if (emitter.is_light()) {
|
|
|
|
/* Light object. */
|
|
|
|
kemitter.light.id = emitter.light_id;
|
|
|
|
kemitter.mesh_light.shader_flag = 0;
|
|
|
|
kemitter.mesh_light.object_id = OBJECT_NONE;
|
|
|
|
flatten.light_array[~emitter.light_id] = emitter_index;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* Mesh instance. */
|
|
|
|
assert(emitter.is_mesh());
|
|
|
|
kemitter.mesh.object_id = emitter.object_id;
|
|
|
|
kemitter.mesh_light.shader_flag = 0;
|
|
|
|
kemitter.mesh_light.object_id = OBJECT_NONE;
|
|
|
|
flatten.mesh_array[emitter.object_id] = emitter_index;
|
|
|
|
|
|
|
|
/* Create instance node. One instance node will be the same as the
|
|
|
|
* reference node, and for that it will recursively build the subtree. */
|
|
|
|
LightTreeNode *instance_node = emitter.root.get();
|
|
|
|
LightTreeNode *reference_node = instance_node->get_reference();
|
|
|
|
|
|
|
|
auto map_it = flatten.instances.find(reference_node);
|
|
|
|
if (map_it == flatten.instances.end()) {
|
|
|
|
if (instance_node != reference_node) {
|
|
|
|
/* Flatten the node with the subtree first so the subsequent instances know the index. */
|
|
|
|
std::swap(instance_node->type, reference_node->type);
|
|
|
|
std::swap(instance_node->variant_type, reference_node->variant_type);
|
|
|
|
}
|
|
|
|
instance_node->type &= ~LIGHT_TREE_INSTANCE;
|
|
|
|
}
|
|
|
|
|
|
|
|
kemitter.mesh.node_id = light_tree_flatten(
|
|
|
|
flatten, instance_node, knodes, kemitters, next_node_index);
|
|
|
|
|
|
|
|
KernelLightTreeNode &kinstance_node = knodes[kemitter.mesh.node_id];
|
|
|
|
kinstance_node.bit_trail = node.bit_trail;
|
|
|
|
|
|
|
|
if (map_it != flatten.instances.end()) {
|
|
|
|
kinstance_node.instance.reference = map_it->second;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
flatten.instances[reference_node] = kemitter.mesh.node_id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
kemitter.bit_trail = node.bit_trail;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int light_tree_flatten(LightTreeFlatten &flatten,
|
|
|
|
const LightTreeNode *node,
|
|
|
|
KernelLightTreeNode *knodes,
|
|
|
|
KernelLightTreeEmitter *kemitters,
|
|
|
|
int &next_node_index)
|
|
|
|
{
|
|
|
|
/* Convert both inner nodes and primitives to device representation. */
|
|
|
|
const int node_index = next_node_index++;
|
2023-05-24 11:36:13 +00:00
|
|
|
int left_child = -1, right_child = -1;
|
2023-05-05 14:32:59 +00:00
|
|
|
|
|
|
|
if (node->is_leaf() || node->is_distant()) {
|
|
|
|
light_tree_leaf_emitters_copy_and_flatten(flatten, *node, knodes, kemitters, next_node_index);
|
|
|
|
}
|
|
|
|
else if (node->is_inner()) {
|
2023-05-24 11:36:13 +00:00
|
|
|
left_child = light_tree_flatten(flatten,
|
|
|
|
node->get_inner().children[LightTree::left].get(),
|
|
|
|
knodes,
|
|
|
|
kemitters,
|
|
|
|
next_node_index);
|
|
|
|
right_child = light_tree_flatten(flatten,
|
2023-05-05 14:32:59 +00:00
|
|
|
node->get_inner().children[LightTree::right].get(),
|
|
|
|
knodes,
|
|
|
|
kemitters,
|
|
|
|
next_node_index);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* Instance node that is not inner or leaf, but just references another. */
|
|
|
|
assert(node->is_instance());
|
|
|
|
}
|
|
|
|
|
2023-05-24 11:36:13 +00:00
|
|
|
light_tree_node_copy_to_device(knodes[node_index], *node, left_child, right_child);
|
2023-05-05 14:32:59 +00:00
|
|
|
|
|
|
|
return node_index;
|
|
|
|
}
|
|
|
|
|
2023-05-24 11:36:13 +00:00
|
|
|
static void light_tree_emitters_copy_and_flatten(LightTreeFlatten &flatten,
|
|
|
|
const LightTreeNode *node,
|
|
|
|
KernelLightTreeNode *knodes,
|
|
|
|
KernelLightTreeEmitter *kemitters,
|
|
|
|
int &next_node_index)
|
|
|
|
{
|
|
|
|
/* Convert only emitters to device representation. */
|
|
|
|
if (node->is_leaf() || node->is_distant()) {
|
|
|
|
light_tree_leaf_emitters_copy_and_flatten(flatten, *node, knodes, kemitters, next_node_index);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
assert(node->is_inner());
|
|
|
|
|
|
|
|
light_tree_emitters_copy_and_flatten(flatten,
|
|
|
|
node->get_inner().children[LightTree::left].get(),
|
|
|
|
knodes,
|
|
|
|
kemitters,
|
|
|
|
next_node_index);
|
|
|
|
light_tree_emitters_copy_and_flatten(flatten,
|
|
|
|
node->get_inner().children[LightTree::right].get(),
|
|
|
|
knodes,
|
|
|
|
kemitters,
|
|
|
|
next_node_index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static std::pair<int, LightTreeMeasure> light_tree_specialize_nodes_flatten(
|
|
|
|
const LightTreeFlatten &flatten,
|
|
|
|
LightTreeNode *node,
|
|
|
|
const uint64_t light_link_mask,
|
|
|
|
const int depth,
|
|
|
|
vector<KernelLightTreeNode> &knodes,
|
|
|
|
int &next_node_index)
|
|
|
|
{
|
|
|
|
assert(!node->is_instance());
|
|
|
|
|
|
|
|
/* Convert inner nodes to device representation, specialized for light linking. */
|
|
|
|
int node_index, left_child = -1, right_child = -1;
|
|
|
|
|
|
|
|
LightTreeNode new_node(LightTreeMeasure::empty, node->bit_trail);
|
|
|
|
|
|
|
|
if (depth == 0 && !(node->light_link.set_membership & light_link_mask)) {
|
|
|
|
/* Ensure there is always a root node. */
|
|
|
|
node_index = next_node_index++;
|
|
|
|
new_node.make_leaf(-1, 0);
|
|
|
|
}
|
|
|
|
else if (node->light_link.shareable && node->light_link.shared_node_index != -1) {
|
|
|
|
/* Share subtree already built for another light link set. */
|
|
|
|
return std::make_pair(node->light_link.shared_node_index, node->measure);
|
|
|
|
}
|
|
|
|
else if (node->is_leaf() || node->is_distant()) {
|
|
|
|
/* Specialize leaf node. */
|
|
|
|
node_index = next_node_index++;
|
|
|
|
int first_emitter = -1;
|
|
|
|
int num_emitters = 0;
|
|
|
|
|
|
|
|
for (int i = 0; i < node->get_leaf().num_emitters; i++) {
|
|
|
|
const LightTreeEmitter &emitter = flatten.emitters[node->get_leaf().first_emitter_index + i];
|
|
|
|
if (emitter.light_set_membership & light_link_mask) {
|
|
|
|
/* Assumes emitters are consecutive due to LighTree::sort_leaf. */
|
|
|
|
if (first_emitter == -1) {
|
|
|
|
first_emitter = node->get_leaf().first_emitter_index + i;
|
|
|
|
}
|
|
|
|
num_emitters++;
|
|
|
|
new_node.measure.add(emitter.measure);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(first_emitter != -1);
|
2023-05-30 15:39:50 +00:00
|
|
|
|
|
|
|
/* Preserve the type of the node, so that the kernel can do proper decision when sampling node
|
|
|
|
* with multiple distant lights in it. */
|
|
|
|
if (node->is_leaf()) {
|
|
|
|
new_node.make_leaf(first_emitter, num_emitters);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
new_node.make_distant(first_emitter, num_emitters);
|
|
|
|
}
|
2023-05-24 11:36:13 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
assert(node->is_inner());
|
|
|
|
assert(new_node.is_inner());
|
|
|
|
|
|
|
|
/* Specialize inner node. */
|
|
|
|
LightTreeNode *left_node = node->get_inner().children[LightTree::left].get();
|
|
|
|
LightTreeNode *right_node = node->get_inner().children[LightTree::right].get();
|
|
|
|
|
|
|
|
/* Skip nodes that have only one child. We have a single bit trail for each
|
|
|
|
* primitive, bit_skip is incremented in the child node to skip the bit for
|
|
|
|
* this parent node. */
|
|
|
|
LightTreeNode *only_node = nullptr;
|
|
|
|
if (!(left_node->light_link.set_membership & light_link_mask)) {
|
|
|
|
only_node = right_node;
|
|
|
|
}
|
|
|
|
else if (!(right_node->light_link.set_membership & light_link_mask)) {
|
|
|
|
only_node = left_node;
|
|
|
|
}
|
|
|
|
if (only_node) {
|
|
|
|
const auto [only_index, only_measure] = light_tree_specialize_nodes_flatten(
|
|
|
|
flatten, only_node, light_link_mask, depth + 1, knodes, next_node_index);
|
|
|
|
|
|
|
|
assert(only_index != -1);
|
|
|
|
knodes[only_index].bit_skip++;
|
|
|
|
return std::make_pair(only_index, only_measure);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create inner node. */
|
|
|
|
node_index = next_node_index++;
|
|
|
|
|
|
|
|
const auto [left_index, left_measure] = light_tree_specialize_nodes_flatten(
|
|
|
|
flatten, left_node, light_link_mask, depth + 1, knodes, next_node_index);
|
|
|
|
const auto [right_index, right_measure] = light_tree_specialize_nodes_flatten(
|
|
|
|
flatten, right_node, light_link_mask, depth + 1, knodes, next_node_index);
|
|
|
|
|
|
|
|
new_node.measure = left_measure;
|
|
|
|
new_node.measure.add(right_measure);
|
|
|
|
|
|
|
|
left_child = left_index;
|
|
|
|
right_child = right_index;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Convert to kernel node. */
|
|
|
|
if (knodes.size() <= node_index) {
|
|
|
|
knodes.resize(node_index + 1);
|
|
|
|
}
|
|
|
|
light_tree_node_copy_to_device(knodes[node_index], new_node, left_child, right_child);
|
|
|
|
|
|
|
|
if (node->light_link.shareable) {
|
|
|
|
node->light_link.shared_node_index = node_index;
|
|
|
|
}
|
|
|
|
|
|
|
|
return std::make_pair(node_index, new_node.measure);
|
|
|
|
}
|
|
|
|
|
2022-12-05 19:16:10 +00:00
|
|
|
void LightManager::device_update_tree(Device *,
|
2022-12-02 18:04:00 +00:00
|
|
|
DeviceScene *dscene,
|
|
|
|
Scene *scene,
|
|
|
|
Progress &progress)
|
|
|
|
{
|
|
|
|
KernelIntegrator *kintegrator = &dscene->data.integrator;
|
|
|
|
|
|
|
|
if (!kintegrator->use_light_tree) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update light tree. */
|
|
|
|
progress.set_status("Updating Lights", "Computing tree");
|
|
|
|
|
|
|
|
/* TODO: For now, we'll start with a smaller number of max lights in a node.
|
|
|
|
* More benchmarking is needed to determine what number works best. */
|
2023-04-04 14:17:05 +00:00
|
|
|
LightTree light_tree(scene, dscene, progress, 8);
|
|
|
|
LightTreeNode *root = light_tree.build(scene, dscene);
|
2023-04-18 09:50:53 +00:00
|
|
|
if (progress.get_cancel()) {
|
|
|
|
return;
|
|
|
|
}
|
2022-12-02 18:04:00 +00:00
|
|
|
|
2023-05-05 14:32:59 +00:00
|
|
|
/* Create arguments for recursive tree flatten. */
|
|
|
|
LightTreeFlatten flatten;
|
|
|
|
flatten.scene = scene;
|
|
|
|
flatten.emitters = light_tree.get_emitters();
|
|
|
|
flatten.object_lookup_offset = dscene->object_lookup_offset.data();
|
2022-12-02 18:04:00 +00:00
|
|
|
/* We want to create separate arrays corresponding to triangles and lights,
|
|
|
|
* which will be used to index back into the light tree for PDF calculations. */
|
2023-05-05 14:32:59 +00:00
|
|
|
flatten.light_array = dscene->light_to_tree.alloc(kintegrator->num_lights);
|
|
|
|
flatten.mesh_array = dscene->object_to_tree.alloc(scene->objects.size());
|
|
|
|
flatten.triangle_array = dscene->triangle_to_tree.alloc(light_tree.num_triangles);
|
2022-12-02 18:04:00 +00:00
|
|
|
|
2023-05-24 11:36:13 +00:00
|
|
|
/* Allocate emitters */
|
2023-04-04 14:17:05 +00:00
|
|
|
const size_t num_emitters = light_tree.num_emitters();
|
2023-05-05 14:32:59 +00:00
|
|
|
KernelLightTreeEmitter *kemitters = dscene->light_tree_emitters.alloc(num_emitters);
|
2023-04-04 14:17:05 +00:00
|
|
|
|
|
|
|
/* Update integrator state. */
|
|
|
|
kintegrator->use_direct_light = num_emitters > 0;
|
2022-12-02 18:04:00 +00:00
|
|
|
|
2023-05-24 11:36:13 +00:00
|
|
|
/* Test if light linking is used. */
|
|
|
|
const bool use_light_linking = root && (light_tree.light_link_receiver_used != 1);
|
|
|
|
KernelLightLinkSet *klight_link_sets = dscene->data.light_link_sets;
|
|
|
|
memset(klight_link_sets, 0, sizeof(dscene->data.light_link_sets));
|
2022-12-02 18:04:00 +00:00
|
|
|
|
2023-05-05 14:32:59 +00:00
|
|
|
VLOG_INFO << "Use light tree with " << num_emitters << " emitters and " << light_tree.num_nodes
|
|
|
|
<< " nodes.";
|
|
|
|
|
2023-05-24 11:36:13 +00:00
|
|
|
if (!use_light_linking) {
|
|
|
|
/* Regular light tree without linking. */
|
|
|
|
KernelLightTreeNode *knodes = dscene->light_tree_nodes.alloc(light_tree.num_nodes);
|
|
|
|
|
|
|
|
if (root) {
|
|
|
|
int next_node_index = 0;
|
|
|
|
light_tree_flatten(flatten, root, knodes, kemitters, next_node_index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
int next_node_index = 0;
|
|
|
|
|
|
|
|
vector<KernelLightTreeNode> light_link_nodes;
|
|
|
|
|
|
|
|
/* Write primitives, and any subtrees for instances. */
|
|
|
|
if (root) {
|
|
|
|
/* Reserve enough size of all instance subtrees, then shrink back to
|
|
|
|
* actual number of nodes used. */
|
|
|
|
light_link_nodes.resize(light_tree.num_nodes);
|
|
|
|
light_tree_emitters_copy_and_flatten(
|
|
|
|
flatten, root, light_link_nodes.data(), kemitters, next_node_index);
|
|
|
|
light_link_nodes.resize(next_node_index);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Specialized light trees for linking. */
|
|
|
|
for (uint64_t tree_index = 0; tree_index < LIGHT_LINK_SET_MAX; tree_index++) {
|
|
|
|
const uint64_t tree_mask = uint64_t(1) << tree_index;
|
|
|
|
if (!(light_tree.light_link_receiver_used & tree_mask)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (root) {
|
|
|
|
klight_link_sets[tree_index].light_tree_root =
|
|
|
|
light_tree_specialize_nodes_flatten(
|
|
|
|
flatten, root, tree_mask, 0, light_link_nodes, next_node_index)
|
|
|
|
.first;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Allocate and copy nodes into device array. */
|
|
|
|
KernelLightTreeNode *knodes = dscene->light_tree_nodes.alloc(light_link_nodes.size());
|
|
|
|
memcpy(knodes, light_link_nodes.data(), light_link_nodes.size() * sizeof(*knodes));
|
|
|
|
|
|
|
|
VLOG_INFO << "Specialized light tree for light linking, with "
|
|
|
|
<< light_link_nodes.size() - light_tree.num_nodes << " additional nodes.";
|
|
|
|
}
|
|
|
|
|
2022-12-02 18:04:00 +00:00
|
|
|
/* Copy arrays to device. */
|
|
|
|
dscene->light_tree_nodes.copy_to_device();
|
|
|
|
dscene->light_tree_emitters.copy_to_device();
|
|
|
|
dscene->light_to_tree.copy_to_device();
|
2023-04-14 16:52:12 +00:00
|
|
|
dscene->object_to_tree.copy_to_device();
|
|
|
|
dscene->object_lookup_offset.copy_to_device();
|
2022-12-02 18:04:00 +00:00
|
|
|
dscene->triangle_to_tree.copy_to_device();
|
|
|
|
}
|
|
|
|
|
2019-04-17 04:17:24 +00:00
|
|
|
static void background_cdf(
|
|
|
|
int start, int end, int res_x, int res_y, const vector<float3> *pixels, float2 *cond_cdf)
|
2015-03-12 10:58:43 +00:00
|
|
|
{
|
2019-04-17 04:17:24 +00:00
|
|
|
int cdf_width = res_x + 1;
|
|
|
|
/* Conditional CDFs (rows, U direction). */
|
|
|
|
for (int i = start; i < end; i++) {
|
|
|
|
float sin_theta = sinf(M_PI_F * (i + 0.5f) / res_y);
|
|
|
|
float3 env_color = (*pixels)[i * res_x];
|
|
|
|
float ave_luminance = average(env_color);
|
|
|
|
|
|
|
|
cond_cdf[i * cdf_width].x = ave_luminance * sin_theta;
|
|
|
|
cond_cdf[i * cdf_width].y = 0.0f;
|
|
|
|
|
|
|
|
for (int j = 1; j < res_x; j++) {
|
|
|
|
env_color = (*pixels)[i * res_x + j];
|
|
|
|
ave_luminance = average(env_color);
|
|
|
|
|
|
|
|
cond_cdf[i * cdf_width + j].x = ave_luminance * sin_theta;
|
|
|
|
cond_cdf[i * cdf_width + j].y = cond_cdf[i * cdf_width + j - 1].y +
|
|
|
|
cond_cdf[i * cdf_width + j - 1].x / res_x;
|
|
|
|
}
|
|
|
|
|
2020-11-30 11:21:44 +00:00
|
|
|
const float cdf_total = cond_cdf[i * cdf_width + res_x - 1].y +
|
|
|
|
cond_cdf[i * cdf_width + res_x - 1].x / res_x;
|
2019-04-17 04:17:24 +00:00
|
|
|
|
|
|
|
/* stuff the total into the brightness value for the last entry, because
|
|
|
|
* we are going to normalize the CDFs to 0.0 to 1.0 afterwards */
|
|
|
|
cond_cdf[i * cdf_width + res_x].x = cdf_total;
|
|
|
|
|
2020-11-30 11:21:44 +00:00
|
|
|
if (cdf_total > 0.0f) {
|
|
|
|
const float cdf_total_inv = 1.0f / cdf_total;
|
|
|
|
for (int j = 1; j < res_x; j++) {
|
2019-04-17 04:17:24 +00:00
|
|
|
cond_cdf[i * cdf_width + j].y *= cdf_total_inv;
|
2020-11-30 11:21:44 +00:00
|
|
|
}
|
|
|
|
}
|
2019-04-17 04:17:24 +00:00
|
|
|
|
|
|
|
cond_cdf[i * cdf_width + res_x].y = 1.0f;
|
|
|
|
}
|
2015-03-12 10:58:43 +00:00
|
|
|
}
|
|
|
|
|
2016-02-06 19:43:44 +00:00
|
|
|
void LightManager::device_update_background(Device *device,
|
|
|
|
DeviceScene *dscene,
|
|
|
|
Scene *scene,
|
2019-04-17 04:17:24 +00:00
|
|
|
Progress &progress)
|
2012-01-20 17:49:17 +00:00
|
|
|
{
|
2022-11-30 19:17:45 +00:00
|
|
|
KernelIntegrator *kintegrator = &dscene->data.integrator;
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 18:27:10 +00:00
|
|
|
KernelBackground *kbackground = &dscene->data.background;
|
2019-04-17 04:17:24 +00:00
|
|
|
Light *background_light = NULL;
|
|
|
|
|
2022-11-30 19:17:45 +00:00
|
|
|
bool background_mis = false;
|
|
|
|
|
2019-04-17 04:17:24 +00:00
|
|
|
/* find background light */
|
|
|
|
foreach (Light *light, scene->lights) {
|
2022-11-30 19:17:45 +00:00
|
|
|
if (light->light_type == LIGHT_BACKGROUND && light->is_enabled) {
|
2019-04-17 04:17:24 +00:00
|
|
|
background_light = light;
|
2022-11-30 19:17:45 +00:00
|
|
|
background_mis |= light->use_mis;
|
2019-04-17 04:17:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-30 19:17:45 +00:00
|
|
|
kbackground->portal_weight = kintegrator->num_portals > 0 ? 1.0f : 0.0f;
|
|
|
|
kbackground->map_weight = background_mis ? 1.0f : 0.0f;
|
|
|
|
kbackground->sun_weight = 0.0f;
|
|
|
|
|
2019-04-17 04:17:24 +00:00
|
|
|
/* no background light found, signal renderer to skip sampling */
|
|
|
|
if (!background_light || !background_light->is_enabled) {
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 18:27:10 +00:00
|
|
|
kbackground->map_res_x = 0;
|
|
|
|
kbackground->map_res_y = 0;
|
|
|
|
kbackground->use_mis = (kbackground->portal_weight > 0.0f);
|
2019-04-17 04:17:24 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
progress.set_status("Updating Lights", "Importance map");
|
|
|
|
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 18:27:10 +00:00
|
|
|
int2 environment_res = make_int2(0, 0);
|
|
|
|
Shader *shader = scene->background->get_shader(scene);
|
|
|
|
int num_suns = 0;
|
2023-01-20 00:22:47 +00:00
|
|
|
float sun_average_radiance = 0.0f;
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 18:27:10 +00:00
|
|
|
foreach (ShaderNode *node, shader->graph->nodes) {
|
2021-03-15 15:11:12 +00:00
|
|
|
if (node->type == EnvironmentTextureNode::get_node_type()) {
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 18:27:10 +00:00
|
|
|
EnvironmentTextureNode *env = (EnvironmentTextureNode *)node;
|
|
|
|
if (!env->handle.empty()) {
|
|
|
|
ImageMetaData metadata = env->handle.metadata();
|
2022-02-10 09:37:00 +00:00
|
|
|
environment_res.x = max(environment_res.x, (int)metadata.width);
|
|
|
|
environment_res.y = max(environment_res.y, (int)metadata.height);
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 18:27:10 +00:00
|
|
|
}
|
|
|
|
}
|
2021-03-15 15:11:12 +00:00
|
|
|
if (node->type == SkyTextureNode::get_node_type()) {
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 18:27:10 +00:00
|
|
|
SkyTextureNode *sky = (SkyTextureNode *)node;
|
2020-11-04 10:17:38 +00:00
|
|
|
if (sky->get_sky_type() == NODE_SKY_NISHITA && sky->get_sun_disc()) {
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 18:27:10 +00:00
|
|
|
/* Ensure that the input coordinates aren't transformed before they reach the node.
|
|
|
|
* If that is the case, the logic used for sampling the sun's location does not work
|
|
|
|
* and we have to fall back to map-based sampling. */
|
|
|
|
const ShaderInput *vec_in = sky->input("Vector");
|
|
|
|
if (vec_in && vec_in->link && vec_in->link->parent) {
|
|
|
|
ShaderNode *vec_src = vec_in->link->parent;
|
2021-03-15 15:11:12 +00:00
|
|
|
if ((vec_src->type != TextureCoordinateNode::get_node_type()) ||
|
2023-05-01 22:42:26 +00:00
|
|
|
(vec_in->link != vec_src->output("Generated")))
|
|
|
|
{
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 18:27:10 +00:00
|
|
|
environment_res.x = max(environment_res.x, 4096);
|
|
|
|
environment_res.y = max(environment_res.y, 2048);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-12 23:52:07 +00:00
|
|
|
/* Determine sun direction from lat/long and texture mapping. */
|
2020-11-04 10:17:38 +00:00
|
|
|
float latitude = sky->get_sun_elevation();
|
2023-04-17 15:29:27 +00:00
|
|
|
float longitude = sky->get_sun_rotation() + M_PI_2_F;
|
2020-07-12 23:52:07 +00:00
|
|
|
float3 sun_direction = make_float3(
|
|
|
|
cosf(latitude) * cosf(longitude), cosf(latitude) * sinf(longitude), sinf(latitude));
|
|
|
|
Transform sky_transform = transform_inverse(sky->tex_mapping.compute_transform());
|
|
|
|
sun_direction = transform_direction(&sky_transform, sun_direction);
|
|
|
|
|
|
|
|
/* Pack sun direction and size. */
|
2020-08-17 15:48:53 +00:00
|
|
|
float half_angle = sky->get_sun_size() * 0.5f;
|
2020-07-12 23:52:07 +00:00
|
|
|
kbackground->sun = make_float4(
|
|
|
|
sun_direction.x, sun_direction.y, sun_direction.z, half_angle);
|
|
|
|
|
2022-11-30 19:17:45 +00:00
|
|
|
/* empirical value */
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 18:27:10 +00:00
|
|
|
kbackground->sun_weight = 4.0f;
|
2023-01-20 00:22:47 +00:00
|
|
|
sun_average_radiance = sky->get_sun_average_radiance();
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 18:27:10 +00:00
|
|
|
environment_res.x = max(environment_res.x, 512);
|
|
|
|
environment_res.y = max(environment_res.y, 256);
|
|
|
|
num_suns++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If there's more than one sun, fall back to map sampling instead. */
|
2023-04-17 13:57:02 +00:00
|
|
|
kbackground->use_sun_guiding = (num_suns == 1);
|
|
|
|
if (!kbackground->use_sun_guiding) {
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 18:27:10 +00:00
|
|
|
kbackground->sun_weight = 0.0f;
|
|
|
|
environment_res.x = max(environment_res.x, 4096);
|
|
|
|
environment_res.y = max(environment_res.y, 2048);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Enable MIS for background sampling if any strategy is active. */
|
|
|
|
kbackground->use_mis = (kbackground->portal_weight + kbackground->map_weight +
|
|
|
|
kbackground->sun_weight) > 0.0f;
|
2019-04-17 04:17:24 +00:00
|
|
|
|
|
|
|
/* get the resolution from the light's size (we stuff it in there) */
|
|
|
|
int2 res = make_int2(background_light->map_resolution, background_light->map_resolution / 2);
|
|
|
|
/* If the resolution isn't set manually, try to find an environment texture. */
|
|
|
|
if (res.x == 0) {
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 18:27:10 +00:00
|
|
|
res = environment_res;
|
2019-04-17 04:17:24 +00:00
|
|
|
if (res.x > 0 && res.y > 0) {
|
2022-06-16 17:39:13 +00:00
|
|
|
VLOG_INFO << "Automatically set World MIS resolution to " << res.x << " by " << res.y
|
|
|
|
<< "\n";
|
2019-04-17 04:17:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* If it's still unknown, just use the default. */
|
|
|
|
if (res.x == 0 || res.y == 0) {
|
|
|
|
res = make_int2(1024, 512);
|
2022-06-16 17:39:13 +00:00
|
|
|
VLOG_INFO << "Setting World MIS resolution to default\n";
|
2019-04-17 04:17:24 +00:00
|
|
|
}
|
Cycles: Add new Sky Texture method including direct sunlight
This commit adds a new model to the Sky Texture node, which is based on a
method by Nishita et al. and works by basically simulating volumetric
scattering in the atmosphere.
By making some approximations (such as only considering single scattering),
we get a fairly simple and fast simulation code that takes into account
Rayleigh and Mie scattering as well as Ozone absorption.
This code is used to precompute a 512x128 texture which is then looked up
during render time, and is fast enough to allow real-time tweaking in the
viewport.
Due to the nature of the simulation, it exposes several parameters that
allow for lots of flexibility in choosing the look and matching real-world
conditions (such as Air/Dust/Ozone density and altitude).
Additionally, the same volumetric approach can be used to compute absorption
of the direct sunlight, so the model also supports adding direct sunlight.
This makes it significantly easier to set up Sun+Sky illumination where
the direction, intensity and color of the sun actually matches the sky.
In order to support properly sampling the direct sun component, the commit
also adds logic for sampling a specific area to the kernel light sampling
code. This is combined with portal and background map sampling using MIS.
This sampling logic works for the common case of having one Sky texture
going into the Background shader, but if a custom input to the Vector
node is used or if there are multiple Sky textures, it falls back to using
only background map sampling (while automatically setting the resolution to
4096x2048 if auto resolution is used).
More infos and preview can be found here:
https://docs.google.com/document/d/1gQta0ygFWXTrl5Pmvl_nZRgUw0mWg0FJeRuNKS36m08/view
Underlying model, implementation and documentation by Marco (@nacioss).
Improvements, cleanup and sun sampling by @lukasstockner.
Differential Revision: https://developer.blender.org/D7896
2020-06-17 18:27:10 +00:00
|
|
|
kbackground->map_res_x = res.x;
|
|
|
|
kbackground->map_res_y = res.y;
|
2019-04-17 04:17:24 +00:00
|
|
|
|
|
|
|
vector<float3> pixels;
|
|
|
|
shade_background_pixels(device, dscene, res.x, res.y, pixels, progress);
|
|
|
|
|
|
|
|
if (progress.get_cancel())
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* build row distributions and column distribution for the infinite area environment light */
|
|
|
|
int cdf_width = res.x + 1;
|
|
|
|
float2 *marg_cdf = dscene->light_background_marginal_cdf.alloc(res.y + 1);
|
|
|
|
float2 *cond_cdf = dscene->light_background_conditional_cdf.alloc(cdf_width * res.y);
|
|
|
|
|
|
|
|
double time_start = time_dt();
|
2020-06-05 10:53:38 +00:00
|
|
|
|
|
|
|
/* Create CDF in parallel. */
|
|
|
|
const int rows_per_task = divide_up(10240, res.x);
|
|
|
|
parallel_for(blocked_range<size_t>(0, res.y, rows_per_task),
|
|
|
|
[&](const blocked_range<size_t> &r) {
|
|
|
|
background_cdf(r.begin(), r.end(), res.x, res.y, &pixels, cond_cdf);
|
|
|
|
});
|
2019-04-17 04:17:24 +00:00
|
|
|
|
|
|
|
/* marginal CDFs (column, V direction, sum of rows) */
|
|
|
|
marg_cdf[0].x = cond_cdf[res.x].x;
|
|
|
|
marg_cdf[0].y = 0.0f;
|
|
|
|
|
|
|
|
for (int i = 1; i < res.y; i++) {
|
|
|
|
marg_cdf[i].x = cond_cdf[i * cdf_width + res.x].x;
|
|
|
|
marg_cdf[i].y = marg_cdf[i - 1].y + marg_cdf[i - 1].x / res.y;
|
|
|
|
}
|
|
|
|
|
|
|
|
float cdf_total = marg_cdf[res.y - 1].y + marg_cdf[res.y - 1].x / res.y;
|
|
|
|
marg_cdf[res.y].x = cdf_total;
|
|
|
|
|
2023-01-20 00:22:47 +00:00
|
|
|
float map_average_radiance = cdf_total * M_PI_2_F;
|
|
|
|
if (sun_average_radiance > 0.0f) {
|
|
|
|
/* The weighting here is just a heuristic that was empirically determined.
|
|
|
|
* The sun's average radiance is much higher than the map's average radiance,
|
2023-01-20 04:19:32 +00:00
|
|
|
* but we don't want to weight the background light too much because
|
|
|
|
* visibility is not accounted for anyway. */
|
2023-01-20 00:22:47 +00:00
|
|
|
background_light->set_average_radiance(0.8f * map_average_radiance +
|
|
|
|
0.2f * sun_average_radiance);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
background_light->set_average_radiance(map_average_radiance);
|
|
|
|
}
|
2022-12-02 18:04:00 +00:00
|
|
|
|
2019-04-17 04:17:24 +00:00
|
|
|
if (cdf_total > 0.0f)
|
|
|
|
for (int i = 1; i < res.y; i++)
|
|
|
|
marg_cdf[i].y /= cdf_total;
|
|
|
|
|
|
|
|
marg_cdf[res.y].y = 1.0f;
|
|
|
|
|
2022-06-16 17:39:13 +00:00
|
|
|
VLOG_WORK << "Background MIS build time " << time_dt() - time_start << "\n";
|
2019-04-17 04:17:24 +00:00
|
|
|
|
|
|
|
/* update device */
|
|
|
|
dscene->light_background_marginal_cdf.copy_to_device();
|
|
|
|
dscene->light_background_conditional_cdf.copy_to_device();
|
2012-01-20 17:49:17 +00:00
|
|
|
}
|
|
|
|
|
2022-12-02 18:04:00 +00:00
|
|
|
void LightManager::device_update_lights(Device *device, DeviceScene *dscene, Scene *scene)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2022-11-30 19:17:45 +00:00
|
|
|
/* Counts lights in the scene. */
|
|
|
|
size_t num_lights = 0;
|
|
|
|
size_t num_portals = 0;
|
|
|
|
size_t num_background_lights = 0;
|
|
|
|
size_t num_distant_lights = 0;
|
|
|
|
bool use_light_mis = false;
|
2019-04-17 04:17:24 +00:00
|
|
|
|
|
|
|
foreach (Light *light, scene->lights) {
|
2022-11-30 19:17:45 +00:00
|
|
|
if (light->is_enabled) {
|
2019-04-17 04:17:24 +00:00
|
|
|
num_lights++;
|
2022-11-30 19:17:45 +00:00
|
|
|
|
|
|
|
if (light->light_type == LIGHT_DISTANT) {
|
|
|
|
num_distant_lights++;
|
|
|
|
}
|
|
|
|
else if (light->light_type == LIGHT_POINT || light->light_type == LIGHT_SPOT) {
|
|
|
|
use_light_mis |= (light->size > 0.0f && light->use_mis);
|
|
|
|
}
|
|
|
|
else if (light->light_type == LIGHT_AREA) {
|
|
|
|
use_light_mis |= light->use_mis;
|
|
|
|
}
|
|
|
|
else if (light->light_type == LIGHT_BACKGROUND) {
|
|
|
|
num_distant_lights++;
|
|
|
|
num_background_lights++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (light->is_portal) {
|
|
|
|
num_portals++;
|
2019-04-17 04:17:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-30 19:17:45 +00:00
|
|
|
/* Update integrator settings. */
|
|
|
|
KernelIntegrator *kintegrator = &dscene->data.integrator;
|
2022-12-02 18:04:00 +00:00
|
|
|
kintegrator->use_light_tree = scene->integrator->get_use_light_tree() &&
|
|
|
|
device->info.has_light_tree;
|
2022-11-30 19:17:45 +00:00
|
|
|
kintegrator->num_lights = num_lights;
|
|
|
|
kintegrator->num_distant_lights = num_distant_lights;
|
|
|
|
kintegrator->num_background_lights = num_background_lights;
|
|
|
|
kintegrator->use_light_mis = use_light_mis;
|
2019-04-17 04:17:24 +00:00
|
|
|
|
2022-11-30 19:17:45 +00:00
|
|
|
kintegrator->num_portals = num_portals;
|
|
|
|
kintegrator->portal_offset = num_lights;
|
|
|
|
|
|
|
|
/* Create KernelLight for every portal and enabled light in the scene. */
|
|
|
|
KernelLight *klights = dscene->lights.alloc(num_lights + num_portals);
|
2019-04-17 04:17:24 +00:00
|
|
|
|
|
|
|
int light_index = 0;
|
2022-11-30 19:17:45 +00:00
|
|
|
int portal_index = num_lights;
|
2019-04-17 04:17:24 +00:00
|
|
|
|
|
|
|
foreach (Light *light, scene->lights) {
|
2022-11-30 19:17:45 +00:00
|
|
|
/* Consider moving portals update to their own function
|
|
|
|
* keeping this one more manageable. */
|
|
|
|
if (light->is_portal) {
|
|
|
|
assert(light->light_type == LIGHT_AREA);
|
|
|
|
|
|
|
|
float3 extentu = light->axisu * (light->sizeu * light->size);
|
|
|
|
float3 extentv = light->axisv * (light->sizev * light->size);
|
2022-12-02 14:21:57 +00:00
|
|
|
|
|
|
|
float len_u, len_v;
|
|
|
|
float3 axis_u = normalize_len(extentu, &len_u);
|
|
|
|
float3 axis_v = normalize_len(extentv, &len_v);
|
|
|
|
float area = len_u * len_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 13:35:25 +00:00
|
|
|
if (light->ellipse) {
|
2023-07-03 13:08:28 +00:00
|
|
|
area *= M_PI_4_F;
|
2022-11-30 19:17:45 +00:00
|
|
|
}
|
|
|
|
float invarea = (area != 0.0f) ? 1.0f / area : 1.0f;
|
2023-07-03 13:08:28 +00:00
|
|
|
if (light->ellipse) {
|
|
|
|
/* Negative inverse area indicates ellipse. */
|
|
|
|
invarea = -invarea;
|
|
|
|
}
|
2022-11-30 19:17:45 +00:00
|
|
|
float3 dir = light->dir;
|
|
|
|
|
|
|
|
dir = safe_normalize(dir);
|
|
|
|
|
|
|
|
klights[portal_index].co = light->co;
|
2022-12-02 14:21:57 +00:00
|
|
|
klights[portal_index].area.axis_u = axis_u;
|
|
|
|
klights[portal_index].area.len_u = len_u;
|
|
|
|
klights[portal_index].area.axis_v = axis_v;
|
|
|
|
klights[portal_index].area.len_v = len_v;
|
2022-11-30 19:17:45 +00:00
|
|
|
klights[portal_index].area.invarea = invarea;
|
|
|
|
klights[portal_index].area.dir = dir;
|
|
|
|
klights[portal_index].tfm = light->tfm;
|
|
|
|
klights[portal_index].itfm = transform_inverse(light->tfm);
|
|
|
|
|
|
|
|
portal_index++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2019-04-17 04:17:24 +00:00
|
|
|
if (!light->is_enabled) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
float3 co = light->co;
|
|
|
|
Shader *shader = (light->shader) ? light->shader : scene->default_light;
|
|
|
|
int shader_id = scene->shader_manager->get_shader_id(shader);
|
|
|
|
int max_bounces = light->max_bounces;
|
|
|
|
float random = (float)light->random_id * (1.0f / (float)0xFFFFFFFF);
|
|
|
|
|
|
|
|
if (!light->cast_shadow)
|
|
|
|
shader_id &= ~SHADER_CAST_SHADOW;
|
|
|
|
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 15:59:20 +00:00
|
|
|
if (!light->use_camera) {
|
|
|
|
shader_id |= SHADER_EXCLUDE_CAMERA;
|
|
|
|
}
|
2019-04-17 04:17:24 +00:00
|
|
|
if (!light->use_diffuse) {
|
|
|
|
shader_id |= SHADER_EXCLUDE_DIFFUSE;
|
|
|
|
}
|
|
|
|
if (!light->use_glossy) {
|
|
|
|
shader_id |= SHADER_EXCLUDE_GLOSSY;
|
|
|
|
}
|
|
|
|
if (!light->use_transmission) {
|
|
|
|
shader_id |= SHADER_EXCLUDE_TRANSMIT;
|
|
|
|
}
|
|
|
|
if (!light->use_scatter) {
|
|
|
|
shader_id |= SHADER_EXCLUDE_SCATTER;
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 15:59:20 +00:00
|
|
|
}
|
|
|
|
if (!light->is_shadow_catcher) {
|
|
|
|
shader_id |= SHADER_EXCLUDE_SHADOW_CATCHER;
|
2019-04-17 04:17:24 +00:00
|
|
|
}
|
|
|
|
|
2020-11-04 10:17:38 +00:00
|
|
|
klights[light_index].type = light->light_type;
|
2019-05-12 11:41:23 +00:00
|
|
|
klights[light_index].strength[0] = light->strength.x;
|
|
|
|
klights[light_index].strength[1] = light->strength.y;
|
|
|
|
klights[light_index].strength[2] = light->strength.z;
|
2019-04-17 04:17:24 +00:00
|
|
|
|
2023-07-07 15:15:18 +00:00
|
|
|
if (light->light_type == LIGHT_POINT || light->light_type == LIGHT_SPOT) {
|
2019-04-17 04:17:24 +00:00
|
|
|
shader_id &= ~SHADER_AREA_LIGHT;
|
|
|
|
|
|
|
|
float radius = light->size;
|
2023-07-07 15:15:18 +00:00
|
|
|
|
2023-07-03 13:08:28 +00:00
|
|
|
float invarea = (radius == 0.0f) ? 1.0f / 4.0f :
|
|
|
|
(light->normalize) ? 1.0f / (4.0f * M_PI_F * radius * radius) :
|
|
|
|
1.0f;
|
|
|
|
|
2023-07-07 15:15:18 +00:00
|
|
|
/* Convert radiant flux to radiance or radiant intensity. */
|
2023-07-03 13:08:28 +00:00
|
|
|
float eval_fac = invarea * M_1_PI_F;
|
2019-04-17 04:17:24 +00:00
|
|
|
|
|
|
|
if (light->use_mis && radius > 0.0f)
|
|
|
|
shader_id |= SHADER_USE_MIS;
|
|
|
|
|
2022-11-30 19:17:45 +00:00
|
|
|
klights[light_index].co = co;
|
2019-04-17 04:17:24 +00:00
|
|
|
klights[light_index].spot.radius = radius;
|
2023-07-07 15:15:18 +00:00
|
|
|
klights[light_index].spot.eval_fac = eval_fac;
|
2019-04-17 04:17:24 +00:00
|
|
|
}
|
2020-11-04 10:17:38 +00:00
|
|
|
else if (light->light_type == LIGHT_DISTANT) {
|
2019-04-17 04:17:24 +00:00
|
|
|
shader_id &= ~SHADER_AREA_LIGHT;
|
|
|
|
|
Cycles: Change sun lamp to have uniform intensity at high angles
This fixes the issue described in https://projects.blender.org/blender/blender/issues/108957.
Instead of modeling distant lights like a disk light at infinity, it models them as cones. This way, the radiance is constant across the entire range of directions that it covers.
For smaller angles, the difference is very subtle, but for very large angles it becomes obvious (here's the file from #108957, the angle is 179°):
| Old | New |
| - | - |
| ![old_bigsun.png](/attachments/4ef8e7a7-1a29-4bdf-a74c-3cfa103bf1e7) | ![new_bigsun.png](/attachments/d53c7749-2672-40b6-9048-ccf2fffceeb7) |
One notable detail is the sampling method: Using `sample_uniform_cone` can increase noise, since the sampling method no longer preserves the stratification of the samples. This is visible in the "light tree multi distant" test scene.
Turns out we can do better, and after a bit of testing I found a way to adapt the concentric Shirley mapping to uniform cone sampling. I hope the comment explains the logic behind it reasonably well.
Here's the result, note that even the noise distribution is the same when using the new sampling:
| Method | Old | New, basic sampling | New, concentric sampling |
| - | - |- | - |
| Image | ![old.png](/attachments/b3258a70-f015-4065-a774-193974cce439) | ![new_basic.png](/attachments/a9008576-0af6-4152-a687-c800fd958bbd) | ![new_concentric.png](/attachments/769b6c43-34bc-434e-a4fd-ce69addd1ba5) |
| Render time (at higher spp)| 9.03sec | 8.79sec | 8.96sec |
I'm not sure if I got the `light->normalized` handling right, since I don't really know what the expectation from Hydra is here.
Co-authored-by: Weizhen Huang <weizhen@blender.org>
Pull Request: https://projects.blender.org/blender/blender/pulls/108996
2023-07-07 15:20:19 +00:00
|
|
|
float3 dir = safe_normalize(light->dir);
|
2019-05-15 12:45:33 +00:00
|
|
|
float angle = light->angle / 2.0f;
|
2019-04-17 04:17:24 +00:00
|
|
|
|
Cycles: Change sun lamp to have uniform intensity at high angles
This fixes the issue described in https://projects.blender.org/blender/blender/issues/108957.
Instead of modeling distant lights like a disk light at infinity, it models them as cones. This way, the radiance is constant across the entire range of directions that it covers.
For smaller angles, the difference is very subtle, but for very large angles it becomes obvious (here's the file from #108957, the angle is 179°):
| Old | New |
| - | - |
| ![old_bigsun.png](/attachments/4ef8e7a7-1a29-4bdf-a74c-3cfa103bf1e7) | ![new_bigsun.png](/attachments/d53c7749-2672-40b6-9048-ccf2fffceeb7) |
One notable detail is the sampling method: Using `sample_uniform_cone` can increase noise, since the sampling method no longer preserves the stratification of the samples. This is visible in the "light tree multi distant" test scene.
Turns out we can do better, and after a bit of testing I found a way to adapt the concentric Shirley mapping to uniform cone sampling. I hope the comment explains the logic behind it reasonably well.
Here's the result, note that even the noise distribution is the same when using the new sampling:
| Method | Old | New, basic sampling | New, concentric sampling |
| - | - |- | - |
| Image | ![old.png](/attachments/b3258a70-f015-4065-a774-193974cce439) | ![new_basic.png](/attachments/a9008576-0af6-4152-a687-c800fd958bbd) | ![new_concentric.png](/attachments/769b6c43-34bc-434e-a4fd-ce69addd1ba5) |
| Render time (at higher spp)| 9.03sec | 8.79sec | 8.96sec |
I'm not sure if I got the `light->normalized` handling right, since I don't really know what the expectation from Hydra is here.
Co-authored-by: Weizhen Huang <weizhen@blender.org>
Pull Request: https://projects.blender.org/blender/blender/pulls/108996
2023-07-07 15:20:19 +00:00
|
|
|
if (light->use_mis && angle > 0.0f) {
|
2019-04-17 04:17:24 +00:00
|
|
|
shader_id |= SHADER_USE_MIS;
|
Cycles: Change sun lamp to have uniform intensity at high angles
This fixes the issue described in https://projects.blender.org/blender/blender/issues/108957.
Instead of modeling distant lights like a disk light at infinity, it models them as cones. This way, the radiance is constant across the entire range of directions that it covers.
For smaller angles, the difference is very subtle, but for very large angles it becomes obvious (here's the file from #108957, the angle is 179°):
| Old | New |
| - | - |
| ![old_bigsun.png](/attachments/4ef8e7a7-1a29-4bdf-a74c-3cfa103bf1e7) | ![new_bigsun.png](/attachments/d53c7749-2672-40b6-9048-ccf2fffceeb7) |
One notable detail is the sampling method: Using `sample_uniform_cone` can increase noise, since the sampling method no longer preserves the stratification of the samples. This is visible in the "light tree multi distant" test scene.
Turns out we can do better, and after a bit of testing I found a way to adapt the concentric Shirley mapping to uniform cone sampling. I hope the comment explains the logic behind it reasonably well.
Here's the result, note that even the noise distribution is the same when using the new sampling:
| Method | Old | New, basic sampling | New, concentric sampling |
| - | - |- | - |
| Image | ![old.png](/attachments/b3258a70-f015-4065-a774-193974cce439) | ![new_basic.png](/attachments/a9008576-0af6-4152-a687-c800fd958bbd) | ![new_concentric.png](/attachments/769b6c43-34bc-434e-a4fd-ce69addd1ba5) |
| Render time (at higher spp)| 9.03sec | 8.79sec | 8.96sec |
I'm not sure if I got the `light->normalized` handling right, since I don't really know what the expectation from Hydra is here.
Co-authored-by: Weizhen Huang <weizhen@blender.org>
Pull Request: https://projects.blender.org/blender/blender/pulls/108996
2023-07-07 15:20:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const float one_minus_cosangle = 2.0f * sqr(sinf(0.5f * angle));
|
|
|
|
const float pdf = (angle > 0.0f) ? (M_1_2PI_F / one_minus_cosangle) : 1.0f;
|
2019-04-17 04:17:24 +00:00
|
|
|
|
2022-11-30 19:17:45 +00:00
|
|
|
klights[light_index].co = dir;
|
Cycles: Change sun lamp to have uniform intensity at high angles
This fixes the issue described in https://projects.blender.org/blender/blender/issues/108957.
Instead of modeling distant lights like a disk light at infinity, it models them as cones. This way, the radiance is constant across the entire range of directions that it covers.
For smaller angles, the difference is very subtle, but for very large angles it becomes obvious (here's the file from #108957, the angle is 179°):
| Old | New |
| - | - |
| ![old_bigsun.png](/attachments/4ef8e7a7-1a29-4bdf-a74c-3cfa103bf1e7) | ![new_bigsun.png](/attachments/d53c7749-2672-40b6-9048-ccf2fffceeb7) |
One notable detail is the sampling method: Using `sample_uniform_cone` can increase noise, since the sampling method no longer preserves the stratification of the samples. This is visible in the "light tree multi distant" test scene.
Turns out we can do better, and after a bit of testing I found a way to adapt the concentric Shirley mapping to uniform cone sampling. I hope the comment explains the logic behind it reasonably well.
Here's the result, note that even the noise distribution is the same when using the new sampling:
| Method | Old | New, basic sampling | New, concentric sampling |
| - | - |- | - |
| Image | ![old.png](/attachments/b3258a70-f015-4065-a774-193974cce439) | ![new_basic.png](/attachments/a9008576-0af6-4152-a687-c800fd958bbd) | ![new_concentric.png](/attachments/769b6c43-34bc-434e-a4fd-ce69addd1ba5) |
| Render time (at higher spp)| 9.03sec | 8.79sec | 8.96sec |
I'm not sure if I got the `light->normalized` handling right, since I don't really know what the expectation from Hydra is here.
Co-authored-by: Weizhen Huang <weizhen@blender.org>
Pull Request: https://projects.blender.org/blender/blender/pulls/108996
2023-07-07 15:20:19 +00:00
|
|
|
klights[light_index].distant.angle = angle;
|
|
|
|
klights[light_index].distant.one_minus_cosangle = one_minus_cosangle;
|
|
|
|
klights[light_index].distant.pdf = pdf;
|
|
|
|
klights[light_index].distant.eval_fac = (light->normalize && angle > 0) ?
|
|
|
|
M_1_PI_F / sqr(sinf(angle)) :
|
|
|
|
1.0f;
|
2023-07-10 10:20:47 +00:00
|
|
|
klights[light_index].distant.half_inv_sin_half_angle = 0.5f / sinf(0.5f * angle);
|
2019-04-17 04:17:24 +00:00
|
|
|
}
|
2020-11-04 10:17:38 +00:00
|
|
|
else if (light->light_type == LIGHT_BACKGROUND) {
|
|
|
|
uint visibility = scene->background->get_visibility();
|
2019-04-17 04:17:24 +00:00
|
|
|
|
2022-11-30 19:17:45 +00:00
|
|
|
dscene->data.background.light_index = light_index;
|
|
|
|
|
2019-04-17 04:17:24 +00:00
|
|
|
shader_id &= ~SHADER_AREA_LIGHT;
|
|
|
|
shader_id |= SHADER_USE_MIS;
|
|
|
|
|
|
|
|
if (!(visibility & PATH_RAY_DIFFUSE)) {
|
|
|
|
shader_id |= SHADER_EXCLUDE_DIFFUSE;
|
|
|
|
}
|
|
|
|
if (!(visibility & PATH_RAY_GLOSSY)) {
|
|
|
|
shader_id |= SHADER_EXCLUDE_GLOSSY;
|
|
|
|
}
|
|
|
|
if (!(visibility & PATH_RAY_TRANSMIT)) {
|
|
|
|
shader_id |= SHADER_EXCLUDE_TRANSMIT;
|
|
|
|
}
|
|
|
|
if (!(visibility & PATH_RAY_VOLUME_SCATTER)) {
|
|
|
|
shader_id |= SHADER_EXCLUDE_SCATTER;
|
|
|
|
}
|
|
|
|
}
|
2020-11-04 10:17:38 +00:00
|
|
|
else if (light->light_type == LIGHT_AREA) {
|
2022-11-30 19:17:45 +00:00
|
|
|
float3 extentu = light->axisu * (light->sizeu * light->size);
|
|
|
|
float3 extentv = light->axisv * (light->sizev * light->size);
|
2022-12-02 14:21:57 +00:00
|
|
|
|
|
|
|
float len_u, len_v;
|
|
|
|
float3 axis_u = normalize_len(extentu, &len_u);
|
|
|
|
float3 axis_v = normalize_len(extentv, &len_v);
|
|
|
|
float area = len_u * len_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 13:35:25 +00:00
|
|
|
if (light->ellipse) {
|
2023-07-03 13:08:28 +00:00
|
|
|
area *= M_PI_4_F;
|
2019-04-17 04:17:24 +00:00
|
|
|
}
|
2023-01-04 12:38:32 +00:00
|
|
|
float invarea = (light->normalize && area != 0.0f) ? 1.0f / area : 1.0f;
|
2023-07-03 13:08:28 +00:00
|
|
|
if (light->ellipse) {
|
|
|
|
/* Negative inverse area indicates ellipse. */
|
|
|
|
invarea = -invarea;
|
|
|
|
}
|
2019-04-17 04:17:24 +00:00
|
|
|
float3 dir = light->dir;
|
|
|
|
|
2023-06-22 15:47:54 +00:00
|
|
|
const float half_spread = 0.5f * light->spread;
|
2022-12-07 17:51:26 +00:00
|
|
|
const float tan_half_spread = light->spread == M_PI_F ? FLT_MAX : tanf(half_spread);
|
2021-04-01 03:35:56 +00:00
|
|
|
/* Normalization computed using:
|
2022-12-07 17:51:26 +00:00
|
|
|
* integrate cos(x) * (1 - tan(x) / tan(a)) * sin(x) from x = 0 to a, a being half_spread.
|
2022-12-08 01:36:04 +00:00
|
|
|
* Divided by tan_half_spread to simplify the attenuation computation in `area.h`. */
|
2023-06-22 15:47:54 +00:00
|
|
|
/* Using third-order Taylor expansion at small angles for better accuracy. */
|
|
|
|
const float normalize_spread = half_spread > 0.05f ? 1.0f / (tan_half_spread - half_spread) :
|
|
|
|
3.0f / powf(half_spread, 3.0f);
|
2021-04-01 03:35:56 +00:00
|
|
|
|
2019-04-17 04:17:24 +00:00
|
|
|
dir = safe_normalize(dir);
|
|
|
|
|
|
|
|
if (light->use_mis && area != 0.0f)
|
|
|
|
shader_id |= SHADER_USE_MIS;
|
|
|
|
|
2022-11-30 19:17:45 +00:00
|
|
|
klights[light_index].co = co;
|
2022-12-02 14:21:57 +00:00
|
|
|
klights[light_index].area.axis_u = axis_u;
|
|
|
|
klights[light_index].area.len_u = len_u;
|
|
|
|
klights[light_index].area.axis_v = axis_v;
|
|
|
|
klights[light_index].area.len_v = len_v;
|
2019-04-17 04:17:24 +00:00
|
|
|
klights[light_index].area.invarea = invarea;
|
2022-11-30 19:17:45 +00:00
|
|
|
klights[light_index].area.dir = dir;
|
2022-12-07 17:51:26 +00:00
|
|
|
klights[light_index].area.tan_half_spread = tan_half_spread;
|
2021-04-01 03:35:56 +00:00
|
|
|
klights[light_index].area.normalize_spread = normalize_spread;
|
2019-04-17 04:17:24 +00:00
|
|
|
}
|
2023-07-07 15:15:18 +00:00
|
|
|
if (light->light_type == LIGHT_SPOT) {
|
2023-06-23 13:38:56 +00:00
|
|
|
/* Scale axes to accommodate non-uniform scaling. */
|
|
|
|
float3 scaled_axis_u = light->axisu / len_squared(light->axisu);
|
|
|
|
float3 scaled_axis_v = light->axisv / len_squared(light->axisv);
|
|
|
|
float len_z;
|
|
|
|
/* Keep direction normalized. */
|
|
|
|
float3 dir = safe_normalize_len(light->dir, &len_z);
|
2023-01-26 15:17:08 +00:00
|
|
|
|
2022-11-30 19:17:45 +00:00
|
|
|
float cos_half_spot_angle = cosf(light->spot_angle * 0.5f);
|
2023-06-22 15:19:01 +00:00
|
|
|
float spot_smooth = 1.0f / ((1.0f - cos_half_spot_angle) * light->spot_smooth);
|
2019-04-17 04:17:24 +00:00
|
|
|
|
2023-06-23 13:38:56 +00:00
|
|
|
klights[light_index].spot.scaled_axis_u = scaled_axis_u;
|
|
|
|
klights[light_index].spot.scaled_axis_v = scaled_axis_v;
|
2023-01-26 15:17:08 +00:00
|
|
|
klights[light_index].spot.dir = dir;
|
2022-11-30 19:17:45 +00:00
|
|
|
klights[light_index].spot.cos_half_spot_angle = cos_half_spot_angle;
|
2023-07-07 15:15:18 +00:00
|
|
|
klights[light_index].spot.half_cot_half_spot_angle = 0.5f / tanf(light->spot_angle * 0.5f);
|
2023-06-23 13:38:56 +00:00
|
|
|
klights[light_index].spot.inv_len_z = 1.0f / len_z;
|
2019-04-17 04:17:24 +00:00
|
|
|
klights[light_index].spot.spot_smooth = spot_smooth;
|
|
|
|
}
|
|
|
|
|
|
|
|
klights[light_index].shader_id = shader_id;
|
|
|
|
|
|
|
|
klights[light_index].max_bounces = max_bounces;
|
|
|
|
klights[light_index].random = random;
|
Cycles: approximate shadow caustics using manifold next event estimation
This adds support for selective rendering of caustics in shadows of refractive
objects. Example uses are rendering of underwater caustics and eye caustics.
This is based on "Manifold Next Event Estimation", a method developed for
production rendering. The idea is to selectively enable shadow caustics on a
few objects in the scene where they have a big visual impact, without impacting
render performance for the rest of the scene.
The Shadow Caustic option must be manually enabled on light, caustic receiver
and caster objects. For such light paths, the Filter Glossy option will be
ignored and replaced by sharp caustics.
Currently this method has a various limitations:
* Only caustics in shadows of refractive objects work, which means no caustics
from reflection or caustics that outside shadows. Only up to 4 refractive
caustic bounces are supported.
* Caustic caster objects should have smooth normals.
* Not currently support for Metal GPU rendering.
In the future this method may be extended for more general caustics.
TECHNICAL DETAILS
This code adds manifold next event estimation through refractive surface(s) as a
new sampling technique for direct lighting, i.e. finding the point on the
refractive surface(s) along the path to a light sample, which satisfies Fermat's
principle for a given microfacet normal and the path's end points. This
technique involves walking on the "specular manifold" using a pseudo newton
solver. Such a manifold is defined by the specular constraint matrix from the
manifold exploration framework [2]. For each refractive interface, this
constraint is defined by enforcing that the generalized half-vector projection
onto the interface local tangent plane is null. The newton solver guides the
walk by linearizing the manifold locally before reprojecting the linear solution
onto the refractive surface. See paper [1] for more details about the technique
itself and [3] for the half-vector light transport formulation, from which it is
derived.
[1] Manifold Next Event Estimation
Johannes Hanika, Marc Droske, and Luca Fascione. 2015.
Comput. Graph. Forum 34, 4 (July 2015), 87–97.
https://jo.dreggn.org/home/2015_mnee.pdf
[2] Manifold exploration: a Markov Chain Monte Carlo technique for rendering
scenes with difficult specular transport Wenzel Jakob and Steve Marschner.
2012. ACM Trans. Graph. 31, 4, Article 58 (July 2012), 13 pages.
https://www.cs.cornell.edu/projects/manifolds-sg12/
[3] The Natural-Constraint Representation of the Path Space for Efficient
Light Transport Simulation. Anton S. Kaplanyan, Johannes Hanika, and Carsten
Dachsbacher. 2014. ACM Trans. Graph. 33, 4, Article 102 (July 2014), 13 pages.
https://cg.ivd.kit.edu/english/HSLT.php
The code for this samping technique was inserted at the light sampling stage
(direct lighting). If the walk is successful, it turns off path regularization
using a specialized flag in the path state (PATH_MNEE_SUCCESS). This flag tells
the integrator not to blur the brdf roughness further down the path (in a child
ray created from BSDF sampling). In addition, using a cascading mechanism of
flag values, we cull connections to caustic lights for this and children rays,
which should be resolved through MNEE.
This mechanism also cancels the MIS bsdf counter part at the casutic receiver
depth, in essence leaving MNEE as the only sampling technique from receivers
through refractive casters to caustic lights. This choice might not be optimal
when the light gets large wrt to the receiver, though this is usually not when
you want to use MNEE.
This connection culling strategy removes a fair amount of fireflies, at the cost
of introducing a slight bias. Because of the selective nature of the culling
mechanism, reflective caustics still benefit from the native path
regularization, which further removes fireflies on other surfaces (bouncing
light off casters).
Differential Revision: https://developer.blender.org/D13533
2022-04-01 13:44:24 +00:00
|
|
|
klights[light_index].use_caustics = light->use_caustics;
|
2019-04-17 04:17:24 +00:00
|
|
|
|
|
|
|
klights[light_index].tfm = light->tfm;
|
|
|
|
klights[light_index].itfm = transform_inverse(light->tfm);
|
|
|
|
|
2022-04-01 22:11:11 +00:00
|
|
|
auto it = scene->lightgroups.find(light->lightgroup);
|
|
|
|
if (it != scene->lightgroups.end()) {
|
|
|
|
klights[light_index].lightgroup = it->second;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
klights[light_index].lightgroup = LIGHTGROUP_NONE;
|
|
|
|
}
|
|
|
|
|
2023-05-24 11:36:13 +00:00
|
|
|
klights[light_index].light_set_membership = light->light_set_membership;
|
|
|
|
klights[light_index].shadow_set_membership = light->shadow_set_membership;
|
|
|
|
|
2019-04-17 04:17:24 +00:00
|
|
|
light_index++;
|
|
|
|
}
|
|
|
|
|
2022-11-30 19:17:45 +00:00
|
|
|
VLOG_INFO << "Number of lights sent to the device: " << num_lights;
|
2019-04-17 04:17:24 +00:00
|
|
|
|
|
|
|
dscene->lights.copy_to_device();
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
2019-04-17 04:17:24 +00:00
|
|
|
void LightManager::device_update(Device *device,
|
|
|
|
DeviceScene *dscene,
|
|
|
|
Scene *scene,
|
|
|
|
Progress &progress)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
Cycles: optimize device updates
This optimizes device updates (during user edits or frame changes in
the viewport) by avoiding unnecessary computations. To achieve this,
we use a combination of the sockets' update flags as well as some new
flags passed to the various managers when tagging for an update to tell
exactly what the tagging is for (e.g. shader was modified, object was
removed, etc.).
Besides avoiding recomputations, we also avoid resending to the devices
unmodified data arrays, thus reducing bandwidth usage. For OptiX and
Embree, BVH packing was also multithreaded.
The performance improvements may vary depending on the used device (CPU
or GPU), and the content of the scene. Simple scenes (e.g. with no adaptive
subdivision or volumes) rendered using OptiX will benefit from this work
the most.
On average, for a variety of animated scenes, this gives a 3x speedup.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79174
Differential Revision: https://developer.blender.org/D9555
2021-01-22 14:01:26 +00:00
|
|
|
if (!need_update())
|
2019-04-17 04:17:24 +00:00
|
|
|
return;
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2020-10-01 21:16:01 +00:00
|
|
|
scoped_callback_timer timer([scene](double time) {
|
|
|
|
if (scene->update_stats) {
|
|
|
|
scene->update_stats->light.times.add_entry({"device_update", time});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2022-06-16 17:39:13 +00:00
|
|
|
VLOG_INFO << "Total " << scene->lights.size() << " lights.";
|
2016-04-22 08:55:26 +00:00
|
|
|
|
2021-02-05 05:23:34 +00:00
|
|
|
/* Detect which lights are enabled, also determines if we need to update the background. */
|
2020-05-14 15:41:37 +00:00
|
|
|
test_enabled_lights(scene);
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2020-05-14 15:41:37 +00:00
|
|
|
device_free(device, dscene, need_update_background);
|
2013-06-08 13:43:38 +00:00
|
|
|
|
2022-11-30 19:17:45 +00:00
|
|
|
device_update_lights(device, dscene, scene);
|
2019-04-17 04:17:24 +00:00
|
|
|
if (progress.get_cancel())
|
|
|
|
return;
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2020-05-14 15:41:37 +00:00
|
|
|
if (need_update_background) {
|
|
|
|
device_update_background(device, dscene, scene, progress);
|
|
|
|
if (progress.get_cancel())
|
|
|
|
return;
|
|
|
|
}
|
2012-01-20 17:49:17 +00:00
|
|
|
|
2022-11-30 19:17:45 +00:00
|
|
|
device_update_distribution(device, dscene, scene, progress);
|
|
|
|
if (progress.get_cancel())
|
|
|
|
return;
|
|
|
|
|
2022-12-02 18:04:00 +00:00
|
|
|
device_update_tree(device, dscene, scene, progress);
|
|
|
|
if (progress.get_cancel())
|
|
|
|
return;
|
|
|
|
|
2019-04-17 04:17:24 +00:00
|
|
|
device_update_ies(dscene);
|
|
|
|
if (progress.get_cancel())
|
|
|
|
return;
|
Cycles: Add Support for IES files as textures for light strength
This patch adds support for IES files, a file format that is commonly used to store the directional intensity distribution of light sources.
The new IES node is supposed to be plugged into the Strength input of the Emission node of the lamp.
Since people generating IES files do not really seem to care about the standard, the parser is flexible enough to accept all test files I have tried.
Some common weirdnesses are distributing values over multiple lines that should go into one line, using commas instead of spaces as delimiters and adding various useless stuff at the end of the file.
The user interface of the node is similar to the script node, the user can either select an internal Text or load a file.
Internally, IES files are handled similar to Image textures: They are stored in slots by the LightManager and each unique IES is assigned to one slot.
The local coordinate system of the lamp is used, so that the direction of the light can be changed. For UI reasons, it's usually best to add an area light,
rotate it and then change its type, since especially the point light does not immediately show its local coordinate system in the viewport.
Reviewers: #cycles, dingto, sergey, brecht
Reviewed By: #cycles, dingto, brecht
Subscribers: OgDEV, crazyrobinhood, secundar, cardboard, pisuke, intrah, swerner, micah_denn, harvester, gottfried, disnel, campbellbarton, duarteframos, Lapineige, brecht, juicyfruit, dingto, marek, rickyblender, bliblubli, lockal, sergey
Differential Revision: https://developer.blender.org/D1543
2018-05-26 22:46:37 +00:00
|
|
|
|
Cycles: optimize device updates
This optimizes device updates (during user edits or frame changes in
the viewport) by avoiding unnecessary computations. To achieve this,
we use a combination of the sockets' update flags as well as some new
flags passed to the various managers when tagging for an update to tell
exactly what the tagging is for (e.g. shader was modified, object was
removed, etc.).
Besides avoiding recomputations, we also avoid resending to the devices
unmodified data arrays, thus reducing bandwidth usage. For OptiX and
Embree, BVH packing was also multithreaded.
The performance improvements may vary depending on the used device (CPU
or GPU), and the content of the scene. Simple scenes (e.g. with no adaptive
subdivision or volumes) rendered using OptiX will benefit from this work
the most.
On average, for a variety of animated scenes, this gives a 3x speedup.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79174
Differential Revision: https://developer.blender.org/D9555
2021-01-22 14:01:26 +00:00
|
|
|
update_flags = UPDATE_NONE;
|
2020-05-14 15:41:37 +00:00
|
|
|
need_update_background = false;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
2020-05-14 15:41:37 +00:00
|
|
|
void LightManager::device_free(Device *, DeviceScene *dscene, const bool free_background)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2022-12-02 18:04:00 +00:00
|
|
|
dscene->light_tree_nodes.free();
|
|
|
|
dscene->light_tree_emitters.free();
|
|
|
|
dscene->light_to_tree.free();
|
2023-04-14 16:52:12 +00:00
|
|
|
dscene->object_to_tree.free();
|
2023-04-03 09:43:23 +00:00
|
|
|
dscene->object_lookup_offset.free();
|
2022-12-02 18:04:00 +00:00
|
|
|
dscene->triangle_to_tree.free();
|
|
|
|
|
2019-04-17 04:17:24 +00:00
|
|
|
dscene->light_distribution.free();
|
|
|
|
dscene->lights.free();
|
2020-05-14 15:41:37 +00:00
|
|
|
if (free_background) {
|
|
|
|
dscene->light_background_marginal_cdf.free();
|
|
|
|
dscene->light_background_conditional_cdf.free();
|
|
|
|
}
|
2019-04-17 04:17:24 +00:00
|
|
|
dscene->ies_lights.free();
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
Cycles: optimize device updates
This optimizes device updates (during user edits or frame changes in
the viewport) by avoiding unnecessary computations. To achieve this,
we use a combination of the sockets' update flags as well as some new
flags passed to the various managers when tagging for an update to tell
exactly what the tagging is for (e.g. shader was modified, object was
removed, etc.).
Besides avoiding recomputations, we also avoid resending to the devices
unmodified data arrays, thus reducing bandwidth usage. For OptiX and
Embree, BVH packing was also multithreaded.
The performance improvements may vary depending on the used device (CPU
or GPU), and the content of the scene. Simple scenes (e.g. with no adaptive
subdivision or volumes) rendered using OptiX will benefit from this work
the most.
On average, for a variety of animated scenes, this gives a 3x speedup.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79174
Differential Revision: https://developer.blender.org/D9555
2021-01-22 14:01:26 +00:00
|
|
|
void LightManager::tag_update(Scene * /*scene*/, uint32_t flag)
|
|
|
|
{
|
|
|
|
update_flags |= flag;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool LightManager::need_update() const
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
Cycles: optimize device updates
This optimizes device updates (during user edits or frame changes in
the viewport) by avoiding unnecessary computations. To achieve this,
we use a combination of the sockets' update flags as well as some new
flags passed to the various managers when tagging for an update to tell
exactly what the tagging is for (e.g. shader was modified, object was
removed, etc.).
Besides avoiding recomputations, we also avoid resending to the devices
unmodified data arrays, thus reducing bandwidth usage. For OptiX and
Embree, BVH packing was also multithreaded.
The performance improvements may vary depending on the used device (CPU
or GPU), and the content of the scene. Simple scenes (e.g. with no adaptive
subdivision or volumes) rendered using OptiX will benefit from this work
the most.
On average, for a variety of animated scenes, this gives a 3x speedup.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79174
Differential Revision: https://developer.blender.org/D9555
2021-01-22 14:01:26 +00:00
|
|
|
return update_flags != UPDATE_NONE;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
2019-08-14 12:04:23 +00:00
|
|
|
int LightManager::add_ies_from_file(const string &filename)
|
Cycles: Add Support for IES files as textures for light strength
This patch adds support for IES files, a file format that is commonly used to store the directional intensity distribution of light sources.
The new IES node is supposed to be plugged into the Strength input of the Emission node of the lamp.
Since people generating IES files do not really seem to care about the standard, the parser is flexible enough to accept all test files I have tried.
Some common weirdnesses are distributing values over multiple lines that should go into one line, using commas instead of spaces as delimiters and adding various useless stuff at the end of the file.
The user interface of the node is similar to the script node, the user can either select an internal Text or load a file.
Internally, IES files are handled similar to Image textures: They are stored in slots by the LightManager and each unique IES is assigned to one slot.
The local coordinate system of the lamp is used, so that the direction of the light can be changed. For UI reasons, it's usually best to add an area light,
rotate it and then change its type, since especially the point light does not immediately show its local coordinate system in the viewport.
Reviewers: #cycles, dingto, sergey, brecht
Reviewed By: #cycles, dingto, brecht
Subscribers: OgDEV, crazyrobinhood, secundar, cardboard, pisuke, intrah, swerner, micah_denn, harvester, gottfried, disnel, campbellbarton, duarteframos, Lapineige, brecht, juicyfruit, dingto, marek, rickyblender, bliblubli, lockal, sergey
Differential Revision: https://developer.blender.org/D1543
2018-05-26 22:46:37 +00:00
|
|
|
{
|
2019-04-17 04:17:24 +00:00
|
|
|
string content;
|
2018-05-27 21:46:02 +00:00
|
|
|
|
2019-04-17 04:17:24 +00:00
|
|
|
/* If the file can't be opened, call with an empty line */
|
|
|
|
if (filename.empty() || !path_read_text(filename.c_str(), content)) {
|
|
|
|
content = "\n";
|
|
|
|
}
|
Cycles: Add Support for IES files as textures for light strength
This patch adds support for IES files, a file format that is commonly used to store the directional intensity distribution of light sources.
The new IES node is supposed to be plugged into the Strength input of the Emission node of the lamp.
Since people generating IES files do not really seem to care about the standard, the parser is flexible enough to accept all test files I have tried.
Some common weirdnesses are distributing values over multiple lines that should go into one line, using commas instead of spaces as delimiters and adding various useless stuff at the end of the file.
The user interface of the node is similar to the script node, the user can either select an internal Text or load a file.
Internally, IES files are handled similar to Image textures: They are stored in slots by the LightManager and each unique IES is assigned to one slot.
The local coordinate system of the lamp is used, so that the direction of the light can be changed. For UI reasons, it's usually best to add an area light,
rotate it and then change its type, since especially the point light does not immediately show its local coordinate system in the viewport.
Reviewers: #cycles, dingto, sergey, brecht
Reviewed By: #cycles, dingto, brecht
Subscribers: OgDEV, crazyrobinhood, secundar, cardboard, pisuke, intrah, swerner, micah_denn, harvester, gottfried, disnel, campbellbarton, duarteframos, Lapineige, brecht, juicyfruit, dingto, marek, rickyblender, bliblubli, lockal, sergey
Differential Revision: https://developer.blender.org/D1543
2018-05-26 22:46:37 +00:00
|
|
|
|
2019-08-14 12:04:23 +00:00
|
|
|
return add_ies(content);
|
Cycles: Add Support for IES files as textures for light strength
This patch adds support for IES files, a file format that is commonly used to store the directional intensity distribution of light sources.
The new IES node is supposed to be plugged into the Strength input of the Emission node of the lamp.
Since people generating IES files do not really seem to care about the standard, the parser is flexible enough to accept all test files I have tried.
Some common weirdnesses are distributing values over multiple lines that should go into one line, using commas instead of spaces as delimiters and adding various useless stuff at the end of the file.
The user interface of the node is similar to the script node, the user can either select an internal Text or load a file.
Internally, IES files are handled similar to Image textures: They are stored in slots by the LightManager and each unique IES is assigned to one slot.
The local coordinate system of the lamp is used, so that the direction of the light can be changed. For UI reasons, it's usually best to add an area light,
rotate it and then change its type, since especially the point light does not immediately show its local coordinate system in the viewport.
Reviewers: #cycles, dingto, sergey, brecht
Reviewed By: #cycles, dingto, brecht
Subscribers: OgDEV, crazyrobinhood, secundar, cardboard, pisuke, intrah, swerner, micah_denn, harvester, gottfried, disnel, campbellbarton, duarteframos, Lapineige, brecht, juicyfruit, dingto, marek, rickyblender, bliblubli, lockal, sergey
Differential Revision: https://developer.blender.org/D1543
2018-05-26 22:46:37 +00:00
|
|
|
}
|
|
|
|
|
2019-08-14 12:04:23 +00:00
|
|
|
int LightManager::add_ies(const string &content)
|
Cycles: Add Support for IES files as textures for light strength
This patch adds support for IES files, a file format that is commonly used to store the directional intensity distribution of light sources.
The new IES node is supposed to be plugged into the Strength input of the Emission node of the lamp.
Since people generating IES files do not really seem to care about the standard, the parser is flexible enough to accept all test files I have tried.
Some common weirdnesses are distributing values over multiple lines that should go into one line, using commas instead of spaces as delimiters and adding various useless stuff at the end of the file.
The user interface of the node is similar to the script node, the user can either select an internal Text or load a file.
Internally, IES files are handled similar to Image textures: They are stored in slots by the LightManager and each unique IES is assigned to one slot.
The local coordinate system of the lamp is used, so that the direction of the light can be changed. For UI reasons, it's usually best to add an area light,
rotate it and then change its type, since especially the point light does not immediately show its local coordinate system in the viewport.
Reviewers: #cycles, dingto, sergey, brecht
Reviewed By: #cycles, dingto, brecht
Subscribers: OgDEV, crazyrobinhood, secundar, cardboard, pisuke, intrah, swerner, micah_denn, harvester, gottfried, disnel, campbellbarton, duarteframos, Lapineige, brecht, juicyfruit, dingto, marek, rickyblender, bliblubli, lockal, sergey
Differential Revision: https://developer.blender.org/D1543
2018-05-26 22:46:37 +00:00
|
|
|
{
|
2019-04-17 04:17:24 +00:00
|
|
|
uint hash = hash_string(content.c_str());
|
|
|
|
|
|
|
|
thread_scoped_lock ies_lock(ies_mutex);
|
|
|
|
|
|
|
|
/* Check whether this IES already has a slot. */
|
|
|
|
size_t slot;
|
|
|
|
for (slot = 0; slot < ies_slots.size(); slot++) {
|
|
|
|
if (ies_slots[slot]->hash == hash) {
|
|
|
|
ies_slots[slot]->users++;
|
|
|
|
return slot;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Try to find an empty slot for the new IES. */
|
|
|
|
for (slot = 0; slot < ies_slots.size(); slot++) {
|
|
|
|
if (ies_slots[slot]->users == 0 && ies_slots[slot]->hash == 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If there's no free slot, add one. */
|
|
|
|
if (slot == ies_slots.size()) {
|
|
|
|
ies_slots.push_back(new IESSlot());
|
|
|
|
}
|
|
|
|
|
|
|
|
ies_slots[slot]->ies.load(content);
|
|
|
|
ies_slots[slot]->users = 1;
|
|
|
|
ies_slots[slot]->hash = hash;
|
|
|
|
|
Cycles: optimize device updates
This optimizes device updates (during user edits or frame changes in
the viewport) by avoiding unnecessary computations. To achieve this,
we use a combination of the sockets' update flags as well as some new
flags passed to the various managers when tagging for an update to tell
exactly what the tagging is for (e.g. shader was modified, object was
removed, etc.).
Besides avoiding recomputations, we also avoid resending to the devices
unmodified data arrays, thus reducing bandwidth usage. For OptiX and
Embree, BVH packing was also multithreaded.
The performance improvements may vary depending on the used device (CPU
or GPU), and the content of the scene. Simple scenes (e.g. with no adaptive
subdivision or volumes) rendered using OptiX will benefit from this work
the most.
On average, for a variety of animated scenes, this gives a 3x speedup.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79174
Differential Revision: https://developer.blender.org/D9555
2021-01-22 14:01:26 +00:00
|
|
|
update_flags = UPDATE_ALL;
|
2020-05-14 15:41:37 +00:00
|
|
|
need_update_background = true;
|
2019-04-17 04:17:24 +00:00
|
|
|
|
|
|
|
return slot;
|
Cycles: Add Support for IES files as textures for light strength
This patch adds support for IES files, a file format that is commonly used to store the directional intensity distribution of light sources.
The new IES node is supposed to be plugged into the Strength input of the Emission node of the lamp.
Since people generating IES files do not really seem to care about the standard, the parser is flexible enough to accept all test files I have tried.
Some common weirdnesses are distributing values over multiple lines that should go into one line, using commas instead of spaces as delimiters and adding various useless stuff at the end of the file.
The user interface of the node is similar to the script node, the user can either select an internal Text or load a file.
Internally, IES files are handled similar to Image textures: They are stored in slots by the LightManager and each unique IES is assigned to one slot.
The local coordinate system of the lamp is used, so that the direction of the light can be changed. For UI reasons, it's usually best to add an area light,
rotate it and then change its type, since especially the point light does not immediately show its local coordinate system in the viewport.
Reviewers: #cycles, dingto, sergey, brecht
Reviewed By: #cycles, dingto, brecht
Subscribers: OgDEV, crazyrobinhood, secundar, cardboard, pisuke, intrah, swerner, micah_denn, harvester, gottfried, disnel, campbellbarton, duarteframos, Lapineige, brecht, juicyfruit, dingto, marek, rickyblender, bliblubli, lockal, sergey
Differential Revision: https://developer.blender.org/D1543
2018-05-26 22:46:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void LightManager::remove_ies(int slot)
|
|
|
|
{
|
2019-04-17 04:17:24 +00:00
|
|
|
thread_scoped_lock ies_lock(ies_mutex);
|
Cycles: Add Support for IES files as textures for light strength
This patch adds support for IES files, a file format that is commonly used to store the directional intensity distribution of light sources.
The new IES node is supposed to be plugged into the Strength input of the Emission node of the lamp.
Since people generating IES files do not really seem to care about the standard, the parser is flexible enough to accept all test files I have tried.
Some common weirdnesses are distributing values over multiple lines that should go into one line, using commas instead of spaces as delimiters and adding various useless stuff at the end of the file.
The user interface of the node is similar to the script node, the user can either select an internal Text or load a file.
Internally, IES files are handled similar to Image textures: They are stored in slots by the LightManager and each unique IES is assigned to one slot.
The local coordinate system of the lamp is used, so that the direction of the light can be changed. For UI reasons, it's usually best to add an area light,
rotate it and then change its type, since especially the point light does not immediately show its local coordinate system in the viewport.
Reviewers: #cycles, dingto, sergey, brecht
Reviewed By: #cycles, dingto, brecht
Subscribers: OgDEV, crazyrobinhood, secundar, cardboard, pisuke, intrah, swerner, micah_denn, harvester, gottfried, disnel, campbellbarton, duarteframos, Lapineige, brecht, juicyfruit, dingto, marek, rickyblender, bliblubli, lockal, sergey
Differential Revision: https://developer.blender.org/D1543
2018-05-26 22:46:37 +00:00
|
|
|
|
2019-04-17 04:17:24 +00:00
|
|
|
if (slot < 0 || slot >= ies_slots.size()) {
|
|
|
|
assert(false);
|
|
|
|
return;
|
|
|
|
}
|
Cycles: Add Support for IES files as textures for light strength
This patch adds support for IES files, a file format that is commonly used to store the directional intensity distribution of light sources.
The new IES node is supposed to be plugged into the Strength input of the Emission node of the lamp.
Since people generating IES files do not really seem to care about the standard, the parser is flexible enough to accept all test files I have tried.
Some common weirdnesses are distributing values over multiple lines that should go into one line, using commas instead of spaces as delimiters and adding various useless stuff at the end of the file.
The user interface of the node is similar to the script node, the user can either select an internal Text or load a file.
Internally, IES files are handled similar to Image textures: They are stored in slots by the LightManager and each unique IES is assigned to one slot.
The local coordinate system of the lamp is used, so that the direction of the light can be changed. For UI reasons, it's usually best to add an area light,
rotate it and then change its type, since especially the point light does not immediately show its local coordinate system in the viewport.
Reviewers: #cycles, dingto, sergey, brecht
Reviewed By: #cycles, dingto, brecht
Subscribers: OgDEV, crazyrobinhood, secundar, cardboard, pisuke, intrah, swerner, micah_denn, harvester, gottfried, disnel, campbellbarton, duarteframos, Lapineige, brecht, juicyfruit, dingto, marek, rickyblender, bliblubli, lockal, sergey
Differential Revision: https://developer.blender.org/D1543
2018-05-26 22:46:37 +00:00
|
|
|
|
2019-04-17 04:17:24 +00:00
|
|
|
assert(ies_slots[slot]->users > 0);
|
|
|
|
ies_slots[slot]->users--;
|
Cycles: Add Support for IES files as textures for light strength
This patch adds support for IES files, a file format that is commonly used to store the directional intensity distribution of light sources.
The new IES node is supposed to be plugged into the Strength input of the Emission node of the lamp.
Since people generating IES files do not really seem to care about the standard, the parser is flexible enough to accept all test files I have tried.
Some common weirdnesses are distributing values over multiple lines that should go into one line, using commas instead of spaces as delimiters and adding various useless stuff at the end of the file.
The user interface of the node is similar to the script node, the user can either select an internal Text or load a file.
Internally, IES files are handled similar to Image textures: They are stored in slots by the LightManager and each unique IES is assigned to one slot.
The local coordinate system of the lamp is used, so that the direction of the light can be changed. For UI reasons, it's usually best to add an area light,
rotate it and then change its type, since especially the point light does not immediately show its local coordinate system in the viewport.
Reviewers: #cycles, dingto, sergey, brecht
Reviewed By: #cycles, dingto, brecht
Subscribers: OgDEV, crazyrobinhood, secundar, cardboard, pisuke, intrah, swerner, micah_denn, harvester, gottfried, disnel, campbellbarton, duarteframos, Lapineige, brecht, juicyfruit, dingto, marek, rickyblender, bliblubli, lockal, sergey
Differential Revision: https://developer.blender.org/D1543
2018-05-26 22:46:37 +00:00
|
|
|
|
2019-04-17 04:17:24 +00:00
|
|
|
/* If the slot has no more users, update the device to remove it. */
|
Cycles: optimize device updates
This optimizes device updates (during user edits or frame changes in
the viewport) by avoiding unnecessary computations. To achieve this,
we use a combination of the sockets' update flags as well as some new
flags passed to the various managers when tagging for an update to tell
exactly what the tagging is for (e.g. shader was modified, object was
removed, etc.).
Besides avoiding recomputations, we also avoid resending to the devices
unmodified data arrays, thus reducing bandwidth usage. For OptiX and
Embree, BVH packing was also multithreaded.
The performance improvements may vary depending on the used device (CPU
or GPU), and the content of the scene. Simple scenes (e.g. with no adaptive
subdivision or volumes) rendered using OptiX will benefit from this work
the most.
On average, for a variety of animated scenes, this gives a 3x speedup.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79174
Differential Revision: https://developer.blender.org/D9555
2021-01-22 14:01:26 +00:00
|
|
|
if (ies_slots[slot]->users == 0) {
|
|
|
|
update_flags |= UPDATE_ALL;
|
|
|
|
need_update_background = true;
|
|
|
|
}
|
Cycles: Add Support for IES files as textures for light strength
This patch adds support for IES files, a file format that is commonly used to store the directional intensity distribution of light sources.
The new IES node is supposed to be plugged into the Strength input of the Emission node of the lamp.
Since people generating IES files do not really seem to care about the standard, the parser is flexible enough to accept all test files I have tried.
Some common weirdnesses are distributing values over multiple lines that should go into one line, using commas instead of spaces as delimiters and adding various useless stuff at the end of the file.
The user interface of the node is similar to the script node, the user can either select an internal Text or load a file.
Internally, IES files are handled similar to Image textures: They are stored in slots by the LightManager and each unique IES is assigned to one slot.
The local coordinate system of the lamp is used, so that the direction of the light can be changed. For UI reasons, it's usually best to add an area light,
rotate it and then change its type, since especially the point light does not immediately show its local coordinate system in the viewport.
Reviewers: #cycles, dingto, sergey, brecht
Reviewed By: #cycles, dingto, brecht
Subscribers: OgDEV, crazyrobinhood, secundar, cardboard, pisuke, intrah, swerner, micah_denn, harvester, gottfried, disnel, campbellbarton, duarteframos, Lapineige, brecht, juicyfruit, dingto, marek, rickyblender, bliblubli, lockal, sergey
Differential Revision: https://developer.blender.org/D1543
2018-05-26 22:46:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void LightManager::device_update_ies(DeviceScene *dscene)
|
|
|
|
{
|
2019-04-17 04:17:24 +00:00
|
|
|
/* Clear empty slots. */
|
|
|
|
foreach (IESSlot *slot, ies_slots) {
|
|
|
|
if (slot->users == 0) {
|
|
|
|
slot->hash = 0;
|
|
|
|
slot->ies.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Shrink the slot table by removing empty slots at the end. */
|
|
|
|
int slot_end;
|
|
|
|
for (slot_end = ies_slots.size(); slot_end; slot_end--) {
|
|
|
|
if (ies_slots[slot_end - 1]->users > 0) {
|
|
|
|
/* If the preceding slot has users, we found the new end of the table. */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* The slot will be past the new end of the table, so free it. */
|
|
|
|
delete ies_slots[slot_end - 1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ies_slots.resize(slot_end);
|
|
|
|
|
|
|
|
if (ies_slots.size() > 0) {
|
|
|
|
int packed_size = 0;
|
|
|
|
foreach (IESSlot *slot, ies_slots) {
|
|
|
|
packed_size += slot->ies.packed_size();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ies_lights starts with an offset table that contains the offset of every slot,
|
|
|
|
* or -1 if the slot is invalid.
|
|
|
|
* Following that table, the packed valid IES lights are stored. */
|
|
|
|
float *data = dscene->ies_lights.alloc(ies_slots.size() + packed_size);
|
|
|
|
|
|
|
|
int offset = ies_slots.size();
|
|
|
|
for (int i = 0; i < ies_slots.size(); i++) {
|
|
|
|
int size = ies_slots[i]->ies.packed_size();
|
|
|
|
if (size > 0) {
|
|
|
|
data[i] = __int_as_float(offset);
|
|
|
|
ies_slots[i]->ies.pack(data + offset);
|
|
|
|
offset += size;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
data[i] = __int_as_float(-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
dscene->ies_lights.copy_to_device();
|
|
|
|
}
|
Cycles: Add Support for IES files as textures for light strength
This patch adds support for IES files, a file format that is commonly used to store the directional intensity distribution of light sources.
The new IES node is supposed to be plugged into the Strength input of the Emission node of the lamp.
Since people generating IES files do not really seem to care about the standard, the parser is flexible enough to accept all test files I have tried.
Some common weirdnesses are distributing values over multiple lines that should go into one line, using commas instead of spaces as delimiters and adding various useless stuff at the end of the file.
The user interface of the node is similar to the script node, the user can either select an internal Text or load a file.
Internally, IES files are handled similar to Image textures: They are stored in slots by the LightManager and each unique IES is assigned to one slot.
The local coordinate system of the lamp is used, so that the direction of the light can be changed. For UI reasons, it's usually best to add an area light,
rotate it and then change its type, since especially the point light does not immediately show its local coordinate system in the viewport.
Reviewers: #cycles, dingto, sergey, brecht
Reviewed By: #cycles, dingto, brecht
Subscribers: OgDEV, crazyrobinhood, secundar, cardboard, pisuke, intrah, swerner, micah_denn, harvester, gottfried, disnel, campbellbarton, duarteframos, Lapineige, brecht, juicyfruit, dingto, marek, rickyblender, bliblubli, lockal, sergey
Differential Revision: https://developer.blender.org/D1543
2018-05-26 22:46:37 +00:00
|
|
|
}
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
CCL_NAMESPACE_END
|