Sunday, August 2, 2009

The 0.001 Release of the Data Origami Library for Blender

This is a shell that will be expended in the future. It simplifies the problem of setting up an image in Blender. Other postings will build examples on top of this module.
For now, it is recommended to place this file in C:\tmp. I'll use that location in example scripts. A future release will have a more permanent recommended home.
Code: Download Code for the Origami Library 0.001. This file can be placed arbitrarily. Any script which imports this module must reference it by the full path because of how Blender handles files.
#!BPY
__doc__ = """
OLib_xxxx.py
Rev 0.001
This module setups up a scene for static rendering, animation or game engine operation
This module provides useful library functions.

This module does nothing from the Blender command line

------------------
History:
rev 0.001 8/2/2009
   Initial release to test structure and functionality
 edt 
"""

__author__ = "edt"
__version__ = "0.001 2009/08/03"
__url__="Website, dataOrigami.blogspot.com"
##############################################################

__doc__ = """
This module setups up a scene for static rendering, animation or game engine operation
This module imports useful library functions.

rev 0.001
   Initial release to test structure and functionality
 edt 8/2/2009
"""

 
import Blender
import Blender.Mathutils
from Blender.Mathutils import *

class Image(object):
 def __init__(self,name='Scene'):
  # create new scene
  scene = Blender.Scene.New(name)
  scene.makeCurrent()
  ##############################################################
  # add a camera and set it up
  #     
  camdata = Blender.Camera.New() 
  cam = scene.objects.new(camdata) 
  # use setLocation to control the position of the camera
  scene.objects.camera = cam
  self.cam   = cam
  self._lookAt_x = 0
  self._lookAt_y = 0
  self._lookAt_z = 0
  self.lookFrom(2.481,-1.508,1.1)
  ##############################################################
  # add a lamp and set it up
  #
  lampData = Blender.Lamp.New() 
  lampData.setEnergy(1.0) 
  lampData.setType('Lamp')
  lampData.mode |= Blender.Lamp.Modes["RayShadow"]  # make shadows appear
  lamp = scene.objects.new(lampData) 
  lamp.setLocation(2.0,2.0,5.0) 
  lamp.setEuler(120*(3.1415/180),30*(3.1415/180),-30*(3.1415/180))
  #
  ################################################################
  # setup world
  world = Blender.World.New(name+'_World')
  world.setCurrent()
  
  
  self.scene = scene
  self.lamp  = lamp
  self.world = world
 
 def lookFrom(self,*args):
  if len(args)==1:
   # we have an object which contains look information
   x = args[0].x
   y = args[0].y
   z = args[0].z
  elif len(args)==3:
   # we have x,y,z coordinates
   x = args[0]
   y = args[1]
   z = args[2]
  # set camera position to x,y,z 
  self.cam.setLocation(x,y,z)
  self.lookAt()
 
 def lookAt(self,*args):
  if len(args)==0:
   to_x = self._lookAt_x
   to_y = self._lookAt_y
   to_z = self._lookAt_z
   up_x = 0
   up_y = 1
   up_z = 0
  elif len(args)==1:
   # we have an object which contains look information
   to_x = args[0].x
   to_y = args[0].y
   to_z = args[0].z
   up_x = 0
   up_y = 1
   up_z = 0
  elif len(args)==2:
   # we have an object which contains look information
   to_x = args[0].x
   to_y = args[0].y
   to_z = args[0].z
   up_x = args[1].x
   up_y = args[1].y
   up_z = args[1].z
  elif len(args)==3:
   # we have x,y,z coordinates
   to_x = args[0]
   to_y = args[1]
   to_z = args[2]
   up_x = 0
   up_y = 1
   up_z = 0
  elif len(args)==6:
   # we have x,y,z coordinates
   to_x = args[0]
   to_y = args[1]
   to_z = args[2]
   up_x = args[3]
   up_y = args[4]
   up_z = args[5]
  # save view target
  self._lookAt_x = to_x
  self._lookAt_y = to_y
  self._lookAt_z = to_z
  # set camera position to x,y,z 
  from_x, from_y, from_z = self.cam.getLocation()
  p1 = Vector([from_x,from_y,from_z])
  p2 = Vector([to_x,to_y,to_z])
  
  # form a vector that points in the direction from p1 to p2
  dir = p2-p1                  
  #print 'from='+str(p1)
  #print 'to='+str(p2)
  #print 'dir='+str(dir)
  
  dir.normalize()
  #u = dir
  up = Vector([up_x,up_y,up_z])
  up.normalize()
  dir_ref = Vector([0,0,-1.0])   # direction the camera naturally points w/o rotation
  if True: #abs(AngleBetweenVecs(dir,dir_ref))>1e-6:
   d = -dir
   e = up-up*DotVecs(dir,up)
   e.normalize()
   f = -CrossVecs(d,e)
   A = Matrix(
     [f[0],f[1],f[2],0],
     [e[0],e[1],e[2],0],
     [d[0],d[1],d[2],0],
     [from_x,from_y,from_z,1])
  else:
   # the direction of view is parallel to the z-axis
   A = Matrix(
     [1,0,0,0],
     [0,1,0,0],
     [0,0,1,0],
     [from_x,from_y,from_z,1]) 
  # apply the transform to the camera   
  self.cam.setMatrix(A)

 def add(self,item,name='noName'):
  # this method allows any object to be added to the scene
  ob = self.scene.objects.new(item,name)
  return ob
  
 def delete(self,item):
  self.scene.objects.unlink(item)
  
 def addSphere(self,**kwargs):
  # default the values
  diameter = kwargs.get('diameter',1.0)
  segments = kwargs.get('segments',8)
  rings = kwargs.get('rings',8)
  loc   = kwargs.get('location',[0,0,0])
  useIco = kwargs.get('useIco',False)
  useUV = kwargs.get('useUV',True)
  subdivisions = kwargs.get('subdivisions',2)
  name = kwargs.get('name','sphere')
  if useIco:
   sphere = Blender.Mesh.Primitives.Icosphere(subdivisions,diameter)
  else: 
   sphere = Blender.Mesh.Primitives.UVsphere(segments,rings,diameter)
  ob = self.add(sphere,name)  
  ob.setLocation(loc)
  return ob
  
 def addCube(self,*kwargs):
  pass
  
 def addCylinder(self,**kwargs):
  pass
  
 def addPlane(self,**kwargs):
  pass
 
 def addText(self,**kwargs):
  loc   = kwargs.get('location',[0,0,0])
  name  = kwargs.get('name','sphere')
  txtStr= kwargs.get('text','Default Message')
  width = kwargs.get('width',1.0)
  height= kwargs.get('height',1.0)
  col   = kwargs.get('color',[1.0,1.0,1.0])
  align = kwargs.get('align','LEFT')
  txt = Blender.Text3d.New()
  txt.setText(txtStr)
  txt.setSize(0.1)
  alignDict = {'LEFT':Blender.Text3d.LEFT,'RIGHT':Blender.Text3d.RIGHT,
      'MIDDLE':Blender.Text3d.MIDDLE, 'FLUSH':Blender.Text3d.FLUSH}
  txt.setAlignment(alignDict[align])
  mat=Blender.Material.New('textMat')
  mat.rgbCol = col
  ob = self.add(txt)
  me = Blender.Mesh.New('textMesh')
  me.getFromObject(ob)
  me.materials += [mat]
  self.delete(ob)
  newOb = self.add(me,name)
  
  # force a redraw to ensure that the bounding box is updated!!
  Blender.Window.RedrawAll() 
  boundBox = newOb.getBoundBox(1)
  upperBox = max(boundBox)
  lowerBox = min(boundBox)
  initialWidth = upperBox[0]-lowerBox[0]
  initialHeight = upperBox[1]-lowerBox[1]
  widthRatio = width/initialWidth
  heightRatio = height/initialHeight
  ratio = min(widthRatio,heightRatio)
  
  newOb.setSize(ratio,ratio,ratio)
  newOb.setLocation(loc)
  return newOb


 
 def addWorld(self,**kwargs):
  pass
 
 def drawNow(self,**kwargs):
  xSize = kwargs.get('xSize',1024)
  ySize = kwargs.get('ySize',800)
  overSampleLevel = kwargs.get('oversamplingLevel',16)
  #print 'Image.drawNow() executing'
  self.context = self.scene.getRenderingContext() 
  # enable seperate window for rendering 
  Blender.Scene.Render.EnableDispWin() 
  self.context.imageType = Blender.Scene.Render.JPEG
  if overSampleLevel>0:
   self.context.enableOversampling(True)
   self.context.setOversamplingLevel(overSampleLevel)
  else:
   self.context.enableOversampling(False)   
  self.context.imageSizeX(xSize)
  self.context.imageSizeY(ySize)
  # draw the image 
  self.context.render()   
 
 def save(self,filename='image.jpg'):
  self.drawNow()
  self.context.saveRenderedImage(filename) 

class Animation(object):
 pass
 
class BEG(object):
 pass


# This does not work with Blender
#if name=='__main__':
# # test/demo codes here
# pass
 

To copy the code snippets easily, see:http://dataorigami.blogspot.com/2009/06/how-to-easily-copy-code-snippets-from.html

To execute the script in Blender, see:http://dataorigami.blogspot.com/2009/06/how-to-execute-script-from-command-line.html

To work with the script in a simple IDE, see:http://dataorigami.blogspot.com/2009/04/developing-scripts-for-blender.html

No comments:

Post a Comment