mirror of
https://github.com/blender/blender
synced 2026-09-29 04:37:17 +03:00
This adds back lightprobe plane support for Blended Material and Shader to RGB evaluation. This adds a parallax property on the Lightprobe Planes to tweak the amount of (non-physical) distortion caused by normals. Unlike legacy EEVEE (4.1) this implementation does not do any raytracing even if raytracing is enabled in the render options. Instead, it uses the same heuristic when raytracing was disabled in 4.1. However, it now uses the new parallax amount from the planar lightprobe property. The heuristic fades out reflections if the normal differs from the reflection direction or if roughness is not small. To avoid big regression in compile time, the sampling of the planar probe is done only once for all the BSDFs and using the average normal. Fix #135198 Pull Request: https://projects.blender.org/blender/blender/pulls/158483
414 lines
12 KiB
Python
414 lines
12 KiB
Python
# SPDX-FileCopyrightText: 2009-2023 Blender Authors
|
|
#
|
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
from bpy.types import Panel
|
|
from bpy.app.translations import contexts as i18n_contexts
|
|
from bl_ui.space_properties import PropertiesAnimationMixin
|
|
|
|
|
|
class DataButtonsPanel:
|
|
bl_space_type = 'PROPERTIES'
|
|
bl_region_type = 'WINDOW'
|
|
bl_context = "data"
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
engine = context.engine
|
|
return context.lightprobe and (engine in cls.COMPAT_ENGINES)
|
|
|
|
|
|
class DATA_PT_context_lightprobe(DataButtonsPanel, Panel):
|
|
bl_label = ""
|
|
bl_options = {'HIDE_HEADER'}
|
|
COMPAT_ENGINES = {
|
|
'BLENDER_RENDER',
|
|
'BLENDER_EEVEE'
|
|
}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
|
|
ob = context.object
|
|
probe = context.lightprobe
|
|
space = context.space_data
|
|
|
|
if ob:
|
|
layout.template_ID(ob, "data")
|
|
elif probe:
|
|
layout.template_ID(space, "pin_id")
|
|
|
|
|
|
class DATA_PT_lightprobe(DataButtonsPanel, Panel):
|
|
bl_label = "Probe"
|
|
COMPAT_ENGINES = {'BLENDER_RENDER'}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
|
|
probe = context.lightprobe
|
|
|
|
# layout.prop(probe, "type")
|
|
|
|
if probe.type == 'VOLUME':
|
|
col = layout.column()
|
|
col.prop(probe, "influence_distance", text="Distance")
|
|
col.prop(probe, "falloff")
|
|
col.prop(probe, "intensity")
|
|
|
|
sub = col.column(align=True)
|
|
sub.prop(probe, "resolution_x", text="Resolution X")
|
|
sub.prop(probe, "resolution_y", text="Y")
|
|
sub.prop(probe, "resolution_z", text="Z")
|
|
|
|
elif probe.type == 'PLANE':
|
|
col = layout.column()
|
|
col.prop(probe, "influence_distance", text="Distance")
|
|
col.prop(probe, "falloff")
|
|
else:
|
|
col = layout.column()
|
|
col.prop(probe, "influence_type")
|
|
|
|
if probe.influence_type == 'ELIPSOID':
|
|
col.prop(probe, "influence_distance", text="Radius")
|
|
else:
|
|
col.prop(probe, "influence_distance", text="Size")
|
|
|
|
col.prop(probe, "falloff")
|
|
col.prop(probe, "intensity")
|
|
|
|
sub = col.column(align=True)
|
|
if probe.type == 'PLANE':
|
|
sub.prop(probe, "clip_start", text="Clipping Offset")
|
|
else:
|
|
sub.prop(probe, "clip_start", text="Clipping Start")
|
|
sub.prop(probe, "clip_end", text="End", text_ctxt=i18n_contexts.id_camera)
|
|
|
|
|
|
class DATA_PT_lightprobe_eevee(DataButtonsPanel, Panel):
|
|
bl_label = "Probe"
|
|
COMPAT_ENGINES = {'BLENDER_EEVEE'}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
|
|
probe = context.lightprobe
|
|
|
|
if probe.type == 'VOLUME':
|
|
col = layout.column()
|
|
|
|
col.prop(probe, "intensity")
|
|
|
|
col.separator()
|
|
|
|
sub = col.column(align=True)
|
|
sub.prop(probe, "normal_bias")
|
|
sub.prop(probe, "view_bias")
|
|
sub.prop(probe, "facing_bias")
|
|
|
|
col.separator()
|
|
|
|
col.prop(probe, "validity_threshold")
|
|
sub = col.column(align=True)
|
|
sub.prop(probe, "dilation_threshold")
|
|
sub.prop(probe, "dilation_radius", text="Radius")
|
|
|
|
col.separator()
|
|
|
|
elif probe.type == 'SPHERE':
|
|
col = layout.column()
|
|
col.prop(probe, "influence_type")
|
|
|
|
if probe.influence_type == 'ELIPSOID':
|
|
influence_text = "Radius"
|
|
else:
|
|
influence_text = "Size"
|
|
|
|
col.prop(probe, "influence_distance", text=influence_text)
|
|
col.prop(probe, "falloff")
|
|
|
|
elif probe.type == 'PLANE':
|
|
col = layout.column()
|
|
col.prop(probe, "influence_distance", text="Distance")
|
|
col.prop(probe, "parallax_distance", text="Parallax")
|
|
pass
|
|
else:
|
|
# Currently unsupported
|
|
pass
|
|
|
|
|
|
class DATA_PT_lightprobe_visibility(DataButtonsPanel, Panel):
|
|
bl_label = "Visibility"
|
|
bl_parent_id = "DATA_PT_lightprobe"
|
|
COMPAT_ENGINES = {'BLENDER_RENDER'}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
|
|
probe = context.lightprobe
|
|
|
|
col = layout.column()
|
|
|
|
if probe.type == 'VOLUME':
|
|
col.prop(probe, "visibility_buffer_bias", text="Bias")
|
|
col.prop(probe, "visibility_bleed_bias", text="Bleed Bias")
|
|
col.prop(probe, "visibility_blur", text="Blur")
|
|
|
|
row = col.row(align=True)
|
|
row.prop(probe, "visibility_collection")
|
|
row.prop(probe, "invert_visibility_collection", text="", icon='ARROW_LEFTRIGHT')
|
|
|
|
|
|
class DATA_PT_lightprobe_capture(DataButtonsPanel, Panel):
|
|
bl_label = "Capture"
|
|
COMPAT_ENGINES = {'BLENDER_EEVEE'}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
engine = context.engine
|
|
return context.lightprobe and context.lightprobe.type in {'SPHERE', 'PLANE'} and (engine in cls.COMPAT_ENGINES)
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
|
|
probe = context.lightprobe
|
|
|
|
col = layout.column()
|
|
|
|
if probe.type == 'SPHERE':
|
|
sub = col.column(align=True)
|
|
sub.prop(probe, "clip_start", text="Clipping Start")
|
|
sub.prop(probe, "clip_end", text="End", text_ctxt=i18n_contexts.id_camera)
|
|
elif probe.type == 'PLANE':
|
|
col.prop(probe, "clip_start", text="Clipping Offset")
|
|
|
|
|
|
class DATA_PT_lightprobe_bake(DataButtonsPanel, Panel):
|
|
bl_label = "Bake"
|
|
COMPAT_ENGINES = {'BLENDER_EEVEE'}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
engine = context.engine
|
|
return context.lightprobe and context.lightprobe.type == 'VOLUME' and (engine in cls.COMPAT_ENGINES)
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = False
|
|
|
|
col = layout.column()
|
|
row = col.row(align=True)
|
|
row.operator("object.lightprobe_cache_bake").subset = 'ACTIVE'
|
|
row.operator("object.lightprobe_cache_free", text="", icon='TRASH').subset = 'ACTIVE'
|
|
|
|
|
|
class DATA_PT_lightprobe_bake_resolution(DataButtonsPanel, Panel):
|
|
bl_label = "Resolution"
|
|
bl_parent_id = "DATA_PT_lightprobe_bake"
|
|
COMPAT_ENGINES = {'BLENDER_EEVEE'}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = False
|
|
|
|
probe = context.lightprobe
|
|
|
|
col = layout.column()
|
|
|
|
sub = col.column(align=True)
|
|
sub.prop(probe, "resolution_x", text="Resolution X")
|
|
sub.prop(probe, "resolution_y", text="Y")
|
|
sub.prop(probe, "resolution_z", text="Z")
|
|
|
|
col.prop(probe, "bake_samples")
|
|
col.prop(probe, "surfel_density")
|
|
|
|
|
|
class DATA_PT_lightprobe_bake_capture(DataButtonsPanel, Panel):
|
|
bl_label = "Capture"
|
|
bl_parent_id = "DATA_PT_lightprobe_bake"
|
|
COMPAT_ENGINES = {'BLENDER_EEVEE'}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = False
|
|
|
|
probe = context.lightprobe
|
|
|
|
col = layout.column()
|
|
|
|
col.prop(probe, "capture_distance", text="Distance")
|
|
|
|
col = layout.column(heading="Contributions", align=True)
|
|
col.prop(probe, "capture_world", text="World")
|
|
col.prop(probe, "capture_indirect", text="Indirect Light")
|
|
col.prop(probe, "capture_emission", text="Emission")
|
|
|
|
|
|
class DATA_PT_lightprobe_bake_offset(DataButtonsPanel, Panel):
|
|
bl_label = "Offset"
|
|
bl_parent_id = "DATA_PT_lightprobe_bake_capture"
|
|
bl_options = {'DEFAULT_CLOSED'}
|
|
COMPAT_ENGINES = {'BLENDER_EEVEE'}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = False
|
|
|
|
probe = context.lightprobe
|
|
|
|
col = layout.column(align=True)
|
|
col.prop(probe, "surface_bias")
|
|
col.prop(probe, "escape_bias")
|
|
|
|
|
|
class DATA_PT_lightprobe_bake_clamping(DataButtonsPanel, Panel):
|
|
bl_label = "Clamping"
|
|
bl_parent_id = "DATA_PT_lightprobe_bake_capture"
|
|
bl_options = {'DEFAULT_CLOSED'}
|
|
COMPAT_ENGINES = {'BLENDER_EEVEE'}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = False
|
|
|
|
probe = context.lightprobe
|
|
|
|
col = layout.column(align=True)
|
|
col.prop(probe, "clamp_direct", text="Direct Light")
|
|
col.prop(probe, "clamp_indirect", text="Indirect Light")
|
|
|
|
|
|
class DATA_PT_lightprobe_parallax(DataButtonsPanel, Panel):
|
|
bl_label = "Custom Parallax"
|
|
bl_options = {'DEFAULT_CLOSED'}
|
|
COMPAT_ENGINES = {
|
|
'BLENDER_RENDER',
|
|
'BLENDER_EEVEE',
|
|
}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
engine = context.engine
|
|
return context.lightprobe and context.lightprobe.type == 'SPHERE' and (engine in cls.COMPAT_ENGINES)
|
|
|
|
def draw_header(self, context):
|
|
probe = context.lightprobe
|
|
self.layout.prop(probe, "use_custom_parallax", text="")
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
|
|
probe = context.lightprobe
|
|
|
|
col = layout.column()
|
|
col.active = probe.use_custom_parallax
|
|
|
|
col.prop(probe, "parallax_type")
|
|
|
|
if probe.parallax_type == 'ELIPSOID':
|
|
col.prop(probe, "parallax_distance", text="Radius")
|
|
else:
|
|
col.prop(probe, "parallax_distance", text="Size")
|
|
|
|
|
|
class DATA_PT_lightprobe_display(DataButtonsPanel, Panel):
|
|
bl_label = "Viewport Display"
|
|
bl_options = {'DEFAULT_CLOSED'}
|
|
COMPAT_ENGINES = {'BLENDER_RENDER'}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = False
|
|
|
|
ob = context.object
|
|
probe = context.lightprobe
|
|
|
|
col = layout.column()
|
|
|
|
if probe.type == 'PLANE':
|
|
col.prop(ob, "empty_display_size", text="Arrow Size")
|
|
col.prop(probe, "show_influence")
|
|
|
|
if probe.type in {'VOLUME', 'SPHERE'}:
|
|
col.prop(probe, "show_influence")
|
|
col.prop(probe, "show_clip")
|
|
|
|
if probe.type == 'SPHERE':
|
|
sub = col.column()
|
|
sub.active = probe.use_custom_parallax
|
|
sub.prop(probe, "show_parallax")
|
|
|
|
|
|
class DATA_PT_lightprobe_display_eevee(DataButtonsPanel, Panel):
|
|
bl_label = "Viewport Display"
|
|
bl_options = {'DEFAULT_CLOSED'}
|
|
COMPAT_ENGINES = {'BLENDER_EEVEE'}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = False
|
|
|
|
ob = context.object
|
|
probe = context.lightprobe
|
|
|
|
col = layout.column()
|
|
|
|
if probe.type in {'VOLUME', 'SPHERE'}:
|
|
row = col.row(heading="Data")
|
|
row.prop(probe, "use_data_display", text="")
|
|
subrow = row.row()
|
|
subrow.active = probe.use_data_display
|
|
subrow.prop(probe, "data_display_size", text="Size", slider=True)
|
|
col.prop(probe, "show_clip")
|
|
col.prop(probe, "show_influence")
|
|
|
|
if probe.type == 'SPHERE':
|
|
sub = col.column()
|
|
sub.active = probe.use_custom_parallax
|
|
sub.prop(probe, "show_parallax")
|
|
|
|
if probe.type == 'PLANE':
|
|
col.prop(ob, "empty_display_size", text="Arrow Size")
|
|
col.prop(probe, "use_data_display", text="Capture")
|
|
col.prop(probe, "show_influence")
|
|
|
|
|
|
class DATA_PT_lightprobe_animation(DataButtonsPanel, PropertiesAnimationMixin, Panel):
|
|
COMPAT_ENGINES = {'BLENDER_EEVEE'}
|
|
_animated_id_context_property = "lightprobe"
|
|
|
|
|
|
classes = (
|
|
DATA_PT_context_lightprobe,
|
|
DATA_PT_lightprobe,
|
|
DATA_PT_lightprobe_eevee,
|
|
DATA_PT_lightprobe_capture,
|
|
DATA_PT_lightprobe_bake,
|
|
DATA_PT_lightprobe_bake_resolution,
|
|
DATA_PT_lightprobe_bake_capture,
|
|
DATA_PT_lightprobe_bake_clamping,
|
|
DATA_PT_lightprobe_bake_offset,
|
|
DATA_PT_lightprobe_visibility,
|
|
DATA_PT_lightprobe_parallax,
|
|
DATA_PT_lightprobe_display,
|
|
DATA_PT_lightprobe_display_eevee,
|
|
DATA_PT_lightprobe_animation,
|
|
)
|
|
|
|
if __name__ == "__main__": # only for live edit.
|
|
from bpy.utils import register_class
|
|
for cls in classes:
|
|
register_class(cls)
|