- Jun 29, 2015
-
-
Bastien Montagne authored
Somehow our mapping from FBX int 'enum' code to string representation of rotation order was pure nonsense, only giving correct result for default 'XYZ'. Note that we fallback to EulerXYZ in case of 'SphericXYZ', not even sure what this is! Conflicts: io_scene_fbx/__init__.py
-
- Jun 18, 2015
-
-
Bastien Montagne authored
So, it appears some importers (at least UE4) do not use UnitScaleFactor defined by FBX, which is assumed to be a way to say 'this FBX file uses units n times default FBX unit' (default FBX unit being centimeter - afaik, at least I saw some FBX from Max with a UnitScaleFactor of 2.54 - inches). Hence, we have to add yet another stupid option to apply that 'unit scaling' to objects instead (as part of global scaling)... Hurra.
-
Bastien Montagne authored
-
Bastien Montagne authored
Man... this scaling issue becomes ridiculous! Tried to fix it again also regarding (what is supposed to be) FBX scale/units handling. Since we store Blender's unit system (with 1BU == 1m in case of none) as the UnitScaleFactor element, we actually *do not* have to also scale objects themselves... In theory. Since I have to wait hours here to get my UE4 repo updated and rebuild the monster, comitting this now, we'll see later for FBXSDK behavior.
-
- Jun 08, 2015
-
-
Campbell Barton authored
- Jun 05, 2015
-
-
Bastien Montagne authored
-
- Jun 04, 2015
-
-
Bastien Montagne authored
This only fixes the 'symptoms', root of the issue here is that we get a weird covariance matrix - Blender's own invert function errors on it, this script's matrix_invert func does give some result, but in any case final result is not what one would expect...
-
- Jun 03, 2015
-
-
Bastien Montagne authored
-
- May 31, 2015
-
-
Folkert de Vries authored
-
- May 29, 2015
-
-
Pablo Vazquez authored
Don't print tile size on terminal, was only for debug
-
- May 26, 2015
-
-
Greg Zaal authored
Also reduce default margin slightly, especially for spacing between vertically-aligned nodes.
-
- May 24, 2015
-
-
Brendon Murphy authored
-
Brendon Murphy authored
-
Brendon Murphy authored
-
- May 22, 2015
-
-
Bastien Montagne authored
Still unsure we are doing the 'right' thing here, but at least let's be consistent between our importer and exporter!
-
Bastien Montagne authored
-
Bastien Montagne authored
This sounds suspicious to me, but it’s FBX, so could be the solution, we'll see...
-
- May 20, 2015
-
-
Brendon Murphy authored
-
- May 19, 2015
-
-
Bastien Montagne authored
Now, we consider default BU as 1 meter (100 FBX units), instead of 1 FBX unit (1cm)...
-
Bastien Montagne authored
Yes... 10h of work, for a oneliner fixing a simple stupid dummy missing connection between the empty used as armature 'object', and its (void, useless) 'NodeAttribute' data... Why such basic harmless error breaks something (aparently) completly unrelated - and why is it breaking anything, btw - is to be added on the Olympus Mons of FBXSDK madness. Not to mention the usual total lack of parsing warnings/errors from that 'thing'.
-
Bastien Montagne authored
-
- May 18, 2015
-
-
Bastien Montagne authored
-
Bastien Montagne authored
-
Bastien Montagne authored
-
Bastien Montagne authored
Trying to fix the ugly scaling issue with FBX and animated armatures. No luck so far, all those changes make our generated file closer to those generated by 'official' FBX apps, but does not seem to fix or solve anything...
-
Bastien Montagne authored
-
- May 11, 2015
-
-
Daniel Salazar authored
-
- May 06, 2015
-
-
Bastien Montagne authored
Also, fixed wrong '2.75' blender version statement - no need to update that unless mandatory, this is minimal working version, not 'current' version... And please, always remove menus *before* unregistering, otherwise UI code may try to access removed classes (menus, shortcuts, operators, etc.).
-
- May 04, 2015
-
-
Bastien Montagne authored
-
Brendon Murphy authored
-
Brendon Murphy authored
Updated Authors, added built in xyz math object presets
-
Brendon Murphy authored
-
Brendon Murphy authored
-
- May 03, 2015
-
-
Bastien Montagne authored
Limited, because STL only stores face normals, so we can only fake this by setting all clnors of a same face to that face normal... Guess use case are rather limited, but does not hurt to have it either.
-
- May 02, 2015
-
-
Greg Zaal authored
Tile size would be recalculated constantly (every scene update) when the calculated size was less than 8 pixels (blender's own hard limit) diff --git a/render_auto_tile_size.py b/render_auto_tile_size.py index a773281..00f848e 100644 --- a/render_auto_tile_size.py +++ b/render_auto_tile_size.py @@ -20,7 +20,7 @@ bl_info = { "name": "Auto Tile Size", "description": "Estimate and set the tile size that will render the fastest", "author": "Greg Zaal", - "version": (3, 0), + "version": (3, 1), "blender": (2, 74, 0), "location": "Render Settings > Performance", "warning": "", @@ -300,6 +300,12 @@ def do_set_tile_size(context): else: settings.threads_error = False + # Make sure tile sizes are within the internal limit + tile_x = max(8, tile_x) + tile_y = max(8, tile_y) + tile_x = min(65536, tile_x) + tile_y = min(65536, tile_y) + render.tile_x = tile_x render.tile_y = tile_y
-
Greg Zaal authored
- Let the user choose a specific number for the target tile size (not only limited to powers of 2). - If there are more render threads available than tiles, reduce the tile size until all threads will be utilized - this means you can do tiny border-renders and still utilize 100% of your CPU. - Number of tiles is now displayed in the UI. - Minor tweaks to tooltips and function names. NOTE: The math of calculating the maximum tile size possible while still using all the threads is a bit wonky - it's functional, but not nice. Occasionally when there are many CPU threads (e.g. 16), only 15 of them will be used. Math is not my forte, so some help in this area would be much appreciated. diff --git a/render_auto_tile_size.py b/render_auto_tile_size.py index 8ece451..a773281 100644 --- a/render_auto_tile_size.py +++ b/render_auto_tile_size.py @@ -20,8 +20,8 @@ bl_info = { "name": "Auto Tile Size", "description": "Estimate and set the tile size that will render the fastest", "author": "Greg Zaal", - "version": (2, 7), - "blender": (2, 72, 0), + "version": (3, 0), + "blender": (2, 74, 0), "location": "Render Settings > Performance", "warning": "", "wiki_url": "http://wiki.blender.org/index.php?title=Extensions:2.6/Py/Scripts/Render/Auto_Tile_Size", @@ -31,7 +31,7 @@ bl_info = { import bpy from bpy.app.handlers import persistent -from math import ceil, floor +from math import ceil, floor, sqrt SUPPORTED_RENDER_ENGINES = {'CYCLES', 'BLENDER_RENDER'} @@ -55,16 +55,14 @@ class AutoTileSizeSettings(bpy.types.PropertyGroup): name="Target GPU Tile Size", items=TILE_SIZES, default='256', - description="Square dimentions of tiles", + description="Square dimentions of tiles for GPU rendering", update=_update_tile_size) - cpu_choice = bpy.props.EnumProperty( name="Target CPU Tile Size", items=TILE_SIZES, default='32', - description="Square dimentions of tiles", + description="Square dimentions of tiles for CPU rendering", update=_update_tile_size) - bi_choice = bpy.props.EnumProperty( name="Target CPU Tile Size", items=TILE_SIZES, @@ -72,6 +70,37 @@ class AutoTileSizeSettings(bpy.types.PropertyGroup): description="Square dimentions of tiles", update=_update_tile_size) + gpu_custom = bpy.props.IntProperty( + name="Target Size", + default=256, + min=8, # same as blender's own limits + max=65536, + description="Custom target tile size for GPU rendering", + update=_update_tile_size) + cpu_custom = bpy.props.IntProperty( + name="Target Size", + default=32, + min=8, # same as blender's own limits + max=65536, + description="Custom target tile size for CPU rendering", + update=_update_tile_size) + bi_custom = bpy.props.IntProperty( + name="Target Size", + default=64, + min=8, # same as blender's own limits + max=65536, + description="Custom target tile size", + update=_update_tile_size) + + target_type = bpy.props.EnumProperty( + name="Target tile size", + items=( + ('po2', "Po2", "A choice between powers of 2 (16, 32, 64...)"), + ('custom', "Custom", "Choose any number as the tile size target")), + default='po2', + description="Method of choosing the target tile size", + update=_update_tile_size) + use_optimal = bpy.props.BoolProperty( name="Optimal Tiles", default=True, @@ -89,9 +118,16 @@ class AutoTileSizeSettings(bpy.types.PropertyGroup): default=False, description="Show extra options for more control over the calculated tile size") + thread_error_correct = bpy.props.BoolProperty( + name="Fix", + default=True, + description="Reduce the tile size so that all your available threads are used.", + update=_update_tile_size) + # Internally used props (not for GUI) first_run = bpy.props.BoolProperty(default=True, options={'HIDDEN'}) threads_error = bpy.props.BoolProperty(options={'HIDDEN'}) + num_tiles = bpy.props.IntVectorProperty(default=(0, 0), size=2, options={'HIDDEN'}) prev_choice = bpy.props.StringProperty(default='', options={'HIDDEN'}) prev_engine = bpy.props.StringProperty(default='', options={'HIDDEN'}) prev_device = bpy.props.StringProperty(default='', options={'HIDDEN'}) @@ -109,16 +145,17 @@ def ats_poll(context): return True -def ats_get_engine_is_gpu(engine, device, userpref): +def engine_is_gpu(engine, device, userpref): return engine == 'CYCLES' and device == 'GPU' and userpref.system.compute_device_type != 'NONE' -def ats_get_tilesize_prop(engine, device, userpref): - if ats_get_engine_is_gpu(engine, device, userpref): - return "gpu_choice" +def get_tilesize_prop(engine, device, userpref): + target_type = "_choice" if bpy.context.scene.ats_settings.target_type == 'po2' else "_custom" + if engine_is_gpu(engine, device, userpref): + return ("gpu" + target_type) elif engine == 'CYCLES': - return "cpu_choice" - return "bi_choice" + return ("cpu" + target_type) + return ("bi" + target_type) @persistent @@ -137,9 +174,9 @@ def on_scene_update(scene): # scene.cycles might not always exist (Cycles is an addon)... device = scene.cycles.device if engine == 'CYCLES' else settings.prev_device border = render.use_border - threads = render.threads + threads = get_threads(context, device) - choice = getattr(settings, ats_get_tilesize_prop(engine, device, userpref)) + choice = getattr(settings, get_tilesize_prop(engine, device, userpref)) res = get_actual_res(render) actual_ts = (render.tile_x, render.tile_y) @@ -150,7 +187,7 @@ def on_scene_update(scene): device != settings.prev_device or border != settings.prev_border or threads != settings.prev_threads or - choice != settings.prev_choice or + str(choice) != settings.prev_choice or res != settings.prev_res[:] or border_res != settings.prev_border_res[:] or actual_ts != settings.prev_actual_tile_size[:]) @@ -163,6 +200,61 @@ def get_actual_res(render): # floor is implicitly done by int conversion... return (int(render.resolution_x * rend_percent), int(render.resolution_y * rend_percent)) +def get_threads(context, device): + render = context.scene.render + engine = render.engine + userpref = context.user_preferences + + if engine_is_gpu(engine, device, userpref): + gpu_device_str = userpref.system.compute_device + if 'MULTI' in gpu_device_str: + threads = int(gpu_device_str.split('_')[-1]) + else: + threads = 1 + else: + threads = render.threads + + return threads + +def max_tile_size(threads, xres, yres): + ''' Give the largest tile size that will still use all threads ''' + + render_area = xres * yres + tile_area = render_area / threads + tile_length = sqrt(tile_area) + + # lists: num x tiles, num y tiles, squareness, total tiles + perfect_attempts = [] # attempts with correct number of tiles + attempts = [] # all attempts, even if incorrect number of tiles + + axes = [xres, yres] + funcs = [floor, ceil] + + for axis in axes: + sec_axis = yres if axis == xres else xres + for func in funcs: + primary = func(axis / tile_length) + if primary > 0: + secondary = threads / primary + ts_p = axis/primary + ts_s = sec_axis/secondary + squareness = max(ts_p, ts_s) - min(ts_p, ts_s) + attempt = [primary if axis == xres else secondary, primary if axis != xres else secondary, squareness, primary * secondary] + if attempt not in attempts: + attempts.append(attempt) + if secondary.is_integer(): # will only be an integer if there are the right number of tiles + perfect_attempts.append(attempt) + + if perfect_attempts: # prefer to use attempt that has exactly the right number of tiles + attempts = perfect_attempts + + attempt = sorted(attempts, key=lambda k: k[2])[0] # pick set with most square tiles + numtiles_x = round(attempt[0]) + numtiles_y = round(attempt[1]) + tile_x = ceil(xres / numtiles_x) + tile_y = ceil(yres / numtiles_y) + + return (tile_x, tile_y) def do_set_tile_size(context): if not ats_poll(context): @@ -176,7 +268,6 @@ def do_set_tile_size(context): engine = render.engine device = scene.cycles.device if engine == 'CYCLES' else settings.prev_device border = render.use_border - threads = render.threads realxres, realyres = xres, yres = res = get_actual_res(scene.render) @@ -184,11 +275,12 @@ def do_set_tile_size(context): xres = round(xres * (render.border_max_x - render.border_min_x)) yres = round(yres * (render.border_max_y - render.border_min_y)) - choice = getattr(settings, ats_get_tilesize_prop(engine, device, userpref)) + choice = getattr(settings, get_tilesize_prop(engine, device, userpref)) target = int(choice) numtiles_x = ceil(xres / target) numtiles_y = ceil(yres / target) + settings.num_tiles = (numtiles_x, numtiles_y) if settings.use_optimal: tile_x = ceil(xres / numtiles_x) tile_y = ceil(yres / numtiles_y) @@ -198,20 +290,25 @@ def do_set_tile_size(context): print("Tile size: %dx%d (%dx%d tiles)" % (tile_x, tile_y, ceil(xres / tile_x), ceil(yres / tile_y))) - render.tile_x = tile_x - render.tile_y = tile_y - # Detect if there are fewer tiles than available threads - if ((numtiles_x * numtiles_y) < threads) and not ats_get_engine_is_gpu(engine, device, userpref): + threads = get_threads(context, device) + if ((numtiles_x * numtiles_y) < threads): settings.threads_error = True + if settings.thread_error_correct: + tile_x, tile_y = max_tile_size(threads, xres, yres) + settings.num_tiles = (ceil(xres/tile_x), ceil(yres/tile_y)) else: settings.threads_error = False + render.tile_x = tile_x + render.tile_y = tile_y + + settings.prev_engine = engine settings.prev_device = device settings.prev_border = border settings.prev_threads = threads - settings.prev_choice = choice + settings.prev_choice = str(choice) settings.prev_res = res settings.prev_border_res = (render.border_min_x, render.border_min_y, render.border_max_x, render.border_max_y) settings.prev_actual_tile_size = (tile_x, tile_y) @@ -252,16 +349,21 @@ def ui_layout(engine, layout, context): row.prop(settings, "is_enabled", toggle=True) row.prop(settings, "use_advanced_ui", toggle=True, text="", icon='PREFERENCES') - sub = col.column(align=True) + sub = col.column(align=False) sub.enabled = settings.is_enabled if settings.use_advanced_ui: - sub.label("Target tile size:") + row = sub.row(align=True) + row.label("Target tile size:") + row.separator() + row.prop(settings, "target_type", expand=True) row = sub.row(align=True) - row.prop(settings, ats_get_tilesize_prop(engine, device, userpref), expand=True) + row.prop(settings, get_tilesize_prop(engine, device, userpref), expand=True) sub.prop(settings, "use_optimal", text="Calculate Optimal Size") + sub.label("Number of tiles: %s x %s (Total: %s)" % (settings.num_tiles[0], settings.num_tiles[1], settings.num_tiles[0] * settings.num_tiles[1])) + if settings.first_run: sub = layout.column(align=True) sub.operator("render.autotilesize_set", text="First-render fix", icon='ERROR') @@ -272,9 +374,11 @@ def ui_layout(engine, layout, context): if (render.tile_x / render.tile_y > 2) or (render.tile_x / render.tile_y < 0.5): # if not very square tile sub.label(text="Warning: Tile size is not very square", icon='ERROR') sub.label(text=" Try a slightly different resolution") - sub.label(text=" or choose \"Exact\" above") if settings.threads_error: - sub.label(text="Warning: Fewer tiles than render threads", icon='ERROR') + row = sub.row(align=True) + row.alignment = 'CENTER' + row.label(text="Warning: Fewer tiles than threads.", icon='ERROR') + row.prop(settings, 'thread_error_correct') def menu_func_cycles(self, context):
-
- May 01, 2015
-
-
Howard Trickey authored
This is really a different bug that the one that was reopened but I didn't know that when I reopened it. It shouldn't happen that vertices get repeated in a face, but when doing it happens in extreme cases, and for now am fixing by just removing those duplicates before calling the make-face routine.
-
Howard Trickey authored
Crash caused by some vertices in the input model being doubled. The code to test for the maximum inset deduped the vertices but the faces were not remapped. Fixed by having that test code not dedup the vertices.
-
Greg Zaal authored
Adding an image sequence now works for Shader nodes too (not sure when this broke?) Also improved/fixed the logic of figuring out what image sequence the user is trying to add - sometimes they select only one frame, sometimes they select all the frames (Blender itself is inconsistent about this behavior)
-