First, we need data.
In Blender, you can animate characters using controllers, that could be meshes, curves, etc. If you only animate a character by grabbing, rotating and scaling controllers, you could get accurate data analyzing those controllers transformations.
It's possible to read the bones (actually pose-bones) rotation data, but in this case we'll focus in the controllers transformations.
How do you export data from Blender?
- By using python scripts in the Text Editor panel.
Your objects are in the center panel (3D View), and, on the right side panel, the Text Editor
To store data, you need data first. Create a scene with different objects (meshes, curves, etc), and animate them by grabbing and rotating. If you don't know how to add objects and keyframes, ask mr. Google. It's not the objective of this post to teach how to use Blender.
Try to understand the code reading the comments (in python coments are after "#" and in processing is after "//")
Try to understand the code reading the comments (in python coments are after "#" and in processing is after "//")
If you already have animated objects, you can add the following python script to the Text Editor:
#http://creativec0d1ng.blogspot.com.br/ by Italo Travenzoli import bpy import os main_path = os.getcwd() #define the main path to the current working directory of a process. print("writing to: " + main_path + "\n\n") #print the path to the console outfile = os.path.join(main_path, 'test.txt') #define the out file by using the main_path variable and the name of the file outfile = open('test.txt', 'w') #open the file to write on it sce = bpy.context.scene #get the current scene #writes the txt file with open('test.txt', 'w') as outfile: outfile.write("<Animation>\n") #write the first open tag for objects in bpy.data.objects: #for each object in the scene... ob = bpy.data.objects[objects.name] #the ob variable is set as the object in context outfile.write("<Object name=\"" + ob.name + "\">\n") #write the next tag Object with the parameter name, that'll be filled with the object name for frame in range(sce.frame_end + 1): #for each frame in the range of frames of the animation sce.frame_set(frame) #set the frame of the scene as the frame in context posx = ob.location[0] #get the position in X of the object in context posy = ob.location[1] #get the position in Y of the object in context posz = ob.location[2] #get the position in Z of the object in context rotx = ob.rotation_euler[0] #get the rotation in X of the object in context roty = ob.rotation_euler[1] #get the position in Y of the object in context rotz = ob.rotation_euler[2] #get the position in Z of the object in context outfile.write("<frame id=\"" + str(frame)+ "\">\n") #write the next tag "frame" with the parameter "id" #pos outfile.write("<position ") #write the next tag "position" outfile.write("posX=\"" + str(posx) + "\" ") #write the position in X of the object in context as a parameter outfile.write("posY=\"" + str(posy) + "\" ") #write the position in Y of the object in context as a parameter outfile.write("posZ=\"" + str(posz) + "\" ") #write the position in Z of the object in context as a parameter outfile.write("/>\n") #close the tag "position" and break the line #rot outfile.write("<rotation ") #write the next tag "rotation" outfile.write("rotX=\"" + str(rotx) + "\" ") #write the rotation in X of the object in context as a parameter outfile.write("rotY=\"" + str(roty) + "\" ") #write the rotation in Y of the object in context as a parameter outfile.write("rotZ=\"" + str(rotz) + "\" ") #write the rotation in Z of the object in context as a parameter outfile.write("/>\n") #close the tag "rotation" and break the line outfile.write("</frame>\n") #close the tag "frame" and break the line outfile.write("</Object>\n") #close the tag "Object" and break the line outfile.write("</Animation>\n") #close the tag "Animation" and break the line outfile.close() #close the file
Run the script!!
This script genetates a .txt file with all the positions and rotations of each object in each frame.
This script genetates a .txt file with all the positions and rotations of each object in each frame.
Open the generated "test.txt" file and put a line above everything:
<?xml version="1.0" encoding="ISO-8859-1"?>
Save as a XML file, with "data.xml" name.
Now you are able to visualize it with Processing. I used Processing 2.0b8 with controlP5 and proXML libraries.
Create a Processing sketch, save, and, inside of the sketch folder, create a "data" folder. Paste the "data.xml" inside of it.
Ta dah!
Create a Processing sketch, save, and, inside of the sketch folder, create a "data" folder. Paste the "data.xml" inside of it.
//http://creativec0d1ng.blogspot.com.br/ by Italo Travenzoli import proxml.*; //import proxml library import controlP5.*; //import controlP5 library ControlP5 cp5; //define a ControlP5 object Slider abc; //define a abc slider object float posX, posY, posZ; //float variables for positions String objName; // string variable for object name int frameSelector = 0; //variable to select frames, initialized with the 0 position int objectSelector = 0; //variable to select objects, initialized with the 0 position int numFrames=0; // //variable to count the number of frames in the animation, initialized with the 0 position float [] pointsX; //array of floats (x positions) float [] pointsY; //array of floats (y positions) float varYMap; //float variable to map the y variation //xml element to store and load the data of the xml XMLElement Animation; XMLElement Object; XMLElement frame; XMLElement framePointer; XMLElement position; XMLElement positionPointer; XMLElement rotation; XMLElement rotationPointer; XMLInOut xmlInOut; void setup() { size(600, 350); //size xmlInOut = new XMLInOut(this); try { xmlInOut.loadElement("data.xml"); //load the data.xml file } catch(Exception e) { //if the xml file could not be loaded it has to be created // xmlEvent(new XMLElement("Animation")); } //controls cp5 = new ControlP5(this); //new ControlP5 object // add a horizontal sliders, the value of this slider will be linked // to variable 'sliderValue' cp5.addSlider("objectSelector") //slider to select the object .setPosition(50, 25) .setWidth(200) .setRange(0, (Animation.countChildren()-1)) // set the range of the slider by achieving the number of objects in the scene .setValue(0) .setSliderMode(Slider.FLEXIBLE) ; // use Slider.FIX or Slider.FLEXIBLE to change the slider handle // by default it is Slider.FIX numFrames=(Object.countChildren()-1); //variable that receives the number of frames in the scene cp5.addSlider("frameSelector") //slider to select the frame .setPosition(50, 50) .setWidth(400) .setRange(0, numFrames) // set the range of the slider by achieving the number of frames in the scene .setValue(0) .setSliderMode(Slider.FLEXIBLE) ; pointsX= new float [numFrames]; //create the array for x positions by defining its size with the number of frames pointsY= new float [numFrames]; //create the array for y positions by defining its size with the number of frames } void xmlEvent(XMLElement element) { Animation = element; //define the Animation element as the element (first tag of XML) Object = Animation.getChild(0); //define the Object element as the -first- child of Animation tag in position 0 (the first object of the xml file) } void draw() { background(150); //gray bg fill(0); //black fill Object = Animation.getChild(objectSelector); //Define the object in context by receiving the data from the objectSelector slider objName =(Object.getAttribute("name")); //get the name of the object in context frame = Object.getChild(frameSelector); //Define the frame in context by receiving the data from the frameSelector slider position = frame.getChild(0); //reach the position tag as the first child of the frame tag rotation = frame.getChild(1); //reach the rotation tag as the second child of the frame tag posX = position.getFloatAttribute("posX"); //define the posX variable by getting the float value of the posX attribute posY = position.getFloatAttribute("posY"); //define the posY variable by getting the float value of the posY attribute posZ = position.getFloatAttribute("posZ"); //define the posZ variable by getting the float value of the posZ attribute //write text on screen textSize(20); text("object: "+ objName, 50, 100); text("frame: "+frameSelector, 50, 150); text("posX: "+ posX, 50, 200); text("posY: "+posY, 50, 250); text("posZ: "+posZ, 50, 300); //graph //get all the values of positions in every frame of the object in context and store in the array for (int i=0; i<numFrames;i++) { framePointer = Object.getChild(i); positionPointer = framePointer.getChild(0); rotationPointer = framePointer.getChild(1); pointsX[i] = positionPointer.getFloatAttribute("posX"); pointsY[i] = positionPointer.getFloatAttribute("posY"); } //draw the graph - explained in details here: http://creativec0d1ng.blogspot.com.br/2012/11/graphs-and-processing.html //draw a lighter gray rect to serve as frame for the graph fill(180); noStroke(); rect(width/2-10, height/2-100+50, 295, 200); int ponto1x=width/2; int ponto1y=height/2+50; int ponto2x=width-20; int ponto2y=height/2+50; PVector [] pontos = new PVector [numFrames]; PVector [] var = new PVector [numFrames]; for (int i=0;i<numFrames;i++) { pontos[i] = new PVector (0, 0, 0); var [i] = new PVector (0, 0, 0); } noFill(); stroke(255, 0, 0); strokeWeight(2); beginShape(); for (int i=0;i<numFrames;i++) { float X=(lerp(ponto1x, ponto2x, i/float(numFrames))); float Y=(lerp(ponto1y, ponto2y, i/float(numFrames))); pontos[i].set(X, Y, 0); var[i].set(0, map(pointsY[i]-pointsY[0], 0, 2, 0, 100), 0); pontos[i].add(var[i]); vertex(pontos[i].x, pontos[i].y); } endShape(); fill(255, 0, 0); frameSelector = constrain(frameSelector, 0, numFrames-1); ellipse(map(frameSelector, 0, numFrames, ponto1x, ponto2x), height/2+50+map(pointsY[frameSelector]-pointsY[0], 0, 2, 0, 100), 10, 10); }
Ta dah!
No comments:
Post a Comment