5
$\begingroup$

I wonder if it is possible to use external image sources (http, ftp, sftp, ...) directly or cached as resources in the shader.

The question is not about how to basically download a file with Python, or access a paid service like Blender Cloud (which, by the way, can only load images from Blender Cloud, and not from your own URLs), but about how to easily load an image into Blender and keep it up to date by specifying an URL instead of a local path!

$\endgroup$
6
  • 2
    $\begingroup$ it may be possible to create a custom node that has a python script to essentially download/scrape the image from the URL and pass it as the node's output.. I mean one way or another youll need to download it or cache it.. this kind of does that in a shader node type manner $\endgroup$
    – Derek Eden
    Commented May 4, 2022 at 15:49
  • $\begingroup$ @DerekEden That sounds like a possible way for me, thanks! Sure, locally the file must land somehow once, the question is rather, how can one automate that. $\endgroup$
    – quellenform
    Commented May 4, 2022 at 16:03
  • $\begingroup$ yeah it's not possible. the only way is to validate or load the image urls whenever you open the blender file using scritpt like subprocess.run(["curl", url, "-o", img_path]); bpy.data.images.load(img_path) to cache the images into bpy.data.images $\endgroup$
    – Harry McKenzie
    Commented Aug 26, 2023 at 6:31
  • 1
    $\begingroup$ oh coz you said The question is not about how to basically download a file with Python. so i thought you didn't want a python solution but rather blender directly display the url image haha. yes exactly, it should work, probably with a script node, i have the script, i can make the node :D $\endgroup$
    – Harry McKenzie
    Commented Aug 26, 2023 at 7:31
  • 1
    $\begingroup$ @HarryMcKenzie Please excuse this misleading wording! I meant that I know in principle how to load a file, but the question rather refers to how you can basically process a URL as a source, so that an online source can be synchronized in the background with Blender. For example, a (fictional) scenario where the images are on a web server (HTTP/HTTPS/FTP), and not local or stored on the local network. $\endgroup$
    – quellenform
    Commented Aug 26, 2023 at 7:44

2 Answers 2

5
$\begingroup$

Yes it is possible. You can basically register a script that will automatically run and fetch the images from a URL path whenever you open your blend file. Just make sure you register the script using menu Text > Register in the Text Editor. The URL image can then be assigned to an Image Texture node in your Shader Node tree. Just make sure you know the name of the node. In this example I have prepared a material Material.001 that has an empty Image Texture node with name ImageTexture.001 both referenced in the script.

enter image description here

Don't run the script. Just save the blend file and the next time you open the file, it automatically loads and assigns the URL image to the Image Texture.

enter image description here

Here's the script I have registered. Try any image URL :)

import bpy
import subprocess
import os
import time

CACHE_PATH = os.path.join(os.path.expanduser("~"), "Desktop")

def load_url_into_image_texture(url, image_texture_node):
    img_path = os.path.join(CACHE_PATH, "image-" + str(time.time()))
    subprocess.run(["curl", url, "-o", img_path])
    print("Image cached to:", img_path)
    image_texture_node.image = bpy.data.images.load(img_path)

image_texture_node = bpy.data.materials["Material.001"].node_tree.nodes["ImageTexture.001"]
url = "https://www.gravatar.com/avatar/e567cde16c9e469be11645dfb4057f23?s=256&d=identicon&r=PG"
load_url_into_image_texture(url, image_texture_node)

image_texture_node = bpy.data.materials["Material.002"].node_tree.nodes["ImageTexture.002"]
url = "https://i.sstatic.net/hBXGA.jpg"
load_url_into_image_texture(url, image_texture_node)

Here's another implementation as addon, where you can input an image URL and press a button to load the image:

enter image description here

import bpy
import subprocess
import os
import time

CACHE_PATH = os.path.join(os.path.expanduser("~"), "Desktop")

class NONSENSE_PT_LoadImageAddonPanel(bpy.types.Panel):
    bl_label = "Load Image Addon Panel"
    bl_idname = "NONSENSE_PT_LoadImageAddonPanel"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = 'Load Image'

    def draw(self, context):
        layout = self.layout
        row = layout.row()
        row.label(text="Enter an Image URL:")
        row = layout.row()
        row.prop(context.scene, "image_url", text="")
        row = layout.row()
        row.operator("load.load_image_url", text="Load Image URL")

class PT_LoadImage(bpy.types.Operator):
    bl_idname = "load.load_image_url"
    bl_label = "Load Image"

    def load_url_into_image_texture(self, url, image_texture_node):
        img_path = os.path.join(CACHE_PATH, "image-" + str(time.time()))
        subprocess.run(["curl", url, "-o", img_path])
        print("Image cached to:", img_path)
        image_texture_node.image = bpy.data.images.load(img_path)

    def execute(self, context):
        image_url = context.scene.image_url
        print("Load Image URL:", image_url)
        
        image_texture_node = bpy.data.materials["Material.001"].node_tree.nodes["ImageTexture.001"]
        self.load_url_into_image_texture(image_url, image_texture_node)
        
        return {'FINISHED'}

def register():
    bpy.types.Scene.image_url = bpy.props.StringProperty(name="")
    bpy.utils.register_class(NONSENSE_PT_LoadImageAddonPanel)
    bpy.utils.register_class(PT_LoadImage)

def unregister():
    bpy.utils.unregister_class(NONSENSE_PT_LoadImageAddonPanel)
    bpy.utils.unregister_class(PT_LoadImage)
    del bpy.types.Scene.image_url

if __name__ == "__main__":
    register()

By the way, you can also load images using the requests module, whichever works faster for you.

import bpy
import os
import requests

CACHE_PATH = os.path.join(os.path.expanduser("~"), "Desktop")
img_path = os.path.join(CACHE_PATH, "image.jpg")

response = requests.get("https://i.sstatic.net/hBXGA.jpg")
with open(img_path, "wb") as f:
    f.write(response.content)

image = bpy.data.images.load(filepath=img_path)
$\endgroup$
2
  • 1
    $\begingroup$ Wow, wonderful, this looks very promising! Please give me a little time to test it. If I read this correctly, the URLs are hardcoded though, right? Is there any way to handle that via a custom node and an input field? Also, can this be synced at the touch of a button, or does it require restarting Blender each time? $\endgroup$
    – quellenform
    Commented Aug 26, 2023 at 12:02
  • $\begingroup$ That's a good question I will investigate! Yeah I think it is possible to sync at the touch of a button since we can trigger the script when a button is pressed and get the input url and load it, but I don't think you can have a custom node automatically trigger a script when a url is input in the node's url field. There needs to be some refresh button on the custom node if a button were possible. Also the Image Texture does not have an input socket for the image, so we can't really even pass an image. $\endgroup$
    – Harry McKenzie
    Commented Aug 26, 2023 at 12:11
4
$\begingroup$

No.

Blender itself does not have the in-built parts of a web browser/spider that interpret URIs and fetch their content automatically. You would have to modify its file handling code to recognize URIs and manage a content cache for that to become available generally.

The best you can do now is what many add-ons are doing: keep a local cache and validate it when Blender starts.

$\endgroup$
2
  • $\begingroup$ Thanks for the input! Definitely sounds like a bunch of Python code that would be needed for this.... $\endgroup$
    – quellenform
    Commented May 4, 2022 at 16:07
  • $\begingroup$ I assume that same is not possible for particle and Fluid caches? It's quite tedious to segment parts of caches to fit Zip file limits for rendering farms (e.g., SheepIt), and just wanted to check before making a suggestion on "rightclickselect". $\endgroup$
    – james_t
    Commented Oct 26, 2022 at 21:57

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .