#!BPY __doc__ = """ PlotExample02.py Example demonstrating the following techniques in Blender 2.48: 1) Use of the transform matrix 2) Use of material properties to control how objects are rendered 3) Delete (unlink) and replacement of default objects in a scene 4) Use of cross products to generate a basis for the transform matrix 5) Using python to render an image 6) Using python to save the rendered image to disk 7) Use of Blender Vector and Matrix classes 8) Defining a function in Python 9) Adding text using text3d 10) Sizing text to a box using getBoundingBox() This script is executed at the command line by: >blender -P plotExample02.py """ __author__ = "edt" __version__ = "1.0 2009/07/01" __url__="Website, dataOrigami.blogspot.com" ##########################################################3 import Blender import bpy from Blender import * from Blender.Scene import Render from Blender import Text ############################################################## # load the template blender file Blender.Load('c:\\tmp\\bgeExample004.blend') ############################################################## # load the modules used in the script import Blender import bpy from Blender import * from Blender.Scene import Render from Blender import Text from Blender import Mathutils from Blender.Mathutils import * import math ############################################################## # define function(s) def frange(start, end=None, inc=None): "A range function, that does accept float increments..." if end == None: end = start + 0.0 start = 0.0 if inc == None: inc = 1.0 L = [] while 1: next = start + len(L) * inc if inc < 0 and next >= end: break elif inc < 0 and next <= end: break L.append(next) return L def lineSegMe(p1,p2,dia=0.1,verts=16): """ This function returns a mesh which forms a line from point p1 to p2. The points can be passes as either blender vectors or lists of [x,y,z] points. This line is cylinder which goes from point p1 to p2. Optionally the diameter and number of vertices used to describe the line are passed. ------------------- The line is formed by creating a cylinder with a length equal to the distance point p1 and p2. The line is then oriented using the transform matrix to rotate and translate the cylinder. """ # use the class constructors from Blender to form vectors for p1 and p2 p1 = Vector(p1) p2 = Vector(p2) # form a vector that points in the direction from p1 to p2 dir = p2-p1 # get the length of the line we want that goes from p1 to p2 length = dir.length # use Mesh.Primitives.Cylinder to create a mesh for the line me = Mesh.Primitives.Cylinder(verts,dia,length) ############### # in the next few steps, the direction vector is used to form a basis # see http://en.wikipedia.org/wiki/Basis_(linear_algebra) # which allows us to create a transform matrix to rotate the cylinder # along the direction we want. The basic idea is that the vector from # p1 to p2 points in the direction we want. The cylinder created by # Mesh.Primitives.Cylinder is oriented along the z-axis. To rotate the # cylinder, we # rotate the z-axis in this direction. To completely specify # how to rotate, we need to provide information on how to rotate the x and y axes. # To define this, a matrix which is orthonormal (see http://en.wikipedia.org/wiki/Orthonormal) # is created from the direction vector. To create the other vectors in the # orthonormal basis, cross products are used to find orthogonal vectors. # # use the normalize function to set the length of the direction vector to 1 dir.normalize() u = dir uu = Vector([0,0,1.0]) #print AngleBetweenVecs(u,uu) if (abs(AngleBetweenVecs(u,uu))%180.0)>1e-3: # the direction of the line is different # from the z-axis # find the orthonormal basis v = CrossVecs(u,uu) w = CrossVecs(u,v) # form the transform matrix: # > The first 3 rows and 3 columns form # a rotation matrix because the any vertex transformed by this # matrix will be the same distance from the origin as the original # vertex. If this property is not preserved, then any shape formed # will be skewed and scaled by the transform. # > The first 3 columns in the last row define the translation # applied to any vertex. In this function, the translation move the # moves the end of the cylinder to the origin, then moves the end # to p1. A = Matrix( [w[0],w[1],w[2],0], [v[0],v[1],v[2],0], [u[0],u[1],u[2],0], [dir[0]/2.0*length+p1[0],dir[1]/2.0*length+p1[1],dir[2]/2.0*length+p1[2],1]) else: # the direction of the line is parallel to the z-axis # see the notes above on how the matrix is formed. A = Matrix( [1,0,0,0], [0,1,0,0], [0,0,1,0], [dir[0]/2.0*length+p1[0],dir[1]/2.0*length+p1[1],dir[2]/2.0*length+p1[2],1]) # apply the transform to the cylinder me.transform(A,True) return me def curve(pList,color=[1.0,1.0,1.0],dia=0.1,verts=4): lineMeList = [] mat = Material.New('lineMat') # create a new Material for the line mat.rgbCol = color # change the color of the line for i in range(0,len(pList)-1): p1 = pList[i] p2 = pList[i+1] lineMe = lineSegMe(p1,p2,dia,verts) lineMe.materials += [mat] lineMeList.append(lineMe) # check to see if another line segment will follow if i<len(pList)-2: jointMe = Mesh.Primitives.UVsphere(verts,verts,dia/2.0) A = Matrix( [1,0,0,0], [0,1,0,0], [0,0,1,0], [p2[0],p2[1],p2[2],1]) jointMe.transform(A,True) jointMe.materials += [mat] lineMeList.append(jointMe) return lineMeList def scrubScene(saveList=[]): 'removes all objects in scene, except objects in save list' scene = Scene.GetCurrent() for ob in scene.objects: if not ob.getName() in saveList: scene.objects.unlink(ob) def combineMeshesIntoOb(meList,obName): 'adds all meshes in meList into a single object in the scene' # TODO: add logic to detect empty list # TODO: add logic to enable/disable joining join = False rooted = False for me in meList: if not rooted: combinedOb= scene.objects.new(me,obName) rooted = True else: localCombinedOb = scene.objects.new(me,'local'+obName) if join: combinedOb.join([localCombinedOb]) scene.objects.unlink(localCombinedOb) return combinedOb def textInBox(txtStr="defaultText",col=[1.0,1.0,1.0],width=1.0,height=1.0): txt = Text3d.New() txt.setText(txtStr) txt.setSize(0.1) mat=Material.New('textMat') mat.rgbCol = col ob = scene.objects.new(txt) me = Blender.Mesh.New('textMesh') me.getFromObject(ob) me.materials += [mat] scene.objects.unlink(ob) newOb = scene.objects.new(me) # force a redraw to ensure that the bounding box is updated!! 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.setMaterials([mat]) return newOb ############################################################## ############################################################## ############################################################## # name for the embedded script in the loaded file gameScriptName = 'MainScript.py' ############################################################## # Get rid of the lamp and cube from the default scene # - leave the camera, it has the linkages for the scripting # for the BGE. # - Note: Do NOT make any object the BGE scripts invisible # via ob.layers=[], this will disable the scripts # attached to the object. scene = Scene.GetCurrent() for ob in scene.objects: print ob.getName() if ((cmp(ob.getName(),'Lamp')==0) (cmp(ob.getName(),'Cube')==0)): scene.objects.unlink(ob) ############################################################## # find camera in file and set it up # #camdata = Camera.New() #cam = scene.objects.new(camdata) cam = Blender.Object.Get('Camera') # use setLocation to control the position of the camera cam.setLocation(0.9,0.5,2.1) # use set Euler to control the angle of the camera cam.setEuler(0*(3.1415/180),10*(3.1415/180),0*(3.1415/180)) scene.objects.camera = cam ############################################################## # add a lamp and set it up # lampData = Lamp.New() lampData.setEnergy(1.0) lampData.setType('Lamp') lampData.mode = 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)) ############################################################## # load the data # f = open('c:\\tmp\\EmploymentPopRatio.txt', 'r') foundData = False data = {'x':[],'y':[],'z':[]} labels = {'x':[],'y':[],'z':[]} for line in f: fields = line.split(',') if not foundData: for entry in fields: if entry == 'Year': # this is the header row of data foundData = True else: print len(line) if len(line)>1: for i in range(0,13): if i==0: print line print fields[0] year = float(fields[0]) else: month = i if not fields[i]==' ': print '::'+fields[i]+'' data['x'].append(float(year+(month-1)/12.0)) labels['x'].append(str(year)+','+str(month)) data['y'].append(float(fields[i])) data['z'].append(0.05) ############################# ############################# axisList = ['x','y','z'] # setup the data ranges graphSetup = {} graphSetup["x"]={'max':2010,'min':1940,'inc':10} graphSetup["y"]={'max':70,'min':50,'inc':5} graphSetup["z"]={'max':1,'min':0,'inc':1} graphSetup["title"]='Employment to Population Ratio' graphSetup["xLabels"]=[] for x in frange(graphSetup['x']['min'],graphSetup['x']['max']+graphSetup['x']['inc'],graphSetup['x']['inc']): graphSetup['xLabels'].append(str(x)) print graphSetup['xLabels'] # scale the data for presentation scale={} offset={} for axis in axisList: scale[axis]=1.0/float(graphSetup[axis]['max']-graphSetup[axis]['min']) offset[axis] = float(graphSetup[axis]['min']) # build point list pointList = [] for i in range(0,len(data['x'])): p = {} for axis in scale.keys(): p[axis]=(data[axis][i]-offset[axis])*scale[axis] point = Vector([p['x'],p['y'],p['z']]) pointList.append(point) ############################################################## # create the objects in the scene and bind materials to them # draw the data from the graph meList = curve(pointList,[1.0,0.1,0.4],0.01,8) combineMeshesIntoOb(meList,'curveOb') # ############################## # create a grid for the different axes # tics = {} scaledTics = {'x':[],'y':[],'z':[]} for axis in scaledTics.keys(): tics[axis]=frange(graphSetup[axis]['min'], graphSetup[axis]['max']+graphSetup[axis]['inc'], graphSetup[axis]['inc']) for tic in tics[axis]: scaledTics[axis].append((tic-offset[axis])*scale[axis]) # draw x-y axes def plotGrid(tics={'x':[],'y':[],'z':[]},axes=['x','y'],col=[1.0,1.0,0.0],isTics=False): '' def plotGridLines(tics,axis,P1,P2,col): 'plot the grid elements' for tic in tics[axis]: R = Vector([tic,1.0,0.0]) point1 = P1*R point2 = P2*R pointList = [point1,point2] meList = curve(pointList,col,0.01,8) combineMeshesIntoOb(meList,'GridElement') # def plotGridCorners(cornerLocs,col): mat = Material.New('axisMat') # create a new Material called 'newMat' mat.rgbCol = col for i in range(0,len(cornerLocs)): cornerMe = Mesh.Primitives.UVsphere(32,32,0.01) cornerOb = scene.objects.new(cornerMe,'originOb') cornerOb.getData(False,True).materials+=[mat] cornerOb.setLocation(cornerLocs[i][0],cornerLocs[i][1],cornerLocs[i][2]) # if isTics: gridLen = 0.1 else: gridLen = 1.0 if 'x' in axes and 'y' in axes: P1 = Matrix([1.0,0.0,0.0],[0.0,0.0,0.0],[0.0,0.0,0.0]) P2 = Matrix([1.0,0.0,0.0],[0.0,gridLen,0.0],[0.0,0.0,0.0]) plotGridLines(tics,'x',P1,P2,col) P1 = Matrix([0.0,gridLen,0.0],[1.0,0.0,0.0],[0.0,0.0,0.0]) P2 = Matrix([0.0,0.0,0.0],[1.0,0.0,0.0],[0.0,0.0,0.0]) plotGridLines(tics,'y',P1,P2,col) if isTics: cornerLocs =[[0,0,0]] else: cornerLocs =[[0,0,0],[0,1,0],[1,1,0],[1,0,0]] plotGridCorners(cornerLocs,col) elif 'x' in axes and 'z' in axes: P1 = Matrix([1.0,0.0,0.0],[0.0,0.0,0.0],[0.0,0.0,0.0]) P2 = Matrix([1.0,0.0,0.0],[0.0,0.0,0.0],[0.0,gridLen,0.0]) plotGridLines(tics,'x',P1,P2,col) P1 = Matrix([0.0,0.0,0.0],[0.0,0.0,0.0],[1.0,0.0,0.0]) P2 = Matrix([0.0,gridLen,0.0],[0.0,0.0,0.0],[1.0,0.0,0.0]) plotGridLines(tics,'z',P1,P2,col) if isTics: cornerLocs =[[0,0,0]] else: cornerLocs =[[0,0,0],[0,1,0],[0,1,1],[0,0,1]] plotGridCorners(cornerLocs,col) elif 'y' in axes and 'z' in axes: P1 = Matrix([0.0,0.0,0.0],[1.0,0.0,0.0],[0.0,0.0,0.0]) P2 = Matrix([0.0,0.0,0.0],[1.0,0.0,0.0],[0.0,gridLen,0.0]) plotGridLines(tics,'y',P1,P2,col) P1 = Matrix([0.0,0.0,0.0],[0.0,gridLen,0.0],[1.0,0.0,0.0]) P2 = Matrix([0.0,0.0,0.0],[0.0,0.0,0.0],[1.0,0.0,0.0]) plotGridLines(tics,'z',P1,P2,col) if isTics: cornerLocs =[[0,0,0]] else: cornerLocs =[[0,0,0],[0,1,0],[1,1,0],[1,0,0]] plotGridCorners(cornerLocs,col) plotGrid(scaledTics,axes=['x','y'],col=[1.0,1.0,0.0],isTics=False) #plotGrid(scaledTics,axes=['x','z'],col=[1.0,1.0,0.0],isTics=False) #plotGrid(scaledTics,axes=['y','z'],col=[1.0,1.0,0.0],isTics=False) ############################## # create x-axis labels # for i in range(0,len(graphSetup['xLabels'])): label = graphSetup['xLabels'][i] xLoc = scaledTics['x'][i] xTicOb=textInBox(label,[1.0,0.0,0.0],0.1,0.1) xTicOb.setLocation(xLoc,-0.01,0.05) xTicOb.setEuler(0.0,0.0,-90.0*(3.1415/180.0)) ############################## # create y-axis labels # for i in range(0,len(tics['y'])): yLabel = str(tics['y'][i])+'%' yLoc = scaledTics['y'][i] yTicOb=textInBox(yLabel,[1.0,0.0,0.0],0.1,0.1) yTicOb.setLocation(-0.11,yLoc-0.025,0.05) ############################## # create a title # titleOb=textInBox(graphSetup['title'],[1.0,0.0,0.0],1.0,1.0) titleOb.setLocation(0.0,1.05,0.05) ############################## # mat = Material.New('xyBackMat') # create a new Material called 'newMat' mat.rgbCol = [1.0, 1.0, 1.0] # change its color xyBackMe = Mesh.Primitives.Grid(2,2) A = Matrix( [0.5,0,0,0], [0,0.5,0,0], [0,0,0.5,0], [0.5,0.5,-0.05,1]) xyBackMe.transform(A,True) xyBackOb = scene.objects.new(xyBackMe,'xyBackMe') xyBackOb.getData(False,True).materials += [mat] ######################################## ######################################## ####################################### # setup the event handler to animate the polygon # # create the text that handles the event gameScript = """ ####################################### # tasks for each iteration thru this script # 1) Output diagnostic information to console # 2) pan the camera in response to the mouse and keyboard # a) x,y controlled by arrow keys # b) rotation controlled by shift arrow keys # c) mouse moves in x,y # d) shift mouse cause rotation # 3) rotate the dislayed objects at a fixed rate using system time print 'BGE script executing...' import Blender print Blender.sys.time() # GameLogic has been added to the global namespace no need to import # for keyboard event comparison import GameKeys # support for Vector(), Matrix() types and advanced functions like AngleBetweenVecs(v1,v2) and RotationMatrix(...) import Mathutils # for functions like getWindowWidth(), getWindowHeight() import Rasterizer # for matrix operations import Mathutils def main(): print 'linked script started' frame = Blender.Get('curframe') sc = Blender.Scene.GetCurrent() print 'linked script completed - Frame %d' % frame frame = frame+1 Blender.Set('curframe',frame) cont = GameLogic.getCurrentController() # The KX_GameObject that owns this controller. own = cont.getOwner() # for scripts that deal with spacial logic own_pos = own.getPosition() # Some example functions, remove to write your own script. # check for a positive sensor, will run on any object without errors. print 'Logic info for KX_GameObject', own.getName() input = False for sens in cont.getSensors(): # The sensor can be on another object, we may want to use it own_sens = sens.getOwner() print ' sensor:', sens.getName(), if sens.isPositive(): print '(true)' input = True else: print '(false)' sensName = sens.getName() if sensName=='sMouse': print '..mouse x = '+ str(sens.getXPosition()) print '..mouse y = '+ str(sens.getYPosition()) if (sensName=='sKeyboard') and (sens.isPositive()): keyList = sens.getCurrentlyPressedKeys() keyStr = '' for key in keyList: keyStr = keyStr + str(key[0]) + ',' print '..key = '+keyStr for actu in cont.getActuators(): # The actuator can be on another object, we may want to use it own_actu = actu.getOwner() print ' actuator:', sens.getName() # This runs the actuator or turns it off # note that actuators will continue to run unless explicitly turned off. if input: GameLogic.addActiveActuator(actu, True) else: GameLogic.addActiveActuator(actu, False) # Its also good practice to get sensors and actuators by names # so any changes to their order wont break the script. sce = GameLogic.getCurrentScene() ob = sce.getObjectList()['OBCamera'] sens = cont.getSensor('sKeyboard') if sens.isPositive(): print '--key pressed--' fullKeyList = sens.getCurrentlyPressedKeys() keyList=[] for key in fullKeyList: keyList.append(key[0]) pos = ob.getPosition() orientL = ob.getOrientation() orientM = Mathutils.Matrix(orientL[0],orientL[1],orientL[2]) orientM.transpose() orient = orientM.toEuler() if (GameKeys.RIGHTSHIFTKEY in keyList) or (GameKeys.LEFTSHIFTKEY in keyList): print '--Shift Pressed--' if GameKeys.RIGHTARROWKEY in keyList: orient[1]=orient[1]+0.5 print '--Right Arrow Key--' elif GameKeys.LEFTARROWKEY in keyList: orient[1]=orient[1]-0.5 print '--Left Arrow Key--' if GameKeys.UPARROWKEY in keyList: orient[0]=orient[0]+0.5 print '--Up Arrow Key--' elif GameKeys.DOWNARROWKEY in keyList: orient[0]=orient[0]-0.5 print '--Down Arrow Key--' else: print '--other key--' else: if GameKeys.RIGHTARROWKEY in keyList: pos[0]=pos[0]-0.02 print '--Right Arrow Key--' elif GameKeys.LEFTARROWKEY in keyList: pos[0]=pos[0]+0.02 print '--Left Arrow Key--' if GameKeys.UPARROWKEY in keyList: pos[1]=pos[1]-0.02 print '--Up Arrow Key--' elif GameKeys.DOWNARROWKEY in keyList: pos[1]=pos[1]+0.02 print '--Down Arrow Key--' else: print '--other key--' orientM = orient.toMatrix() orientM.transpose() ob.setOrientation(orientM) ob.setPosition(pos) #ob.setPosition([frame/20.0,0.0,0.0]) main() """ #EVENT = "FrameChanged" txt = Text.Get(gameScriptName) #get the gamescript txt.clear() # clear the existing script txt.write(gameScript) # appending text ####################################### # set 3-d view to use the camera Blender.Window.CameraView() ########################################
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