/**
@page axexamples AX Code Examples @section axexamplesintro AX Code Examples @par This page demonstrates a range of examples which use AX to manipulate OpenVDB point and volume data and can be used as a quick start demonstration on the capabilities of the software. These examples are constantly being updated but do not cover all aspects of AX! @section axexamplecontents Contents - @ref axexamplepoints - @ref axexamplepointbasic - @ref axexamplepointdelete - @ref axexamplepointdrag - @ref axexamplepointcurlnoise - @ref axexamplepointtransforms - @ref axexamplevolumes - @ref axexamplevolumeclamp - @ref axexamplevolumevel - @ref axexamplevolumeblend @section axexamplepoints Points Examples @par These examples demonstrate how to use AX on OpenVDB points grids. @subsection axexamplepointbasic Basic point attributes @par Below is a small example which demonstrates working with a few point attributes. The @ symbol is the identifier for an AX attribute. The type of each attribute is specified before the @ symbol and the name is specified afterwards. For example: @b `int@count` would imply an @b integer attribute called @b count. @par In this example there are three point attributes: a @b float attribute @b speed, a @b vec3f float attribute @b velocity and a @b vec3f float attribute @b colour. @par This snippet uses the functions @ref axlength "length" and @ref axfit "fit" to give points a colour between black and white based on their speed. @par @code{.c} // This statement writes to a new float attribute called speed and reads from a // vector float attribute called velocity. The length function is used here to // return the length of the point's velocity vector. float@speed = length(vec3f@velocity); // Points that move faster than this threshold will all be mapped to the same // colour (white). float fast_threshold = 6.f; // Writing a single value to a vector will mean that all components of the // vector are assigned the same value. vec3f@colour = fit(float@speed, 0, fast_threshold, 0, 1); @endcode @par The @b velocity attribute in this example is assumed to exist and have a range of values to produce some visual variance in colour. The attributes @b speed and @b colour do not need to exist before this snippet is run as the attributes are only written to and will be created on the fly. @par @note In Houdini (AX SOP) changing the name of the attribute from @b colour to @b Cd will result in the points being given a colour in the viewport as Cd is a special attribute. @subsection axexamplepointdelete Deleting Points @par This example demonstrates a simple way of removing points from a VDB points grid. It uses a combination of @ref axrand and @ref axdeletepoint to randomly delete roughly half of the points in the input VDB points grid. @par @code{.c} float threshold = 0.5f; // The rand function takes a seed and produces a random value between 0 and 1. // The integer attribute id from the points is used to seed the rand function. // If the value from rand is greater than the threshold (0.5) then delete the point. if (rand(int64@id) > threshold) { deletepoint(); } @endcode @par The @b id attribute in this example is assumed to be a unique @b integer for each point in the VDB points grid such that @ref axrand will receive a different seed value per point producing a good distribution of random values. @subsection axexamplepointdrag Applying Drag @par This example shows something a bit more complex: modifying a point's velocity with a drag force and then moving the point with the modified velocity. @par @code{.c} float dt = 1.0f / (4.0f * 24.0f); // timestep vec3f gravity = {0.0f, -9.81f, 0.0f}; // gravity vec3f dV = {2.0f, 0.0f, 0.0f} - v@v; // drag float lengthV = length(dV); float Re = lengthV * @rad / 1.225f; float C = 0.0f; if (Re > 1000.0f) C = 24.0f / Re; else C = 0.424f; // calculate drag force vec3f drag = 0.5f * 1.2f * C * lengthV * dV * 4.0f * 3.14f * pow(@rad, 2.0f); // update velocity v@v += (gravity - drag / ((4.0f / 3.0f) * 3.14f * pow(@rad, 3.0f))) * dt; // update position v@P += v@v * dt; @endcode @par The final AX command, `v@P += v@v * dt;` writes to the position attribute of the points @b `v@P`. Whenever position is written to in this way, the AX `PointExecutable` will move (re-bucket) points in PointDataGrids. @subsection axexamplepointcurlnoise Curl Noise @par The following example demonstrates using various native AX functions to calculate a position based curl noise on points in a particular group, and to use that calculation to update point velocities. @par @code{.c} // Only calcualte noise and apply it to points if the current point is NOT in // a group called "escaped". Note that the PointExecutable also has native // support for group based execution. if (!ingroup("escaped")) { // Read custom data float amplitude = $amplitude; float persistence = $persistence; float lacunarity = $lacunarity; vec3f freq = vec3f$frequency; vec3f offset = vec3f$offset; vec3f noise = 0.0f; // Position based curl simplex noise for (int octave = 0; octave < int($octaves); ++octave) { vec3f noisePos = vec3f@P * freq + offset; noise += curlsimplexnoise(noisePos) * amplitude; amplitude *= persistence; freq *= lacunarity; } // Apply noise scaled by the current velocity length vec3f@v += length(vec3f@v) * noise; } @endcode @subsection axexamplepointtransforms Transformations @par AX supports 3x3 and 4x4 matrix types and various transformations. They can be accessed via row, column operators or as a flat array and have defined operators (such as matrix multiplication etc.). The following demonstrates some trivial matrix math on VDB Point positions. @par @code{.c} // get the 4x4 identity matrix. note that scalar->matrix promotion handles // this, so writing 'mat4f transform = 1;' has the same effect. mat4f transform = identity4(); // set the X transform component transform[3,0] = 5; // pre scale the matrix. this is equal to writing: 'transform = scale * transform;' vec3f scale = { 1,2,3 }; prescale(transform, scale); // double the value of the scale Y component transform[5] *= 2; // construct a basic rotation matrix, representing 90 degree rotation around Y float degrees = 90.0f; float rad = radians(degrees); mat3f rotation = { cos(rad), 0.0f, -sin(rad), 0.0f, 1.0f, 0.0f, sin(rad), 0.0f, cos(rad) }; // apply the rotation and transformation to the current points position vec3f@P *= rotation; vec3f@P *= transform; @endcode

@section axexamplevolumes Volume Examples @par These examples demonstrate how to use AX on VDB volume grids. @subsection axexamplevolumeclamp Volume Clamping @par Below is a small example of reading adn writing to voxels within a VDB volume. As with points, the @ symbol specifies an access to a named volume, with the type of each volume preceding it and the name appearing as a suffix. For example: `float@density` would imply a @b float volume called @b density. @par This snippet uses @ref axclamp function to constrain the @b density attribute between zero and one. @par @code{.c} float@density = clamp(float@density, 0.f, 1.f); @endcode @subsection axexamplevolumevel Velocity Update @par AX can be used to read and write to multiple volumes. Here we have a typical example of a eulerian velocity update which takes into account an updated vector force and scalar mass. @par @code{.c} // Access the current timestep - this could instead be provided by the AX // integration and made accessible with custom data (i/e: float$timestep) float dt = 1.0f / 24.0f; // read from the mass grid the corresponding (matching index space) value float mass = float@mass; // safe divide, in case mass is zero float massInverse = 0.0f; if (mass > 0.0f) massInverse = 1.0f / mass; // update the current velocity value by scaling the corresponding force // by the timestep and inverse mass vec3f@vel += dt * massInverse * vec3f@force; @endcode @subsection axexamplevolumeblend Linear Blending @par Here we demonstrate how AX can be used to blend two volumes together. Note that only the volumes which are written to are executed over. In the below code, only @b `@surface_a` is written to. This means that the final blended result, stored in `surface_a`, will only be updated in `surface_a`'s topology. Should we want a combined blend of @b non @b overlapping areas of both surface a and b, we would need to activate a's topology with respect to b first. @par @code{.c} // time constants for each run. float time = float$time; float maxDuration = 100.0f; // read both surface a and surface b values float a = @surface_a; // source value float b = @surface_b; // target value // calculate the fractional mask value in respect to time float mask = time / maxDuration; // optionally scale the mask by a per index space density. if // $enable_density_mask is true, a density grid is used to vary the blend per // voxel if ($enable_density_mask) mask *= @density; // finally, clamp the mask value and update the level set value in surface a. // Note that this may produce a no longer valid level set and might need to be // rebuilt! mask = clamp(mask, 0.0f, 1.0f); @surface_a = a + (b-a) * mask; @endcode
*/