PDA

View Full Version : ("Hello Py4D")


ThePriest
07-07-2010, 06:39 AM
I've spent a couple of weeks learning Python and boring as the sample material has been, I've made good progress. I installed Py4D tonight and was shocked at the complexity of creating something as simple as a rounded cylinder.

I'm clueless as to what step to take next, I could spend a few more months learning simple GUI stuff and figuring out how to make Python play ball in a strictly 2d world, but I would like to start to get some perspective on what to learn inside of Cinema.

To begin even some simple experimentation with Py4D, what's the best next step?
What's an easy starting point? Where can I find good reference material or additional plugins?

It would be great to say that by Version 12, that I can at least solve some simple issues with Python.

Thanks

LucentDreams
07-07-2010, 07:41 AM
finding an object in a hierarchy

Creating a tag on an object

Moving an object

Creating an object.

These are the basics that are essential imo. I'm not a great scripter in COFFEE or in Python, to be honest I've yet to delve into python enough to even accomplish this very list. But to me these are the key basics that I need in scripts often as a lot of the common time savers are things where you find an object and create some other object in relation, or add a tag onto a specific object etc.

I felt dumb just a week ago in asking Per to write a script for me that simply took a hierarchy of objects and converted them to empty instance objects I didn't even need anything fancy in terms of it linking a new object in or anything, I just needed something that would allow me to select all of a certain kind of object, and then replace them with an empty instance I could later link in what ever object I needed. It's really something I should have known by now but I code so little and infrequent that I forget so much of it each time I come back.

halninekilo
07-07-2010, 01:58 PM
Hi ThePriest,

I am sorry that learning python was a boring experience for you.

To me ist was most interesting and much fun, since Pythons syntax is delightfully different from other dynamic languages.
I guess it always depends on the material you work with.

Your next step should be to get to know the C4D SDK, while I would also encourage you to 'make python play ball' :)

AS for material and a starting point, I can humbly offer this two links to my examples...

This post is mostly about particles:
http://www.smart-page.net/blog/2010/04/10/py4d-examples-particle-party/
And this one deals with creating primitive geometry:
http://www.smart-page.net/blog/2010/06/25/the-binary-kite-even-more-cubes-with-py4d/

Hope you have fun!


- Jan

Scott Ayers
07-07-2010, 03:11 PM
I've tried to make Sebastian understand how EXTREMELY important it is to have examples under each and every function definition so new people can learn this stuff. That's how they do it in Maya and it's wonderful.
But we'll have to wait and see if he does anything about it.

I haven't done a lot yet with Py4D. Because I'm waiting to see what he does with the docs.
But here's a few notes I've taken for doing the basics. They should help you to at least get started.

-ScottA

ThePriest
07-07-2010, 05:06 PM
Thanks for the samples Scott, will take a look at those very shortly.

I didn't mean to suggest that learning Python is boring, I too find it to be a very friendly experience and I'm eager to learn more. However the learning materials I have here, could have been a little bit more involved creatively.

The C4D SDK is scary business, I feel I need a degree in computer science to even begin comprehending what some of the functions mean. Perhaps some day somebody will release an introductory guide to Py4D that gets us off on the right foot.

Scott Ayers
07-07-2010, 05:46 PM
The examples in the SDK are loaded with typos, missing variable errors. And many of the examples are either unfinished, or written in smooshed together manner that you'll need to know enough about programming to separate them into the proper pre-pass section/main section in order for them to run.
However...Once you learn the basic programming principles(which are very easy). The SDK can be a fantastic learning tool.
You can use it like a practice workbook to go through the examples and fix all of the broken parts and smooshed together examples like homework.
But first you have to have someone teach you the basics before you can do that. And there's the rub.
You can't use the SDK until you first know what you're doing. And you can't learn what you're doing from the SDK.
It's the old catch 22.

We're coming up on R12. And there isn't a single intro to coffee tutorial to be found on the internet that really does a good job of taking a newbie by the hand and going through the process.
That just blows my mind.
I've been thinking a lot about creating a YouTube channel dedicated to"Scripting for artists in C4D".
I've learned so much about this stuff. But I'm still a learner myself. So I understand what you new guys need, and aren't getting.
I just need to screw up the courage to do it.

