Versioning function to replace legacy instancing panel by geometry node modifier #105494
|
@ -981,22 +981,8 @@ static ShaderNode *add_node(Scene *scene,
|
|||
sky->set_sun_disc(b_sky_node.sun_disc());
|
||||
sky->set_sun_size(b_sky_node.sun_size());
|
||||
sky->set_sun_intensity(b_sky_node.sun_intensity());
|
||||
/* Patch sun position to be able to animate daylight cycle while keeping the shading code
|
||||
* simple. */
|
||||
float sun_rotation = b_sky_node.sun_rotation();
|
||||
/* Wrap into [-2PI..2PI] range. */
|
||||
float sun_elevation = fmodf(b_sky_node.sun_elevation(), M_2PI_F);
|
||||
/* Wrap into [-PI..PI] range. */
|
||||
if (fabsf(sun_elevation) >= M_PI_F) {
|
||||
sun_elevation -= copysignf(2.0f, sun_elevation) * M_PI_F;
|
||||
}
|
||||
/* Wrap into [-PI/2..PI/2] range while keeping the same absolute position. */
|
||||
if (sun_elevation >= M_PI_2_F || sun_elevation <= -M_PI_2_F) {
|
||||
sun_elevation = copysignf(M_PI_F, sun_elevation) - sun_elevation;
|
||||
sun_rotation += M_PI_F;
|
||||
}
|
||||
sky->set_sun_elevation(sun_elevation);
|
||||
sky->set_sun_rotation(sun_rotation);
|
||||
sky->set_sun_elevation(b_sky_node.sun_elevation());
|
||||
sky->set_sun_rotation(b_sky_node.sun_rotation());
|
||||
sky->set_altitude(b_sky_node.altitude());
|
||||
sky->set_air_density(b_sky_node.air_density());
|
||||
sky->set_dust_density(b_sky_node.dust_density());
|
||||
|
|
|
@ -55,21 +55,29 @@ void WorkTileScheduler::reset_scheduler_state()
|
|||
|
||||
VLOG_WORK << "Will schedule tiles of size " << tile_size_;
|
||||
|
||||
if (VLOG_IS_ON(3)) {
|
||||
/* The logging is based on multiple tiles scheduled, ignoring overhead of multi-tile scheduling
|
||||
* and purely focusing on the number of used path states. */
|
||||
const int num_path_states_in_tile = tile_size_.width * tile_size_.height *
|
||||
tile_size_.num_samples;
|
||||
const int num_tiles = max_num_path_states_ / num_path_states_in_tile;
|
||||
VLOG_WORK << "Number of unused path states: "
|
||||
<< max_num_path_states_ - num_tiles * num_path_states_in_tile;
|
||||
const int num_path_states_in_tile = tile_size_.width * tile_size_.height *
|
||||
tile_size_.num_samples;
|
||||
|
||||
if (num_path_states_in_tile == 0) {
|
||||
num_tiles_x_ = 0;
|
||||
num_tiles_y_ = 0;
|
||||
num_tiles_per_sample_range_ = 0;
|
||||
}
|
||||
else {
|
||||
if (VLOG_IS_ON(3)) {
|
||||
/* The logging is based on multiple tiles scheduled, ignoring overhead of multi-tile
|
||||
* scheduling and purely focusing on the number of used path states. */
|
||||
const int num_tiles = max_num_path_states_ / num_path_states_in_tile;
|
||||
VLOG_WORK << "Number of unused path states: "
|
||||
<< max_num_path_states_ - num_tiles * num_path_states_in_tile;
|
||||
}
|
||||
|
||||
num_tiles_x_ = divide_up(image_size_px_.x, tile_size_.width);
|
||||
num_tiles_y_ = divide_up(image_size_px_.y, tile_size_.height);
|
||||
num_tiles_per_sample_range_ = divide_up(samples_num_, tile_size_.num_samples);
|
||||
}
|
||||
|
||||
num_tiles_x_ = divide_up(image_size_px_.x, tile_size_.width);
|
||||
num_tiles_y_ = divide_up(image_size_px_.y, tile_size_.height);
|
||||
|
||||
total_tiles_num_ = num_tiles_x_ * num_tiles_y_;
|
||||
num_tiles_per_sample_range_ = divide_up(samples_num_, tile_size_.num_samples);
|
||||
|
||||
next_work_index_ = 0;
|
||||
total_work_size_ = total_tiles_num_ * num_tiles_per_sample_range_;
|
||||
|
|
|
@ -20,6 +20,7 @@ KERNEL_STRUCT_BEGIN(KernelBackground, background)
|
|||
/* xyz store direction, w the angle. float4 instead of float3 is used
|
||||
* to ensure consistent padding/alignment across devices. */
|
||||
KERNEL_STRUCT_MEMBER(background, float4, sun)
|
||||
KERNEL_STRUCT_MEMBER(background, int, use_sun_guiding)
|
||||
/* Only shader index. */
|
||||
KERNEL_STRUCT_MEMBER(background, int, surface_shader)
|
||||
KERNEL_STRUCT_MEMBER(background, int, volume_shader)
|
||||
|
@ -39,6 +40,10 @@ KERNEL_STRUCT_MEMBER(background, int, use_mis)
|
|||
KERNEL_STRUCT_MEMBER(background, int, lightgroup)
|
||||
/* Light Index. */
|
||||
KERNEL_STRUCT_MEMBER(background, int, light_index)
|
||||
/* Padding. */
|
||||
KERNEL_STRUCT_MEMBER(background, int, pad1)
|
||||
KERNEL_STRUCT_MEMBER(background, int, pad2)
|
||||
KERNEL_STRUCT_MEMBER(background, int, pad3)
|
||||
KERNEL_STRUCT_END(KernelBackground)
|
||||
|
||||
/* BVH: own BVH2 if no native device acceleration struct used. */
|
||||
|
|
|
@ -132,11 +132,11 @@ color sky_radiance_nishita(vector dir, float nishita_data[10], string filename)
|
|||
/* definitions */
|
||||
vector sun_dir = geographical_to_direction(sun_elevation, sun_rotation + M_PI_2);
|
||||
float sun_dir_angle = precise_angle(dir, sun_dir);
|
||||
float half_angular = angular_diameter / 2.0;
|
||||
float half_angular = angular_diameter * 0.5;
|
||||
float dir_elevation = M_PI_2 - direction[0];
|
||||
|
||||
/* if ray inside sun disc render it, otherwise render sky.
|
||||
* alternatively, ignore the sun if we're evaluating the background texture. */
|
||||
/* If the ray is inside the sun disc, render it, otherwise render the sky.
|
||||
* Alternatively, ignore the sun if we're evaluating the background texture. */
|
||||
if (sun_dir_angle < half_angular && sun_disc == 1 && raytype("importance_bake") != 1) {
|
||||
/* get 2 pixels data */
|
||||
color pixel_bottom = color(nishita_data[0], nishita_data[1], nishita_data[2]);
|
||||
|
|
|
@ -84,8 +84,8 @@ ccl_device_inline void sample_uniform_cone(const float3 N,
|
|||
ccl_device_inline float pdf_uniform_cone(const float3 N, float3 D, float angle)
|
||||
{
|
||||
float zMin = cosf(angle);
|
||||
float z = dot(N, D);
|
||||
if (z > zMin) {
|
||||
float z = precise_angle(N, D);
|
||||
if (z < angle) {
|
||||
return M_1_2PI_F / (1.0f - zMin);
|
||||
}
|
||||
return 0.0f;
|
||||
|
|
|
@ -138,12 +138,13 @@ ccl_device float3 sky_radiance_nishita(KernelGlobals kg,
|
|||
/* definitions */
|
||||
float3 sun_dir = geographical_to_direction(sun_elevation, sun_rotation + M_PI_2_F);
|
||||
float sun_dir_angle = precise_angle(dir, sun_dir);
|
||||
float half_angular = angular_diameter / 2.0f;
|
||||
float half_angular = angular_diameter * 0.5f;
|
||||
float dir_elevation = M_PI_2_F - direction.x;
|
||||
|
||||
/* if ray inside sun disc render it, otherwise render sky.
|
||||
* alternatively, ignore the sun if we're evaluating the background texture. */
|
||||
if (sun_disc && sun_dir_angle < half_angular && !(path_flag & PATH_RAY_IMPORTANCE_BAKE)) {
|
||||
/* If the ray is inside the sun disc, render it, otherwise render the sky.
|
||||
* Alternatively, ignore the sun if we're evaluating the background texture. */
|
||||
if (sun_disc && sun_dir_angle < half_angular &&
|
||||
!((path_flag & PATH_RAY_IMPORTANCE_BAKE) && kernel_data.background.use_sun_guiding)) {
|
||||
/* get 2 pixels data */
|
||||
float y;
|
||||
|
||||
|
|
|
@ -730,7 +730,7 @@ void LightManager::device_update_background(Device *device,
|
|||
|
||||
/* Determine sun direction from lat/long and texture mapping. */
|
||||
float latitude = sky->get_sun_elevation();
|
||||
float longitude = M_2PI_F - sky->get_sun_rotation() + M_PI_2_F;
|
||||
float longitude = sky->get_sun_rotation() + M_PI_2_F;
|
||||
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());
|
||||
|
@ -752,7 +752,8 @@ void LightManager::device_update_background(Device *device,
|
|||
}
|
||||
|
||||
/* If there's more than one sun, fall back to map sampling instead. */
|
||||
if (num_suns != 1) {
|
||||
kbackground->use_sun_guiding = (num_suns == 1);
|
||||
if (!kbackground->use_sun_guiding) {
|
||||
kbackground->sun_weight = 0.0f;
|
||||
environment_res.x = max(environment_res.x, 4096);
|
||||
environment_res.y = max(environment_res.y, 2048);
|
||||
|
|
|
@ -758,12 +758,7 @@ static void sky_texture_precompute_nishita(SunSky *sunsky,
|
|||
float pixel_top[3];
|
||||
SKY_nishita_skymodel_precompute_sun(
|
||||
sun_elevation, sun_size, altitude, air_density, dust_density, pixel_bottom, pixel_top);
|
||||
/* limit sun rotation between 0 and 360 degrees */
|
||||
sun_rotation = fmodf(sun_rotation, M_2PI_F);
|
||||
if (sun_rotation < 0.0f) {
|
||||
sun_rotation += M_2PI_F;
|
||||
}
|
||||
sun_rotation = M_2PI_F - sun_rotation;
|
||||
|
||||
/* send data to svm_sky */
|
||||
sunsky->nishita_data[0] = pixel_bottom[0];
|
||||
sunsky->nishita_data[1] = pixel_bottom[1];
|
||||
|
@ -873,6 +868,37 @@ NODE_DEFINE(SkyTextureNode)
|
|||
|
||||
SkyTextureNode::SkyTextureNode() : TextureNode(get_node_type()) {}
|
||||
|
||||
void SkyTextureNode::simplify_settings(Scene * /* scene */)
|
||||
{
|
||||
/* Patch sun position so users are able to animate the daylight cycle while keeping the shading
|
||||
* code simple. */
|
||||
float new_sun_elevation = sun_elevation;
|
||||
float new_sun_rotation = sun_rotation;
|
||||
|
||||
/* Wrap `new_sun_elevation` into [-2PI..2PI] range. */
|
||||
new_sun_elevation = fmodf(new_sun_elevation, M_2PI_F);
|
||||
/* Wrap `new_sun_elevation` into [-PI..PI] range. */
|
||||
if (fabsf(new_sun_elevation) >= M_PI_F) {
|
||||
new_sun_elevation -= copysignf(2.0f, new_sun_elevation) * M_PI_F;
|
||||
}
|
||||
/* Wrap `new_sun_elevation` into [-PI/2..PI/2] range while keeping the same absolute position. */
|
||||
if (new_sun_elevation >= M_PI_2_F || new_sun_elevation <= -M_PI_2_F) {
|
||||
new_sun_elevation = copysignf(M_PI_F, new_sun_elevation) - new_sun_elevation;
|
||||
new_sun_rotation += M_PI_F;
|
||||
}
|
||||
|
||||
/* Wrap `new_sun_rotation` into [-2PI..2PI] range. */
|
||||
new_sun_rotation = fmodf(new_sun_rotation, M_2PI_F);
|
||||
/* Wrap `new_sun_rotation` into [0..2PI] range. */
|
||||
if (new_sun_rotation < 0.0f) {
|
||||
new_sun_rotation += M_2PI_F;
|
||||
}
|
||||
new_sun_rotation = M_2PI_F - new_sun_rotation;
|
||||
|
||||
sun_elevation = new_sun_elevation;
|
||||
sun_rotation = new_sun_rotation;
|
||||
}
|
||||
|
||||
void SkyTextureNode::compile(SVMCompiler &compiler)
|
||||
{
|
||||
ShaderInput *vector_in = input("Vector");
|
||||
|
|
|
@ -167,6 +167,8 @@ class SkyTextureNode : public TextureNode {
|
|||
NODE_SOCKET_API(float3, vector)
|
||||
ImageHandle handle;
|
||||
|
||||
void simplify_settings(Scene *scene);
|
||||
|
||||
float get_sun_size()
|
||||
{
|
||||
/* Clamping for numerical precision. */
|
||||
|
|
|
@ -1046,7 +1046,7 @@ class I18nMessages:
|
|||
self.unescape()
|
||||
|
||||
def write(self, kind, dest):
|
||||
self.writers[kind](self, dest)
|
||||
return self.writers[kind](self, dest)
|
||||
|
||||
def write_messages_to_po(self, fname, compact=False):
|
||||
"""
|
||||
|
@ -1126,8 +1126,8 @@ class I18nMessages:
|
|||
"-o",
|
||||
fname,
|
||||
)
|
||||
ret = subprocess.call(cmd)
|
||||
return
|
||||
ret = subprocess.run(cmd, capture_output=True)
|
||||
return ret
|
||||
# XXX Code below is currently broken (generates corrupted mo files it seems :( )!
|
||||
# Using http://www.gnu.org/software/gettext/manual/html_node/MO-Files.html notation.
|
||||
# Not generating hash table!
|
||||
|
@ -1427,7 +1427,7 @@ class I18n:
|
|||
self.unescape()
|
||||
|
||||
def write(self, kind, langs=set()):
|
||||
self.writers[kind](self, langs)
|
||||
return self.writers[kind](self, langs)
|
||||
|
||||
def write_to_po(self, langs=set()):
|
||||
"""
|
||||
|
|
|
@ -96,7 +96,7 @@ class AddPresetBase:
|
|||
# Reset preset name
|
||||
wm = bpy.data.window_managers[0]
|
||||
if name == wm.preset_name:
|
||||
wm.preset_name = 'New Preset'
|
||||
wm.preset_name = data_('New Preset')
|
||||
|
||||
filename = self.as_filename(name)
|
||||
|
||||
|
|
|
@ -14,10 +14,48 @@ extern "C" {
|
|||
|
||||
struct LightProbe;
|
||||
struct Main;
|
||||
struct BlendWriter;
|
||||
struct BlendDataReader;
|
||||
struct LightProbeObjectCache;
|
||||
struct LightProbeGridCacheFrame;
|
||||
struct Object;
|
||||
|
||||
void BKE_lightprobe_type_set(struct LightProbe *probe, short lightprobe_type);
|
||||
void *BKE_lightprobe_add(struct Main *bmain, const char *name);
|
||||
|
||||
void BKE_lightprobe_cache_blend_write(struct BlendWriter *writer,
|
||||
struct LightProbeObjectCache *cache);
|
||||
|
||||
void BKE_lightprobe_cache_blend_read(struct BlendDataReader *reader,
|
||||
struct LightProbeObjectCache *cache);
|
||||
|
||||
/**
|
||||
* Create a single empty irradiance grid cache.
|
||||
*/
|
||||
struct LightProbeGridCacheFrame *BKE_lightprobe_grid_cache_frame_create(void);
|
||||
|
||||
/**
|
||||
* Free a single grid cache.
|
||||
*/
|
||||
void BKE_lightprobe_grid_cache_frame_free(struct LightProbeGridCacheFrame *cache);
|
||||
|
||||
/**
|
||||
* Create the grid cache list depending on the lightprobe baking settings.
|
||||
* The list is left empty to be filled by the baking process.
|
||||
*/
|
||||
void BKE_lightprobe_cache_create(struct Object *object);
|
||||
|
||||
/**
|
||||
* Free all irradiance grids allocated for the given object.
|
||||
*/
|
||||
void BKE_lightprobe_cache_free(struct Object *object);
|
||||
|
||||
/**
|
||||
* Return the number of sample stored inside an irradiance cache.
|
||||
* This depends on the light cache type.
|
||||
*/
|
||||
int64_t BKE_lightprobe_grid_cache_frame_sample_count(const struct LightProbeGridCacheFrame *cache);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -170,7 +170,10 @@ static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data)
|
|||
{
|
||||
const int cb_flag = cb_data->cb_flag;
|
||||
|
||||
if (cb_flag & (IDWALK_CB_EMBEDDED | IDWALK_CB_EMBEDDED_NOT_OWNING)) {
|
||||
/* NOTE: Support remapping of `IDWALK_CB_EMBEDDED_NON_OWNING` pointers, this is necessary in some
|
||||
* complex low-level ID manipulation cases (e.g. in ID swapping, see #BKE_lib_id_swap & co).
|
||||
*/
|
||||
if (cb_flag & IDWALK_CB_EMBEDDED) {
|
||||
return IDWALK_RET_NOP;
|
||||
}
|
||||
|
||||
|
@ -890,8 +893,8 @@ static void libblock_relink_to_newid_prepare_data(Main *bmain,
|
|||
static int id_relink_to_newid_looper(LibraryIDLinkCallbackData *cb_data)
|
||||
{
|
||||
const int cb_flag = cb_data->cb_flag;
|
||||
if (cb_flag & (IDWALK_CB_EMBEDDED | IDWALK_CB_EMBEDDED_NOT_OWNING |
|
||||
IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) {
|
||||
/* NOTE: For now, support remapping `IDWALK_CB_EMBEDDED_NON_OWNING` pointers. */
|
||||
if (cb_flag & (IDWALK_CB_EMBEDDED | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) {
|
||||
return IDWALK_RET_NOP;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include "DNA_lightprobe_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BLI_math_base.h"
|
||||
#include "BLI_span.hh"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BKE_anim_data.h"
|
||||
|
@ -129,3 +131,137 @@ void *BKE_lightprobe_add(Main *bmain, const char *name)
|
|||
|
||||
return probe;
|
||||
}
|
||||
|
||||
static void lightprobe_grid_cache_frame_blend_write(BlendWriter *writer,
|
||||
const LightProbeGridCacheFrame *cache)
|
||||
{
|
||||
BLO_write_struct_array(writer, LightProbeGridCacheFrame, cache->block_len, cache->block_infos);
|
||||
|
||||
int64_t sample_count = BKE_lightprobe_grid_cache_frame_sample_count(cache);
|
||||
|
||||
BLO_write_float3_array(writer, sample_count, (float *)cache->irradiance.L0);
|
||||
BLO_write_float3_array(writer, sample_count, (float *)cache->irradiance.L1_a);
|
||||
BLO_write_float3_array(writer, sample_count, (float *)cache->irradiance.L1_b);
|
||||
BLO_write_float3_array(writer, sample_count, (float *)cache->irradiance.L1_c);
|
||||
|
||||
BLO_write_float_array(writer, sample_count, cache->visibility.L0);
|
||||
BLO_write_float_array(writer, sample_count, cache->visibility.L1_a);
|
||||
BLO_write_float_array(writer, sample_count, cache->visibility.L1_b);
|
||||
BLO_write_float_array(writer, sample_count, cache->visibility.L1_c);
|
||||
|
||||
BLO_write_struct_array(
|
||||
writer, LightProbeGridCacheFrame, sample_count, cache->connectivity.bitmask);
|
||||
}
|
||||
|
||||
static void lightprobe_grid_cache_frame_blend_read(BlendDataReader *reader,
|
||||
LightProbeGridCacheFrame *cache)
|
||||
{
|
||||
if (!ELEM(cache->data_layout,
|
||||
LIGHTPROBE_CACHE_ADAPTIVE_RESOLUTION,
|
||||
LIGHTPROBE_CACHE_UNIFORM_GRID)) {
|
||||
/* Do not try to read data from incompatible layout. Clear all pointers. */
|
||||
memset(cache, 0, sizeof(*cache));
|
||||
return;
|
||||
}
|
||||
|
||||
BLO_read_data_address(reader, &cache->block_infos);
|
||||
|
||||
int64_t sample_count = BKE_lightprobe_grid_cache_frame_sample_count(cache);
|
||||
|
||||
/* Baking data is not stored. */
|
||||
cache->baking.L0 = nullptr;
|
||||
cache->baking.L1_a = nullptr;
|
||||
cache->baking.L1_b = nullptr;
|
||||
cache->baking.L1_c = nullptr;
|
||||
cache->surfels = nullptr;
|
||||
cache->surfels_len = 0;
|
||||
|
||||
BLO_read_float3_array(reader, sample_count, (float **)&cache->irradiance.L0);
|
||||
BLO_read_float3_array(reader, sample_count, (float **)&cache->irradiance.L1_a);
|
||||
BLO_read_float3_array(reader, sample_count, (float **)&cache->irradiance.L1_b);
|
||||
BLO_read_float3_array(reader, sample_count, (float **)&cache->irradiance.L1_c);
|
||||
|
||||
BLO_read_float_array(reader, sample_count, &cache->visibility.L0);
|
||||
BLO_read_float_array(reader, sample_count, &cache->visibility.L1_a);
|
||||
BLO_read_float_array(reader, sample_count, &cache->visibility.L1_b);
|
||||
BLO_read_float_array(reader, sample_count, &cache->visibility.L1_c);
|
||||
|
||||
BLO_read_data_address(reader, &cache->connectivity.bitmask);
|
||||
}
|
||||
|
||||
void BKE_lightprobe_cache_blend_write(BlendWriter *writer, LightProbeObjectCache *cache)
|
||||
{
|
||||
if (cache->grid_static_cache != nullptr) {
|
||||
BLO_write_struct(writer, LightProbeGridCacheFrame, cache->grid_static_cache);
|
||||
lightprobe_grid_cache_frame_blend_write(writer, cache->grid_static_cache);
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_lightprobe_cache_blend_read(BlendDataReader *reader, LightProbeObjectCache *cache)
|
||||
{
|
||||
if (cache->grid_static_cache != nullptr) {
|
||||
BLO_read_data_address(reader, &cache->grid_static_cache);
|
||||
lightprobe_grid_cache_frame_blend_read(reader, cache->grid_static_cache);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T> static void spherical_harmonic_free(T &data)
|
||||
{
|
||||
MEM_SAFE_FREE(data.L0);
|
||||
MEM_SAFE_FREE(data.L1_a);
|
||||
MEM_SAFE_FREE(data.L1_b);
|
||||
MEM_SAFE_FREE(data.L1_c);
|
||||
}
|
||||
|
||||
LightProbeGridCacheFrame *BKE_lightprobe_grid_cache_frame_create()
|
||||
{
|
||||
LightProbeGridCacheFrame *cache = static_cast<LightProbeGridCacheFrame *>(
|
||||
MEM_callocN(sizeof(LightProbeGridCacheFrame), "LightProbeGridCacheFrame"));
|
||||
return cache;
|
||||
}
|
||||
|
||||
void BKE_lightprobe_grid_cache_frame_free(LightProbeGridCacheFrame *cache)
|
||||
{
|
||||
MEM_SAFE_FREE(cache->block_infos);
|
||||
spherical_harmonic_free(cache->baking);
|
||||
spherical_harmonic_free(cache->irradiance);
|
||||
spherical_harmonic_free(cache->visibility);
|
||||
MEM_SAFE_FREE(cache->connectivity.bitmask);
|
||||
MEM_SAFE_FREE(cache->surfels);
|
||||
|
||||
MEM_SAFE_FREE(cache);
|
||||
}
|
||||
|
||||
void BKE_lightprobe_cache_create(Object *object)
|
||||
{
|
||||
BLI_assert(object->lightprobe_cache == nullptr);
|
||||
|
||||
object->lightprobe_cache = static_cast<LightProbeObjectCache *>(
|
||||
MEM_callocN(sizeof(LightProbeObjectCache), "LightProbeObjectCache"));
|
||||
}
|
||||
|
||||
void BKE_lightprobe_cache_free(Object *object)
|
||||
{
|
||||
if (object->lightprobe_cache == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
LightProbeObjectCache *cache = object->lightprobe_cache;
|
||||
|
||||
if (cache->shared == false) {
|
||||
if (cache->grid_static_cache != nullptr) {
|
||||
BKE_lightprobe_grid_cache_frame_free(cache->grid_static_cache);
|
||||
}
|
||||
}
|
||||
|
||||
MEM_SAFE_FREE(object->lightprobe_cache);
|
||||
}
|
||||
|
||||
int64_t BKE_lightprobe_grid_cache_frame_sample_count(const LightProbeGridCacheFrame *cache)
|
||||
{
|
||||
if (cache->data_layout == LIGHTPROBE_CACHE_ADAPTIVE_RESOLUTION) {
|
||||
return cache->block_len * cube_i(cache->block_size);
|
||||
}
|
||||
/* LIGHTPROBE_CACHE_UNIFORM_GRID */
|
||||
return cache->size[0] * cache->size[1] * cache->size[2];
|
||||
}
|
||||
|
|
|
@ -267,6 +267,18 @@ static void object_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const in
|
|||
if (ob_src->lightgroup) {
|
||||
ob_dst->lightgroup = (LightgroupMembership *)MEM_dupallocN(ob_src->lightgroup);
|
||||
}
|
||||
|
||||
if ((flag & LIB_ID_COPY_SET_COPIED_ON_WRITE) != 0) {
|
||||
if (ob_src->lightprobe_cache) {
|
||||
/* Reference the original object data. */
|
||||
ob_dst->lightprobe_cache = (LightProbeObjectCache *)MEM_dupallocN(ob_src->lightprobe_cache);
|
||||
ob_dst->lightprobe_cache->shared = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Do not copy lightprobe's cache. */
|
||||
ob_dst->lightprobe_cache = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static void object_free_data(ID *id)
|
||||
|
@ -319,6 +331,8 @@ static void object_free_data(ID *id)
|
|||
BKE_previewimg_free(&ob->preview);
|
||||
|
||||
MEM_SAFE_FREE(ob->lightgroup);
|
||||
|
||||
BKE_lightprobe_cache_free(ob);
|
||||
}
|
||||
|
||||
static void library_foreach_modifiersForeachIDLink(void *user_data,
|
||||
|
@ -597,6 +611,11 @@ static void object_blend_write(BlendWriter *writer, ID *id, const void *id_addre
|
|||
if (ob->lightgroup) {
|
||||
BLO_write_struct(writer, LightgroupMembership, ob->lightgroup);
|
||||
}
|
||||
|
||||
if (ob->lightprobe_cache) {
|
||||
BLO_write_struct(writer, LightProbeObjectCache, ob->lightprobe_cache);
|
||||
BKE_lightprobe_cache_blend_write(writer, ob->lightprobe_cache);
|
||||
}
|
||||
}
|
||||
|
||||
/* XXX deprecated - old animation system */
|
||||
|
@ -815,6 +834,11 @@ static void object_blend_read_data(BlendDataReader *reader, ID *id)
|
|||
BKE_previewimg_blend_read(reader, ob->preview);
|
||||
|
||||
BLO_read_data_address(reader, &ob->lightgroup);
|
||||
|
||||
BLO_read_data_address(reader, &ob->lightprobe_cache);
|
||||
if (ob->lightprobe_cache) {
|
||||
BKE_lightprobe_cache_blend_read(reader, ob->lightprobe_cache);
|
||||
}
|
||||
}
|
||||
|
||||
/* XXX deprecated - old animation system */
|
||||
|
|
|
@ -3104,6 +3104,7 @@ static void read_libblock_undo_restore_at_old_address(FileData *fd, Main *main,
|
|||
* lib-linking to restore some data that should never be affected by undo, e.g. the 3D cursor of
|
||||
* #Scene. */
|
||||
id_old->orig_id = id;
|
||||
id_old->tag |= LIB_TAG_UNDO_OLD_ID_REREAD_IN_PLACE;
|
||||
|
||||
BLI_addtail(new_lb, id_old);
|
||||
BLI_addtail(old_lb, id);
|
||||
|
@ -3122,18 +3123,21 @@ static bool read_libblock_undo_restore(
|
|||
return true;
|
||||
}
|
||||
}
|
||||
else if (id_type->flags & IDTYPE_FLAGS_NO_MEMFILE_UNDO) {
|
||||
/* Skip reading any 'no undo' datablocks (typically UI-like ones), existing ones are kept.
|
||||
* See `setup_app_data` for details. */
|
||||
CLOG_INFO(&LOG_UNDO,
|
||||
2,
|
||||
"UNDO: skip restore datablock %s, 'NO_MEMFILE_UNDO' type of ID",
|
||||
id->name);
|
||||
return true;
|
||||
}
|
||||
else if (bhead->code == ID_LINK_PLACEHOLDER) {
|
||||
/* Restore linked datablock. */
|
||||
if (read_libblock_undo_restore_linked(fd, main, id, bhead)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (id_type->flags & IDTYPE_FLAGS_NO_MEMFILE_UNDO) {
|
||||
/* Skip reading any UI datablocks, existing ones are kept. We don't
|
||||
* support pointers from other datablocks to UI datablocks so those
|
||||
* we also don't put UI datablocks in fd->libmap. */
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Restore local datablocks. */
|
||||
ID *id_old = nullptr;
|
||||
|
|
|
@ -41,6 +41,9 @@ void SCENE_OT_view_layer_remove_unused_lightgroups(struct wmOperatorType *ot);
|
|||
void SCENE_OT_light_cache_bake(struct wmOperatorType *ot);
|
||||
void SCENE_OT_light_cache_free(struct wmOperatorType *ot);
|
||||
|
||||
void OBJECT_OT_lightprobe_cache_bake(struct wmOperatorType *ot);
|
||||
void OBJECT_OT_lightprobe_cache_free(struct wmOperatorType *ot);
|
||||
|
||||
void SCENE_OT_render_view_add(struct wmOperatorType *ot);
|
||||
void SCENE_OT_render_view_remove(struct wmOperatorType *ot);
|
||||
|
||||
|
|
|
@ -28,6 +28,9 @@ void ED_operatortypes_render()
|
|||
WM_operatortype_append(OBJECT_OT_material_slot_move);
|
||||
WM_operatortype_append(OBJECT_OT_material_slot_remove_unused);
|
||||
|
||||
WM_operatortype_append(OBJECT_OT_lightprobe_cache_bake);
|
||||
WM_operatortype_append(OBJECT_OT_lightprobe_cache_free);
|
||||
|
||||
WM_operatortype_append(MATERIAL_OT_new);
|
||||
WM_operatortype_append(TEXTURE_OT_new);
|
||||
WM_operatortype_append(WORLD_OT_new);
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "BKE_image.h"
|
||||
#include "BKE_layer.h"
|
||||
#include "BKE_lib_id.h"
|
||||
#include "BKE_lightprobe.h"
|
||||
#include "BKE_linestyle.h"
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_material.h"
|
||||
|
@ -53,6 +54,7 @@
|
|||
|
||||
#include "DEG_depsgraph.h"
|
||||
#include "DEG_depsgraph_build.h"
|
||||
#include "DEG_depsgraph_query.h"
|
||||
|
||||
#ifdef WITH_FREESTYLE
|
||||
# include "BKE_freestyle.h"
|
||||
|
@ -1332,6 +1334,8 @@ enum {
|
|||
LIGHTCACHE_SUBSET_ALL = 0,
|
||||
LIGHTCACHE_SUBSET_DIRTY,
|
||||
LIGHTCACHE_SUBSET_CUBE,
|
||||
LIGHTCACHE_SUBSET_SELECTED,
|
||||
LIGHTCACHE_SUBSET_ACTIVE,
|
||||
};
|
||||
|
||||
static void light_cache_bake_tag_cache(Scene *scene, wmOperator *op)
|
||||
|
@ -1348,6 +1352,9 @@ static void light_cache_bake_tag_cache(Scene *scene, wmOperator *op)
|
|||
case LIGHTCACHE_SUBSET_DIRTY:
|
||||
/* Leave tag untouched. */
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1492,6 +1499,169 @@ void SCENE_OT_light_cache_bake(wmOperatorType *ot)
|
|||
RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
|
||||
}
|
||||
|
||||
/* NOTE: New version destined to replace the old lightcache bake operator. */
|
||||
|
||||
static void lightprobe_cache_bake_start(bContext *C, wmOperator *op)
|
||||
{
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
|
||||
auto is_irradiance_volume = [](Object *ob) -> bool {
|
||||
return ob->type == OB_LIGHTPROBE &&
|
||||
static_cast<LightProbe *>(ob->data)->type == LIGHTPROBE_TYPE_GRID;
|
||||
};
|
||||
|
||||
auto irradiance_volume_setup = [](Object *ob) {
|
||||
BKE_lightprobe_cache_free(ob);
|
||||
BKE_lightprobe_cache_create(ob);
|
||||
DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
|
||||
};
|
||||
|
||||
int subset = RNA_enum_get(op->ptr, "subset");
|
||||
switch (subset) {
|
||||
case LIGHTCACHE_SUBSET_ALL: {
|
||||
FOREACH_OBJECT_BEGIN (scene, view_layer, ob) {
|
||||
if (is_irradiance_volume(ob)) {
|
||||
irradiance_volume_setup(ob);
|
||||
}
|
||||
}
|
||||
FOREACH_OBJECT_END;
|
||||
break;
|
||||
}
|
||||
case LIGHTCACHE_SUBSET_DIRTY: {
|
||||
FOREACH_OBJECT_BEGIN (scene, view_layer, ob) {
|
||||
if (is_irradiance_volume(ob) && ob->lightprobe_cache && ob->lightprobe_cache->dirty) {
|
||||
irradiance_volume_setup(ob);
|
||||
}
|
||||
}
|
||||
FOREACH_OBJECT_END;
|
||||
break;
|
||||
}
|
||||
case LIGHTCACHE_SUBSET_SELECTED: {
|
||||
uint objects_len = 0;
|
||||
ObjectsInViewLayerParams parameters;
|
||||
parameters.filter_fn = nullptr;
|
||||
parameters.no_dup_data = true;
|
||||
Object **objects = BKE_view_layer_array_selected_objects_params(
|
||||
view_layer, nullptr, &objects_len, ¶meters);
|
||||
for (Object *ob : blender::MutableSpan<Object *>(objects, objects_len)) {
|
||||
if (is_irradiance_volume(ob)) {
|
||||
irradiance_volume_setup(ob);
|
||||
}
|
||||
}
|
||||
MEM_freeN(objects);
|
||||
break;
|
||||
}
|
||||
case LIGHTCACHE_SUBSET_ACTIVE: {
|
||||
Object *active_ob = CTX_data_active_object(C);
|
||||
if (is_irradiance_volume(active_ob)) {
|
||||
irradiance_volume_setup(active_ob);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int lightprobe_cache_bake_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
|
||||
lightprobe_cache_bake_start(C, op);
|
||||
|
||||
WM_event_add_modal_handler(C, op);
|
||||
|
||||
/* store actual owner of job, so modal operator could check for it,
|
||||
* the reason of this is that active scene could change when rendering
|
||||
* several layers from compositor #31800. */
|
||||
op->customdata = scene;
|
||||
|
||||
WM_cursor_wait(false);
|
||||
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
static int lightprobe_cache_bake_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
Scene *scene = (Scene *)op->customdata;
|
||||
|
||||
/* No running bake, remove handler and pass through. */
|
||||
if (0 == WM_jobs_test(CTX_wm_manager(C), scene, WM_JOB_TYPE_LIGHT_BAKE)) {
|
||||
return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
/* Running bake. */
|
||||
switch (event->type) {
|
||||
case EVT_ESCKEY:
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
return OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
static void lightprobe_cache_bake_cancel(bContext *C, wmOperator *op)
|
||||
{
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
Scene *scene = (Scene *)op->customdata;
|
||||
|
||||
/* Kill on cancel, because job is using op->reports. */
|
||||
WM_jobs_kill_type(wm, scene, WM_JOB_TYPE_LIGHT_BAKE);
|
||||
}
|
||||
|
||||
/* Executes blocking bake. */
|
||||
static int lightprobe_cache_bake_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
lightprobe_cache_bake_start(C, op);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void OBJECT_OT_lightprobe_cache_bake(wmOperatorType *ot)
|
||||
{
|
||||
static const EnumPropertyItem light_cache_subset_items[] = {
|
||||
{LIGHTCACHE_SUBSET_ALL, "ALL", 0, "All Light Probes", "Bake all light probes"},
|
||||
{LIGHTCACHE_SUBSET_DIRTY,
|
||||
"DIRTY",
|
||||
0,
|
||||
"Dirty Only",
|
||||
"Only bake light probes that are marked as dirty"},
|
||||
{LIGHTCACHE_SUBSET_SELECTED,
|
||||
"SELECTED",
|
||||
0,
|
||||
"Selected Only",
|
||||
"Only bake selected light probes"},
|
||||
{LIGHTCACHE_SUBSET_ACTIVE, "ACTIVE", 0, "Active Only", "Only bake the active light probe"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
/* identifiers */
|
||||
ot->name = "Bake Light Cache";
|
||||
ot->idname = "OBJECT_OT_lightprobe_cache_bake";
|
||||
ot->description = "Bake the active view layer lighting";
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke = lightprobe_cache_bake_invoke;
|
||||
ot->modal = lightprobe_cache_bake_modal;
|
||||
ot->cancel = lightprobe_cache_bake_cancel;
|
||||
ot->exec = lightprobe_cache_bake_exec;
|
||||
|
||||
ot->prop = RNA_def_int(ot->srna,
|
||||
"delay",
|
||||
0,
|
||||
0,
|
||||
2000,
|
||||
"Delay",
|
||||
"Delay in millisecond before baking starts",
|
||||
0,
|
||||
2000);
|
||||
RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
|
||||
|
||||
ot->prop = RNA_def_enum(
|
||||
ot->srna, "subset", light_cache_subset_items, 0, "Subset", "Subset of probes to update");
|
||||
RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@ -1541,6 +1711,49 @@ void SCENE_OT_light_cache_free(wmOperatorType *ot)
|
|||
ot->poll = light_cache_free_poll;
|
||||
}
|
||||
|
||||
/* NOTE: New version destined to replace the old lightcache bake operator. */
|
||||
|
||||
static bool lightprobe_cache_free_poll(bContext *C)
|
||||
{
|
||||
Object *object = CTX_data_active_object(C);
|
||||
|
||||
return object && object->lightprobe_cache != nullptr;
|
||||
}
|
||||
|
||||
static int lightprobe_cache_free_exec(bContext *C, wmOperator * /*op*/)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
Object *object = CTX_data_active_object(C);
|
||||
|
||||
/* Kill potential bake job first (see #57011). */
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
WM_jobs_kill_type(wm, scene, WM_JOB_TYPE_LIGHT_BAKE);
|
||||
|
||||
if (object->lightprobe_cache == nullptr) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
BKE_lightprobe_cache_free(object);
|
||||
|
||||
DEG_id_tag_update(&object->id, ID_RECALC_COPY_ON_WRITE);
|
||||
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, scene);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void OBJECT_OT_lightprobe_cache_free(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Delete Light Cache";
|
||||
ot->idname = "OBJECT_OT_lightprobe_cache_free";
|
||||
ot->description = "Delete cached indirect lighting";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = lightprobe_cache_free_exec;
|
||||
ot->poll = lightprobe_cache_free_poll;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
|
|
@ -159,7 +159,7 @@ static void createTransMeshSkin(bContext *UNUSED(C), TransInfo *t)
|
|||
|
||||
if (mirror_data.vert_map) {
|
||||
tc->data_mirror_len = mirror_data.mirror_elem_len;
|
||||
tc->data_mirror = MEM_mallocN(mirror_data.mirror_elem_len * sizeof(*tc->data_mirror),
|
||||
tc->data_mirror = MEM_callocN(mirror_data.mirror_elem_len * sizeof(*tc->data_mirror),
|
||||
__func__);
|
||||
|
||||
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) {
|
||||
|
|
|
@ -239,21 +239,39 @@ static void memfile_undosys_step_decode(struct bContext *C,
|
|||
bmain, id, memfile_undosys_step_id_reused_cb, nullptr, IDWALK_READONLY);
|
||||
}
|
||||
|
||||
/* NOTE: Tagging `ID_RECALC_COPY_ON_WRITE` here should not be needed in practice, since
|
||||
* modified IDs should already have other depsgraph update tags anyway. However, for sakes of
|
||||
* consistency, it's better to effectively use it, since content of that ID pointer does have
|
||||
* been modified. */
|
||||
unsigned int recalc_flags = id->recalc | ((id->tag & LIB_TAG_UNDO_OLD_ID_REREAD_IN_PLACE) ?
|
||||
ID_RECALC_COPY_ON_WRITE :
|
||||
0);
|
||||
/* Tag depsgraph to update data-block for changes that happened between the
|
||||
* current and the target state, see direct_link_id_restore_recalc(). */
|
||||
if (id->recalc != 0) {
|
||||
DEG_id_tag_update_ex(bmain, id, id->recalc);
|
||||
if (recalc_flags != 0) {
|
||||
DEG_id_tag_update_ex(bmain, id, recalc_flags);
|
||||
}
|
||||
|
||||
bNodeTree *nodetree = ntreeFromID(id);
|
||||
if (nodetree != nullptr && nodetree->id.recalc != 0) {
|
||||
DEG_id_tag_update_ex(bmain, &nodetree->id, nodetree->id.recalc);
|
||||
if (nodetree != nullptr) {
|
||||
recalc_flags = nodetree->id.recalc;
|
||||
if (id->tag & LIB_TAG_UNDO_OLD_ID_REREAD_IN_PLACE) {
|
||||
recalc_flags |= ID_RECALC_COPY_ON_WRITE;
|
||||
}
|
||||
if (recalc_flags != 0) {
|
||||
DEG_id_tag_update_ex(bmain, &nodetree->id, recalc_flags);
|
||||
}
|
||||
}
|
||||
if (GS(id->name) == ID_SCE) {
|
||||
Scene *scene = (Scene *)id;
|
||||
if (scene->master_collection != nullptr && scene->master_collection->id.recalc != 0) {
|
||||
DEG_id_tag_update_ex(
|
||||
bmain, &scene->master_collection->id, scene->master_collection->id.recalc);
|
||||
if (scene->master_collection != nullptr) {
|
||||
recalc_flags = scene->master_collection->id.recalc;
|
||||
if (id->tag & LIB_TAG_UNDO_OLD_ID_REREAD_IN_PLACE) {
|
||||
recalc_flags |= ID_RECALC_COPY_ON_WRITE;
|
||||
}
|
||||
if (recalc_flags != 0) {
|
||||
DEG_id_tag_update_ex(bmain, &scene->master_collection->id, recalc_flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -264,7 +282,7 @@ static void memfile_undosys_step_decode(struct bContext *C,
|
|||
|
||||
FOREACH_MAIN_ID_BEGIN (bmain, id) {
|
||||
/* Clear temporary tag. */
|
||||
id->tag &= ~LIB_TAG_UNDO_OLD_ID_REUSED;
|
||||
id->tag &= ~(LIB_TAG_UNDO_OLD_ID_REUSED | LIB_TAG_UNDO_OLD_ID_REREAD_IN_PLACE);
|
||||
|
||||
/* We only start accumulating from this point, any tags set up to here
|
||||
* are already part of the current undo state. This is done in a second
|
||||
|
|
|
@ -485,6 +485,12 @@ void AbstractHierarchyIterator::context_update_for_graph_index(
|
|||
{
|
||||
/* Update the HierarchyContext so that it is consistent with the graph index. */
|
||||
context->export_parent = graph_index.object;
|
||||
|
||||
/* If the parent type is such that it cannot be exported (at least not currently to USD or
|
||||
* Alembic), always check the parent for animation. */
|
||||
const short partype = context->object->partype & PARTYPE;
|
||||
context->animation_check_include_parent |= ELEM(partype, PARBONE, PARVERT1, PARVERT3, PARSKEL);
|
||||
|
||||
if (context->export_parent != context->object->parent) {
|
||||
/* The parent object in Blender is NOT used as the export parent. This means
|
||||
* that the world transform of this object can be influenced by objects that
|
||||
|
|
|
@ -840,6 +840,13 @@ enum {
|
|||
* RESET_AFTER_USE
|
||||
*/
|
||||
LIB_TAG_UNDO_OLD_ID_REUSED = 1 << 17,
|
||||
/**
|
||||
* ID has be re-read in-place, the ID address is the same as in the old BMain, but the content is
|
||||
* different.
|
||||
*
|
||||
* RESET_AFTER_USE
|
||||
*/
|
||||
LIB_TAG_UNDO_OLD_ID_REREAD_IN_PLACE = 1 << 18,
|
||||
|
||||
/* ------------------------------------------------------------------------------------------- */
|
||||
/**
|
||||
|
|
|
@ -61,9 +61,6 @@ typedef struct LightProbe {
|
|||
struct Image *image;
|
||||
/** Object visibility group, inclusive or exclusive. */
|
||||
struct Collection *visibility_grp;
|
||||
|
||||
/* Runtime display data */
|
||||
float distfalloff, distgridinf;
|
||||
} LightProbe;
|
||||
|
||||
/* Probe->type */
|
||||
|
@ -201,6 +198,137 @@ enum {
|
|||
LIGHTCACHETEX_UINT = (1 << 2),
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Irradiance grid data storage
|
||||
*
|
||||
* Each spherical harmonic band is stored separately. This allow loading only a specific band.
|
||||
* The layout of each array is set by the #LightProbeGridType.
|
||||
* Any unavailable data is be set to nullptr.
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* Irradiance data (RGB) stored along visibility (A).
|
||||
* This is the format used during baking and is used for visualizing the baking process.
|
||||
*/
|
||||
typedef struct LightProbeBakingData {
|
||||
float (*L0)[4];
|
||||
float (*L1_a)[4];
|
||||
float (*L1_b)[4];
|
||||
float (*L1_c)[4];
|
||||
} LightProbeBakingData;
|
||||
|
||||
/**
|
||||
* Irradiance stored as RGB triple using scene linear color space.
|
||||
*/
|
||||
typedef struct LightProbeIrradianceData {
|
||||
float (*L0)[3];
|
||||
float (*L1_a)[3];
|
||||
float (*L1_b)[3];
|
||||
float (*L1_c)[3];
|
||||
} LightProbeIrradianceData;
|
||||
|
||||
/**
|
||||
* Normalized visibility of distant light. Used for compositing grids together.
|
||||
*/
|
||||
typedef struct LightProbeVisibilityData {
|
||||
float *L0;
|
||||
float *L1_a;
|
||||
float *L1_b;
|
||||
float *L1_c;
|
||||
} LightProbeVisibilityData;
|
||||
|
||||
/**
|
||||
* Used to avoid light leaks. Validate visibility between each grid sample.
|
||||
*/
|
||||
typedef struct LightProbeConnectivityData {
|
||||
/** Stores a bitmask of valid connections within a cell. */
|
||||
uint8_t *bitmask;
|
||||
} LightProbeConnectivityData;
|
||||
|
||||
/**
|
||||
* Defines one block of data inside the grid cache data arrays.
|
||||
* The block size if the same for all the blocks.
|
||||
*/
|
||||
typedef struct LightProbeBlockData {
|
||||
/* Offset inside the level-of-detail this block starts. */
|
||||
int offset[3];
|
||||
/* Level-of-detail this block is from. */
|
||||
int level;
|
||||
} LightProbeBlockData;
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name LightProbeGridCacheFrame
|
||||
*
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* A frame worth of baked lighting data.
|
||||
*/
|
||||
typedef struct LightProbeGridCacheFrame {
|
||||
/** Number of samples in the highest level of detail. */
|
||||
int size[3];
|
||||
/** Spatial layout type of the data stored inside the data arrays. */
|
||||
int data_layout;
|
||||
|
||||
/** Sparse or adaptive layout only: number of blocks inside data arrays. */
|
||||
int block_len;
|
||||
/** Sparse or adaptive layout only: size of a block in samples. All 3 dimensions are equal. */
|
||||
int block_size;
|
||||
/** Sparse or adaptive layout only: specify the blocks positions. */
|
||||
LightProbeBlockData *block_infos;
|
||||
|
||||
/** In-progress baked data. Not stored in file. */
|
||||
LightProbeBakingData baking;
|
||||
/** Baked data. */
|
||||
LightProbeIrradianceData irradiance;
|
||||
LightProbeVisibilityData visibility;
|
||||
LightProbeConnectivityData connectivity;
|
||||
|
||||
char _pad[4];
|
||||
|
||||
/** Number of debug surfels. */
|
||||
int surfels_len;
|
||||
/** Debug surfels used to visualize the baking process. Not stored in file. */
|
||||
void *surfels;
|
||||
} LightProbeGridCacheFrame;
|
||||
|
||||
/** #LightProbeGridCacheFrame.data_layout (int) */
|
||||
enum {
|
||||
/** Simple uniform grid. Raw output from GPU. Used during the baking process. */
|
||||
LIGHTPROBE_CACHE_UNIFORM_GRID = 0,
|
||||
/** Fills the space with different level of resolution. More efficient storage. */
|
||||
LIGHTPROBE_CACHE_ADAPTIVE_RESOLUTION = 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* Per object container of baked data.
|
||||
* Should be called #LightProbeCache but name is already taken.
|
||||
*/
|
||||
typedef struct LightProbeObjectCache {
|
||||
/** Allow correct versioning / different types of data for the same layout. */
|
||||
int cache_type;
|
||||
/** True if this cache references the original object's cache. */
|
||||
char shared;
|
||||
/** True if the cache has been tagged for automatic baking. */
|
||||
char dirty;
|
||||
|
||||
char _pad0[2];
|
||||
|
||||
struct LightProbeGridCacheFrame *grid_static_cache;
|
||||
} LightProbeObjectCache;
|
||||
|
||||
/** #LightProbeObjectCache.type (int) */
|
||||
enum {
|
||||
/** Light cache was just created and is not yet baked. Keep as 0 for default value. */
|
||||
LIGHTPROBE_CACHE_TYPE_NONE = 0,
|
||||
/** Light cache is baked for one specific frame and capture all indirect lighting. */
|
||||
LIGHTPROBE_CACHE_TYPE_STATIC = 1,
|
||||
};
|
||||
|
||||
/** \} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -34,6 +34,7 @@ struct FluidsimSettings;
|
|||
struct GeometrySet;
|
||||
struct Ipo;
|
||||
struct LightgroupMembership;
|
||||
struct LightProbeGridCacheFrame;
|
||||
struct Material;
|
||||
struct Mesh;
|
||||
struct Object;
|
||||
|
@ -449,6 +450,11 @@ typedef struct Object {
|
|||
/** Lightgroup membership information. */
|
||||
struct LightgroupMembership *lightgroup;
|
||||
|
||||
/** Irradiance caches baked for this object (light-probes only). */
|
||||
struct LightProbeObjectCache *lightprobe_cache;
|
||||
|
||||
void *_pad9;
|
||||
|
||||
/** Runtime evaluation data (keep last). */
|
||||
Object_Runtime runtime;
|
||||
} Object;
|
||||
|
|
Loading…
Reference in New Issue