1
$\begingroup$

So I have a library of 556 HDRIs, and I would like to add them to the Blender Asset Browser. The way I've seen many people do it is to create a new scene for each HDRI and name it accordingly, then mark the scene as an asset. This won't do, as my HDRI library is absolutely huge. Is there a way to do a batch import or something like that, to add all of them to the asset browser at once, or in a quick way? Keep in mind that all of these are not in separate blend files, and are only in the .exr format.

Thanks so much!

$\endgroup$
4
  • $\begingroup$ Do you mean World instead of Scene? A scene cannot be marked as an asset (i.sstatic.net/gEIsg.jpg) $\endgroup$
    – Blunder
    Commented Aug 16, 2022 at 21:43
  • $\begingroup$ You first need to import the hdris as Blender Images, and then batch mark these images as assets (with the latest beta version). You can't add regular images as assets in Blender. $\endgroup$
    – Gorgious
    Commented Aug 17, 2022 at 5:38
  • $\begingroup$ I wrote a little script that does exactly this but also creates worlds as assets. You can drag and drop them into the viewport, just like you can with materials, and you can categorize them. That's really nice. I can post an answer later if needed. $\endgroup$
    – Blunder
    Commented Aug 17, 2022 at 8:29
  • $\begingroup$ @Blunder I would love for you to post an answer! $\endgroup$ Commented Aug 18, 2022 at 1:00

1 Answer 1

1
$\begingroup$

Here is a script that imports HDR images, creates world settings (worlds), marks them as asset and creates a preview for them.

The script requires a few things.

  • Blender 3.3. For Blender 3.2, you need a little patch. Increase the number in line 37, e.g. return 1.0 and comment out lines 19 to 21 by adding a # at the beginning of the line. For the technical details see the linked questions at the end of this answer.

  • It also requires a template node setup in the World setttings named "World (template") (line 53). There must be an Environment Texture node so the image can be defined there. The name of the node (Environment Texture) is important, not the label. (The values can be changed in the N-panel, just in case you have more than one of these nodes.) world template

  • the generated default preview images for HDRIs look very odd for some reason. So I used a plane as a preview object with a simple material (see screenshot). The plane object must be in the XZ plane (add a plane, rotate it by 90° along X-axis, and apply Rotation) because Blender uses automatically a certain point of view to render a preview image from the plane. It does not use the camera as it does for poses. example world assets

The script looks for HDR images with *.hdr and *.exr file extensions (line 70+71) in the folder that is defined in line 68. If you want to search in subfolders you can set recursive = True and specify a folder something like C:/blender/projects/**/hdri. Then it will look for HDRIs in every subfolder named hdri that is in C:/blender/projects. Of course, C:/blender/projects/** works as well to search all subfolders in the given base folder. For the file path separator use a / not a \.

To run the script, go to Scripting workplace, create a new text data block (menu Text > New Alt+N), copy & paste the code and press the run button.

For messages and errors check the system console. Use main menu entry Window > Toggle System Console if the window is not open.

import bpy
import glob
from os import path 
import functools

def load_image(image_path):
    basename = path.basename(image_path)
    img = bpy.data.images.get(basename)
    if img is None:
        try:
            img = bpy.data.images.load(image_path)
        except:
            print("ERROR: Cannot load image %s" % image_path)

    return img


def create_hdri_previews(assets, callback):
    if bpy.app.is_job_running('RENDER_PREVIEW'):     # Blender 3.3!
        print("Waiting for render...")
        return 0.2  # waiting time
    
    while assets:  # generate next preview
        world = assets.pop()                
        print(f"Creating preview for world {world.name}...")
        
        # set image in the preview object's material
        obj = bpy.context.active_object
        image = world.node_tree.nodes['Environment Texture'].image
        obj.material_slots[0].material.node_tree.nodes['Image Texture'].image = image          

        # start preview render
        override = bpy.context.copy()
        override["id"] = world
        with bpy.context.temp_override(**override):
            bpy.ops.ed.lib_id_generate_preview_from_object()
        return 0.2
    
    callback()
    return None


def create_world(image_path):
    image = load_image(image_path)
    if image is None: return
    
    worldname = image.name.lower().replace('_', ' ')
    worldname = worldname.replace('.exr', '').replace('.hdr', '')
    worldname = worldname.title()
    
    world = bpy.data.worlds.get(worldname)
    if world is None:
        template = bpy.data.worlds.get('World (template)')   # <------ World template
        world = template.copy()
        world.name = worldname 
        
    world.node_tree.nodes['Environment Texture'].image = image
    world.asset_mark() 

    return world


def message_end():
    print('All previews have been generated!')
    

if __name__ == "__main__":
    data_path = 'C:/tmp'     #  <-------------------- HDRI files   
    
    hdri_files = glob.glob(f"{data_path}/*.hdr", recursive = False)
    hdri_files.extend(glob.glob(f"{data_path}/*.exr", recursive = False))

    assets = []
    for image_path in hdri_files:
        
        print(image_path) 
        assets.append(create_world(image_path))
        
    print(f"{len(hdri_files)} files processed.")
    
    # create preview images
    bpy.app.timers.register(
        functools.partial(
            create_hdri_previews, 
            assets, 
            message_end
        )
    )

Related questions about the preview generation. Kudos to Gorgious.

$\endgroup$
6
  • $\begingroup$ This is a handy script ! I'm pleased to see my answers helped you ;) Would you mind if I used a modified version of your script in my asset utilities addon with proper credit, of course ? $\endgroup$
    – Gorgious
    Commented Aug 21, 2022 at 20:47
  • 1
    $\begingroup$ @Gorgious Hi. Yes, your answers helped a lot with the preview images. I am happy if my script is of any use. Feel free to use and modify it for your addon. $\endgroup$
    – Blunder
    Commented Aug 22, 2022 at 23:10
  • $\begingroup$ Everything seems to work fine, except that it crashes after it finishes creating everything, resulting in nothing being saved. The error is pretty long, but it starts with: Calloc returns null: len=134217728 in imb_addrectfloatImBuf, total 605046876. Blender 3.3 $\endgroup$ Commented Aug 29, 2022 at 22:50
  • $\begingroup$ @Zany_Zachary1 are you using blender 3.3+ ? $\endgroup$
    – Gorgious
    Commented Aug 30, 2022 at 5:40
  • $\begingroup$ O-oh, memory errors! >.< What happens if you disable the generation of the preview images? (Comment out (#) or remove the last block of lines of the script). I haven't tested with that many files. Maybe it's too many files at once or they are too big. Try a folder with only 100 images. The script loads image files only once. Same for the world settings. $\endgroup$
    – Blunder
    Commented Aug 30, 2022 at 11:26

You must log in to answer this question.

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