diff --git a/.ci/windows_amd_base_files/README_VERY_IMPORTANT.txt b/.ci/windows_amd_base_files/README_VERY_IMPORTANT.txt index 26aeeee52..2c72c8a13 100755 --- a/.ci/windows_amd_base_files/README_VERY_IMPORTANT.txt +++ b/.ci/windows_amd_base_files/README_VERY_IMPORTANT.txt @@ -1,27 +1,27 @@ -As of the time of writing this you need a recent driver. Updating to the latest driver is recommended. - -HOW TO RUN: - -If you have a AMD gpu: - -run_amd_gpu.bat - -If you have memory issues you can try enabling the new dynamic memory management by running comfyui with: - -run_amd_gpu_enable_dynamic_vram.bat - -IF YOU GET A RED ERROR IN THE UI MAKE SURE YOU HAVE A MODEL/CHECKPOINT IN: ComfyUI\models\checkpoints - -You can download the stable diffusion XL one from: https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0/blob/main/sd_xl_base_1.0_0.9vae.safetensors - - -RECOMMENDED WAY TO UPDATE: -To update the ComfyUI code: update\update_comfyui.bat - - -TO SHARE MODELS BETWEEN COMFYUI AND ANOTHER UI: -In the ComfyUI directory you will find a file: extra_model_paths.yaml.example -Rename this file to: extra_model_paths.yaml and edit it with your favorite text editor. - - - +As of the time of writing this you need a recent driver. Updating to the latest driver is recommended. + +HOW TO RUN: + +If you have a AMD gpu: + +run_amd_gpu.bat + +If you have memory issues you can try enabling the new dynamic memory management by running comfyui with: + +run_amd_gpu_enable_dynamic_vram.bat + +IF YOU GET A RED ERROR IN THE UI MAKE SURE YOU HAVE A MODEL/CHECKPOINT IN: ComfyUI\models\checkpoints + +You can download the stable diffusion XL one from: https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0/blob/main/sd_xl_base_1.0_0.9vae.safetensors + + +RECOMMENDED WAY TO UPDATE: +To update the ComfyUI code: update\update_comfyui.bat + + +TO SHARE MODELS BETWEEN COMFYUI AND ANOTHER UI: +In the ComfyUI directory you will find a file: extra_model_paths.yaml.example +Rename this file to: extra_model_paths.yaml and edit it with your favorite text editor. + + + diff --git a/.github/workflows/check-line-endings.yml b/.github/workflows/check-line-endings.yml index eeb594d6c..a69a24a87 100644 --- a/.github/workflows/check-line-endings.yml +++ b/.github/workflows/check-line-endings.yml @@ -17,7 +17,7 @@ jobs: - name: Check for Windows line endings (CRLF) run: | # Get the list of changed files in the PR - CHANGED_FILES=$(git diff --name-only ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }}) + CHANGED_FILES=$(git diff --name-only ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }} -- ':!.ci') # Flag to track if CRLF is found CRLF_FOUND=false diff --git a/comfy_extras/nodes_load_3d.py b/comfy_extras/nodes_load_3d.py index 77dd1173b..455897859 100644 --- a/comfy_extras/nodes_load_3d.py +++ b/comfy_extras/nodes_load_3d.py @@ -51,6 +51,14 @@ class Load3D(IO.ComfyNode): ], ) + @classmethod + def validate_inputs(cls, model_file, **kwargs) -> bool | str: + if not model_file or model_file == "none": + return True + if not folder_paths.exists_annotated_filepath(model_file): + return f"Invalid 3D model file: {model_file}" + return True + @classmethod def execute(cls, model_file, image, **kwargs) -> IO.NodeOutput: image_path = folder_paths.get_annotated_filepath(image['image']) @@ -148,34 +156,34 @@ class Preview3DAdvanced(IO.ComfyNode): ], tooltip="3D model file from an upstream 3D node.", ), - IO.Load3D.Input("image"), - IO.Load3DCamera.Input("camera_info", optional=True, advanced=True), IO.Load3DModelInfo.Input("model_3d_info", optional=True, advanced=True), + IO.Load3D.Input("viewport_state"), + IO.Load3DCamera.Input("camera_info", optional=True, advanced=True), IO.Int.Input("width", default=1024, min=1, max=4096, step=1), IO.Int.Input("height", default=1024, min=1, max=4096, step=1), ], outputs=[ IO.File3DAny.Output(display_name="model_3d"), - IO.Load3DCamera.Output(display_name="camera_info"), IO.Load3DModelInfo.Output(display_name="model_3d_info"), + IO.Load3DCamera.Output(display_name="camera_info"), IO.Int.Output(display_name="width"), IO.Int.Output(display_name="height"), ], ) @classmethod - def execute(cls, model_3d: Types.File3D, image, width: int, height: int, **kwargs) -> IO.NodeOutput: + def execute(cls, model_3d: Types.File3D, viewport_state, width: int, height: int, **kwargs) -> IO.NodeOutput: filename = f"preview3d_advanced_{uuid.uuid4().hex}.{model_3d.format}" - model_3d.save_to(os.path.join(folder_paths.get_output_directory(), filename)) + model_3d.save_to(os.path.join(folder_paths.get_temp_directory(), filename)) camera_info_input = kwargs.get("camera_info", None) - camera_info = camera_info_input if camera_info_input is not None else image['camera_info'] + camera_info = camera_info_input if camera_info_input is not None else viewport_state['camera_info'] model_3d_info_input = kwargs.get("model_3d_info", None) - model_3d_info = model_3d_info_input if model_3d_info_input is not None else image.get('model_3d_info', []) + model_3d_info = model_3d_info_input if model_3d_info_input is not None else viewport_state.get('model_3d_info', []) return IO.NodeOutput( model_3d, - camera_info, model_3d_info, + camera_info, width, height, ui=UI.PreviewUI3DAdvanced(filename, camera_info, model_3d_info), @@ -216,34 +224,34 @@ class PreviewGaussianSplat(IO.ComfyNode): ], tooltip="A gaussian splat 3D file.", ), - IO.Load3D.Input("image"), - IO.Load3DCamera.Input("camera_info", optional=True, advanced=True), IO.Load3DModelInfo.Input("model_3d_info", optional=True, advanced=True), + IO.Load3D.Input("viewport_state"), + IO.Load3DCamera.Input("camera_info", optional=True, advanced=True), IO.Int.Input("width", default=1024, min=1, max=4096, step=1), IO.Int.Input("height", default=1024, min=1, max=4096, step=1), ], outputs=[ IO.File3DSplatAny.Output(display_name="model_3d"), - IO.Load3DCamera.Output(display_name="camera_info"), IO.Load3DModelInfo.Output(display_name="model_3d_info"), + IO.Load3DCamera.Output(display_name="camera_info"), IO.Int.Output(display_name="width"), IO.Int.Output(display_name="height"), ], ) @classmethod - def execute(cls, model_3d: Types.File3D, image, width: int, height: int, **kwargs) -> IO.NodeOutput: + def execute(cls, model_3d: Types.File3D, viewport_state, width: int, height: int, **kwargs) -> IO.NodeOutput: filename = f"preview_splat_{uuid.uuid4().hex}.{model_3d.format}" - model_3d.save_to(os.path.join(folder_paths.get_output_directory(), filename)) + model_3d.save_to(os.path.join(folder_paths.get_temp_directory(), filename)) camera_info_input = kwargs.get("camera_info", None) - camera_info = camera_info_input if camera_info_input is not None else image['camera_info'] + camera_info = camera_info_input if camera_info_input is not None else viewport_state['camera_info'] model_3d_info_input = kwargs.get("model_3d_info", None) - model_3d_info = model_3d_info_input if model_3d_info_input is not None else image.get('model_3d_info', []) + model_3d_info = model_3d_info_input if model_3d_info_input is not None else viewport_state.get('model_3d_info', []) return IO.NodeOutput( model_3d, - camera_info, model_3d_info, + camera_info, width, height, ui=UI.PreviewUI3DAdvanced(filename, camera_info, model_3d_info), @@ -275,34 +283,34 @@ class PreviewPointCloud(IO.ComfyNode): ], tooltip="Point cloud file (.ply)", ), - IO.Load3D.Input("image"), - IO.Load3DCamera.Input("camera_info", optional=True, advanced=True), IO.Load3DModelInfo.Input("model_3d_info", optional=True, advanced=True), + IO.Load3D.Input("viewport_state"), + IO.Load3DCamera.Input("camera_info", optional=True, advanced=True), IO.Int.Input("width", default=1024, min=1, max=4096, step=1), IO.Int.Input("height", default=1024, min=1, max=4096, step=1), ], outputs=[ IO.File3DPointCloudAny.Output(display_name="model_3d"), - IO.Load3DCamera.Output(display_name="camera_info"), IO.Load3DModelInfo.Output(display_name="model_3d_info"), + IO.Load3DCamera.Output(display_name="camera_info"), IO.Int.Output(display_name="width"), IO.Int.Output(display_name="height"), ], ) @classmethod - def execute(cls, model_3d: Types.File3D, image, width: int, height: int, **kwargs) -> IO.NodeOutput: + def execute(cls, model_3d: Types.File3D, viewport_state, width: int, height: int, **kwargs) -> IO.NodeOutput: filename = f"preview_pointcloud_{uuid.uuid4().hex}.{model_3d.format}" - model_3d.save_to(os.path.join(folder_paths.get_output_directory(), filename)) + model_3d.save_to(os.path.join(folder_paths.get_temp_directory(), filename)) camera_info_input = kwargs.get("camera_info", None) - camera_info = camera_info_input if camera_info_input is not None else image['camera_info'] + camera_info = camera_info_input if camera_info_input is not None else viewport_state['camera_info'] model_3d_info_input = kwargs.get("model_3d_info", None) - model_3d_info = model_3d_info_input if model_3d_info_input is not None else image.get('model_3d_info', []) + model_3d_info = model_3d_info_input if model_3d_info_input is not None else viewport_state.get('model_3d_info', []) return IO.NodeOutput( model_3d, - camera_info, model_3d_info, + camera_info, width, height, ui=UI.PreviewUI3DAdvanced(filename, camera_info, model_3d_info),