Cycles: Display RenderPass in Viewport

This change allows the user to select a renderpass in the 3d viewport.

Added support for external renderers to extend the `View3DShading` struct.
This way Blender doesn't need to know the features an external render engine wants to support.
Note that the View3DShading is also available in the scene->display.shading; although this is
supported, it does not make sense for render engines to put something here as it is really
scene/workbench related.

Currently cycles assumes that it always needs to calculate the combined pass; it ignores the
`pass_flag` in KernelFilm. We could optimize this but that was not in scope of this change

Reviewed By: brecht

Differential Revision: https://developer.blender.org/D5689
This commit is contained in:
Jeroen Bakker 2019-09-05 12:47:20 +02:00
parent d4f8bc80a4
commit 7e61e59725
Notes: blender-bot 2023-07-10 10:12:37 +02:00
Referenced by commit 1cb938ef2c, Cycles: Fix viewport rendering when displaying as byte and not half float
20 changed files with 330 additions and 61 deletions

View File

@ -151,6 +151,44 @@ enum_texture_limit = (
('8192', "8192", "Limit texture size to 8192 pixels", 7),
)
enum_view3d_shading_render_pass= (
('', "General", ""),
('COMBINED', "Combined", "Show the Combined Render pass", 1),
('EMISSION', "Emission", "Show the Emission render pass", 33),
('BACKGROUND', "Background", "Show the Background render pass", 34),
('AO', "Ambient Occlusion", "Show the Ambient Occlusion render pass", 35),
('', "Light", ""),
('DIFFUSE_DIRECT', "Diffuse Direct", "Show the Diffuse Direct render pass", 38),
('DIFFUSE_INDIRECT', "Diffuse Indirect", "Show the Diffuse Indirect render pass", 39),
('DIFFUSE_COLOR', "Diffuse Color", "Show the Diffuse Color render pass", 40),
('GLOSSY_DIRECT', "Glossy Direct", "Show the Glossy Direct render pass", 41),
('GLOSSY_INDIRECT', "Glossy Indirect", "Show the Glossy Indirect render pass", 42),
('GLOSSY_COLOR', "Glossy Color", "Show the Glossy Color render pass", 43),
('', "", ""),
('TRANSMISSION_DIRECT', "Transmission Direct", "Show the Transmission Direct render pass", 44),
('TRANSMISSION_INDIRECT', "Transmission Indirect", "Show the Transmission Indirect render pass", 45),
('TRANSMISSION_COLOR', "Transmission Color", "Show the Transmission Color render pass", 46),
('SUBSURFACE_DIRECT', "Subsurface Direct", "Show the Subsurface Direct render pass", 47),
('SUBSURFACE_INDIRECT', "Subsurface Indirect", "Show the Subsurface Indirect render pass", 48),
('SUBSURFACE_COLOR', "Subsurface Color", "Show the Subsurface Color render pass", 49),
('VOLUME_DIRECT', "Volume Direct", "Show the Volume Direct render pass", 50),
('VOLUME_INDIRECT', "Volume Indirect", "Show the Volume Indirect render pass", 51),
('', "Data", ""),
('NORMAL', "Normal", "Show the Normal render pass", 3),
('UV', "UV", "Show the UV render pass", 4),
('MIST', "Mist", "Show the Mist render pass", 32),
)
class CyclesRenderSettings(bpy.types.PropertyGroup):
@ -1475,6 +1513,15 @@ class CyclesPreferences(bpy.types.AddonPreferences):
self.draw_impl(self.layout, context)
class CyclesView3DShadingSettings(bpy.types.PropertyGroup):
render_pass: EnumProperty(
name="Render Pass",
description="Render pass to show in the 3D Viewport",
items=enum_view3d_shading_render_pass,
default='COMBINED',
)
def register():
bpy.utils.register_class(CyclesRenderSettings)
bpy.utils.register_class(CyclesCameraSettings)
@ -1488,6 +1535,12 @@ def register():
bpy.utils.register_class(CyclesDeviceSettings)
bpy.utils.register_class(CyclesPreferences)
bpy.utils.register_class(CyclesRenderLayerSettings)
bpy.utils.register_class(CyclesView3DShadingSettings)
bpy.types.View3DShading.cycles = bpy.props.PointerProperty(
name="Cycles Settings",
type=CyclesView3DShadingSettings,
)
def unregister():
@ -1503,3 +1556,4 @@ def unregister():
bpy.utils.unregister_class(CyclesDeviceSettings)
bpy.utils.unregister_class(CyclesPreferences)
bpy.utils.unregister_class(CyclesRenderLayerSettings)
bpy.utils.unregister_class(CyclesView3DShadingSettings)

