The ups and downs state of learning Python. Mostly it goes up. |
PYTHON "FILE" COMMAND
You may recall my previous post on Python programming:
http://blendersushi.blogspot.com.au/2012/12/python-importing-and-visualizing-data.html
That is only ONE of MANY WAYS you can import data and use it inside Blender using Python script.
On that post, I am using Blender bpy module and Python csv module. The csv module seems to be specifically designed to read comma separated value data, which I think was the right module to use to read that data.
Apparently we can also use Python FILE command to READ and even to WRITE data.
http://www.blog.pythonlibrary.org/2010/09/04/python-101-how-to-open-a-file-or-program/
http://docs.python.org/release/1.5/tut/node47.html#SECTION008210000000000000000
So, this post is just a quick additional note to that previous post. Hopefully it can be useful.
PYTHON IS UNIVERSAL, I LIKE IT
I am still slowly learning Python here and there. There are still many areas of Python that I do not understand (such as: how this language can be useful inside 3D packages), but I think I started to understand some patterns and some often used terminologies.
At the moment, I am studying Python for use inside Blender and Maya. Also for Houdini, a bit.
I watched many video tutorials that talk about Python for both Blender and Maya. Also, I read plenty of blogs talking about Python and its usage inside Blender and Maya.
HACKING MAYA PYTHON SCRIPT AND USING IT FOR BLENDER
Something cool I realized today is the flexibility of this language to "talk" to many 3D programs out there that support Python language.
Today, for example, I was studying Maya's Python from this blog:
"Creating Curve from Stock Price Data" - Maya Python Way
http://u2325.com/tutorial/mayapython/3.html
The article talks about how you can READ and IMPORT data from outside into Maya and then PARSE and USE the data to CREATE CURVE.
He explained each step quite well, I definitely recommend you to have a read. Especially those related to Python in general. Also, the steps will help you to understand the whole procedure from getting the original data, passing it into the 3D software using Python, and so on.
In Maya, the full script goes to something like this, as I borrowed from that blog with slight modification and added comments:
import maya.cmds as mc
stockPath = "C:/google_stock.csv"
closePrices = []
dayCount = 0
scale = .01
f = open(stockPath)
line = f.readline()
while line:
if "Date" not in line and line != "":
parts = line.split(",")
closePrices.append(( dayCount * scale, float(parts[4]) * scale, 0))
dayCount = dayCount + 1
line = f.readline()
f.close()
# Create Curve and Rename
mc.curve( p= closePrices, n='priceCurve' )
I recommend you to read the full tutorial details over there to understand the logic behind the code, even though the code is for Maya, we can actually use it for Blender.
From all those Python code, the only real Maya command is down below:
From all those Python code, the only real Maya command is down below:
mc.curve( p = closePrices, n='priceCurve')
That command is to CREATE CURVE based on the data passed into it. The rest of commands is really Python script, such as the IMPORT MODULE command at the very top.
I thought, it's pretty cool. Simple example, but very thoughful and useful.
Then, I was wondering if I could simply use the same Python Script inside Blender?
Then, I was wondering if I could simply use the same Python Script inside Blender?
After all, there is only 1 simple Maya command in the end. It should be easy, right? Well.... yes and no. If only Blender Curve command works as SIMPLE as Maya and in similar fashion, we can probably plug in the data like that.
FORTUNATELY, there is another blog talking about Blender Python Scripting and it EXACTLY gives the answer I was looking for, including the explanation:
A quick read, that modified script of Blender "CREATE CURVE" seems to be the perfect for what I am trying to do. Yes, so Blender commands can be modified to work much simpler.
So, I mix and match both code together.
Below is the modified version of the script above, combined with Blender Scripting "CREATE CURVE" code:
import bpy
from mathutils import Vector
# FROM BLENDER SCRIPTING BLOG
# http://blenderscripting.blogspot.com.au/2011/05/blender-25-python-bezier-from-list-of.html
w = 1 # weight
listOfVectors = [Vector((0,0,0)),Vector((1,0,0)),Vector((2,0,0)),Vector((2,3,0)),
Vector((0,2,1))]
def MakePolyLine(objname, curvename, cList):
curvedata = bpy.data.curves.new(name=curvename, type='POLY')
curvedata.dimensions = '3D'
objectdata = bpy.data.objects.new(objname, curvedata)
objectdata.location = (0,0,0) #object origin
bpy.context.scene.objects.link(objectdata)
polyline = curvedata.splines.new('NURBS')
polyline.points.add(len(cList)-1)
for num in range(len(cList)):
x, y, z = cList[num]
polyline.points[num].co = (x, y, z, w)
polyline.order_u = len(polyline.points)-1
polyline.use_endpoint_u = True
# FROM U2325 BLOG
# http://u2325.com/tutorial/mayapython/5.html
stockPath = "C:/google_stock.csv"
closePrices = []
dayCount = 0
scale = .01
f = open(stockPath)
line = f.readline()
while line:
if "Date" not in line and line != "":
parts = line.split(",")
closePrices.append(( dayCount * scale, float(parts[4]) * scale, 0))
dayCount = dayCount + 1
line = f.readline()
f.close()
# Create Curve and Rename - Blender Scripting Style
# MakePolyLine("NameOfMyCurveObject", "NameOfMyCurve", listOfVectors)
MakePolyLine("MyCurveObject", "MyCurveData", closePrices)
When I ran that script, the magic happens: IT WORKS!
Yes, it actually does work right away.
And this is because the data flow and the functions of the the Python script is fundamentally the same. The data imported is the same, it gets processed (parsed), manipulated and turned into a list of 3 values or Vector values, and it simply goes into the Blender modified CREATE CURVE command and ... so it does the job!
And this is because the data flow and the functions of the the Python script is fundamentally the same. The data imported is the same, it gets processed (parsed), manipulated and turned into a list of 3 values or Vector values, and it simply goes into the Blender modified CREATE CURVE command and ... so it does the job!
Now that we discover a little truth of Python, you might as well want to read this article by Chad about "Python Scripting for Maya Artists":
http://www.chadvernon.com/blog/resources/python-scripting-for-maya-artists/
Any Python scripts that is generic is very likely to be reusable.
Any Python scripts that is generic is very likely to be reusable.
JOHN MAEDA
My next reading will be this book. I had a quick look and read it casually. I like it a lot. Such a SIMPLE way to think of programming, especially for Computer Graphics and Design.
This guy, John Maeda, is not new in my dictionary. He has been quite an INSPIRATION for me quite a while since my student years. But not until recently when I read this book and UNDERSTAND what he is trying to say, I found this guy is really GENIUS.
That book helps to understand the LOGIC and FLOW of programming, visually. The book is pretty old and the program used inside the book is also really old. Luckily, the "Design By Numbers" program is still running on current machine and the book theory is really applicable.
The program is similar to Processing, but A LOT SIMPLER and very VISUAL (suitable for CG artist who wanted to understand CG and its beauty via programming).
In that book, John Maeda talks about procedural way of generating DOT and LINE (with unlimited variations) like no other computer graphic artists/developers, while at the same time explaining the concept of LOOP (repeat) and VARIABLE and ITERATION and COMMAND, and so on.
The cool thing is that he limits the whole thing to 100 x 100 pixel grid. Only. Maybe kind of like the Game of GO and its limitless variations.
So perhaps, we can do the same inside Blender. Why don't we mark around with Python to simply produce 3D position in space and ask Blender to do something with it.
Let say, simply creating bunch of Box or Sphere in certain position of 3D space, based on certain range of values. This code below creates bunch of Spheres in Sine pattern because I use Python MATH module.
import bpy
import math
for item in range(0,100,2):
locx = (item) * 1
locy = math.sin(item*0.1) * 20
#bpy.ops.mesh.primitive_cube_add(location=(locx, locy, 0), rotation=(0, 0, 0))
bpy.ops.mesh.primitive_uv_sphere_add(size=0.5, location=(locx, locy, 0))
I guess, that is another good way to approach Python programming and writing, especially for ARTIST. Do SIMPLE script first, and repeat using all kind of different ways.
Book like that often has a lot of really nice conceptual coding, from beginner to advance scripts. Some of them is good and applicable for 3D coding.
import bpy
# Original script was based on:
# Processing Sketch PDE by Ira Greenberg, Dated: August 7, 2005
# Book Title: "Processing Creative Coding Computational Foundation"
# http://www.amazon.com/Processing-Creative-Coding-Computational-Foundation/dp/159059617X
# Blender's default 20 layers visibility for the object
myLayerDefault = (True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False)
# Setup the Pyramide
numberOfSteps = 20
gradientRadius = 20;
interval = gradientRadius/numberOfSteps;
sideOfPyramide = 4 # based on cylinder primitive, how many edges you like
# Create gradient of pyramide
for i in range(numberOfSteps):
bpy.ops.mesh.primitive_cylinder_add(vertices=sideOfPyramide, radius=gradientRadius-(interval*i), depth=1, end_fill_type='NGON', view_align=False, enter_editmode=False, location=(0, 0, i), rotation=(0, 0, 0), layers=myLayerDefault)
EXAMPLE PROCESSING SKETCH CODE TRANSLATED INTO BLENDER PYTHON SCRIPT
Below script is originally written by Ira, the writer of "Processing Creative Coding Computational Foundation". The script is Processing Code to create simple gradient type of 2D artwork:Book like that often has a lot of really nice conceptual coding, from beginner to advance scripts. Some of them is good and applicable for 3D coding.
SCRIPT: Create Pyramide Tower (from primitive cylinder)
import bpy
# Original script was based on:
# Processing Sketch PDE by Ira Greenberg, Dated: August 7, 2005
# Book Title: "Processing Creative Coding Computational Foundation"
# http://www.amazon.com/Processing-Creative-Coding-Computational-Foundation/dp/159059617X
# Blender's default 20 layers visibility for the object
myLayerDefault = (True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False)
# Setup the Pyramide
numberOfSteps = 20
gradientRadius = 20;
interval = gradientRadius/numberOfSteps;
sideOfPyramide = 4 # based on cylinder primitive, how many edges you like
# Create gradient of pyramide
for i in range(numberOfSteps):
bpy.ops.mesh.primitive_cylinder_add(vertices=sideOfPyramide, radius=gradientRadius-(interval*i), depth=1, end_fill_type='NGON', view_align=False, enter_editmode=False, location=(0, 0, i), rotation=(0, 0, 0), layers=myLayerDefault)
IT REALLY WAS NOT EASY AT FIRST
For me, the hardest part learning Python and Blender Python is to see the long Python commands, which is like Object and Method within another Object and Method, within another Object and Method But I guess that is just how Python works with its Object Oriented Programming (OOP) paradigm.
CREATING POLYGON CUBE as Blender Python Operation, foe example, goes something like this:
bpy.ops.mesh.primitive_cube_add(view_align=False, enter_editmode=False, location=(5.72182, 4.81879, 5.76696), rotation=(0, 0, 0), layers=(True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False))
When I saw that command for the very first time, I was totally confused. The command of course can be reduced to this below (without any additional parameters or values or arguments)
bpy.ops.mesh.primitive_cube_add()
That will work as well, because there is the default values for that operation. But of course it will be more useful if we specified values like LOCATION for example.
bpy.ops.mesh.primitive_cube_add( location=(5.72182, 4.81879, 5.76696) )
You can also kind of turning that long operation command into your own like this:
makeCube = bpy.ops.mesh.primitive_cube_add
# without the parenthesis at the end
# this is called "dynamic function calling" according to below:
http://hetland.org/writing/instant-hacking.html
Below code will work, after you add the above snippet, if you want to change Blender command on the fly:
makeCube ( location=(5.72182, 4.81879, 5.76696) )
Knowing that information, we can then play with the imported data from above and pass it as LOCATION for the new object. I am using the Create Sphere command below, because with Sphere I can easily control the RADIUS SIZE of the Sphere:
CONCLUSION
Ok, so that is pretty much my blog post for today.
My point with this Python post is that once we are confident enough to start looking and reading at other people's "recipes" and understand what they do, we can "mix" and use them for our own problem.
Part of the big frustration in programming is often to find "function" or "procedure" that does thing the way you want it. Before finding that solution, sometimes we actually need to really understand the actual question (breaking the problem into smaller parts).
If we could not find that code, we need to build the function ourselves.
Programming may seem and feel like "not for everyone", but even as someone with non-programmer background myself, I found that understanding programming concept can be really beneficial for everyday life, but especially within this Computer Graphics area. Programming is a must have skill.
My point with this Python post is that once we are confident enough to start looking and reading at other people's "recipes" and understand what they do, we can "mix" and use them for our own problem.
Part of the big frustration in programming is often to find "function" or "procedure" that does thing the way you want it. Before finding that solution, sometimes we actually need to really understand the actual question (breaking the problem into smaller parts).
If we could not find that code, we need to build the function ourselves.
Programming may seem and feel like "not for everyone", but even as someone with non-programmer background myself, I found that understanding programming concept can be really beneficial for everyday life, but especially within this Computer Graphics area. Programming is a must have skill.
Hopefully we can further explore this Python universality from perspective of different 3D packages and use the universal knowledge and understanding for all our benefits. Peace!
FURTHER SELF EXPLORATION
http://wiki.blender.org/index.php/Dev:2.5/Py/Scripts/Cookbook/Code_snippets/Three_ways_to_create_objects
http://www.blenderaddons.com/tuts25/triangle25.php
http://blenderscripting.blogspot.com.au/2011/06/using-frompydata.html
This is another alternative of the above, this time we will pass on Vertex Data and create the graph as Mesh Edges:
FURTHER SELF EXPLORATION
http://wiki.blender.org/index.php/Dev:2.5/Py/Scripts/Cookbook/Code_snippets/Three_ways_to_create_objects
http://www.blenderaddons.com/tuts25/triangle25.php
http://blenderscripting.blogspot.com.au/2011/06/using-frompydata.html
This is another alternative of the above, this time we will pass on Vertex Data and create the graph as Mesh Edges:
import bpy
from mathutils import Vector
# FROM U2325 BLOG
# http://u2325.com/tutorial/mayapython/5.html
stockPath = "C:/google_stock.csv"
closePrices = []
dayCount = 0
scale = .01
f = open(stockPath)
line = f.readline()
while line:
if "Date" not in line and line != "":
parts = line.split(",")
closePrices.append(( dayCount * scale, float(parts[4]) * scale, 0))
dayCount = dayCount + 1
line = f.readline()
f.close()
'''
REFERENCES
http://wiki.blender.org/index.php/Dev:2.5/Py/Scripts/Cookbook/Code_snippets/Three_ways_to_create_objects
http://www.blenderaddons.com/tuts25/triangle25.php
http://blenderscripting.blogspot.com.au/2011/06/using-frompydata.html
'''
### Manually create of Polygon Mesh
scn = bpy.context.scene
graphMesh = bpy.data.meshes.new('graphMesh')
# Pass closePrices data from outside CSV data as Vertex XYZ Coordinate
vertData = closePrices
# Connect pair of Vertices data as Edges based on list order of vertices
edgeData = []
a=[]
b=[]
for number in range(len(closePrices)-1):
a.append(number)
b.append(number+1)
edgeData = list(zip(a, b))
graphMesh.from_pydata(vertData, (edgeData), ())
meshOb = bpy.data.objects.new('graphOb', graphMesh)
scn.objects.link(meshOb)
Post a Comment