-ScottA

jonahtobias
07-07-2010, 06:00 PM
Thanks Scott for that python doc!
I would love to just see a screencast of someone making a simple "hello world" plugin in python from start to finish. I'm stuck at some of the most elementary concepts of getting a plugin to work in c4d and the py4d documentation is currently pretty useless for visual people IMO.

C.Smith
07-07-2010, 06:20 PM
Here are my notes to myself for easy remembering of the major stuff:

----------


py4d Headers

import c4d, math, random
from c4d import bitmaps, documents, gui, modules, plugins, storage, symbols as sy, utils

#Python tag gives doc and op (except op is the tag)

#used for script: doc = documents.GetActiveDocument()
obj = op.GetObject()
tag = op
fps = doc.GetFps()
delta = 1/float(fps)

def CS_Time(fs):
t = doc.GetTime().Get()
return utils.Clamp(0, 999999, (t-(fs*delta)))

def main():
t = CS_Time(0) #Arg is frame to start time as zero



-----------

Lists:

Always enclosed in brackets:

a = ['dog', 'cat', 'pig']

a[0]
a[1]

del a[2]

list.append(x)
Add an item to the end of the list; equivalent to a[len(a):] = [x].
a.append('kitty')


list.extend(L)
Extends the list by another list
a.extend(['kitty','goat','puppy'])

list.insert(i, x)
Insert an item at a given position. The first argument is the index of the element before which to insert, so a.insert(0, x) inserts at the front of the list, and a.insert(len(a), x) is equivalent to a.append(x).
a.insert(3,'ferret') #'ferret' will now be the 4th item in the list

list.remove(x)
Remove the first item from the list whose value is x. It is an error if there is no such item.
a.remove('puppy')

list.pop([i])
Remove the item at the given position in the list, and return it. If no index is specified, a.pop() removes and returns the last item in the list. (The square brackets around the i in the method signature denote that the parameter is optional, not that you should type square brackets at that position. You will see this notation frequently in the Python Library Reference.)
a.pop() #removes the last item in the list and returns it's value.

list.index(x)
Return the index in the list of the first item whose value is x. It is an error if there is no such item.
a.index('ferret')

list.count(x)
Return the number of times x appears in the list.
a.count('dog')

list.sort()
Sort the items of the list, in place.
a.sort()

list.reverse()
Reverse the elements of the list, in place.
a.reverse()

---------

Dialogs

#Message Dialog. Used for notices

gui.MessageDialog("This is a message")

- returns an int describing which button was pressed.
- There is a second argument to define what type of dialog

# Question Dialog. For Yes or No

gui.QuestionDialog("Yes or no question")

returns a bool for yes or no.

#Rename Dialog. Used for renaming only

gui.RenameDialog("This is the filled in default text")

returns either a str or FALSE.

#Input Dialog. Good for asking basic questions

gui.InputDialog("This is title or question", ["This is a default answer"])

returns the str

------

Flow Control

if a<b:
return 'a is less than b'

elif a<c:
Return 'a is less than c'

else:
return 'not a match'

while a<b:
Do stuff

for i in xrange (10):
print i # returns 0 - 9

break # Breaks out of a loop skipping any remaining loop code

continue # Like break, except it doesn't leave the loop. It skips that iteration's and starts the next iteration.

-----------

Get Active Camera

def GetCamera(doc):

bd = doc.GetRenderBaseDraw()
cp = bd.GetSceneCamera(doc)
if cp is None: cp = bd.GetEditorCamera()

return cp

------

Help

DIR:

Gives you the methods in the module or in the class

dir(math)

dir(math.sin)

HELP:
Shows you the text defined in the __doc__ string.

help(math.sin)


DocStrings:

The first logical line of a function should be the doc string. It starts with triple quotes and a one line desciption, then a space, then more detail.

You call it with:

myFunction.__doc__

To see the doc string in a function use:

help(myFunction)

------------

Math Functions

#Pi

math.pi

#RangeMapper!

utils.RangeMap(InputValue, MinIn,MaxIn,MinOut,MaxOut,ClampBool, [SplineData])

#abs

abs(-Number)

#int (convert a float or string to an int)

int(12.3)
12

