Small improvements for the Shadow Map Atlas Blender UI
* Made shadow map atlas sizes enum's values dynamic: This allows reducing issues related to picking a "wrong" size for the atlases. * Added a legend below shadow map sizes to have an idea of how much lights can an option fit. * Separated listing of subdivisions to include point lights. * Disable cubemap size if single map is enabled to show that cascade size option is only used.
This commit is contained in:
parent
98eeccd71d
commit
1945439cd1
|
@ -4,6 +4,37 @@ from bpy.props import *
|
|||
import arm.assets as assets
|
||||
import arm.utils
|
||||
|
||||
atlas_sizes = [ ('256', '256', '256'),
|
||||
('512', '512', '512'),
|
||||
('1024', '1024', '1024'),
|
||||
('2048', '2048', '2048'),
|
||||
('4096', '4096', '4096'),
|
||||
('8192', '8192', '8192'),
|
||||
('16384', '16384', '16384'),
|
||||
('32768', '32768', '32768') ]
|
||||
|
||||
def atlas_sizes_from_min(min_size: int) -> list:
|
||||
""" Create an enum list of atlas sizes from a minimal size """
|
||||
sizes = []
|
||||
for i in range(len(atlas_sizes)):
|
||||
if int(atlas_sizes[i][0]) > min_size:
|
||||
sizes.append(atlas_sizes[i])
|
||||
return sizes
|
||||
|
||||
def update_spot_sun_atlas_size_options(scene: bpy.types.Scene, context: bpy.types.Context) -> list:
|
||||
wrd = bpy.data.worlds['Arm']
|
||||
if len(wrd.arm_rplist) <= wrd.arm_rplist_index:
|
||||
return []
|
||||
rpdat = wrd.arm_rplist[wrd.arm_rplist_index]
|
||||
return atlas_sizes_from_min(int(rpdat.rp_shadowmap_cascade))
|
||||
|
||||
def update_point_atlas_size_options(scene: bpy.types.Scene, context: bpy.types.Context) -> list:
|
||||
wrd = bpy.data.worlds['Arm']
|
||||
if len(wrd.arm_rplist) <= wrd.arm_rplist_index:
|
||||
return []
|
||||
rpdat = wrd.arm_rplist[wrd.arm_rplist_index]
|
||||
return atlas_sizes_from_min(int(rpdat.rp_shadowmap_cube) * 2)
|
||||
|
||||
def update_preset(self, context):
|
||||
rpdat = arm.utils.get_rp()
|
||||
if self.rp_preset == 'Desktop':
|
||||
|
@ -271,33 +302,17 @@ class ArmRPListItem(bpy.types.PropertyGroup):
|
|||
('8', '8', '8'),],
|
||||
name="LOD Subdivisions", description="Number of subdivisions of the default tile size for LOD", default='2', update=update_renderpath)
|
||||
rp_shadowmap_atlas_max_size_point: EnumProperty(
|
||||
items=[('1024', '1024', '1024'),
|
||||
('2048', '2048', '2048'),
|
||||
('4096', '4096', '4096'),
|
||||
('8192', '8192', '8192'),
|
||||
('16384', '16384', '16384')],
|
||||
name="Max Atlas Texture Size Points", description="Sets the limit of the size of the texture.", default='8192', update=update_renderpath)
|
||||
items=update_point_atlas_size_options,
|
||||
name="Max Atlas Texture Size Points", description="Sets the limit of the size of the texture.", update=update_renderpath)
|
||||
rp_shadowmap_atlas_max_size_spot: EnumProperty(
|
||||
items=[('1024', '1024', '1024'),
|
||||
('2048', '2048', '2048'),
|
||||
('4096', '4096', '4096'),
|
||||
('8192', '8192', '8192'),
|
||||
('16384', '16384', '16384')],
|
||||
name="Max Atlas Texture Size Spots", description="Sets the limit of the size of the texture.", default='8192', update=update_renderpath)
|
||||
items=update_spot_sun_atlas_size_options,
|
||||
name="Max Atlas Texture Size Spots", description="Sets the limit of the size of the texture.", update=update_renderpath)
|
||||
rp_shadowmap_atlas_max_size_sun: EnumProperty(
|
||||
items=[('1024', '1024', '1024'),
|
||||
('2048', '2048', '2048'),
|
||||
('4096', '4096', '4096'),
|
||||
('8192', '8192', '8192'),
|
||||
('16384', '16384', '16384')],
|
||||
name="Max Atlas Texture Size Sun", description="Sets the limit of the size of the texture.", default='8192', update=update_renderpath)
|
||||
items=update_spot_sun_atlas_size_options,
|
||||
name="Max Atlas Texture Size Sun", description="Sets the limit of the size of the texture.", update=update_renderpath)
|
||||
rp_shadowmap_atlas_max_size: EnumProperty(
|
||||
items=[('1024', '1024', '1024'),
|
||||
('2048', '2048', '2048'),
|
||||
('4096', '4096', '4096'),
|
||||
('8192', '8192', '8192'),
|
||||
('16384', '16384', '16384')],
|
||||
name="Max Atlas Texture Size", description="Sets the limit of the size of the texture.", default='8192', update=update_renderpath)
|
||||
items=update_spot_sun_atlas_size_options,
|
||||
name="Max Atlas Texture Size", description="Sets the limit of the size of the texture.", update=update_renderpath)
|
||||
rp_shadowmap_cube: EnumProperty(
|
||||
items=[('256', '256', '256'),
|
||||
('512', '512', '512'),
|
||||
|
|
|
@ -1332,6 +1332,20 @@ class ARM_PT_RenderPathShadowsPanel(bpy.types.Panel):
|
|||
max = max / 2
|
||||
return l
|
||||
|
||||
def tiles_per_light_type(self, rpdat: arm.props_renderpath.ArmRPListItem, light_type: str) -> int:
|
||||
if light_type == 'point':
|
||||
return 6
|
||||
elif light_type == 'spot':
|
||||
return 1
|
||||
else:
|
||||
return int(rpdat.rp_shadowmap_cascades)
|
||||
|
||||
def lights_number_atlas(self, rpdat: arm.props_renderpath.ArmRPListItem, atlas_size: int, shadowmap_size: int, light_type: str) -> int:
|
||||
'''Compute number lights that could fit in an atlas'''
|
||||
lights = atlas_size / shadowmap_size
|
||||
lights *= lights / self.tiles_per_light_type(rpdat, light_type)
|
||||
return int(lights)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
|
@ -1342,7 +1356,9 @@ class ARM_PT_RenderPathShadowsPanel(bpy.types.Panel):
|
|||
rpdat = wrd.arm_rplist[wrd.arm_rplist_index]
|
||||
|
||||
layout.enabled = rpdat.rp_shadows
|
||||
layout.prop(rpdat, 'rp_shadowmap_cube')
|
||||
col = layout.column()
|
||||
col.enabled = not rpdat.rp_shadowmap_atlas_single_map or not rpdat.rp_shadowmap_atlas
|
||||
col.prop(rpdat, 'rp_shadowmap_cube')
|
||||
layout.prop(rpdat, 'rp_shadowmap_cascade')
|
||||
layout.prop(rpdat, 'rp_shadowmap_cascades')
|
||||
col = layout.column()
|
||||
|
@ -1367,39 +1383,88 @@ class ARM_PT_RenderPathShadowsPanel(bpy.types.Panel):
|
|||
colatlas_lod_info = colatlas_lod.row()
|
||||
colatlas_lod_info.alignment = 'RIGHT'
|
||||
subdivs_list = self.compute_subdivs(int(rpdat.rp_shadowmap_cascade), int(rpdat.rp_shadowmap_atlas_lod_subdivisions))
|
||||
subdiv_text = "Subdivisions: " + ', '.join(map(str, subdivs_list))
|
||||
subdiv_text = "Subdivisions for spot lights: " + ', '.join(map(str, subdivs_list))
|
||||
colatlas_lod_info.label(text=subdiv_text, icon="IMAGE_ZDEPTH")
|
||||
|
||||
if not rpdat.rp_shadowmap_atlas_single_map:
|
||||
colatlas_lod_info = colatlas_lod.row()
|
||||
colatlas_lod_info.alignment = 'RIGHT'
|
||||
subdivs_list = self.compute_subdivs(int(rpdat.rp_shadowmap_cube), int(rpdat.rp_shadowmap_atlas_lod_subdivisions))
|
||||
subdiv_text = "Subdivisions for point lights: " + ', '.join(map(str, subdivs_list))
|
||||
colatlas_lod_info.label(text=subdiv_text, icon="IMAGE_ZDEPTH")
|
||||
|
||||
size_warning = int(rpdat.rp_shadowmap_cascade) > 2048 or int(rpdat.rp_shadowmap_cube) > 2048
|
||||
|
||||
colatlas.prop(rpdat, 'rp_shadowmap_atlas_single_map')
|
||||
# show size for single texture
|
||||
if rpdat.rp_shadowmap_atlas_single_map:
|
||||
colatlas_single = colatlas.column()
|
||||
colatlas_single.prop(rpdat, 'rp_shadowmap_atlas_max_size')
|
||||
if int(rpdat.rp_shadowmap_cascade) >= int(rpdat.rp_shadowmap_atlas_max_size):
|
||||
print(rpdat.rp_shadowmap_atlas_max_size)
|
||||
colatlas_warning = colatlas_single.row()
|
||||
colatlas_warning.alignment = 'RIGHT'
|
||||
colatlas_warning.label(text=f'Warning: {rpdat.rp_shadowmap_atlas_max_size} is too small for the shadowmap size: {rpdat.rp_shadowmap_cascade}', icon="ERROR")
|
||||
if rpdat.rp_shadowmap_atlas_max_size != '':
|
||||
atlas_size = int(rpdat.rp_shadowmap_atlas_max_size)
|
||||
shadowmap_size = int(rpdat.rp_shadowmap_cascade)
|
||||
|
||||
if shadowmap_size > 2048:
|
||||
size_warning = True
|
||||
|
||||
point_lights = self.lights_number_atlas(rpdat, atlas_size, shadowmap_size, 'point')
|
||||
spot_lights = self.lights_number_atlas(rpdat, atlas_size, shadowmap_size, 'spot')
|
||||
dir_lights = self.lights_number_atlas(rpdat, atlas_size, shadowmap_size, 'sun')
|
||||
|
||||
col = colatlas_single.row()
|
||||
col.alignment = 'RIGHT'
|
||||
col.label(text=f'Enough space for { point_lights } point lights or { spot_lights } spot lights or { dir_lights } directional lights.')
|
||||
else:
|
||||
# show size for all types
|
||||
colatlas_mixed = colatlas.column()
|
||||
colatlas_mixed.prop(rpdat, 'rp_shadowmap_atlas_max_size_spot')
|
||||
if int(rpdat.rp_shadowmap_cascade) > int(rpdat.rp_shadowmap_atlas_max_size_spot):
|
||||
colatlas_warning = colatlas_mixed.row()
|
||||
colatlas_warning.alignment = 'RIGHT'
|
||||
colatlas_warning.label(text=f'Warning: {rpdat.rp_shadowmap_atlas_max_size_spot} is too small for the shadowmap size: {rpdat.rp_shadowmap_cascade}', icon="ERROR")
|
||||
|
||||
if rpdat.rp_shadowmap_atlas_max_size_spot != '':
|
||||
atlas_size = int(rpdat.rp_shadowmap_atlas_max_size_spot)
|
||||
shadowmap_size = int(rpdat.rp_shadowmap_cascade)
|
||||
spot_lights = self.lights_number_atlas(rpdat, atlas_size, shadowmap_size, 'spot')
|
||||
|
||||
if shadowmap_size > 2048:
|
||||
size_warning = True
|
||||
|
||||
col = colatlas_mixed.row()
|
||||
col.alignment = 'RIGHT'
|
||||
col.label(text=f'Enough space for {spot_lights} spot lights.')
|
||||
|
||||
colatlas_mixed.prop(rpdat, 'rp_shadowmap_atlas_max_size_point')
|
||||
if int(rpdat.rp_shadowmap_cascade) >= int(rpdat.rp_shadowmap_atlas_max_size_point):
|
||||
colatlas_warning = colatlas_mixed.row()
|
||||
colatlas_warning.alignment = 'RIGHT'
|
||||
colatlas_warning.label(text=f'Warning: {rpdat.rp_shadowmap_atlas_max_size_point} is too small for the shadowmap size: {rpdat.rp_shadowmap_cube}', icon="ERROR")
|
||||
|
||||
if rpdat.rp_shadowmap_atlas_max_size_point != '':
|
||||
atlas_size = int(rpdat.rp_shadowmap_atlas_max_size_point)
|
||||
shadowmap_size = int(rpdat.rp_shadowmap_cube)
|
||||
point_lights = self.lights_number_atlas(rpdat, atlas_size, shadowmap_size, 'point')
|
||||
|
||||
if shadowmap_size > 2048:
|
||||
size_warning = True
|
||||
|
||||
col = colatlas_mixed.row()
|
||||
col.alignment = 'RIGHT'
|
||||
col.label(text=f'Enough space for {point_lights} point lights.')
|
||||
|
||||
colatlas_mixed.prop(rpdat, 'rp_shadowmap_atlas_max_size_sun')
|
||||
if int(rpdat.rp_shadowmap_cascade) >= int(rpdat.rp_shadowmap_atlas_max_size_sun):
|
||||
colatlas_warning = colatlas_mixed.row()
|
||||
colatlas_warning.alignment = 'RIGHT'
|
||||
colatlas_warning.label(text=f'Warning: {rpdat.rp_shadowmap_atlas_max_size_sun} is too small for the shadowmap size: {rpdat.rp_shadowmap_cascade}', icon="ERROR")
|
||||
|
||||
if rpdat.rp_shadowmap_atlas_max_size_sun != '':
|
||||
atlas_size = int(rpdat.rp_shadowmap_atlas_max_size_sun)
|
||||
shadowmap_size = int(rpdat.rp_shadowmap_cascade)
|
||||
dir_lights = self.lights_number_atlas(rpdat, atlas_size, shadowmap_size, 'sun')
|
||||
|
||||
if shadowmap_size > 2048:
|
||||
size_warning = True
|
||||
|
||||
col = colatlas_mixed.row()
|
||||
col.alignment = 'RIGHT'
|
||||
col.label(text=f'Enough space for {dir_lights} directional lights.')
|
||||
|
||||
# show warning when user picks a size higher than 2048 (arbitrary number).
|
||||
if size_warning:
|
||||
col = layout.column()
|
||||
row = col.row()
|
||||
row.alignment = 'RIGHT'
|
||||
row.label(text='Warning: Game will crash if texture size is higher than max texture size allowed by target.', icon='ERROR')
|
||||
|
||||
class ARM_PT_RenderPathVoxelsPanel(bpy.types.Panel):
|
||||
bl_label = "Voxel AO"
|
||||
|
|
Loading…
Reference in a new issue