vpSetVoxelField(3)

vpSetVoxelField πŸ’– (and its bestie vpFieldOffset)

okay so bestie, welcome to the Library Functions Manual section for vpSetVoxelField(3) β€” this is the one where you tell VolPack what your voxels actually look like inside. let's get into it 🫢


✨ NAME ✨

vpSetVoxelField, vpFieldOffset β€” define the size and location of a voxel field πŸ’…


🌸 SYNOPSIS 🌸

#include <volpack.h>

vpResult
vpSetVoxelField(vpc, field_num, field_size, field_offset, field_max)
    vpContext *vpc;
    int field_num;
    int field_size;
    int field_offset;
    int field_max;

int
vpFieldOffset(voxel_ptr, field_name)
    vpContext *vpc;
    LITERAL field_name;

πŸŽ€ ARGUMENTS πŸŽ€

  • vpc β€” the VolPack context, the one you got from vpCreateContext. your whole world basically πŸ’–
  • field_num β€” which field you're defining (number it up! the first field is 0, no cap)
  • field_size β€” how big the field is, in bytes
  • field_offset β€” how many bytes from the beginning of the voxel to the beginning of the field
  • field_max β€” the biggest value that field could ever possibly be
  • voxel_ptr β€” pointer to a C structure that defines the fields inside the voxel
  • field_name β€” the literal name of the voxel field, as written in that C structure

πŸ¦‹ DESCRIPTION πŸ¦‹

so vpSetVoxelField is literally you going "here's how big each field in my voxel is and here's where it lives." that's it, that's the job ✨

once you've picked your sizes and your order for the voxel fields, you call vpSetVoxelSize once, and then you call vpSetVoxelField once for every single field. every field gets its own unique field number β€” that's the field_num argument. first field is 0, next one is 1, and so on, all the way up to one less than the total number of fields you defined with VpSetVoxelSize. πŸ’€ yes it's a lot of calls. you got this.

the field_max argument? that's what gets used to figure out how big your lookup tables need to be, since those tables are indexed by the value in a particular field. and the max field value can be any number from 0 to the maximum unsigned integer representable by the field size. so like, don't get cute with it.


πŸ’œ using a C struct (the iconic move) πŸ’œ

if you declared your voxel layout using a C structure, then you can just use the sizeof operator plus the vpFieldOffset macro to compute field sizes and offsets for you. vpFieldOffset returns the number of bytes from the beginning of a C structure to the beginning of a particular field inside it. periodt.

for example, here's how you'd declare the size and offset for one voxel field:

struct voxel {
    char field0;
    char field1;
    short field2;
} *dummy_voxel;

#define SIZE_0    sizeof(char)
#define OFFSET_0  vpFieldOffset(dummy_voxel, field0)
#define MAX_0     127

vpSetVoxelField(vpc, 0, SIZE_0, OFFSET_0, MAX_0);

πŸ”₯ the rules (do not skip these) πŸ”₯

  • the size of each field must be 1, 2 or 4 bytes. those are the options, bestie.
  • you also have to obey any byte-alignment restrictions your hardware demands. on many machines, two-byte fields have to start on a two-byte boundary, and four-byte fields have to start on a four-byte boundary.
  • the total size of a voxel may also need padding so that voxels packed one after the other still respect those alignment restrictions.
  • if you declare your voxel as a C structure and use the sizeof operator and the vpFieldOffset macro, you should always get correct results. πŸŽ€
  • however β€” if you don't think about alignment restrictions when you pick your voxel field ordering, the compiler may have to insert padding for you, and that means wasted memory. 😭 tragic. avoid.

⭐ fields that VolPack routines actually need ⭐

some VolPack routines require you to declare fields of a particular size so they have somewhere to store their results. the functions that precompute surface normals and gradient magnitudes (see vpVolumeNormals(3), vpScanlineNormals(3), vpClassifyVolume(3), vpClassifyScalars(3) and vpClassifyScanline(3)) can optionally store, in each voxel:

  • a one-byte scalar value
  • a one-byte gradient magnitude
  • a two-byte surface normal value

these constants defined in volpack.h give you the matching maximum field values: VP_SCALAR_MAX, VP_GRAD_MAX, and VP_NORM_MAX. 🫢

and if you decide not to use those functions at all? then there's literally no need to declare those fields. slay, save the bytes.


🧚 a lil opacity note 🧚

it's usually not necessary to declare a field for the voxel opacity if the opacity can be computed from the other voxel fields. see vpSetClassifierTable(3) for further discussion. iykyk πŸ’…

⚠️ heads up bestie: if the call to vpSetVoxelSize succeeds, any existing precomputed volume data structures in the context are destroyed. gone. poof. 😭

🌈 STATE VARIABLES 🌈

you can retrieve the current voxel field parameters with these state variable codes (see vpGeti(3)):

  • VP_FIELD_SIZES
  • VP_FIELD_OFFSETS
  • VP_FIELD_MAXES

πŸ’€ ERRORS πŸ’€

the normal return value is VP_OK. ✨

this error return value is possible:

  • VPERROR_BAD_VALUE β€” the field number, size or offset is out of range. (something's off, check your numbers bestie πŸ™ˆ)

πŸ‘‘ SEE ALSO πŸ‘‘

VolPack(3), vpCreateContext(3), vpSetVoxelSize(3)


and that's the whole page, no notes πŸ’– this was brought to you by the VolPack library manual β€” the vpSetVoxelField(3) page, straight from the Library Functions Manual, courtesy of VolPack. go set some voxel fields, you absolute icon πŸŒΈπŸ¦‹βœ¨

πŸ“¦ where this page comes from