2026-02-16
This commit is contained in:
@@ -29,8 +29,6 @@ from .. import render
|
||||
def frame_change_post_apply_T71908_workaround(context, depsgraph=None):
|
||||
if not render.is_rendering():
|
||||
return
|
||||
if not vcu.is_blender_281():
|
||||
return
|
||||
|
||||
dprops = context.scene.flip_fluid.get_domain_properties()
|
||||
if dprops is None:
|
||||
@@ -76,24 +74,97 @@ def frame_change_post_apply_T71908_workaround(context, depsgraph=None):
|
||||
# Also apply to other FF_GeometryNodes inputs in case the user wants to keyframe these values.
|
||||
|
||||
input_name_list_surface = [
|
||||
"Input_4", # Motion Blur Scale
|
||||
"Input_6", # Enable Motion Blur
|
||||
"Socket_0", # Blur Velocity For Fading
|
||||
"Socket_5", # Shade Smooth Surface
|
||||
"Socket_6", # Blur Iterations
|
||||
"Input_6", # Enable Motion Blur
|
||||
"Input_4", # Motion Blur Scale
|
||||
"Socket_8", # Apply Simulation Time Scale
|
||||
"Socket_9", # Apply Simulation World Scale
|
||||
"Socket_5", # Shade Smooth Surface
|
||||
"Socket_11", # Remove Mesh Near Domain Boundary
|
||||
"Socket_12", # X-
|
||||
"Socket_13", # Y-
|
||||
"Socket_14", # Z-
|
||||
"Socket_15", # X+
|
||||
"Socket_16", # Y+
|
||||
"Socket_17", # Z+
|
||||
"Socket_18", # Distance
|
||||
"Socket_20", # Flatten Mesh Near Domain Boundary
|
||||
"Socket_21", # Water Level Mode
|
||||
"Socket_22", # Water Level
|
||||
"Socket_24", # Flattened Width
|
||||
"Socket_25", # Transition Width
|
||||
"Socket_27", # Store Displacement Attribute
|
||||
"Socket_26", # Store Transition Mask Attribute
|
||||
"Socket_0", # Blur Velocity For Fading
|
||||
"Socket_6", # Blur Iterations
|
||||
]
|
||||
|
||||
input_name_list_particles = [
|
||||
"Input_4", # Motion Blur Scale
|
||||
"Input_6", # Particle Scale
|
||||
"Input_8", # Enable Motion Blur
|
||||
"Input_9", # Enable Point Cloud
|
||||
"Input_10", # Enable Instancing
|
||||
"Socket_0", # Fading Strength
|
||||
"Socket_1", # Fading Width
|
||||
"Socket_2", # Particle Scale Random
|
||||
"Socket_4", # Fading Density
|
||||
"Socket_9", # Shade Smooth Instancing
|
||||
input_name_list_fluid_particles = [
|
||||
"Socket_16", # Apply Material
|
||||
"Input_8", # Enable Motion Blur
|
||||
"Input_4", # Motion Blur Scale
|
||||
"Socket_47", # Apply Simulation Time Scale
|
||||
"Socket_48", # Apply Simulation World Scale
|
||||
"Socket_12", # Particle Display Mode
|
||||
"Input_6", # Particle Scale
|
||||
"Socket_11", # Particle Scale Multiplier
|
||||
"Socket_2", # Particle Scale Random
|
||||
"Socket_21", # Random Bias
|
||||
"Socket_14", # Instancing Mode
|
||||
"Socket_18", # Randomize Instance Rotation
|
||||
"Socket_19", # Align Instance to Velocity
|
||||
"Socket_10", # Shade Smooth Instances
|
||||
"Socket_17", # Realize Instances
|
||||
"Socket_51", # Matched Flattened Surface Displacement
|
||||
"Socket_30", # Age Based Particle Scaling
|
||||
"Socket_31", # Starting Scale Factor
|
||||
"Socket_32", # Scaling Duration (Age)
|
||||
"Socket_33", # Age Offset
|
||||
"Socket_34", # Store Age Scaling Transition Attribute
|
||||
"Socket_24", # Lifetime Based Particle Scaling
|
||||
"Socket_23", # Final Scale Factor
|
||||
"Socket_25", # Scaling Duration (Lifetime)
|
||||
"Socket_26", # Lifetime Offset
|
||||
"Socket_28", # Store Lifetime Scaling Transition Attribute
|
||||
"Socket_36", # Filter Particle by Source ID
|
||||
"Socket_37", # Source ID 0
|
||||
"Socket_38", # Source ID 1
|
||||
"Socket_39", # Source ID 2
|
||||
"Socket_40", # Source ID 3
|
||||
"Socket_41", # Source ID 4
|
||||
"Socket_42", # Source ID 5
|
||||
"Socket_43", # Source ID 6
|
||||
"Socket_44", # Source ID 7
|
||||
"Socket_45", # Source ID 8
|
||||
"Socket_1", # Fading Width
|
||||
"Socket_0", # Fading Strength
|
||||
"Socket_4", # Fading Density
|
||||
]
|
||||
|
||||
input_name_list_whitewater = [
|
||||
"Socket_16", # Apply Material
|
||||
"Input_8", # Enable Motion Blur
|
||||
"Input_4", # Motion Blur Scale
|
||||
"Socket_30", # Apply Simulation Time Scale
|
||||
"Socket_31", # Apply Simulation World Scale
|
||||
"Socket_12", # Particle Display Mode
|
||||
"Input_6", # Particle Scale
|
||||
"Socket_11", # Particle Scale Multiplier
|
||||
"Socket_2", # Particle Scale Random
|
||||
"Socket_21", # Random Bias
|
||||
"Socket_14", # Instancing Mode
|
||||
"Socket_18", # Randomize Instance Rotation
|
||||
"Socket_19", # Align Instance to Velocity
|
||||
"Socket_10", # Shade Smooth Instances
|
||||
"Socket_17", # Realize Instances
|
||||
"Socket_34", # Matched Flattened Surface Displacement
|
||||
"Socket_24", # Lifetime Based Particle Scaling
|
||||
"Socket_23", # Final Scale Factor
|
||||
"Socket_25", # Scaling Duration (Lifetime)
|
||||
"Socket_26", # Lifetime Offset
|
||||
"Socket_28", # Store Lifetime Scaling Transition Attribute
|
||||
"Socket_1", # Fading Width
|
||||
"Socket_0", # Fading Strength
|
||||
"Socket_4", # Fading Density
|
||||
]
|
||||
|
||||
for obj in cache_objects:
|
||||
@@ -103,8 +174,10 @@ def frame_change_post_apply_T71908_workaround(context, depsgraph=None):
|
||||
mod_name = obj.modifiers[i].name
|
||||
if mod_name.startswith("FF_GeometryNodesSurface"):
|
||||
input_name_list = input_name_list_surface
|
||||
elif mod_name.startswith("FF_GeometryNodesFluidParticles") or mod_name.startswith("FF_GeometryNodesWhitewater"):
|
||||
input_name_list = input_name_list_particles
|
||||
elif mod_name.startswith("FF_GeometryNodesFluidParticles"):
|
||||
input_name_list = input_name_list_fluid_particles
|
||||
elif mod_name.startswith("FF_GeometryNodesWhitewater"):
|
||||
input_name_list = input_name_list_whitewater
|
||||
else:
|
||||
continue
|
||||
|
||||
@@ -153,20 +226,12 @@ def load_post_update_cycles_visibility_forward_compatibility_from_blender_3():
|
||||
def set_cycles_ray_visibility(bl_object, is_enabled):
|
||||
# Cycles may not be enabled in the user's preferences
|
||||
try:
|
||||
if vcu.is_blender_30():
|
||||
bl_object.visible_camera = is_enabled
|
||||
bl_object.visible_diffuse = is_enabled
|
||||
bl_object.visible_glossy = is_enabled
|
||||
bl_object.visible_transmission = is_enabled
|
||||
bl_object.visible_volume_scatter = is_enabled
|
||||
bl_object.visible_shadow = is_enabled
|
||||
else:
|
||||
bl_object.cycles_visibility.camera = is_enabled
|
||||
bl_object.cycles_visibility.transmission = is_enabled
|
||||
bl_object.cycles_visibility.diffuse = is_enabled
|
||||
bl_object.cycles_visibility.scatter = is_enabled
|
||||
bl_object.cycles_visibility.glossy = is_enabled
|
||||
bl_object.cycles_visibility.shadow = is_enabled
|
||||
bl_object.visible_camera = is_enabled
|
||||
bl_object.visible_diffuse = is_enabled
|
||||
bl_object.visible_glossy = is_enabled
|
||||
bl_object.visible_transmission = is_enabled
|
||||
bl_object.visible_volume_scatter = is_enabled
|
||||
bl_object.visible_shadow = is_enabled
|
||||
except:
|
||||
pass
|
||||
|
||||
@@ -394,10 +459,10 @@ def is_keyframed_hide_render_issue_relevant(scene):
|
||||
if not obj.animation_data:
|
||||
continue
|
||||
anim_data = obj.animation_data
|
||||
if not anim_data.action or not anim_data.action.fcurves:
|
||||
if not anim_data.action or not anim_data.action.layers[0].strips[0].channelbag(anim_data.action.slots[0]).fcurves:
|
||||
continue
|
||||
|
||||
for fcurve in anim_data.action.fcurves:
|
||||
for fcurve in anim_data.action.layers[0].strips[0].channelbag(anim_data.action.slots[0]).fcurves:
|
||||
if fcurve.data_path == "hide_render":
|
||||
is_relevant = True
|
||||
break
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import bpy, os, json, time
|
||||
import bpy, os, json, time, aud
|
||||
|
||||
from . import version_compatibility_utils as vcu
|
||||
|
||||
@@ -24,12 +24,6 @@ def get_sounds_directory():
|
||||
|
||||
|
||||
def play_sound(json_audio_filepath, block=False):
|
||||
if not vcu.is_blender_28():
|
||||
# aud not supported in Blender 2.79 or lower
|
||||
return
|
||||
|
||||
import aud
|
||||
|
||||
with open(json_audio_filepath, 'r', encoding='utf-8') as f:
|
||||
json_data = json.loads(f.read())
|
||||
|
||||
|
||||
@@ -54,10 +54,11 @@ def flip_fluid_object_to_dict(obj, object_properties):
|
||||
|
||||
def is_property_animated(obj, prop_name, index=0, use_exact_path=False):
|
||||
anim_data = obj.animation_data
|
||||
if not anim_data or not anim_data.action or not anim_data.action.fcurves:
|
||||
|
||||
if not anim_data or not anim_data.action or not anim_data.action.layers[0].strips[0].channelbag(anim_data.action.slots[0]).fcurves:
|
||||
return False
|
||||
|
||||
for fcurve in anim_data.action.fcurves:
|
||||
for fcurve in anim_data.action.layers[0].strips[0].channelbag(anim_data.action.slots[0]).fcurves:
|
||||
path = fcurve.data_path
|
||||
is_match = path.endswith(prop_name)
|
||||
if use_exact_path:
|
||||
@@ -69,10 +70,11 @@ def is_property_animated(obj, prop_name, index=0, use_exact_path=False):
|
||||
|
||||
def is_property_path_animated(obj, path_name, index = 0):
|
||||
anim_data = obj.animation_data
|
||||
if not anim_data or not anim_data.action or not anim_data.action.fcurves:
|
||||
|
||||
if not anim_data or not anim_data.action or not anim_data.action.layers[0].strips[0].channelbag(anim_data.action.slots[0]).fcurves:
|
||||
return False
|
||||
|
||||
for fcurve in anim_data.action.fcurves:
|
||||
for fcurve in anim_data.action.layers[0].strips[0].channelbag(anim_data.action.slots[0]).fcurves:
|
||||
if fcurve.data_path == path_name and fcurve.array_index == index:
|
||||
return True
|
||||
return False
|
||||
@@ -87,7 +89,7 @@ def is_vector_animated(obj, prop_name, vector_size = 3):
|
||||
|
||||
def get_property_fcurve(obj, prop_name, index=0, use_exact_path=False):
|
||||
anim_data = obj.animation_data
|
||||
for fcurve in anim_data.action.fcurves:
|
||||
for fcurve in anim_data.action.layers[0].strips[0].channelbag(anim_data.action.slots[0]).fcurves:
|
||||
path = fcurve.data_path
|
||||
|
||||
is_match = path.endswith(prop_name)
|
||||
@@ -99,7 +101,7 @@ def get_property_fcurve(obj, prop_name, index=0, use_exact_path=False):
|
||||
|
||||
def get_property_fcurve_from_path(obj, path_name, index = 0):
|
||||
anim_data = obj.animation_data
|
||||
for fcurve in anim_data.action.fcurves:
|
||||
for fcurve in anim_data.action.layers[0].strips[0].channelbag(anim_data.action.slots[0]).fcurves:
|
||||
if fcurve.data_path == path_name and fcurve.array_index == index:
|
||||
return fcurve
|
||||
|
||||
|
||||
@@ -22,6 +22,9 @@ IS_INSTALLATION_UTILS_INITIALIZED = False
|
||||
IS_INSTALLATION_COMPLETE = False
|
||||
IS_STABLE_BUILD = True
|
||||
|
||||
SUPPORT_LICENSE_TYPE = "Individual"
|
||||
SUPPORT_LICENSE_ID = "854NV"
|
||||
|
||||
IS_MIXBOX_SUPPORTED = True
|
||||
IS_MIXBOX_INSTALLATION_COMPLETE = False
|
||||
MIXBOX_BOOST_FACTOR = 1.2
|
||||
@@ -164,10 +167,6 @@ def update_preset_library_installation_status():
|
||||
IS_PRESET_LIBRARY_INSTALLATION_COMPLETE = False
|
||||
PRESET_LIBRARY_INSTALLATIONS = []
|
||||
|
||||
if not vcu.is_blender_33():
|
||||
# Asset library is only available in Blender 3.3 or later
|
||||
return
|
||||
|
||||
bl_preferences = bpy.context.preferences
|
||||
bl_filepaths = bl_preferences.filepaths
|
||||
for lib_entry in bl_filepaths.asset_libraries:
|
||||
@@ -251,6 +250,12 @@ def get_library_list():
|
||||
return library_list
|
||||
|
||||
|
||||
def get_support_license_label():
|
||||
global SUPPORT_LICENSE_TYPE
|
||||
global SUPPORT_LICENSE_ID
|
||||
return SUPPORT_LICENSE_TYPE + " " + SUPPORT_LICENSE_ID
|
||||
|
||||
|
||||
def __load_post_update_is_addon_active():
|
||||
tag_addon_inactive()
|
||||
if bpy.context.scene.flip_fluid.is_domain_object_set():
|
||||
|
||||
@@ -20,9 +20,12 @@ from . import version_compatibility_utils as vcu
|
||||
|
||||
IS_INSTALLATION_UTILS_INITIALIZED = False
|
||||
IS_INSTALLATION_COMPLETE = False
|
||||
IS_STABLE_BUILD = @FLUIDENGINE_VERSION_TYPE_IS_STABLE_BUILD_PYTHON@
|
||||
IS_STABLE_BUILD = @FFENGINE_VERSION_TYPE_IS_STABLE_BUILD_PYTHON@
|
||||
|
||||
IS_MIXBOX_SUPPORTED = @FLUIDENGINE_IS_MIXBOX_SUPPORTED@
|
||||
SUPPORT_LICENSE_TYPE = "@FFENGINE_VERSION_SUPPORT_LICENSE_TYPE@"
|
||||
SUPPORT_LICENSE_ID = "@FFENGINE_VERSION_SUPPORT_LICENSE_ID@"
|
||||
|
||||
IS_MIXBOX_SUPPORTED = @FFENGINE_IS_MIXBOX_SUPPORTED@
|
||||
IS_MIXBOX_INSTALLATION_COMPLETE = False
|
||||
MIXBOX_BOOST_FACTOR = 1.2
|
||||
|
||||
@@ -164,10 +167,6 @@ def update_preset_library_installation_status():
|
||||
IS_PRESET_LIBRARY_INSTALLATION_COMPLETE = False
|
||||
PRESET_LIBRARY_INSTALLATIONS = []
|
||||
|
||||
if not vcu.is_blender_33():
|
||||
# Asset library is only available in Blender 3.3 or later
|
||||
return
|
||||
|
||||
bl_preferences = bpy.context.preferences
|
||||
bl_filepaths = bl_preferences.filepaths
|
||||
for lib_entry in bl_filepaths.asset_libraries:
|
||||
@@ -251,6 +250,12 @@ def get_library_list():
|
||||
return library_list
|
||||
|
||||
|
||||
def get_support_license_label():
|
||||
global SUPPORT_LICENSE_TYPE
|
||||
global SUPPORT_LICENSE_ID
|
||||
return SUPPORT_LICENSE_TYPE + " " + SUPPORT_LICENSE_ID
|
||||
|
||||
|
||||
def __load_post_update_is_addon_active():
|
||||
tag_addon_inactive()
|
||||
if bpy.context.scene.flip_fluid.is_domain_object_set():
|
||||
|
||||
@@ -87,102 +87,59 @@ def is_blender_44():
|
||||
|
||||
def is_blender_45():
|
||||
return bpy.app.version >= (4, 5, 0)
|
||||
|
||||
|
||||
def register_dict_property(dict_object, name_str, prop):
|
||||
if is_blender_28():
|
||||
# must use exec as the statement will result in invalid syntax
|
||||
# if script is run in Python versions that do nupport annotation syntax
|
||||
exec("dict_object[name_str]: prop")
|
||||
else:
|
||||
dict_object[name_str] = prop
|
||||
|
||||
|
||||
def convert_attribute_to_28(prop_name):
|
||||
if is_blender_28():
|
||||
p = prop_name
|
||||
return "temp_prop = " + p + "; del " + p + "; " + p + ": temp_prop; del temp_prop"
|
||||
else:
|
||||
return ""
|
||||
print("FLIP Fluids Warning: 'convert_attribute_to_28' method is deprecated. Contact the developers if you see this message. This message is not an error and can be safely ignored.")
|
||||
p = prop_name
|
||||
return "temp_prop = " + p + "; del " + p + "; " + p + ": temp_prop; del temp_prop"
|
||||
|
||||
|
||||
def get_active_object(context=None):
|
||||
if context is None:
|
||||
context = bpy.context
|
||||
if is_blender_28():
|
||||
return context.active_object
|
||||
else:
|
||||
return context.scene.objects.active
|
||||
return context.active_object
|
||||
|
||||
|
||||
def set_active_object(obj, context=None):
|
||||
if context is None:
|
||||
context = bpy.context
|
||||
if is_blender_28():
|
||||
context.view_layer.objects.active = obj
|
||||
else:
|
||||
context.scene.objects.active = obj
|
||||
context.view_layer.objects.active = obj
|
||||
|
||||
|
||||
def select_get(obj):
|
||||
if is_blender_28():
|
||||
return obj.select_get()
|
||||
else:
|
||||
return obj.select
|
||||
return obj.select_get()
|
||||
|
||||
|
||||
def select_set(obj, boolval):
|
||||
if is_blender_28():
|
||||
obj.select_set(boolval)
|
||||
else:
|
||||
obj.select = boolval
|
||||
obj.select_set(boolval)
|
||||
|
||||
|
||||
|
||||
def get_object_display_type(obj):
|
||||
if is_blender_28():
|
||||
return obj.display_type
|
||||
else:
|
||||
return obj.draw_type
|
||||
return obj.display_type
|
||||
|
||||
|
||||
def set_object_display_type(obj, display_type):
|
||||
if is_blender_28():
|
||||
obj.display_type = display_type
|
||||
else:
|
||||
obj.draw_type = display_type
|
||||
obj.display_type = display_type
|
||||
|
||||
|
||||
def set_object_hide_viewport(obj, display_bool):
|
||||
if is_blender_28():
|
||||
if obj.hide_get() != display_bool:
|
||||
obj.hide_set(display_bool)
|
||||
else:
|
||||
if obj.hide != display_bool:
|
||||
obj.hide = display_bool
|
||||
if obj.hide_get() != display_bool:
|
||||
obj.hide_set(display_bool)
|
||||
|
||||
|
||||
def get_object_hide_viewport(obj):
|
||||
if is_blender_28():
|
||||
return obj.hide_get()
|
||||
else:
|
||||
return obj.hide
|
||||
return obj.hide_get()
|
||||
|
||||
|
||||
def toggle_outline_eye_icon(obj):
|
||||
if is_blender_28():
|
||||
obj.hide_viewport = not obj.hide_viewport
|
||||
else:
|
||||
obj.hide = not obj.hide
|
||||
obj.hide_viewport = not obj.hide_viewport
|
||||
|
||||
|
||||
def set_object_instance_type(obj, display_type):
|
||||
if is_blender_28():
|
||||
if obj.instance_type != display_type:
|
||||
obj.instance_type = display_type
|
||||
else:
|
||||
if obj.dupli_type != display_type:
|
||||
obj.dupli_type = display_type
|
||||
if obj.instance_type != display_type:
|
||||
obj.instance_type = display_type
|
||||
|
||||
|
||||
def get_flip_fluids_collection(context):
|
||||
@@ -205,62 +162,52 @@ def get_flip_mesh_collection(context):
|
||||
def link_fluid_mesh_object(obj, context=None):
|
||||
if context is None:
|
||||
context = bpy.context
|
||||
if is_blender_28():
|
||||
mesh_collection = get_flip_mesh_collection(context)
|
||||
mesh_collection.objects.link(obj)
|
||||
else:
|
||||
context.scene.objects.link(obj)
|
||||
mesh_collection = get_flip_mesh_collection(context)
|
||||
mesh_collection.objects.link(obj)
|
||||
|
||||
|
||||
def link_object(obj, context=None):
|
||||
if context is None:
|
||||
context = bpy.context
|
||||
if is_blender_28():
|
||||
flip_collection = get_flip_fluids_collection(context)
|
||||
flip_collection.objects.link(obj)
|
||||
else:
|
||||
context.scene.objects.link(obj)
|
||||
flip_collection = get_flip_fluids_collection(context)
|
||||
flip_collection.objects.link(obj)
|
||||
|
||||
|
||||
def link_object_to_master_scene(obj, context=None):
|
||||
if context is None:
|
||||
context = bpy.context
|
||||
if is_blender_28():
|
||||
context.scene.collection.objects.link(obj)
|
||||
else:
|
||||
context.scene.objects.link(obj)
|
||||
context.scene.collection.objects.link(obj)
|
||||
|
||||
|
||||
def add_to_flip_fluids_collection(obj, context):
|
||||
if context is None:
|
||||
context = bpy.context
|
||||
if is_blender_28():
|
||||
flip_collection = get_flip_fluids_collection(context)
|
||||
if flip_collection.objects.get(obj.name):
|
||||
return
|
||||
flip_collection.objects.link(obj)
|
||||
flip_collection = get_flip_fluids_collection(context)
|
||||
if flip_collection.objects.get(obj.name):
|
||||
return
|
||||
flip_collection.objects.link(obj)
|
||||
|
||||
|
||||
def remove_from_flip_fluids_collection(obj, context):
|
||||
if context is None:
|
||||
context = bpy.context
|
||||
if is_blender_28():
|
||||
flip_collection = get_flip_fluids_collection(context)
|
||||
|
||||
num_collections = 0
|
||||
for collection in bpy.data.collections:
|
||||
if collection.name.startswith("RigidBodyWorld"):
|
||||
# The RigidBodyWorld collection (for RBD objects) is more hidden within the Blend file
|
||||
# and may not be apparent to many users. Ignore this collection in the count so that
|
||||
# it does not appear that the objects dissappear.
|
||||
continue
|
||||
if collection.objects.get(obj.name):
|
||||
num_collections += 1
|
||||
if num_collections == 1 and context.scene.collection.objects.get(obj.name) is None:
|
||||
context.scene.collection.objects.link(obj)
|
||||
flip_collection = get_flip_fluids_collection(context)
|
||||
|
||||
if flip_collection.objects.get(obj.name):
|
||||
flip_collection.objects.unlink(obj)
|
||||
num_collections = 0
|
||||
for collection in bpy.data.collections:
|
||||
if collection.name.startswith("RigidBodyWorld"):
|
||||
# The RigidBodyWorld collection (for RBD objects) is more hidden within the Blend file
|
||||
# and may not be apparent to many users. Ignore this collection in the count so that
|
||||
# it does not appear that the objects dissappear.
|
||||
continue
|
||||
if collection.objects.get(obj.name):
|
||||
num_collections += 1
|
||||
if num_collections == 1 and context.scene.collection.objects.get(obj.name) is None:
|
||||
context.scene.collection.objects.link(obj)
|
||||
|
||||
if flip_collection.objects.get(obj.name):
|
||||
flip_collection.objects.unlink(obj)
|
||||
|
||||
|
||||
def delete_object(obj, remove_mesh_data=True):
|
||||
@@ -282,51 +229,36 @@ def delete_mesh_data(mesh_data):
|
||||
def get_scene_collection(context=None):
|
||||
if context is None:
|
||||
context = bpy.context
|
||||
if is_blender_28():
|
||||
return context.scene.collection
|
||||
else:
|
||||
return context.scene
|
||||
return context.scene.collection
|
||||
|
||||
|
||||
def get_all_scene_objects(context=None):
|
||||
if context is None:
|
||||
context = bpy.context
|
||||
if is_blender_28():
|
||||
return context.scene.collection.all_objects
|
||||
else:
|
||||
return context.scene.objects
|
||||
return context.scene.collection.all_objects
|
||||
|
||||
|
||||
def element_multiply(v1, v2):
|
||||
if is_blender_28():
|
||||
return v1 @ v2
|
||||
else:
|
||||
return v1 * v2
|
||||
return v1 @ v2
|
||||
|
||||
|
||||
def depsgraph_update(context=None):
|
||||
if context is None:
|
||||
context = bpy.context
|
||||
if is_blender_28():
|
||||
depsgraph = context.evaluated_depsgraph_get()
|
||||
depsgraph.update()
|
||||
else:
|
||||
context.scene.update()
|
||||
depsgraph = context.evaluated_depsgraph_get()
|
||||
depsgraph.update()
|
||||
|
||||
|
||||
def object_to_triangle_mesh(obj, matrix_world=None):
|
||||
is_b3d_28 = is_blender_28()
|
||||
|
||||
# To ensure the modifier stack is processed in 2.8, the object's 'hide in viewport'
|
||||
# must be False. This is a limitation of how meshes or exported in Blender.
|
||||
# The 'hide in viewport' status will be set back to the original value at the
|
||||
# end of this method.
|
||||
#
|
||||
# More info: https://developer.blender.org/T71556
|
||||
if is_b3d_28:
|
||||
hide_viewport_status = obj.hide_viewport
|
||||
if hide_viewport_status:
|
||||
obj.hide_viewport = False
|
||||
hide_viewport_status = obj.hide_viewport
|
||||
if hide_viewport_status:
|
||||
obj.hide_viewport = False
|
||||
|
||||
# The 'Edge Split' modifier will disconnect faces from eachother, resulting in
|
||||
# a non-manifold mesh. Disable the edge split modifier from the modifier stack
|
||||
@@ -343,14 +275,9 @@ def object_to_triangle_mesh(obj, matrix_world=None):
|
||||
triangulation_mod = obj.modifiers.new("flip_triangulate", "TRIANGULATE")
|
||||
triangulation_mod.quad_method = 'FIXED'
|
||||
|
||||
if is_b3d_28:
|
||||
depsgraph = bpy.context.evaluated_depsgraph_get()
|
||||
obj_eval = obj.evaluated_get(depsgraph)
|
||||
new_mesh = obj_eval.to_mesh(preserve_all_data_layers=True, depsgraph=depsgraph)
|
||||
else:
|
||||
new_mesh = obj.to_mesh(scene=bpy.context.scene,
|
||||
apply_modifiers=True,
|
||||
settings='RENDER')
|
||||
depsgraph = bpy.context.evaluated_depsgraph_get()
|
||||
obj_eval = obj.evaluated_get(depsgraph)
|
||||
new_mesh = obj_eval.to_mesh(preserve_all_data_layers=True, depsgraph=depsgraph)
|
||||
|
||||
vertex_components = []
|
||||
if matrix_world is None:
|
||||
@@ -360,18 +287,11 @@ def object_to_triangle_mesh(obj, matrix_world=None):
|
||||
vertex_components.append(v.y)
|
||||
vertex_components.append(v.z)
|
||||
else:
|
||||
if is_b3d_28:
|
||||
for mv in new_mesh.vertices:
|
||||
v = matrix_world @ mv.co
|
||||
vertex_components.append(v.x)
|
||||
vertex_components.append(v.y)
|
||||
vertex_components.append(v.z)
|
||||
else:
|
||||
for mv in new_mesh.vertices:
|
||||
v = matrix_world * mv.co
|
||||
vertex_components.append(v.x)
|
||||
vertex_components.append(v.y)
|
||||
vertex_components.append(v.z)
|
||||
for mv in new_mesh.vertices:
|
||||
v = matrix_world @ mv.co
|
||||
vertex_components.append(v.x)
|
||||
vertex_components.append(v.y)
|
||||
vertex_components.append(v.z)
|
||||
|
||||
triangle_indices = []
|
||||
for t in new_mesh.polygons:
|
||||
@@ -382,11 +302,7 @@ def object_to_triangle_mesh(obj, matrix_world=None):
|
||||
tmesh.vertices = array.array('f', vertex_components)
|
||||
tmesh.triangles = array.array('i', triangle_indices)
|
||||
|
||||
if is_b3d_28:
|
||||
obj_eval.to_mesh_clear()
|
||||
else:
|
||||
new_mesh.user_clear()
|
||||
bpy.data.meshes.remove(new_mesh)
|
||||
obj_eval.to_mesh_clear()
|
||||
|
||||
obj.modifiers.remove(triangulation_mod)
|
||||
|
||||
@@ -395,9 +311,8 @@ def object_to_triangle_mesh(obj, matrix_world=None):
|
||||
m.show_render = edge_split_show_render_values.pop(0)
|
||||
m.show_viewport = edge_split_show_viewport_values.pop(0)
|
||||
|
||||
if is_b3d_28:
|
||||
if hide_viewport_status != obj.hide_viewport:
|
||||
obj.hide_viewport = hide_viewport_status
|
||||
if hide_viewport_status != obj.hide_viewport:
|
||||
obj.hide_viewport = hide_viewport_status
|
||||
|
||||
return tmesh
|
||||
|
||||
@@ -428,92 +343,63 @@ def swap_object_mesh_data_geometry(bl_object, vertices=[], triangles=[],
|
||||
mesh_name="Untitled",
|
||||
smooth_mesh=False,
|
||||
octane_mesh_type='Global'):
|
||||
if is_blender_281():
|
||||
# Vertex Groups (Blender >= 3.4)
|
||||
if is_blender_34():
|
||||
vg_layer_names = [vg.name for vg in bl_object.vertex_groups]
|
||||
active_vertex_layer_index = bl_object.vertex_groups.active_index
|
||||
|
||||
# UV Maps
|
||||
uv_layer_names = [uv.name for uv in bl_object.data.uv_layers]
|
||||
is_uv_layer_active = [uv.active for uv in bl_object.data.uv_layers]
|
||||
is_uv_layer_active_render = [uv.active_render for uv in bl_object.data.uv_layers]
|
||||
vg_layer_names = [vg.name for vg in bl_object.vertex_groups]
|
||||
active_vertex_layer_index = bl_object.vertex_groups.active_index
|
||||
|
||||
# Color Attributes (Blender >= 3.2)
|
||||
if is_blender_32():
|
||||
ca_layer_names = [ca.name for ca in bl_object.data.color_attributes]
|
||||
ca_layer_data_types = [ca.data_type for ca in bl_object.data.color_attributes]
|
||||
ca_layer_domain_types = [ca.domain for ca in bl_object.data.color_attributes]
|
||||
active_color_layer_index = bl_object.data.color_attributes.active_color_index
|
||||
active_color_render_index = bl_object.data.color_attributes.render_color_index
|
||||
else:
|
||||
# Vertex Colors (Blender <= 3.1)
|
||||
vc_layer_names = [vc.name for vc in bl_object.data.vertex_colors]
|
||||
is_vc_layer_active = [vc.active for vc in bl_object.data.vertex_colors]
|
||||
is_vc_layer_active_render = [vc.active_render for vc in bl_object.data.vertex_colors]
|
||||
# UV Maps
|
||||
uv_layer_names = [uv.name for uv in bl_object.data.uv_layers]
|
||||
is_uv_layer_active = [uv.active for uv in bl_object.data.uv_layers]
|
||||
is_uv_layer_active_render = [uv.active_render for uv in bl_object.data.uv_layers]
|
||||
|
||||
vertices = numpy.array(vertices, dtype=numpy.float32)
|
||||
num_vertices = vertices.shape[0] // 3
|
||||
vertex_index = numpy.array(triangles, dtype=numpy.int32)
|
||||
loop_start = numpy.array(list(range(0, len(triangles), 3)), dtype=numpy.int32)
|
||||
num_loops = loop_start.shape[0]
|
||||
loop_total = numpy.array([3] * (len(triangles) // 3), dtype=numpy.int32)
|
||||
# Color Attributes
|
||||
ca_layer_names = [ca.name for ca in bl_object.data.color_attributes]
|
||||
ca_layer_data_types = [ca.data_type for ca in bl_object.data.color_attributes]
|
||||
ca_layer_domain_types = [ca.domain for ca in bl_object.data.color_attributes]
|
||||
active_color_layer_index = bl_object.data.color_attributes.active_color_index
|
||||
active_color_render_index = bl_object.data.color_attributes.render_color_index
|
||||
|
||||
bl_object.data.clear_geometry()
|
||||
bl_object.data.from_pydata(vertices, [], triangles)
|
||||
vertices = numpy.array(vertices, dtype=numpy.float32)
|
||||
num_vertices = vertices.shape[0] // 3
|
||||
vertex_index = numpy.array(triangles, dtype=numpy.int32)
|
||||
loop_start = numpy.array(list(range(0, len(triangles), 3)), dtype=numpy.int32)
|
||||
num_loops = loop_start.shape[0]
|
||||
loop_total = numpy.array([3] * (len(triangles) // 3), dtype=numpy.int32)
|
||||
|
||||
_set_mesh_smoothness(bl_object.data, smooth_mesh)
|
||||
_set_octane_mesh_type(bl_object, octane_mesh_type)
|
||||
bl_object.data.clear_geometry()
|
||||
bl_object.data.from_pydata(vertices, [], triangles)
|
||||
|
||||
# Vertex Groups (Blender >= 3.4)
|
||||
if is_blender_34():
|
||||
for i, name in enumerate(vg_layer_names):
|
||||
vg_layer = bl_object.vertex_groups.new(name=name)
|
||||
if active_vertex_layer_index >= 0:
|
||||
bl_object.vertex_groups.active_index = active_vertex_layer_index
|
||||
_set_mesh_smoothness(bl_object.data, smooth_mesh)
|
||||
_set_octane_mesh_type(bl_object, octane_mesh_type)
|
||||
|
||||
# UV Maps
|
||||
for i, name in enumerate(uv_layer_names):
|
||||
uv_layer = bl_object.data.uv_layers.new(name=name)
|
||||
uv_layer.active = is_uv_layer_active[i]
|
||||
uv_layer.active_render = is_uv_layer_active_render[i]
|
||||
# Vertex Groups
|
||||
for i, name in enumerate(vg_layer_names):
|
||||
vg_layer = bl_object.vertex_groups.new(name=name)
|
||||
if active_vertex_layer_index >= 0:
|
||||
bl_object.vertex_groups.active_index = active_vertex_layer_index
|
||||
|
||||
# Color Attributes (Blender >= 3.2)
|
||||
if is_blender_32():
|
||||
for i, name in enumerate(ca_layer_names):
|
||||
ca_layer = bl_object.data.color_attributes.new(
|
||||
name=name,
|
||||
type=ca_layer_data_types[i],
|
||||
domain=ca_layer_domain_types[i]
|
||||
)
|
||||
# Unable to set active color/render index > 0. Possibly a Blender bug that we need
|
||||
# to report. For now, the Color Attributes layer will be limited to a single layer.
|
||||
# As far as we know, this feature does not need to be used outside of Octane Render.
|
||||
"""
|
||||
if active_color_layer_index >= 0:
|
||||
bl_object.data.color_attributes.active_color_index = active_color_layer_index
|
||||
if active_color_render_index >= 0:
|
||||
bl_object.data.color_attributes.render_color_index = active_color_render_index
|
||||
"""
|
||||
else:
|
||||
# Vertex Colors (Blender <= 3.1)
|
||||
for i, name in enumerate(vc_layer_names):
|
||||
vc_layer = bl_object.data.vertex_colors.new(name=name)
|
||||
vc_layer.active = is_vc_layer_active[i]
|
||||
vc_layer.active_render = is_vc_layer_active_render[i]
|
||||
# UV Maps
|
||||
for i, name in enumerate(uv_layer_names):
|
||||
uv_layer = bl_object.data.uv_layers.new(name=name)
|
||||
uv_layer.active = is_uv_layer_active[i]
|
||||
uv_layer.active_render = is_uv_layer_active_render[i]
|
||||
|
||||
else:
|
||||
old_mesh_data = bl_object.data
|
||||
new_mesh_data = bpy.data.meshes.new(mesh_name)
|
||||
new_mesh_data.from_pydata(vertices, [], triangles)
|
||||
bl_object.data = new_mesh_data
|
||||
|
||||
_transfer_mesh_materials(old_mesh_data, new_mesh_data)
|
||||
_set_mesh_smoothness(new_mesh_data, smooth_mesh)
|
||||
_set_octane_mesh_type(bl_object, octane_mesh_type)
|
||||
|
||||
old_mesh_data.user_clear()
|
||||
bpy.data.meshes.remove(old_mesh_data)
|
||||
# Color Attributes
|
||||
for i, name in enumerate(ca_layer_names):
|
||||
ca_layer = bl_object.data.color_attributes.new(
|
||||
name=name,
|
||||
type=ca_layer_data_types[i],
|
||||
domain=ca_layer_domain_types[i]
|
||||
)
|
||||
# Unable to set active color/render index > 0. Possibly a Blender bug that we need
|
||||
# to report. For now, the Color Attributes layer will be limited to a single layer.
|
||||
# As far as we know, this feature does not need to be used outside of Octane Render.
|
||||
"""
|
||||
if active_color_layer_index >= 0:
|
||||
bl_object.data.color_attributes.active_color_index = active_color_layer_index
|
||||
if active_color_render_index >= 0:
|
||||
bl_object.data.color_attributes.render_color_index = active_color_render_index
|
||||
"""
|
||||
|
||||
|
||||
def get_addon_directory():
|
||||
@@ -525,10 +411,7 @@ def get_addon_directory():
|
||||
def get_blender_preferences(context=None):
|
||||
if context is None:
|
||||
context = bpy.context
|
||||
if is_blender_28():
|
||||
return context.preferences
|
||||
else:
|
||||
return context.user_preferences
|
||||
return context.preferences
|
||||
|
||||
|
||||
def get_blender_preferences_temporary_directory(context=None):
|
||||
@@ -548,45 +431,26 @@ def get_addon_preferences(context=None):
|
||||
|
||||
|
||||
def ui_split(ui_element, factor=None, align=None):
|
||||
if is_blender_28():
|
||||
if factor is None and align is None:
|
||||
return ui_element.split()
|
||||
elif factor is None:
|
||||
return ui_element.split(align=align)
|
||||
elif align is None:
|
||||
return ui_element.split(factor=factor)
|
||||
else:
|
||||
return ui_element.split(factor=factor, align=align)
|
||||
if factor is None and align is None:
|
||||
return ui_element.split()
|
||||
elif factor is None:
|
||||
return ui_element.split(align=align)
|
||||
elif align is None:
|
||||
return ui_element.split(factor=factor)
|
||||
else:
|
||||
if factor is None and align is None:
|
||||
return ui_element.split()
|
||||
elif factor is None:
|
||||
return ui_element.split(align=align)
|
||||
elif align is None:
|
||||
return ui_element.split(percentage=factor)
|
||||
else:
|
||||
return ui_element.split(percentage=factor, align=align)
|
||||
return ui_element.split(factor=factor, align=align)
|
||||
|
||||
|
||||
def get_file_folder_icon():
|
||||
if is_blender_28():
|
||||
return "FILEBROWSER"
|
||||
else:
|
||||
return "FILESEL"
|
||||
return "FILEBROWSER"
|
||||
|
||||
|
||||
def get_hide_off_icon():
|
||||
if is_blender_28():
|
||||
return "HIDE_OFF"
|
||||
else:
|
||||
return "RESTRICT_VIEW_OFF"
|
||||
return "HIDE_OFF"
|
||||
|
||||
|
||||
def get_hide_on_icon():
|
||||
if is_blender_28():
|
||||
return "HIDE_ON"
|
||||
else:
|
||||
return "RESTRICT_VIEW_ON"
|
||||
return "HIDE_ON"
|
||||
|
||||
|
||||
def str_removesuffix(input_string, suffix):
|
||||
|
||||
Reference in New Issue
Block a user