[Addon] blenderseed - appleseed Render Exporter

Hi all, here is the appleseed Render exporter for Blender, “blenderseed”.

Download the newest version of blenderseed.

Download the newest version of appleseed

Features:
-Physically correct depth of field
-Mesh lights
-Physical sun/sky models
-Mirrorball/latlong environment maps
-Constant and gradient environment color
-Motion blur: deformation, object, camera
-Duplifaces, dupliverts / object particle systems
-Multiple-BSDF material layering system (Microfacet, Kelemen, Ashikhmin-Shirley, Lambertian, Diffuse BTDF, Specular, Specular BTDF)
-Node materials
-Bump/normal/alpha mapping
-Material preview rendering
-Export to appleseed.studio GUI or Blender image editor integrated rendering
-Direct lighting, path tracing, SPPM
-Linux support.
-Compiled mesh export (only in zipped releases. If downloading source, you must compile it yourself)

To do:
-Dupligroups
-Spherical camera
-Render layers

I tried it, and it looks like it worked (from the console output) but my final appleseed image was blank even though my scene has a plane and a cube in it.

There are a handful bugs in the script, I’m sure, and where it’s saving renders and automatically loading renders from are two of those known issues at the moment :slight_smile: I’m curious though, do you mean that nothing is being rendered, ie., that the saved rendered image in the project directory is also blank? I haven’t yet run into a case like that.

If so, are there lamps or mesh lights in the scene?

I’m curious though, do you mean that nothing is being rendered,

It was the default scene. I added a plane under the cube and scaled it up to catch shadows. The output was an image that was all gray.
I had saved the scene to my desktop and the script did write files there. I did not examine any of the other files generated, only the image.

I know you said it was the default scene, but could you upload it just for giggles?

@Atom - I’ve been working on how it loads renders and I think I’ve got the bugs sorted out. I haven’t committed the changes yet, but I think I realized what the problem may be with your scene. I’ve set the default camera model to ‘thinlens’ instead of ‘pinhole’, and Blender’s default focal distance is 0.00. With the thinlens camera and a focal distance of 0.0, the render is blank. Change the focal distance or change the camera model to pinhole, then try again. Let me know if it’s still blank :slight_smile:

Joel,

I did manage to get output with the Pinhole camera but I do believe there is some disk pathing error for final output generation (notice the console text in RED). I was able to fetch the autosave and see my rendered scene, however.

Here is my console, the output and the scene I am testing with.

Attachments

267_snapjoel_appleseed_render_engine.blend (160 KB)



Yeah, I think I was able to get that fixed yesterday, but I haven’t committed the changes. I’m out of town so I"m having to use my Linux laptop, which for several reasons isn’t getting along with appleseed as well as my desktop. So I can’t do a lot of testing with the changes I made for a few more days.

Edit: I uploaded my changes to dropbox, but have only done a little testing: https://dl.dropboxusercontent.com/u/28450367/render_appleseed.py

What’s the problem?

Franz

Actually it doesn’t have anything to do with Appleseed, it’s all hardware issues. This laptop is just basically useless for rendering, and it doesn’t like it when I try!

Hi all, I’ve updated the exporter. I’ve fixed the pathing errors (though more testing on this would be great), and I’ve added alpha map export. One thing I’ve noticed is that having images set to the correct color space in the texture panel REALLY makes a difference in the render quality. So be sure to do that…

Also added an option when using current development builds to pass the project filename to appleseed.studio when launching it, which will begin rendering automatically.

I tried your new code. Once again, I get a completely GREY output file when I use Thin Lens camera (which is the default). The Pinhole camera does work so maybe it would be a better default for now? Also if you type in a project path and it does not exist, the render fails. It might be a nice feature to determine if the project folder already exists, if not go ahead and try to create it. I am testing with the render set to Internal I don’t really want to deal with that studio app that comes with Appleseed.

Also, it may be possible to monitor the percentage output from the console and route that directly to the Blender percentage bar. Check out Matt Ebb’s 3Delight exporter for example code on how he handled that.

I’ll set the default to pinhole; but remember that the thinlens model does work but only if there’s a focal distance > 0.

You’re right, I’ll add a test for the project directory. It hadn’t occurred to me that someone might be inclined to type something in rather than use the directory browser.

Joel,

I have been playing around with a version of your Appleseed exporter, I noticed you have been updating it on bitbucket as a single script. I took the single script and spread it out across several files. This is typical of other Render Engine AddOns. I thought I would offer it up to you if you are interested in a distributed architecture approach for your Appleseed AddOn.

My version is not as up-to-date or as bug fixed as your current version, but it does render the default Cube when I press F12.

Attachments

render_appleseed_070513.zip (24.9 KB)

Funny you mentioned it; actually Esteban (est777) just made a change to begin the process of splitting it up into modules. I’ve been thinking about doing this for a while, but I wanted to get a lot of the features in first. This is the first somewhat large-scale addon I’ve worked on, so I’ve been a little perplexed as to how to go about interactively adding features into an addon that consists of several modules. Got any tips or advice you can share?

I’ll look at what you’ve done, thank you for that. I’ve been making a ton of changes, even in the last 24 hours!

