[SESI logo]

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:

  • void setWeight(float w)
  • float getWeight() const
    Query or set the weight of the metaball. A positive weight will glue the metaball to other metaballs in its close neighborhood. A negative weight will cut a whole in other metaballs that this primitive comes in contact with. The bigger the weight, the bigger the volume of the metaball within its defined boundaries.

    Kernels are accessed through the TS_KernelList class. There is a DSO mechanism for adding custom kernels (see below).

  • void setMetaKernel(const char *kernel_name)
  • const char *getMetaKernel() const
    Query or set the type of kernel function:

    Kernel Description
    "wyvill" Wyvill model. Similar to the Elendt model, but with a different weight distribution function.
    "elendt" Elendt model. Similar to the Wyvill model, but with a different weight distribution function.
    "blinn" Blinn model. Always puts a sphere at the blob center. The fastest and most stable.
    "links" Links model. Slowest, but providing a good compromise between Blinn and Wyvill.
    "hart" A model suggested by John Hart.
    "prman" The model described in the Pixar release notes for RenderMan.
    custom It is also possible to add custom kernel types for metaballs to Houdini.

  • 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:

  • void setXYexp(float v)
  • void setZexp(float v)
  • float getXYexp(void) const
  • float getZexp(void) const
  • 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