View File

@ -2050,6 +2050,25 @@ class CYCLES_RENDER_PT_simplify_culling(CyclesButtonsPanel, Panel):
sub.prop(cscene, "distance_cull_margin", text="Distance")
class CYCLES_VIEW3D_PT_shading_render_pass(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'HEADER'
bl_label = "Render Pass"
bl_parent_id = 'VIEW3D_PT_shading'
COMPAT_ENGINES = {'CYCLES'}
@classmethod
def poll(cls, context):
return (context.engine in cls.COMPAT_ENGINES
and context.space_data.shading.type == 'RENDERED')
def draw(self, context):
shading = context.space_data.shading
layout = self.layout
layout.prop(shading.cycles, "render_pass", text="")
class CYCLES_VIEW3D_PT_shading_lighting(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'HEADER'
@ -2172,6 +2191,7 @@ classes = (
CYCLES_RENDER_PT_simplify_render,
CYCLES_RENDER_PT_simplify_culling,
CYCLES_VIEW3D_PT_shading_lighting,
CYCLES_VIEW3D_PT_shading_render_pass,
CYCLES_RENDER_PT_motion_blur,
CYCLES_RENDER_PT_motion_blur_curve,
CYCLES_RENDER_PT_film,

View File

@ -899,6 +899,8 @@ BufferParams BlenderSync::get_buffer_params(BL::RenderSettings &b_render,
params.height = height;
}
update_viewport_display_passes(b_v3d, params.passes, false);
return params;
}

View File

@ -206,7 +206,7 @@ void BlenderSync::sync_data(BL::RenderSettings &b_render,
sync_view_layer(b_v3d, b_view_layer);
sync_integrator();
sync_film();
sync_film(b_v3d);
sync_shaders(b_depsgraph, b_v3d);
sync_images();
sync_curve_settings();
@ -336,13 +336,17 @@ void BlenderSync::sync_integrator()
/* Film */
void BlenderSync::sync_film()
void BlenderSync::sync_film(BL::SpaceView3D &b_v3d)
{
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
Film *film = scene->film;
Film prevfilm = *film;
if (b_v3d) {
film->display_pass = update_viewport_display_passes(b_v3d, film->passes, true);
}
film->exposure = get_float(cscene, "film_exposure");
film->filter_type = (FilterType)get_enum(
cscene, "pixel_filter_type", FILTER_NUM_TYPES, FILTER_BLACKMAN_HARRIS);
@ -368,8 +372,10 @@ void BlenderSync::sync_film()
}
}
if (film->modified(prevfilm))
if (film->modified(prevfilm)) {
film->tag_update(scene);
film->tag_passes_update(scene, prevfilm.passes, false);
}
}
/* Render Layer */

View File

@ -116,7 +116,7 @@ class BlenderSync {
int width,
int height,
void **python_thread_state);
void sync_film();
void sync_film(BL::SpaceView3D &b_v3d);
void sync_view();
void sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, bool update_all);
void sync_shaders(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d);

View File

@ -15,6 +15,8 @@
*/
#include "blender_viewport.h"
#include "blender_util.h"
CCL_NAMESPACE_BEGIN
BlenderViewportParameters::BlenderViewportParameters()
@ -59,4 +61,38 @@ const bool BlenderViewportParameters::custom_viewport_parameters() const
return !(use_scene_world && use_scene_lights);
}
PassType BlenderViewportParameters::get_viewport_display_render_pass(BL::SpaceView3D &b_v3d)
{
PassType display_pass = PASS_NONE;
if (b_v3d) {
BL::View3DShading b_view3dshading = b_v3d.shading();
PointerRNA cshading = RNA_pointer_get(&b_view3dshading.ptr, "cycles");
display_pass = (PassType)get_enum(cshading, "render_pass", -1, -1);
}
return display_pass;
}
PassType update_viewport_display_passes(BL::SpaceView3D &b_v3d,
vector<Pass> &passes,
bool reset_passes)
{
if (b_v3d) {
PassType display_pass = BlenderViewportParameters::get_viewport_display_render_pass(b_v3d);
if (reset_passes) {
passes.clear();
/* We always need a combined pass for now. It would be a good optimization
* to support rendering without combined pass. */
Pass::add(PASS_COMBINED, passes);
}
if (display_pass != PASS_COMBINED) {
Pass::add(display_pass, passes);
}
return display_pass;
}
return PASS_NONE;
}
CCL_NAMESPACE_END

