Scripting

Minor Pipeline Tools- Change background of all viewports

The most common email I get from people who have visited this blog is inquiries about the dark color of the background in the screenshots. No it’s not a custom UI, I just have a custom menu with a bunch of stuff including two ridiculously simple scripts… one which cycles the background color in all viewports and one which sets them to this dark grey.

Its Your Friend, Dark Grey

I chose this color for a couple of reasons.

  • With a darker color, particles are much more visible, meaning I can display them as single pixels.
  • The color is dark but just light enough to easily see black wireframes.
  • Have you ever opened Softimage in a dark room full of people using Maya and Nuke? It’s like switching on a searchlight. The light grey color scheme of the Softimage UI is waaaay to bright.

These two little scripts go a long way towards my personal enjoyment of the software. I won’t bother to display them in the post (wordpress kills the formatting), but here’s a file for each…

setAllBackgroundColorsDkGrey

cycleAllBackgroundColor

Since we’re on the topic… Softimage needs a new UI. It’s elegant and functional in many ways, but dated. The light grey is glaring, the huge arrow button looks absurd to new artists, (they’re right) and I have a strong suspicion that it’s a major factor which keeps new artists from Softimage. Just my $0.02.

Minor Pipeline Tools – Logging Distance

There is an awesome thread on the softimage list where the small pipeline enhancements softimage users tend to accumulate in their personal collections are being discussed. In it I vowed to share mine to the community as a whole over time on this blog. So here’s the first one… a little python script I keep in a custom menu, which writes a log (as an anotation in the explorer) of distances between objects.

File (<1kb): LogDistances.py

#—————————————- # Log Distances between 2 objects # 2011 A Moorer #—————————————- xsi = Application xsiRoot = xsi.ActiveSceneRoot lm = xsi.LogMessage root = xsi.ActiveSceneRoot def SelectionCheck(): sel = xsi.Selection if sel.Count <= 1: lm(“Select two objects.”,4) return False if sel.Count >= 3: lm(“More than two objects selected.”,4) return False else: lm(“\nLog Distance\n————————“,32) return True #———————— #Distance Between Centers def ctr_dist( objA, objB ): from math import sqrt,pow # Thx to Alan F for this function Ax, Ay, Az = objA.Kinematics.Global.Transform.GetTranslationValues2() Bx, By, Bz = objB.Kinematics.Global.Transform.GetTranslationValues2() return sqrt( pow(Ax-Bx,2) + pow(Ay-By,2) + pow(Az-Bz,2) ) #———————– #Annotate Distance def annotate( nDist ): if xsi.ClassName(root.Properties[“MeasuredDistances”]): prevText = xsi.getValue(str(root.Properties[“MeasuredDistances”])+”.text”) lm(“Logging new distance measurement…\n”,32) xsi.SetValue(str(root.Properties[“MeasuredDistances”])+”.text”, str(prevText)+nDist, “”) else: oSet = root.AddProperty(“Annotation”,0,”MeasuredDistances”) lm(“Annotation Created.\n”,32) xsi.SetValue(str(oSet)+”.text”, “Distance Measurement Log\r”+”\r ————————————-\n\r” + nDist, “”) return #———————– #Log Distance def LogDist(): try: if SelectionCheck(): fromObj, toObj = xsi.Selection(0), xsi.Selection(1) newDist = “\r\nDistance between <“+fromObj.FullName+”> to <“+toObj.FullName+”> is: ” +str( ctr_dist(fromObj, toObj)) lm(newDist+”\n\n————————\n”,32) annotate(newDist) except: lm (“\n——-\nDistance Script Error.”,4) return True #—————————————- #Call the function – LogDist()

There you go… I hope it proves helpful to some of you. :)

I considered sharing my personal workgroup in it’s entirety, but there’s a lot of trash in there I wouldn’t want to burden people with, plus a considerable amount of stuff which Isn’t mine to share. So until I make a “clean” workgroup I’ll just have to post bits and pieces…

sphRand and even random distributions on a sphere

While taking an excellent math course over at fxPhd someone asked about the math behind Maya’s sphRand command, and it kicked off a back and forth exploration into the difficulties behind getting an even distribution of random points on a sphere. This is useful for any number of applications where random vectors are needed.

[Note: This topic has been covered (better) elsewhere on the web, but I thought it was interesting enough to preserve for myself on this blog. -am]

So how do you generate a random vector in 3D space? The natural inclination is to generate each point based on a simple random azimuth and elevation. But because the circumference of latitudes decreases from the equator towards the poles, the result is an uneven distribution. Generate a few vectors and things will seem fine. But if you generate a large set of thousands of points, you get this:

But we need an even distribution. How about this: generate random values between -1 and 1 for each X, Y and Z. Then normalize those vectors, and again you have a collection of random points on a sphere. But the distribution still isn’t even… you are basically projecting the points of a cubic volume onto the sphere surface:

 

 

You can solve this problem by culling points outside the radius of the sphere (magnitude >1) as they are being generated, and the result is an even distribution on a sphere. This is known as the rejection method, and it works, but it’s inefficient. You are computing a lot of rejected points. Additionally, as a practical matter “N iterations” yields some number less than “N” vectors, making it difficult to specify the total number of vectors to be created by such a function.

 

Enter the trigonometric method (something of a misnomer seeing as how the method involves the integral of the surface of revolution.)

θ = υ(-1,1)

And Φ = υ(0,2π)

Where υ(a,b) is equal to a uniform random scalar.

So, go from Polar to Cartesian coordinates, and you get:

x = cos(θ) cos(Φ)

y = sin(Φ)

z = cos(θ) sin(Φ)

 

And it works.

 

Digression: if you want to get down to the heart of things, getting a random scalar value, or more specifically a repeatable pseudo-random value based on a specified seed, is it’s own challenge. Here’s a snippet of GLSL code, a function written by Stephen Gustavson which generates a “random” scalar value from a scalar seed input… (cos and mod should be familiar…the “fract” function returns the fractional (decimal) portion of it’s input.)

float randomizer(const float x) { float z = mod(x, 5612.0); z = mod(z, 3.1415927 * 2.0); return(fract(cos(z) * 56812.5453)); }

threesixty3D

XSI users may want to check this out, the site has some tools and plugins for XSI, including a free set of ICE compounds, a metaball (pay) plugin, and some very nice scripts.

The $100 euro metaball .addon is pretty nice, many of us have encountered it’s ancestor as the popular free metaball tool which has been around for a while now. Now a grown up product for sale, this plugin adds ICE compatibility as well as the added/cleaner functionality of allowing metaball models to be constructed by hand, through “metapaint” etc. The tool includes not only spherical implicit metaball primitives but cylinders and cubic meta-surfaces, which is a welcome addition. The generated meshes are reasonably clean and can be set to use several models of meshing.

This took just minutes to set up and bake, tuning the meshing was really fast.

There’s a fair amount in here for the money, feature wise. Usage is pretty straightforward, and the mesh generation is fast. Since ICE users are wanting any mesh generation tools they can get their hands on it’s worth taking a look at the free demo, and my first take is that this tool makes a nice compliment to Eric Mootz’s emPolygonizer. It’s definitely a lot of fun to play with!

Fun for the four-minute Borgmann in all of us.