Add new node asset scripts for geometry and shader operations

- Implemented `build_mesh_plane.py` to create a geometry node group for mesh planes with customizable parameters.
- Created `build_shadeless.py` for a shader node group that displays color without scene lighting while preserving shadows and reflections.
- Added `validate.py` to validate the integrity of the newly created node groups and their inputs.
- Introduced `validate_cutout.py` to ensure the functionality of cutout node groups and their dependencies.
- Developed `validate_mesh_plane.py` to test the mesh plane creation and its modifier settings.
This commit is contained in:
2026-08-30 00:17:29 +08:00
parent 7d39fe8c5e
commit 32bcd45d7b
168 changed files with 7213 additions and 13121 deletions

View File

@@ -0,0 +1,120 @@
import bpy
from ..properties import BEN2_MODEL_KEY
from ..runtime import JobOperatorBase
from .common.operator import (
HIDDEN,
background_input_path,
cleanup_temporary_input,
invoke_ai_setup_if_needed,
production_device,
push_undo,
require_environment,
require_model,
source_start_frame,
)
from .common.image import (
default_extract_frames,
is_image_empty,
prepare_image_input,
remove_temporary_input,
video_total_frames,
)
class RemoveImageBackground(bpy.types.Operator):
bl_idname = "anyimage.remove_image_background"
bl_label = "Remove Background"
bl_description = "Remove the background from this Image Empty with BEN2"
bl_options = {"REGISTER"}
@classmethod
def poll(cls, context):
from ..runtime import runtime
return is_image_empty(context.object) and not runtime.server_busy()
def invoke(self, _context, _event):
setup_result = invoke_ai_setup_if_needed()
if setup_result is not None:
return setup_result
return self.execute(_context)
def execute(self, context):
source_object = context.object
total_frames = video_total_frames(source_object.data)
if total_frames > 1:
context.scene.anyimage_settings.video_frames = (
default_extract_frames(source_object)
)
try:
source_path, delete_input = prepare_image_input(
source_object.data,
context.scene,
)
except RuntimeError as error:
self.report({"ERROR"}, str(error))
return {"CANCELLED"}
result = bpy.ops.anyimage.run_background_removal(
input_path=str(source_path),
source_object_name=source_object.name,
delete_input=delete_input,
)
if "CANCELLED" not in result:
return {"FINISHED"}
if delete_input:
remove_temporary_input(source_path)
return {"CANCELLED"}
def apply_background_response(result, source_object_name):
from .common.image import create_color_image, is_image_empty
source_object = bpy.data.objects.get(source_object_name)
if not is_image_empty(source_object):
raise RuntimeError("The source image empty is no longer available")
source_image = source_object.data
source_name = source_image.name
original_fake_user = source_image.use_fake_user
result_image = create_color_image(source_object, result.directory)
source_image.use_fake_user = original_fake_user
if not original_fake_user and int(source_image.users) == 0:
bpy.data.images.remove(source_image)
result_image.name = source_name
push_undo("Remove Background")
class RunBackgroundRemoval(JobOperatorBase, bpy.types.Operator):
bl_idname = "anyimage.run_background_removal"
bl_label = "Run Background Removal"
job_type = "remove-background"
starting_message = "Starting Image Empty background removal"
input_path: bpy.props.StringProperty(options=HIDDEN)
source_object_name: bpy.props.StringProperty(options=HIDDEN)
delete_input: bpy.props.BoolProperty(default=False, options=HIDDEN)
def request(self, context):
require_environment()
require_model(BEN2_MODEL_KEY)
settings = context.scene.anyimage_settings
return {
"input": str(background_input_path(self.input_path)),
"model": BEN2_MODEL_KEY,
"device": production_device().lower(),
"video_frames": settings.video_frames,
"start_frame": source_start_frame(self.source_object_name),
}
def response(self, _context, result):
apply_background_response(result, self.source_object_name)
return "Image background is removed"
def cleanup(self):
cleanup_temporary_input(self.input_path, self.delete_input)