View File

@ -22,6 +22,7 @@
#include "RNA_access.h"
#include "RNA_blender_cpp.h"
#include "render/film.h"
#include "util/util_param.h"
CCL_NAMESPACE_BEGIN
@ -41,8 +42,17 @@ class BlenderViewportParameters {
const bool modified(const BlenderViewportParameters &other) const;
const bool custom_viewport_parameters() const;
friend class BlenderSync;
public:
/* Retrieve the render pass that needs to be displayed on the given `SpaceView3D`
* When the `b_v3d` parameter is not given `PASS_NONE` will be returned. */
static PassType get_viewport_display_render_pass(BL::SpaceView3D &b_v3d);
};
PassType update_viewport_display_passes(BL::SpaceView3D &b_v3d,
vector<Pass> &passes,
bool reset_passes);
CCL_NAMESPACE_END
#endif

View File

@ -16,18 +16,66 @@
CCL_NAMESPACE_BEGIN
ccl_device float4 film_map(KernelGlobals *kg, float4 irradiance, float scale)
ccl_device float4 film_get_pass_result(KernelGlobals *kg,
ccl_global float *buffer,
float sample_scale,
int index,
bool use_display_sample_scale)
{
float exposure = kernel_data.film.exposure;
float4 result = irradiance * scale;
float4 pass_result;
int display_pass_stride = kernel_data.film.display_pass_stride;
int display_pass_components = kernel_data.film.display_pass_components;
if (display_pass_components == 4) {
ccl_global float4 *in = (ccl_global float4 *)(buffer + display_pass_stride +
index * kernel_data.film.pass_stride);
float alpha = use_display_sample_scale ?
(kernel_data.film.use_display_pass_alpha ? in->w : 1.0f / sample_scale) :
1.0f;
pass_result = make_float4(in->x, in->y, in->z, alpha);
int display_divide_pass_stride = kernel_data.film.display_divide_pass_stride;
if (display_divide_pass_stride != -1) {
ccl_global float4 *divide_in = (ccl_global float4 *)(buffer + display_divide_pass_stride +
index * kernel_data.film.pass_stride);
if (divide_in->x != 0.0f) {
pass_result.x /= divide_in->x;
}
if (divide_in->y != 0.0f) {
pass_result.y /= divide_in->y;
}
if (divide_in->z != 0.0f) {
pass_result.z /= divide_in->z;
}
}
if (kernel_data.film.use_display_exposure) {
float exposure = kernel_data.film.exposure;
pass_result *= make_float4(exposure, exposure, exposure, alpha);
}
}
else if (display_pass_components == 1) {
ccl_global float *in = (ccl_global float *)(buffer + display_pass_stride +
index * kernel_data.film.pass_stride);
pass_result = make_float4(*in, *in, *in, 1.0f / sample_scale);
}
return pass_result;
}
ccl_device float4 film_map(KernelGlobals *kg, float4 rgba_in, float scale)
{
float4 result;
/* conversion to srgb */
result.x = color_linear_to_srgb(result.x * exposure);
result.y = color_linear_to_srgb(result.y * exposure);
result.z = color_linear_to_srgb(result.z * exposure);
result.x = color_linear_to_srgb(rgba_in.x);
result.y = color_linear_to_srgb(rgba_in.y);
result.z = color_linear_to_srgb(rgba_in.z);
/* clamp since alpha might be > 1.0 due to russian roulette */
result.w = saturate(result.w);
result.w = saturate(rgba_in.w);
return result;
}
@ -57,15 +105,22 @@ ccl_device void kernel_film_convert_to_byte(KernelGlobals *kg,
/* buffer offset */
int index = offset + x + y * stride;
bool use_display_sample_scale = (kernel_data.film.display_divide_pass_stride == -1);
float4 rgba_in = film_get_pass_result(kg, buffer, sample_scale, index, use_display_sample_scale);
rgba += index;
buffer += index * kernel_data.film.pass_stride;
/* map colors */
float4 irradiance = *((ccl_global float4 *)buffer);
float4 float_result = film_map(kg, irradiance, sample_scale);
uchar4 byte_result = film_float_to_byte(float_result);
*rgba = byte_result;
if (use_display_sample_scale) {
float4 float_result = film_map(kg, rgba_in, sample_scale);
uchar4 byte_result = film_float_to_byte(float_result);
*rgba = byte_result;
}
else {
float4 float_result = film_map(kg, rgba_in, 1.0);
uchar4 byte_result = film_float_to_byte(float_result);
*rgba = byte_result;
}
}
ccl_device void kernel_film_convert_to_half_float(KernelGlobals *kg,
@ -79,21 +134,16 @@ ccl_device void kernel_film_convert_to_half_float(KernelGlobals *kg,
{
/* buffer offset */
int index = offset + x + y * stride;
bool use_display_sample_scale = (kernel_data.film.display_divide_pass_stride == -1);
float4 rgba_in = film_get_pass_result(kg, buffer, sample_scale, index, use_display_sample_scale);
ccl_global float4 *in = (ccl_global float4 *)(buffer + index * kernel_data.film.pass_stride);
ccl_global half *out = (ccl_global half *)rgba + index * 4;
float exposure = kernel_data.film.exposure;
float4 rgba_in = *in;
if (exposure != 1.0f) {
rgba_in.x *= exposure;
rgba_in.y *= exposure;
rgba_in.z *= exposure;
if (use_display_sample_scale) {
float4_store_half(out, rgba_in, sample_scale);
}
else {
float4_store_half(out, rgba_in, 1.0f);
}
float4_store_half(out, rgba_in, sample_scale);
}
CCL_NAMESPACE_END

View File

@ -1168,6 +1168,7 @@ static_assert_align(KernelCamera, 16);
typedef struct KernelFilm {
float exposure;
int pass_flag;
int light_pass_flag;
int pass_stride;
int use_light_pass;
@ -1233,6 +1234,13 @@ typedef struct KernelFilm {
int pass_bvh_intersections;
int pass_ray_bounces;
#endif
/* viewport rendering options */
int display_pass_stride;
int display_pass_components;
int display_divide_pass_stride;
int use_display_exposure;
int use_display_pass_alpha;
} KernelFilm;
static_assert_align(KernelFilm, 16);

View File

@ -64,7 +64,6 @@ class BufferParams {
void get_offset_stride(int &offset, int &stride);
bool modified(const BufferParams &params);
void add_pass(PassType type);
int get_passes_size();
int get_denoising_offset();
int get_denoising_prefiltered_offset();

View File

@ -267,7 +267,7 @@ NODE_DEFINE(Film)
NodeType *type = NodeType::add("film", create);
SOCKET_FLOAT(exposure, "Exposure", 0.8f);
SOCKET_FLOAT(pass_alpha_threshold, "Pass Alpha Threshold", 0.5f);
SOCKET_FLOAT(pass_alpha_threshold, "Pass Alpha Threshold", 0.0f);
static NodeEnum filter_enum;
filter_enum.insert("box", FILTER_BOX);
@ -318,6 +318,13 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
/* update __data */
kfilm->exposure = exposure;
kfilm->pass_flag = 0;
kfilm->display_pass_stride = -1;
kfilm->display_pass_components = 0;
kfilm->display_divide_pass_stride = -1;
kfilm->use_display_exposure = false;
kfilm->use_display_pass_alpha = (display_pass == PASS_COMBINED);
kfilm->light_pass_flag = 0;
kfilm->pass_stride = 0;
kfilm->use_light_pass = use_light_visibility || use_sample_clamp;
@ -464,6 +471,16 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
break;
}
if (pass.type == display_pass) {
kfilm->display_pass_stride = kfilm->pass_stride;
kfilm->display_pass_components = pass.components;
kfilm->use_display_exposure = pass.exposure && (kfilm->exposure != 1.0f);
}
else if (pass.type == PASS_DIFFUSE_COLOR || pass.type == PASS_TRANSMISSION_COLOR ||
pass.type == PASS_GLOSSY_COLOR || pass.type == PASS_SUBSURFACE_COLOR) {
kfilm->display_divide_pass_stride = kfilm->pass_stride;
}
kfilm->pass_stride += pass.components;
}
@ -485,7 +502,18 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
}
kfilm->pass_stride = align_up(kfilm->pass_stride, 4);
kfilm->pass_alpha_threshold = pass_alpha_threshold;
/* When displaying the normal/uv pass in the viewport we need to disable
* transparency.
*
* We also don't need to perform light accumulations. Later we want to optimize this to suppress
* light calculations. */
if (display_pass == PASS_NORMAL || display_pass == PASS_UV) {
kfilm->use_light_pass = 0;
}
else {
kfilm->pass_alpha_threshold = pass_alpha_threshold;
}
/* update filter table */
vector<float> table = filter_table(filter_type, filter_width);
@ -518,7 +546,7 @@ bool Film::modified(const Film &film)
return !Node::equals(film) || !Pass::equals(passes, film.passes);
}
void Film::tag_passes_update(Scene *scene, const vector<Pass> &passes_)
void Film::tag_passes_update(Scene *scene, const vector<Pass> &passes_, bool update_passes)
{
if (Pass::contains(passes, PASS_UV) != Pass::contains(passes_, PASS_UV)) {
scene->mesh_manager->tag_update(scene);
@ -526,10 +554,16 @@ void Film::tag_passes_update(Scene *scene, const vector<Pass> &passes_)
foreach (Shader *shader, scene->shaders)
shader->need_update_mesh = true;
}
else if (Pass::contains(passes, PASS_MOTION) != Pass::contains(passes_, PASS_MOTION))
else if (Pass::contains(passes, PASS_MOTION) != Pass::contains(passes_, PASS_MOTION)) {
scene->mesh_manager->tag_update(scene);
}
else if (Pass::contains(passes, PASS_AO) != Pass::contains(passes_, PASS_AO)) {
scene->integrator->tag_update(scene);
}
passes = passes_;
if (update_passes) {
passes = passes_;
}
}
void Film::tag_update(Scene * /*scene*/)

View File

@ -64,6 +64,7 @@ class Film : public Node {
int denoising_flags;
float pass_alpha_threshold;
PassType display_pass;
int pass_stride;
int denoising_data_offset;
int denoising_clean_offset;
@ -90,7 +91,7 @@ class Film : public Node {
void device_free(Device *device, DeviceScene *dscene, Scene *scene);
bool modified(const Film &film);
void tag_passes_update(Scene *scene, const vector<Pass> &passes_);
void tag_passes_update(Scene *scene, const vector<Pass> &passes_, bool update_passes=true);
void tag_update(Scene *scene);
};

View File

@ -83,7 +83,7 @@ Session::Session(const SessionParams &params_)
display_outdated = false;
gpu_draw_ready = false;
gpu_need_tonemap = false;
gpu_need_display_buffer_update = false;
pause = false;
kernels_loaded = false;
@ -97,8 +97,8 @@ Session::~Session()
/* wait for session thread to end */
progress.set_cancel("Exiting");
gpu_need_tonemap = false;
gpu_need_tonemap_cond.notify_all();
gpu_need_display_buffer_update = false;
gpu_need_display_buffer_update_cond.notify_all();
{
thread_scoped_lock pause_lock(pause_mutex);
@ -110,12 +110,12 @@ Session::~Session()
}
if (params.write_render_cb) {
/* tonemap and write out image if requested */
/* Copy to display buffer and write out image if requested */
delete display;
display = new DisplayBuffer(device, false);
display->reset(buffers->params);
tonemap(params.samples);
copy_to_display_buffer(params.samples);
int w = display->draw_width;
int h = display->draw_height;
@ -168,8 +168,8 @@ void Session::reset_gpu(BufferParams &buffer_params, int samples)
reset_(buffer_params, samples);
gpu_need_tonemap = false;
gpu_need_tonemap_cond.notify_all();
gpu_need_display_buffer_update = false;
gpu_need_display_buffer_update_cond.notify_all();
pause_cond.notify_all();
}
@ -186,11 +186,11 @@ bool Session::draw_gpu(BufferParams &buffer_params, DeviceDrawParams &draw_param
if (!buffer_params.modified(display->params)) {
/* for CUDA we need to do tone-mapping still, since we can
* only access GL buffers from the main thread. */
if (gpu_need_tonemap) {
if (gpu_need_display_buffer_update) {
thread_scoped_lock buffers_lock(buffers_mutex);
tonemap(tile_manager.state.sample);
gpu_need_tonemap = false;
gpu_need_tonemap_cond.notify_all();
copy_to_display_buffer(tile_manager.state.sample);
gpu_need_display_buffer_update = false;
gpu_need_display_buffer_update_cond.notify_all();
}
display->draw(device, draw_params);
@ -307,17 +307,17 @@ void Session::run_gpu()
/* update status and timing */
update_status_time();
gpu_need_tonemap = true;
gpu_need_display_buffer_update = true;
gpu_draw_ready = true;
progress.set_update();
/* wait for tonemap */
/* wait for until display buffer is updated */
if (!params.background) {
while (gpu_need_tonemap) {
while (gpu_need_display_buffer_update) {
if (progress.get_cancel())
break;
gpu_need_tonemap_cond.wait(buffers_lock);
gpu_need_display_buffer_update_cond.wait(buffers_lock);
}
}
@ -561,7 +561,7 @@ void Session::run_cpu()
while (!progress.get_cancel()) {
/* advance to next tile */
bool no_tiles = !tile_manager.next();
bool need_tonemap = false;
bool need_copy_to_display_buffer = false;
DeviceKernelStatus kernel_state = DEVICE_KERNEL_UNKNOWN;
if (no_tiles) {
@ -650,7 +650,7 @@ void Session::run_cpu()
update_status_time();
if (!params.background)
need_tonemap = true;
need_copy_to_display_buffer = true;
if (!device->error_message().empty())
progress.set_error(device->error_message());
@ -668,10 +668,10 @@ void Session::run_cpu()
delayed_reset.do_reset = false;
reset_(delayed_reset.params, delayed_reset.samples);
}
else if (need_tonemap) {
/* tonemap only if we do not reset, we don't we don't
else if (need_copy_to_display_buffer) {
/* Only copy to display_buffer if we do not reset, we don't
* want to show the result of an incomplete sample */
tonemap(tile_manager.state.sample);
copy_to_display_buffer(tile_manager.state.sample);
}
if (!device->error_message().empty())
@ -1044,9 +1044,9 @@ void Session::render()
device->task_add(task);
}
void Session::tonemap(int sample)
void Session::copy_to_display_buffer(int sample)
{
/* add tonemap task */
/* add film conversion task */
DeviceTask task(DeviceTask::FILM_CONVERT);
task.x = tile_manager.state.buffer.full_x;

View File

@ -176,7 +176,7 @@ class Session {
void update_status_time(bool show_pause = false, bool show_done = false);
void tonemap(int sample);
void copy_to_display_buffer(int sample);
void render();
void reset_(BufferParams &params, int samples);
@ -202,8 +202,8 @@ class Session {
volatile bool display_outdated;
volatile bool gpu_draw_ready;
volatile bool gpu_need_tonemap;
thread_condition_variable gpu_need_tonemap_cond;
volatile bool gpu_need_display_buffer_update;
thread_condition_variable gpu_need_display_buffer_update_cond;
bool pause;
thread_condition_variable pause_cond;

View File

@ -550,6 +550,11 @@ void BKE_scene_free_ex(Scene *sce, const bool do_id_user)
sce->eevee.light_cache = NULL;
}
if (sce->display.shading.prop) {
IDP_FreeProperty(sce->display.shading.prop);
sce->display.shading.prop = NULL;
}
/* These are freed on doversion. */
BLI_assert(sce->layer_properties == NULL);
}

View File

@ -6353,6 +6353,14 @@ static void direct_link_lightcache(FileData *fd, LightCache *cache)
cache->grid_data = newdataadr(fd, cache->grid_data);
}
static void direct_link_view3dshading(FileData *fd, View3DShading *shading)
{
if (shading->prop) {
shading->prop = newdataadr(fd, shading->prop);
IDP_DirectLinkGroup_OrFree(&shading->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
}
}
/* check for cyclic set-scene,
* libs can cause this case which is normally prevented, see (T#####) */
#define USE_SETSCENE_CHECK
@ -6987,6 +6995,8 @@ static void direct_link_scene(FileData *fd, Scene *sce)
}
}
direct_link_view3dshading(fd, &sce->display.shading);
sce->layer_properties = newdataadr(fd, sce->layer_properties);
IDP_DirectLinkGroup_OrFree(&sce->layer_properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
}
@ -7255,6 +7265,8 @@ static void direct_link_area(FileData *fd, ScrArea *area)
v3d->fx_settings.ssao = newdataadr(fd, v3d->fx_settings.ssao);
}
direct_link_view3dshading(fd, &v3d->shading);
blo_do_versions_view3d_split_250(v3d, &sl->regionbase);
}
else if (sl->spacetype == SPACE_GRAPH) {

View File

@ -2413,6 +2413,13 @@ static void write_view_settings(WriteData *wd, ColorManagedViewSettings *view_se
}
}
static void write_view3dshading(WriteData *wd, View3DShading *shading)
{
if (shading->prop) {
IDP_WriteProperty(shading->prop, wd);
}
}
static void write_paint(WriteData *wd, Paint *p)
{
if (p->cavity_curve) {
@ -2684,6 +2691,8 @@ static void write_scene(WriteData *wd, Scene *sce)
write_lightcache(wd, sce->eevee.light_cache);
}
write_view3dshading(wd, &sce->display.shading);
/* Freed on doversion. */
BLI_assert(sce->layer_properties == NULL);
}
@ -2850,6 +2859,7 @@ static void write_area_regions(WriteData *wd, ScrArea *area)
if (v3d->fx_settings.dof) {
writestruct(wd, DATA, GPUDOFSettings, 1, v3d->fx_settings.dof);
}
write_view3dshading(wd, &v3d->shading);
}
else if (sl->spacetype == SPACE_GRAPH) {
SpaceGraph *sipo = (SpaceGraph *)sl;

View File

@ -39,6 +39,7 @@
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_icons.h"
#include "BKE_idprop.h"
#include "BKE_lattice.h"
#include "BKE_main.h"
#include "BKE_mball.h"
@ -363,6 +364,11 @@ static void view3d_free(SpaceLink *sl)
if (vd->fx_settings.dof) {
MEM_freeN(vd->fx_settings.dof);
}
if (vd->shading.prop) {
IDP_FreeProperty(vd->shading.prop);
vd->shading.prop = NULL;
}
}
/* spacetype; init callback */

View File

@ -179,6 +179,8 @@ typedef struct View3DShading {
float curvature_ridge_factor;
float curvature_valley_factor;
struct IDProperty *prop;
} View3DShading;
/** 3D Viewport Overlay settings. */

View File

@ -458,6 +458,7 @@ const EnumPropertyItem rna_enum_file_sort_items[] = {
# include "BKE_brush.h"
# include "BKE_colortools.h"
# include "BKE_context.h"
# include "BKE_idprop.h"
# include "BKE_layer.h"
# include "BKE_global.h"
# include "BKE_nla.h"
@ -938,6 +939,18 @@ static bool rna_RegionView3D_is_orthographic_side_view_get(PointerRNA *ptr)
return RV3D_VIEW_IS_AXIS(rv3d->view);
}
static IDProperty *rna_View3DShading_idprops(PointerRNA *ptr, bool create)
{
View3DShading *shading = ptr->data;
if (create && !shading->prop) {
IDPropertyTemplate val = {0};
shading->prop = IDP_New(IDP_GROUP, &val, "View3DShading ID properties");
}
return shading->prop;
}
static void rna_3DViewShading_type_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
ID *id = ptr->owner_id;
@ -3003,6 +3016,7 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna)
RNA_def_struct_path_func(srna, "rna_View3DShading_path");
RNA_def_struct_ui_text(
srna, "3D View Shading Settings", "Settings for shading in the 3D viewport");
RNA_def_struct_idprops_func(srna, "rna_View3DShading_idprops");
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_enum_shading_type_items);