int('12.3')
12

#float (Converts an int or str into a float number)

float(2)
2.0

float('34')
34.0

#Floor (Rounds down to the nearest integer)

math.floor(12.3)
12

#Ceil (Rounds up to the nearest integer)
math.ceil(12.3)
13


#power (To the power of)

2**2

math.pow(x,y)

x to the power of y

#exp (exponential)

math.exp(x)

#Square Root

math.sqrt(x)

#Modulo


#Sin / Cos

--Native to C4D (test speed)
sin = utils.SinCos(t)[:1]
cos = utils.SinCos(t)[1:]

or

sin, cos = utils.SinCos(t)

Explanation: SinCos returns a list of [sin, cos]. So to just get one or the other you need to slice the list.

--Native to Python (test speed)

math.sin(x)
math.cos(x)

#Tangent

math.tan(x)

#Mix

Floats:
utils.MixNum(FloatA, FloatB, 0-1MixAmount)

Vectors:
utils.MixVec(VecA,VecB, 0-1MixAmount)


#Clamp

utils.Clamp(a, b, x)

Clamps x between a and b

#Step (used to see if a number has gone over a threshold)

utils.Step(a,x)

if x is greater than a it retruns 1.0. Otherwise zero.

#Boxstep (used to animate a linear progression between 2 numbers)

utils.Boxstep(startFloat, EndFloat, x)

x is 0 - 1

#Smoothstep (used to animate a Easy Ease progression between 2 numbers)

utils.Smoothstep(startFloat, EndFloat, x)

x is 0 - 1

----------

Matrix Math

def PsrToMatrix(pos, rot, scale):
m = utils.HPBToMatrix(rot)

m.off = pos
m.v1 = m.v1.GetNormalized() * scale.x
m.v2 = m.v2.GetNormalized() * scale.y
m.v3 = m.v3.GetNormalized() * scale.z

return m


Parenting:

ParentM * ChildM



GetGlobalPosition(obj) # Returns the global position of obj
GetGlobalRotation(obj) # Returns the global rotation of obj
GetGlobalScale(obj) # Returns the global scale of obj

SetGlobalPosition(obj, pos) # Sets the global position of obj to pos
SetGlobalRotation(obj, rot) # Sets the global rotation of obj to rot
SetGlobalScale(obj, scale) # Sets the global scale of obj to scale

def GetGlobalPosition(obj):
return obj.GetMg.off

def GetGlobalRotation(obj):
return utils.MatrixToHPB(obj.GetMg)

def GetGlobalScale(obj):
m = obj.GetMg()
return c4d.Vector( m.v1.GetLength(),
m.v2.GetLength(),
m.v3.GetLength())

def SetGlobalPosition(obj, rot):
m = obj.GetMg()
pos = m.off
scale = c4d.Vector( m.v1.GetLength(),
m.v2.GetLength(),
m.v3.GetLength())

m = utils.HPBToMatrix(rot)

m.off = pos
m.v1 = m.v1.GetNormalized() * scale.x
m.v2 = m.v2.GetNormalized() * scale.y
m.v3 = m.v3.GetNormalized() * scale.z

obj.SetMg(m)

def SetGlobalScale(obj, scale):
m = obj.GetMg()

m.v1 = m.v1.GetNormalized() * scale.x
m.v2 = m.v2.GetNormalized() * scale.y
m.v3 = m.v3.GetNormalized() * scale.z

obj.SetMg(m)

---------

Object attributes


Drag the attribute to the python console where you will see it's integer symbol (what is normally an integer but is shown as an ALL-CAPS symbol). In Python the symbols are only in the symbols module so you add sy. If you remember the integer ID for that attribute you wouldn't need the symbols module.

If you drag the Segments X from a cube you see:

Cube[PRIM_CUBE_SUBX]

add sy to the symbol and attach it to the right object. Then assign it a value.

obj[sy.PRIM_CUBE_SUBX] = 10

or get a value:

myVar = obj[sy.PRIM_CUBE_SUBX]


------

Object Names

obj.GetName()
obj.SetName("This Object")

c4d.DrawViews() #refreshes screen but slows things way down. Only use if really needed.

#Find an object by name

doc.SearchObject('Null Object')

