How to calculate divergence of a vector in Volume VOP?

   8298   12   1
User Avatar
Member
131 posts
Joined: Oct. 2011
Offline
Hi,

I know Volume Analysis SOP does this but is it possible to do it in Volume VOP? Is it a matter of evaluating 26 neighbours of any given voxel? Can anyone post a simple example of how this could be done?


Thanks
User Avatar
Staff
6225 posts
Joined: July 2005
Offline
Divergence is commonly a property of a vector volume. This becomes some what trivial to calculate if your vector volume is sampled on a MAC grid. This is something that is non-trivial to figure out in the Volume VOP.

The idea of divergence is to look at a small volume around your sample point. You want to determine if there is a net inflow or outflow of material from that point. A simple mental model is to consider a cubic voxel there. The amount flowing through the face of a cube will be

dot (velocity(face center), face_normal) * face_area

The dot with the face normal is thus selecting the x/y/z components. Note opposing faces have opposite signs, which results in what is quite similar to the definition of a gradient.

You can thus do
vector gradx = volumegradient(.., ‘vel.x’, @P);
vector grady = volumegradient(.., ‘vel.y’, @P);
vector gradz = volumegradient(.., ‘vel.z’, @P);
float divergence = gradx.x() + grady.y() + gradz.z();

The divergence is thus the trace of the 3x3 gradient matrix for the vector field. You can optimize this by computing the gradient on each axis yourself with volume sample, cutting the total number of volume samples to 6.
User Avatar
Member
131 posts
Joined: Oct. 2011
Offline
Thanks Jeff for replying. I didn't understand the last part completely. This operation you showed:

float divergence = gradx.x() + grady.y() + gradz.z();

You have to do it for 26 neighbours or just 6? Because you also said:

“You can optimize this by computing the gradient on each axis yourself with volume sample, cutting the total number of volume samples to 6.”

How does that happen? Sorry I couldn't understand these points. Everything else made a lot of sense.
User Avatar
Staff
6225 posts
Joined: July 2005
Offline
That operation only has to be done once.

Divergence is a scalar field.

If you want to replace the volumegradient() calls with volumesample(), each gradient is replaced with two volumesample()s because we only care about a single axis.
User Avatar
Member
387 posts
Joined: Nov. 2008
Offline
Divergence calculation in volumevop:

Attachments:
divergence.PNG (44.6 KB)

User Avatar
Member
131 posts
Joined: Oct. 2011
Offline
Thanks a lot guys, I am more comfortable with divergence now.

One thing I am curious is to whether to include step size? On odforce Raymond incorporated it into the result but here we didn't mention it.

Thanks again
User Avatar
Staff
6225 posts
Joined: July 2005
Offline
You need step size when you compute the gradient by hand using volumesample(). But if you use volumegradient(), a voxel-size step size is automatically chosen for you.
User Avatar
Member
131 posts
Joined: Oct. 2011
Offline
Thanks Jeff it works as expected now

Btw if I want to calculate the voxel size, can I just get an dimension of the volume and divide it by volumeres(that_dimension)? I assume not directly because the volume might have a transform.

In that case I will multiply bbox.min and bbox.max by the inverse of this transform and then calculate the distance between these points in one 1 axis, then use that as the volume size.

If I am being an idiot and there is a simple way, please let me know
User Avatar
Staff
6225 posts
Joined: July 2005
Offline
Transforms can have tapers, so volume size can vary per voxel.

However, if you know you have cubic voxels, you can just do volumeindextopos() on 0,0,0 and 1,0,0, get the length, and cube.

If you have rectilinear voxels, do it three times for x/y/z.

If you have taper or shear, run on your ix/iy/ix and +1 variants to get eight points and compute the volume of that distorted cube.
User Avatar
Member
131 posts
Joined: Oct. 2011
Offline
Thanks Jeff, I did what you said but I am getting volume division size cubed. So I just take the distance between voxel(0,0,0) and voxel(1,0,0), which gives me the division size i.e. 0.1.

It seems like volume of a volume primitive is already available but I can't access it in VEX builder VOP using volume name.

Also how do you taper a volume? Shear works but for taper you need to scale a single face which is not possible for a volume primitive, right?
User Avatar
Staff
6225 posts
Joined: July 2005
Offline
Well, “voxel size” may mean division size or it may mean voxel volume :> You are getting the cubed as I answered the latter question.

findattribval() can let you look up by name (That is what the volume() functions do internally)

I'm not sure I want to tell you how to taper volumes as you'll find what goes wrong with them :>

Using a Volume SOP you can point it to a camera to get a frustum volume which is thus tapered. Or you can use a Primitive SOP and manually adjust the taper. It works the exact same way as Tubes - a taperx/y value represents the scaling along the Z axis.
User Avatar
Member
131 posts
Joined: Oct. 2011
Offline
Thanks Jeff, everything fit into place now.

Lastly can I just use primitive intrinsic “measuredvolume” for the volume? Does it calculate the volume of a primitive using the 8 points or just a simple bbox?

I did some experiments other than tapering, it updated this volume as I transformed the volume, except shear though because it keeps the volume I guess?

Something like this:

divsize = cbrt((voxelcountx * voxelcounty * voxelcountz) / measuredvolume)
User Avatar
Staff
6225 posts
Joined: July 2005
Offline
I think that may end up failing you for VDBs…
  • Quick Links