I tried to keep the split of the code fairly logical. There is now a properties.py which contains all the panel properties. There is an export.py which does the main work. the init.py just sets things up and registers all the external files. The util.py is kind of a catch-all for code. The ui.py contains all the UI code. Feel free to pass the link on to Esteban if it will help him as well. There is an events.py as well, but it is essentially empty at this time.

What’s your workflow for writing an addon that consists of more than one module? The only thing I can think of is to keep disabling/enabling the addon in the user prefs when I make changes. That’s kinda cumbersome, but is it the only way? Is it possible when working in the text editor to interactively import modules that are ALSO located within the text editor?

What’s your workflow for writing an addon that consists of more than one module?

My workflow is to get the AddOn to the point where I can enable it under User Preferences without a crash. Then save that as my user preferences. Now when I launch Blender my AddOn will always be turned on. I create a default test scene with the Renderer selected, the executable specified and pointing to a valid output fodler. This way I can just open Blender and click that file from the splash screen. This saves multiple steps on each launch of Blender. If the Renderer does not show up as selected at the top of the interface I know the last edit I made (in what ever python file) broke the code.

I typically use an external text editor to edit the code in this case (with single scripts I just the internal editor, however) of mutiple files. I also try to make small changes, test, repeat etc. I find if I make sweeping changes to multiple files without testing in between I end up with more problematic errors to fix rather than making many small changes.

Make small change, launch Blender, test, rinse and repeat as needed.

OK, thank you. I’ve been really curious about that.

Joel,

I have been playing around with the exporter trying to solve the RED text error I mentioned above. This lead to a minor re-write of render_scene. Mainly I created a few more path variables to keep everything clear in my mind and I used os.path.join when concatenating string paths, not + “\” +. This is more OS friendly and can lead to cross platform compatibility for pathing.

This code now correctly loads the image file after the render completes with the Rendering Interface set to Internal. Next step is progress bar, if possible.


GLOBAL_ZERO_PADDING = 4             # The number of zeros to padd strings with when converting INTs to STRINGs.
def returnNameForNumber(passedFrame):
    frame_number = str(passedFrame)
    post_fix = frame_number.zfill(GLOBAL_ZERO_PADDING)
    return post_fix
###############################################################################
# Render scene code here.
###############################################################################
def render_scene(engine, scene):
    bpy.ops.appleseed.export()
    DELAY = 0.1

    cdir = scene.appleseed.project_path    #os.path.dirname( project_file)
    project_file = realpath(scene.appleseed.project_path)
    render_dir = 'render\\' if scene.appleseed.project_path[-1] == '\\' else '\\render\\' 
    render_output = os.path.join( realpath(scene.appleseed.project_path) , render_dir)
    
    width = scene.render.resolution_x
    height = scene.render.resolution_y

    #Set filename to render
    filename = scene.name
    
    if not filename.endswith( ".appleseed"):
        filename += ".appleseed"
        
    filename = os.path.join(realpath(scene.appleseed.project_path), filename)
    
    render_frame_name = "%s_%s%s" % (scene.name, returnNameForNumber(scene.frame_current), scene.render.file_extension)
    filename_to_render = os.path.join(render_dir,render_frame_name)
    current_frame = os.path.join(cdir, filename_to_render)
    
    executable_path = os.path.join(os.path.realpath(efutil.filesystem_path(scene.appleseed.appleseed_path)))
    appleseed_exe = "appleseed.cli.exe" if scene.appleseed.renderer_type == 'CLI' else "appleseed.studio.exe"
    launch_path = os.path.join(executable_path,appleseed_exe)
    
    try:
        for item in os.listdir(render_output):
            if item == render_frame_name:
                os.remove(current_frame)
    except:
        pass
        
    #Start the Appleseed executable
    if scene.appleseed.renderer_type == 'CLI':
        #Get the absolute path to the executable dir
        cmd = (launch_path, filename, '-o', filename_to_render)
    else:    
        cmd = (launch_path, filename)
    
    print ("Current Frame [%s]." % current_frame)    
    print ("Render Output [%s]." % render_output)
    print("CWD: ", cdir)
    print ("Executable Path[%s]" % executable_path)
    print("Rendering with ", cmd[0])
    print("Filename: ", cmd[1])
    print("
")
 
    process = subprocess.Popen( cmd, cwd = cdir, stdout=subprocess.PIPE)

    # Wait for the file to be created
    while not os.path.exists(current_frame):
        if engine.test_break():
            try:
                process.kill()
            except:
                pass
            break

        if process.poll() != None:
            engine.update_stats("", "Appleseed: Error")
            break
        time.sleep( DELAY)

    if os.path.exists(current_frame):
        engine.update_stats("", "Appleseed: Rendering")
        prev_size = -1

        def update_image():
            result = engine.begin_result( 0, 0, width, height)
            lay = result.layers[0]
            # possible the image wont load early on.
            try:
                lay.load_from_file(current_frame)
            except:
                pass

            engine.end_result( result)

        # Update while rendering
        while True:
            if process.poll() != None:
                update_image()
                break

            # user exit
            if engine.test_break():
                try:
                    process.kill()
                except:
                    pass
                break

            # check if the file updated
            new_size = os.path.getsize(current_frame)
            if new_size != prev_size:
                update_image()
                prev_size = new_size

            time.sleep( DELAY)

Check it out if you get some time. See if it works on Linux.