-------

PSR Manipulation

#Get Object P/S/R

op.GetPos()
op.GetRot()
op.GetScale()

#Set Object P/S/R

op.SetPos(Vector)
op.SetRot(Vector)
op.SetScale(Vector)


Reminders:
c4d.Vector(0,0,0)
c4d.DrawViews() #Warning, slows things way down. don't use in a loop.

-------

Splines

obj.ResizeObject(numOfPoints)

obj.SetPoint(index, Pos)

obj.GetSplinePoint(0->1)
returns position vector

obj.Message(c4d.MSG_UPDATE)

----------

Time Stuff

#Get Project FPS
fps = doc.GetFps()

#Set Project FPS
doc.SetFps(24)

#Get current Time
t = doc.GetTime().Get()

#Create delta Time
delta = 1/float(fps)

--------

User Data

--Need Symbols module

a = tag[sy.ID_USERDATA, 1]

b = obj[sy.ID_USERDATA, 2]

-----

Object Creation and insertion

newobj = c4d.BaseObject(c4d.type)

newobj.InsertBefore(obj)

newobj.InsertAfter(obj)

newobj.InsertUnder(obj)



List of Objects (c4d.type):

Obase

Base object.

Opoint

Point object. (PointObject)

Opolygon

Polygon object. (PolygonObject)

Ospline

Spline object. (SplineObject)

Olight

Light.

Ocamera

Camera.

Ofloor

Floor.

Osky

Sky.

Oenvironment

Environment.

Oloft

Loft NURBS.

Offd

FFD.

Oparticle

Particle emitter.

Odeflector

Particle deflector.

Ogravitation

Particle gravitation.

Orotation

Particle rotation.

Owind

Particle wind.

Ofriction

Particle friction.

Oturbulence

Particle turbulence.

Oextrude

Extrude NURBS.

Olathe

Lathe NURBS.

Osweep

Sweep NURBS.

Oattractor

Particle attractor.

Obezier

Bezier NURBS.

Oforeground

Foreground.

Obackground

Background.

Obone

Bone.

Odestructor

Particle destructor.

Ometaball

Metaball.

Oinstance

Instance.

Ohypernurbs

Hyper NURBS.

Obend

Bend deformer.

Obulge

Bulge deformer.

Oshear

Shear deformer.

Otaper

Taper deformer.

Otwist

Twist deformer.

Owave

Wave deformer.

Ostage

Stage.

Oline

Line.

Omicrophone

Microphone.

Oloudspeaker

Loadspeaker.

Onull

Null object.

Osymmetry

Symmetry object.

Owrap

Wrap deformer.

Oboole

Boolean.

Oexplosion

Explosion deformer.

Oformula

Formula deformer.

Omelt

Melt deformer.

Oshatter

Shatter deformer.

Owinddeform

Wind deformer.

Oarray

Array.

Oheadphone

Headphone.

Oconplane

Construction plane.

Oplugin

Plugin object.

Obasedeform

Base deform object.

Opolyreduction

Polygon reduction object.

Ocube

Cube object.

Osphere

Sphere object.

Oplatonic

Platonic object.

Ocone

Cone object.

Otorus

Torus object.

Odisc

Disc object.

Otube

Tube object.

Ofigure

Figure object.

Opyramid

Pyramid object.

Oplane

Plane object.

Ofractal

Fractal object.

Ocylinder

Cylinder object.

Ocapsule

Capsule object.

Ooiltank

Oil-tank object.

Orelief

Relief object.

Osinglepoly

Single polygon object.

Osplineprofile

Profile spline object.

Osplineflower

Flower spline object.

Osplineformula

Formula spline object.

Osplinetext

Text spline object.

Osplinenside

N-sided spline object.

Ospline4side

4-sided spline object.

Osplinecircle

Circle spline object.

Osplinearc

Arc spline object.

Osplinecissoid

Cissoid spline object.

Osplinecycloid

Cycloid spline object.

Osplinehelix

Helix spline object.

Osplinerectangle

Rectangle spline object.

Osplinestar

Star spline object.

Osplinecogwheel

Wheel spline object.

Osplinecontour

Contour spline object.

Oselection

Selection object.

Osds

SDS object.

