9
$\begingroup$

I'm building a model completely in python. This means that I start with an empty scene, and all I want to do is run a python command that creates all meshes and objects. I'm building this python script in vi, just because blender is amazing 3D software, but lousy at making a decent text editor.

Off topic: The main reason for building my model this way, is that I want to have complete control over what I build, complete reproducibility, and I get to store my model in github, having proper version control and clear change sets. I would certainly be interested in hearing some off-topic reactions on how I could do this better/differently.

While developing this script, I constantly want to reload, from scratch, change a line in my script, reload, etc. I was wondering what the best way to achieve this is. My requirements:

  • It has to be simple, a couple of keystrokes, since I'm doing this multiple times per minute.
  • I don't want to restart blender every time, just because it takes a couple of seconds to start blender, and because the blender window doesn't appear in the right spot by default (this latter is possibly fixable).
  • Preferably I start from a new state (as in: File -> new) or in a known saved state (File --> open). Between reruns I do things in the interface and I may accidentally alter some property without knowing it. Ideally this would be reset on the next run.
  • Preferably the execution is triggered by the Python Console, so that errors appear there (and not in the bash console used to start blender).

Things I've tried so far:

Loop over all objects and delete them

I can manually try to delete all objects (using the method described here): http://blenderscripting.blogspot.nl/2012/03/deleting-objects-from-scene.html This doesn't quite work (it crashes if there are hidden objects), but this is probably solvable. However it doesn't satisfy my 3rd requirement. It does allow my to make 1 oneliner that loops over all objects, delete them, and then runs my script again.

Using bpy.ops.wm.read_homefile() to get to the new state

Using this command I can get to the new state, however this also resets the python console, meaning that any subsequent command gets ignored and I can't up-arrow anymore to get it back.

Use bpy.ops.wm.open_mainfile() to get to a known saved state

This suffers from the same problem as the previous bpy.ops.wm.read_homefile, however it allows me to save some history in the python console, so I can up-arrow to it. It works, sort of, but not ideal.

In all of the above settings, I used

exec(compile(open(filename).read(), filename, "exec"))

to execute the script.

My latest plan is to use modules (however I think it would work just as well with the above exec command), and the undo history. Calling operators from a script doesn't add them to the undo history, so if after the running of the script I push onto the undo stack, I can then cmd-Z my way to the previous state. I could probably. When I start, I run once (single is my module name):

import sys; import importlib; sys.path.append("/path/with/my/module"); import single;

Now I use the oneliner

importlib.reload(single); single.build_single((20,25,0)); bpy.ops.ed.undo_push()

whenever I want to see how my program runs. When I'm ready to do a new run, I cmd-Z until I'm back at the beginning (most of the time once, sometimes I did some manual operations and need to press it more often).

Somehow I feel however that there must be a better way to do this, to reset the scene to some saved or new state, while the python script keeps running....

EDIT 2015-5-5

I still haven't found a good solution to this problem. However since all I really needed was to make relatively simple 3D objects for printing on my 3D printer and sending of to Shapeways, I found OpenSCAD more suitable, and 100% text based, which allows me easy checkins into git and changesets. Don't get me wrong, I think Blender is the tool for amazing 3D rendered images and animations, for my use however it was overkill.

$\endgroup$
  • 3
    $\begingroup$ IIRC the window position and size is save in the startup .blend, so if you correctly position the window and then save the startup .blend with Ctrl U it should then start in the right spot by default. $\endgroup$ – gandalf3 Nov 16 '14 at 18:04
  • $\begingroup$ In future, try to avoid "off topic" content as much as possible, especially in such a long question body. It makes it harder for readers to "get to the point" of your question. While it is interesting you want to store it on github, etc, it doesn't really have anything to do with what you're trying to achieve. $\endgroup$ – A Wild RolandiXor May 5 '15 at 16:18
3
$\begingroup$

I fear that this can only give a partial answer.

I wrote an add-on (totally work in progress..but whatever) which gives the python console in Blender a second function. Hitting Enter, executes normal python stuff, but I can type commands and hit Cltr+Enter and the add-on will read the current line and parse it and react to it. One command I do tend to use a lot is wipe it removes all objects/meshes, the code for it is pretty much:

    elif m == 'wipe':
        remove_obj_and_mesh(context)
        add_scrollback('wiped objects and meshes', 'OUTPUT')
        # history_append(text=m, current_character=0, remove_duplicates=True)
        history_append(text=m, remove_duplicates=True)

This even prints the message 'wiped objects and meshes' in blue to the Python console

The code for remove_obj_and_mesh() is:

def remove_obj_and_mesh(context):
    scene = context.scene
    objs = bpy.data.objects
    meshes = bpy.data.meshes
    for obj in objs:
        if obj.type == 'MESH':
            scene.objects.unlink(obj)
            objs.remove(obj)
    for mesh in meshes:
        meshes.remove(mesh)

enter image description here

I've not tested that on hidden objects, but if you can link a representative file / blend state which you would like to wipe entirely or selectively, i recommend posting it and that will let us/me answer more concisely.

ps. blenderscripting.blogspot is my blog, i should probably change that code

$\endgroup$
  • 1
    $\begingroup$ I like your approach. It has been some time, but as I recall the problem is that I want a guarantee that the whole state is reset ---- so any global settings I made, possibly my accidentally hitting some key with special meaning. One example that comes to mind is setting the units from imperial to metric, or scaling them. Because if my Python script only runs because of some special setting, then I have no guarantee I can recreate my file after I quit blender. $\endgroup$ – Claude May 4 '15 at 19:13
  • $\begingroup$ then how about a mix of importing a new .blend which you know is good and filling the console history with a loop of history_append $\endgroup$ – zeffii May 4 '15 at 19:42
  • $\begingroup$ Well, the problem is that you can't import and do anything else in 1 line (which you could copy and then paste whenever needed). See my 2nd and 3rd solution above. By now actually I dropped the blender approach and decided to switch to OpenSCAD which works fine for the work I need it for. It misses probably about 1000000 features but for making relatively simple shapes on your 3d printer it's great! $\endgroup$ – Claude May 4 '15 at 19:51
  • $\begingroup$ @zeffii, I'm trying to do the same thing as whoever asked this question. I do, however, don't want to have to completely restart blender simulations each time I change a line in my script and reload the meshes. Is there any way to pause the simulation, change the environment specs and then resume with the new features loaded? $\endgroup$ – Archana Ram Sep 25 '15 at 19:31
  • $\begingroup$ please ask a fresh question and link it to this, more eyes will see it and I may not have time to respond. $\endgroup$ – zeffii Sep 25 '15 at 19:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.