|
Houdini Development Toolkit - Version 6.5
Side Effects Software Inc. 2004
|
Geometry
Metaballs
Basic Functionality
Aside from circles, spheres, and tubes , houdini
supports quadric and super-quadric metaballs. These primitives are very
lightweight. They are defined primarily by a center point, a weight, and a 3x3
transformation matrix which determines the primitive's size and orientation.
Meta primitives simply define a field of effect. This field can be specified as
an elliptical or super-quadric shape around a point. When two metaballs overlap
in space, their field effect is added together.
The field is specified by a weight and a kernel function. The kernel function
results in a value of 0 at the outside edge of the metaball and a value of 1 at
the center. The kernel function is scaled by the weight to shift the location
of the surface closer or further away from the center. The surface of the
metaballs exists where the field effect produces a value of one.
It is possible for metaballs to have negative weights ("Pusher" metaballs).
This allows holes to be created by effectively subtracting from the surface.
The common functionality of quadric metaballs (GEO_PrimMetaBall) and
super-quadric metaballs (GEO_PrimMetaSQuad) is reflected in their two base
classes: GEO_Quadric and GEO_MetaPrim.
The GEO_MetaPrim class contains a number of public methods, the most significant
of which are:
The super-quadric metaball contains four extra methods to control the shape
of the primitive. They provide simple handles to the Z and XY exponents:
When the exponents are equal to 1, the super-quadric becomes a plain, quadric
metaball.
Class Instantiation
GEO_PrimMetaBall and GEO_PrimMetaSQuad are abstract, which means they cannot
be instantiated. To build a metaball primitive, use the class static
::build() method defined in both GU_PrimMetaBall and GU_PrimMetaSQuad.
The construction method takes several parameters grouped together in a Parms
structure. The most important parameters are the metaball weight, the kernel,
and the 4x4 transformation matrix containing the center, size, and orientation
data.
Here is an example of how to build a quadric and a super-quadric metaball:
GU_Detail gdp;
//
// Build a quadric metaball of weight 5, X radius 2 and Z radius 3 at
// (1,1,1) :
//
GU_PrimMetaBall *metaball;
GU_PrimMetaBallParms metaparms;
metaparms.gdp = &gdp; // geo detail to append to
metaparms.weight = 5; // set the weight
metaparms.xform.scale (2, 1, 3); // set the radii
metaparms.xform.translate(1, 1, 1); // set the center
metaball = GU_PrimMetaBall::build(metaparms, "wyvill");
//
// Build a boxy super-quadric metaball that acts as a pusher metaball
// (i.e. has a negative weight). Also, use a GEO_Point that we provide
// as the metaball center at (1,1,1):
//
GU_PrimMetaSQuad *metasquad;
GU_PrimMetaSQuadParms squadparms;
squadparms.gdp = &gdp; // geo detail to append to
squadparms.weight = -2; // set the weight
squadparms.xyExp = 0.2; // set the XY exponent
squadparms.zExp = 0.08; // set the Z exponent
squadparms.ppt = gdp.appendPoint();
squadparms.ppt->getPos().assign(1,1,1);
metasquad = GU_PrimMetaSQuad::build(squadparms, "blinn");
Always check the result of the ::build() method for failure. A primitive
will not be created unless given valid parameters.
Adding a custom Kernel Evaluator
The kernel is defined by the TS_MetaKernel class. This class
contains a token, a label and four function pointers. The function
pointers are used to evaluate the kernel function, while the token and
label are used for saving/loading and UI.
The parameter to the evaluation functions represents the distance
squared from the center of a unit metaball. The functions are
responsible for evaluating the weight or gradient at the given
distance. The functions should check the bounds on the arguments
passed to it. The code below illustrates a sample kernel function
which uses a half cosine curve as the basis function.
A current restriction is that only the first character of the kernel
token is significant (for binary geometry files at a minimum).
Therefore, it is important to choose a very unique kernel token. The
tokens are case sensitive, so: cubic is different than
Cubic. However, cubic may be equivalent to
cosine (because only the first character is significant).
// Sample kernel function
#include
#include
#include
static float
evalPosition(float t)
{
// Since distance passed in is squared, we must take the root...
t = sqrt(t);
return cos(t*M_PI)*.5 + .5;
}
static float
evalGradient(float t)
{
t = sqrt(t);
return .5*sin(t*M_PI);
}
static float
cosFunc(float t)
{
if (t <= 0) return 1;
if (t >= 1) return 0;
return evalPosition(t);
}
static UT_Interval
cosFuncRange(const UT_Interval &t)
{
if (t.max <= 0) return UT_Interval(1, 1);
if (t.min >= 1) return UT_Interval(0, 0);
float min = cosFunc(t.max);
float max = cosFunc(t.min);
return (min > max) ? UT_Interval(max, min) : UT_Interval(min, max);
}
static float
cosDFunc(float t)
{
if (t <= 0) return 0;
if (t >= 1) return 0;
return evalGradient(t);
}
static UT_Interval
cosDFuncRange(const UT_Interval &t)
{
if (t.max <= 0 || t.min >= 1) return UT_Interval(0, 0);
float min = cosDFunc(t.min);
float max = cosDFunc(t.max);
return (min > max) ? UT_Interval(max, min) : UT_Interval(min, max);
}
// Now, define the kernel table definition
static TS_MetaKernel cosKernel = {
"cosine", // Token
"Half Cosine", // Label
cosFunc,
cosFuncRange,
cosDFunc,
cosDFuncRange
};
// And now, here's the function which installs the kernel
void
newMetaKernel()
{
TS_KernelList::getList()->addKernel(&cosKernel);
}
Table of Contents
Operators |
Surface Operations |
Particle Operations |
Composite Operators |
Channel Operators
Material & Texture |
Objects |
Command and Expression |
Render Output |
Mantra Shaders |
Utility Classes |
Geometry Library |
Image Library |
Clip Library
Customizing UI |
Questions & Answers
Copyright © 2004 Side Effects Software Inc.
477 Richmond Street West, Toronto, Ontario, Canada M5V 3E7