Osplinedeformer

Spline deformer object.

Osplinerail

Spline rail object.

Oatomarray

Atom array object.

Ospherify

Spherify object.

Oexplosionfx

Explosion FX object.

Scott Ayers
07-07-2010, 08:45 PM
Thanks Scott for that python doc!
I would love to just see a screencast of someone making a simple "hello world" plugin in python from start to finish. I'm stuck at some of the most elementary concepts of getting a plugin to work in c4d and the py4d documentation is currently pretty useless for visual people IMO.

Making plugins with Coffee or Python is a completely different subject from writing scripts.
So is using the C++ API to make plugins.
Learning how to write scripts won't teach you how to create the proprietary C4D plugins format that Maxon uses. They are completely separate subjects that need to have their own separate tutorials.
You can be a good script writer and not have a clue how to write them in Maxon's plugin format.

Here's an example of a very simple plugin done with Coffee. Put it in your plugins folder.
I made lots of comments in it to show what each section does. But if you're new to programming it probably won't make much sense.
To convert it into a Hello World example when the button is clicked. Delete all the code from the "CalcDialog::Command(id, msg)" section. And replace it with this: if (id == But_clicked) TextDialog("Hello World", DLG_OK + DLG_ICONEXCLAMATION);

-ScottA

Kuroyume0161
07-07-2010, 08:58 PM
Half the problem with scripting and plugin programming is result visualization from simple typed in commands and algorithms. It takes time to gain experience in how what is typed will show up either in the GUI or as results in the Editor (etc.). For instance, C4D uses an automatic workflow for the GUI (you don't place elements exactly, you just specify layouts with rows and columns and such). This means trial and error to get the GUI workflow to happen and sometimes foregoing more user-friendly arrangements due to layout limitations.

Py4D is layered over the C++ SDK which means that it is less intuitive or simplistic as COFFEE. But this also means that it is just about as powerful as the C++ SDK - and without the friggin' build environment/32-64-bit/C4D version/OS issues for the most part! C++ plugins are built dynamic link libraries linked and registered when Cinema 4D is started. COFFEE and Py4D, for all intensive purposes, are scripts which are run from the source file text (ignoring byte-code compilation and such). While COFFEE/Py4D scripts are different than their plugin counterparts, they are still less complex than C++ by magnitudes!

tcastudios
07-07-2010, 09:03 PM
Scott, first never ever publish a plugin without a registered ID from PlugIn Cafe'.
It the publisher's responsibility to obtain the ID before publishing.

Second, to say that a script and a coffee command plugin is totally different?
It's 99% the same.


Cheers
Lennart

Scott Ayers
07-07-2010, 09:41 PM
Oops,
Sorry about that Lennart. I thought I had written in that file to get an ID from the plugin cafe whenever making your own plugins.

Although the plugins do use the same syntax as scripts. They use lots of special classes in them that you don't normally use when scripting. It's pretty confusing in there when you're new to them and don't know how to use them.
Even if you were good enough at scripting to write your own classes. You still have to learn how to use the ones Maxon wants you to use. And then use them the way that Maxon intended them to be used.
IMHO. That's a completely separate skill set to master than writing scripts. At least it is for me.
But if you think it's a bad idea to say that then I won't say it anymore.

-ScottA

Darter
07-07-2010, 11:34 PM
Remember that the available SDK plugin examples can be used as templates for a relatively easy transition from script to plugin. I think that practical, hands-on experience with an SDK is a great way learn the principles of OOP.

Thanks for the notes Chris.

ThePriest
07-09-2010, 04:34 AM
What version of Python is Py4D based on?
I've spent my time learning 3, but the majority of the tutorials are based on 2

Crap

Mallard
07-09-2010, 08:29 AM
yes, AFAIK the latest Py4D is based on Python 2.6.4 - I haven't come across many serious changes from that one to py 3 though

MWelter
07-09-2010, 11:39 AM
I found that once one is somewhat familiar with python
http://rgruet.free.fr/PQR26/PQR2.6.html
is an excellent reference for all basic/essential things

ernia
07-09-2010, 05:08 PM
Wonderful find, Michael.
Thanks

CGTalk Moderation
07-09-2010, 05:08 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.