Generate Thumbnails for all objects

Was having a brainstorm, thought my idea might have some userfulness for others, just wanted to get some input before I get started.

Background (Non Required Reading). I have an addon which users append blender object resources out of a “library” of objects in another .blend file. This is fine, works great. I even have the operator enum generated dynamically (once per addon load). Now that I’m getting fresh with bgl, I would love to have a tiled set of images mapped to objects in the “library” that I can draw on screen to give the user more than just an object name when it comes time to append. I would like to do the following on a blend file.

What I need (Semi Required Reading).

for each object
1. snap the view to each object in a scene (not to bad) (potentially local z and maybe an “obit down” view)
2. zoom to a certain level (some 3d view calcs) hopefully making my screenshot framed correctly
2a. redraw the screen?
3. grab a screenshot (not a rendering…but Im not opposed to a render)
4. tile all the screenshots into a grid of 32x32 or 64x64 pixel thumbnails. (I think i’ll have to write pixel data…blah)

This doesn’t need to be dynamic. I would just run it once on the resource blend file, and leave the image in the resource blend file.

Concerns:

  1. Do I need to put this on a modal timer so that the screen updates? (I think so)
  2. How can I do this without involving external image editors. Ideally my users could edit their library, click “update library” so to speak and this would be good to go.
  3. Can I limit the screenshot function to just a few pixels? http://www.blender.org/documentation/blender_python_api_2_64_release/bpy.ops.screen.html?highlight=screenshot#bpy.ops.screen.screenshot has a boolean option for fullscreen, but I don’t see an option for defining the region.

Any suggestions before I start hacking away? I’ll probably start playing with it this weekend.
Thanks for your time,
thinking out loud,
-Patmo

1 Like

Just getting started with the viewing each item, tierating through and redrawings. Both of these functions look useful…

http://www.blender.org/documentation/blender_python_api_2_64_release/bpy.ops.view3d.html?highlight=render_border#bpy.ops.view3d.render_border

http://www.blender.org/documentation/blender_python_api_2_64_release/bpy.ops.view3d.html?highlight=zoom_border#bpy.ops.view3d.zoom_border

but getting the zoom/border correct to match the thumbnail size I want will take some thinking.



#    Addon info
# ##### BEGIN GPL LICENSE BLOCK #####
#
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License
#  as published by the Free Software Foundation; either version 2
#  of the License, or (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software Foundation,
#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
import bpy
import math
import time




bl_info = {
    'name': "Scene Object Screenshot Generator",
    'author': "Patrick R. Moore",
    'version': (0,0,1),
    'blender': (2, 6, 6),
    'api': 53613,
    'location': "3D View -> Tool Shelf",
    'description': "Makes a tiled image of all objects in scene",
    'warning': "",
    'wiki_url': "",
    'tracker_url': "",
    'category': '3D View'}




def icon_mn_to_index(m,n,n_columns):
    index = n*n_columns + m
    return index


def icon_index_to_nm(i,n_columns):
        
    m = math.floor(i/n_columns)
    n = math.fmod(i,n_columns)
    
    return [m,n]

    
    
def main(context, obj): #, thumbnail_size):
    
    #object mode
    if context.object.mode != 'OBJEECT':
        bpy.ops.object.mode_set(mode = 'OBJECT')
    


    #select object, unhide it, active
    obj.hide = False
    obj.select = True
    context.scene.objects.active = obj
    
    #hide everything else
    for ob in bpy.data.objects:
        if ob.name != obj.name:
            ob.hide = True


    
    #this makes it have to run from operator in 3d view
    #cant run as script
    region = context.region  
    space = context.space_data
    #rv3d = space.region_3d
    
    if not space.local_view:
        bpy.ops.view3d.localview()
        
    bpy.ops.view3d.view_selected()
    bpy.ops.view3d.viewnumpad(type='TOP', align_active=True)
    bpy.ops.view3d.view_orbit(type='ORBITDOWN')
    bpy.ops.view3d.view_orbit(type='ORBITDOWN')
    bpy.ops.view3d.view_orbit(type='ORBITLEFT')




class SceneObjectThumbnails(bpy.types.Operator):
    """Takes a screen shot of every object in scene"""
    bl_idname = "wm.scene_objects_thumbnails"
    bl_label = "Scene Object Thumbnails"


    _timer = None


    def modal(self, context, event):
        if event.type == 'ESC':
            return self.cancel(context)


        elif event.type == 'TIMER' and ((time.time()-self.time_point) > self.delta):
            if context.space_data.local_view:
                bpy.ops.view3d.localview()
            ob = context.scene.objects[self.iter]
            main(context, ob)
            self.iter += 1
            self.time_point = time.time()
            if self.iter < self.n_obs:
                return {'RUNNING_MODAL'}
            else:
                context.window_manager.event_timer_remove(self._timer)
                return {'FINISHED'}
        
        return {'RUNNING_MODAL'}


    def invoke(self, context, event):
        
        self.n_obs = len(context.scene.objects)
        self.iter = 0
        self.time_point = time.time()
        self.delta = 0.5
        
        self._timer = context.window_manager.event_timer_add(10, context.window)
        context.window_manager.modal_handler_add(self)
        
        return {'RUNNING_MODAL'}
        
    def cancel(self, context):
        context.window_manager.event_timer_remove(self._timer)
        return {'CANCELLED'}




def register():
    bpy.utils.register_class(SceneObjectThumbnails)




def unregister():
    bpy.utils.unregister_class(SceneObjectThumbnails)




if __name__ == "__main__":
    register()