The first two dimensions of scrambled, shuffled Sobol and shuffled PMJ02 are equivalent, so this makes no real difference for the first two dimensions. But Sobol allows us to naturally extend to more dimensions. Pretabulated Sobol is now always used, and the sampling pattern settings is now only available as a debug option. This in turn allows the following two things (also implemented): * Use proper 3D samples for combined lens + motion blur sampling. This notably reduces the noise on objects that are simultaneously out-of-focus and motion blurred. * Use proper 3D samples for combined light selection + light sampling. Cycles was already doing something clever here with 2D samples, but using 3D samples is more straightforward and avoids overloading one of the dimensions. In the future this will also allow for proper sampling of e.g. volumetric light sources and other things that may need three or four dimensions. Differential Revision: https://developer.blender.org/D16443
311 lines
12 KiB
Python
311 lines
12 KiB
Python
# SPDX-License-Identifier: Apache-2.0
|
|
# Copyright 2011-2022 Blender Foundation
|
|
from __future__ import annotations
|
|
|
|
import bpy
|
|
|
|
from bpy.app.handlers import persistent
|
|
|
|
|
|
def custom_bake_remap(scene):
|
|
"""
|
|
Remap bake types into the new types and set the flags accordingly
|
|
"""
|
|
bake_lookup = (
|
|
'COMBINED',
|
|
'AO',
|
|
'SHADOW',
|
|
'NORMAL',
|
|
'UV',
|
|
'EMIT',
|
|
'ENVIRONMENT',
|
|
'DIFFUSE_DIRECT',
|
|
'DIFFUSE_INDIRECT',
|
|
'DIFFUSE_COLOR',
|
|
'GLOSSY_DIRECT',
|
|
'GLOSSY_INDIRECT',
|
|
'GLOSSY_COLOR',
|
|
'TRANSMISSION_DIRECT',
|
|
'TRANSMISSION_INDIRECT',
|
|
'TRANSMISSION_COLOR')
|
|
|
|
diffuse_direct_idx = bake_lookup.index('DIFFUSE_DIRECT')
|
|
|
|
cscene = scene.cycles
|
|
|
|
# Old bake type
|
|
bake_type_idx = cscene.get("bake_type")
|
|
|
|
if bake_type_idx is None:
|
|
cscene.bake_type = 'COMBINED'
|
|
return
|
|
|
|
# File doesn't need versioning
|
|
if bake_type_idx < diffuse_direct_idx:
|
|
return
|
|
|
|
# File needs versioning
|
|
bake_type = bake_lookup[bake_type_idx]
|
|
cscene.bake_type, end = bake_type.split('_')
|
|
|
|
if end == 'DIRECT':
|
|
scene.render.bake.use_pass_indirect = False
|
|
scene.render.bake.use_pass_color = False
|
|
|
|
elif end == 'INDIRECT':
|
|
scene.render.bake.use_pass_direct = False
|
|
scene.render.bake.use_pass_color = False
|
|
|
|
elif end == 'COLOR':
|
|
scene.render.bake.use_pass_direct = False
|
|
scene.render.bake.use_pass_indirect = False
|
|
|
|
|
|
@persistent
|
|
def do_versions(self):
|
|
if bpy.context.preferences.version <= (2, 78, 1):
|
|
prop = bpy.context.preferences.addons[__package__].preferences
|
|
system = bpy.context.preferences.system
|
|
if not prop.is_property_set("compute_device_type"):
|
|
# Device might not currently be available so this can fail
|
|
try:
|
|
if system.legacy_compute_device_type == 1:
|
|
prop.compute_device_type = 'NONE' # Was OpenCL
|
|
elif system.legacy_compute_device_type == 2:
|
|
prop.compute_device_type = 'CUDA'
|
|
else:
|
|
prop.compute_device_type = 'NONE'
|
|
except:
|
|
pass
|
|
|
|
# Init device list for UI
|
|
prop.get_devices(prop.compute_device_type)
|
|
|
|
if bpy.context.preferences.version <= (3, 0, 40):
|
|
# Disable OpenCL device
|
|
prop = bpy.context.preferences.addons[__package__].preferences
|
|
if prop.is_property_set("compute_device_type") and prop['compute_device_type'] == 4:
|
|
prop.compute_device_type = 'NONE'
|
|
|
|
# We don't modify startup file because it assumes to
|
|
# have all the default values only.
|
|
if not bpy.data.is_saved:
|
|
return
|
|
|
|
# Map of versions used by libraries.
|
|
library_versions = {}
|
|
library_versions[bpy.data.version] = [None]
|
|
for library in bpy.data.libraries:
|
|
library_versions.setdefault(library.version, []).append(library)
|
|
|
|
# Do versioning per library, since they might have different versions.
|
|
max_need_versioning = (3, 5, 2)
|
|
for version, libraries in library_versions.items():
|
|
if version > max_need_versioning:
|
|
continue
|
|
|
|
# Scenes
|
|
for scene in bpy.data.scenes:
|
|
if scene.library not in libraries:
|
|
continue
|
|
|
|
# Clamp Direct/Indirect separation in 270
|
|
if version <= (2, 70, 0):
|
|
cscene = scene.cycles
|
|
sample_clamp = cscene.get("sample_clamp", False)
|
|
if (sample_clamp and
|
|
not cscene.is_property_set("sample_clamp_direct") and
|
|
not cscene.is_property_set("sample_clamp_indirect")):
|
|
cscene.sample_clamp_direct = sample_clamp
|
|
cscene.sample_clamp_indirect = sample_clamp
|
|
|
|
# Change of Volume Bounces in 271
|
|
if version <= (2, 71, 0):
|
|
cscene = scene.cycles
|
|
if not cscene.is_property_set("volume_bounces"):
|
|
cscene.volume_bounces = 1
|
|
|
|
# Caustics Reflective/Refractive separation in 272
|
|
if version <= (2, 72, 0):
|
|
cscene = scene.cycles
|
|
if (
|
|
cscene.get("no_caustics", False) and
|
|
not cscene.is_property_set("caustics_reflective") and
|
|
not cscene.is_property_set("caustics_refractive")
|
|
):
|
|
cscene.caustics_reflective = False
|
|
cscene.caustics_refractive = False
|
|
|
|
# Baking types changed
|
|
if version <= (2, 76, 6):
|
|
custom_bake_remap(scene)
|
|
|
|
# Several default changes for 2.77
|
|
if version <= (2, 76, 8):
|
|
cscene = scene.cycles
|
|
|
|
# Samples
|
|
if not cscene.is_property_set("samples"):
|
|
cscene.samples = 10
|
|
|
|
# Preview Samples
|
|
if not cscene.is_property_set("preview_samples"):
|
|
cscene.preview_samples = 10
|
|
|
|
# Filter
|
|
if cscene.get("filter_type", -1) == -1:
|
|
cscene.pixel_filter_type = 'GAUSSIAN'
|
|
|
|
if version <= (2, 76, 10):
|
|
cscene = scene.cycles
|
|
if not cscene.is_property_set("pixel_filter_type"):
|
|
filter_type_int = cscene.get("filter_type", -1)
|
|
if filter_type_int == 0:
|
|
cscene.pixel_filter_type = 'BOX'
|
|
elif filter_type_int == 1:
|
|
cscene.pixel_filter_type = 'GAUSSIAN'
|
|
|
|
if version <= (2, 78, 2):
|
|
cscene = scene.cycles
|
|
if not cscene.is_property_set("light_sampling_threshold"):
|
|
cscene.light_sampling_threshold = 0.0
|
|
|
|
if version <= (2, 79, 0):
|
|
cscene = scene.cycles
|
|
# Default changes
|
|
if not cscene.is_property_set("blur_glossy"):
|
|
cscene.blur_glossy = 0.0
|
|
if not cscene.is_property_set("sample_clamp_indirect"):
|
|
cscene.sample_clamp_indirect = 0.0
|
|
|
|
if version <= (2, 92, 4):
|
|
if scene.render.engine == 'CYCLES':
|
|
for view_layer in scene.view_layers:
|
|
cview_layer = view_layer.cycles
|
|
view_layer.use_pass_cryptomatte_object = cview_layer.get("use_pass_crypto_object", False)
|
|
view_layer.use_pass_cryptomatte_material = cview_layer.get("use_pass_crypto_material", False)
|
|
view_layer.use_pass_cryptomatte_asset = cview_layer.get("use_pass_crypto_asset", False)
|
|
view_layer.pass_cryptomatte_depth = cview_layer.get("pass_crypto_depth", 6)
|
|
|
|
if version <= (2, 93, 7):
|
|
if scene.render.engine == 'CYCLES':
|
|
for view_layer in scene.view_layers:
|
|
cview_layer = view_layer.cycles
|
|
for caov in cview_layer.get("aovs", []):
|
|
aov_name = caov.get("name", "AOV")
|
|
if aov_name in view_layer.aovs:
|
|
continue
|
|
baov = view_layer.aovs.add()
|
|
baov.name = caov.get("name", "AOV")
|
|
baov.type = "COLOR" if caov.get("type", 1) == 1 else "VALUE"
|
|
|
|
if version <= (2, 93, 16):
|
|
cscene = scene.cycles
|
|
ao_bounces = cscene.get("ao_bounces", 0)
|
|
ao_bounces_render = cscene.get("ao_bounces_render", 0)
|
|
if scene.render.use_simplify and (ao_bounces or ao_bounces_render):
|
|
cscene.use_fast_gi = True
|
|
cscene.ao_bounces = ao_bounces
|
|
cscene.ao_bounces_render = ao_bounces_render
|
|
else:
|
|
cscene.ao_bounces = 1
|
|
cscene.ao_bounces_render = 1
|
|
|
|
if version <= (3, 0, 25):
|
|
cscene = scene.cycles
|
|
|
|
# Default changes.
|
|
if not cscene.is_property_set("samples"):
|
|
cscene.samples = 128
|
|
if not cscene.is_property_set("preview_samples"):
|
|
cscene.preview_samples = 32
|
|
if not cscene.is_property_set("use_adaptive_sampling"):
|
|
cscene.use_adaptive_sampling = False
|
|
cscene.use_preview_adaptive_sampling = False
|
|
if not cscene.is_property_set("use_denoising"):
|
|
cscene.use_denoising = False
|
|
if not cscene.is_property_set("use_preview_denoising"):
|
|
cscene.use_preview_denoising = False
|
|
if not cscene.is_property_set("sampling_pattern") or \
|
|
cscene.get('sampling_pattern') >= 2:
|
|
cscene.sampling_pattern = 'TABULATED_SOBOL'
|
|
|
|
# Removal of square samples.
|
|
cscene = scene.cycles
|
|
use_square_samples = cscene.get("use_square_samples", False)
|
|
|
|
if use_square_samples:
|
|
cscene.samples *= cscene.samples
|
|
cscene.preview_samples *= cscene.preview_samples
|
|
for layer in scene.view_layers:
|
|
layer.samples *= layer.samples
|
|
cscene["use_square_samples"] = False
|
|
|
|
# Disable light tree for existing scenes.
|
|
if version <= (3, 5, 3):
|
|
cscene = scene.cycles
|
|
if not cscene.is_property_set("use_light_tree"):
|
|
cscene.use_light_tree = False
|
|
|
|
# Lamps
|
|
for light in bpy.data.lights:
|
|
if light.library not in libraries:
|
|
continue
|
|
|
|
if version <= (2, 76, 5):
|
|
clight = light.cycles
|
|
|
|
# MIS
|
|
if not clight.is_property_set("use_multiple_importance_sampling"):
|
|
clight.use_multiple_importance_sampling = False
|
|
|
|
# Worlds
|
|
for world in bpy.data.worlds:
|
|
if world.library not in libraries:
|
|
continue
|
|
|
|
if version <= (2, 76, 9):
|
|
cworld = world.cycles
|
|
|
|
# World MIS Resolution
|
|
if not cworld.is_property_set("sample_map_resolution"):
|
|
cworld.sample_map_resolution = 256
|
|
|
|
if version <= (2, 79, 4) or \
|
|
(version >= (2, 80, 0) and version <= (2, 80, 18)):
|
|
cworld = world.cycles
|
|
# World MIS
|
|
if not cworld.is_property_set("sampling_method"):
|
|
if cworld.get("sample_as_light", True):
|
|
cworld.sampling_method = 'MANUAL'
|
|
else:
|
|
cworld.sampling_method = 'NONE'
|
|
|
|
# Materials
|
|
for mat in bpy.data.materials:
|
|
if mat.library not in libraries:
|
|
continue
|
|
|
|
if version <= (2, 76, 5):
|
|
cmat = mat.cycles
|
|
# Volume Sampling
|
|
if not cmat.is_property_set("volume_sampling"):
|
|
cmat.volume_sampling = 'DISTANCE'
|
|
|
|
if version <= (2, 79, 2):
|
|
cmat = mat.cycles
|
|
if not cmat.is_property_set("displacement_method"):
|
|
cmat.displacement_method = 'BUMP'
|
|
|
|
# Change default to bump again.
|
|
if version <= (2, 79, 6) or \
|
|
(version >= (2, 80, 0) and version <= (2, 80, 41)):
|
|
cmat = mat.cycles
|
|
if not cmat.is_property_set("displacement_method"):
|
|
cmat.displacement_method = 'DISPLACEMENT'
|
|
|
|
if version <= (3, 5, 3):
|
|
cmat = mat.cycles
|
|
if not cmat.get("sample_as_light", True):
|
|
cmat.emission_sampling = 'NONE'
|