vpSetLookupShader(3)

πŸ’– vpSetLookupShader β€” a little manual page, bestie edition πŸ’–

okay so this is vpSetLookupShader(3) from the Library Functions Manual and it is literally the girlboss of shading lookup tables. sit down, grab a strawberry drink πŸ“, and let's get into it.


✨ NAME ✨

vpSetLookupShader β€” specify shading lookup tables


✨ SYNOPSIS ✨

#include <volpack.h>

vpResult
vpSetLookupShader(vpc, color_channels, num_materials, color_field,
        color_table, color_table_size, weight_field, weight_table,
        weight_table_size)
    vpContext *vpc;
    int color_channels, num_materials;
    int color_field;
    float *color_table;
    int color_table_size;
    int weight_field;
    float *weight_table;
    int weight_table_size;

✨ ARGUMENTS ✨

  • vpc β€” the VolPack context you got from vpCreateContext. your main character ✨
  • color_channels β€” how many color channels per pixel, and it's either 1 or 3. no in-between, no chaos, we love a binary.
  • num_materials β€” how many material types you're working with.
  • color_field β€” the field number of the voxel field that holds the color lookup table index.
  • color_table β€” the color lookup table itself.
  • color_table_size β€” the size of the color lookup table, measured in bytes.
  • weight_field β€” the field number of the voxel field that holds the material weight lookup table index.
  • weight_table β€” the material weight lookup table itself.
  • weight_table_size β€” the size of the material weight lookup table, measured in bytes.

✨ DESCRIPTION ✨

vpSetLookupShader is how you specify the lookup tables that define a shading function. πŸ’…

The lookup-table shading algorithm VolPack gives you is built to support this whole shading model, so let's break it down:

  • every voxel is assumed to hold a mixture of some set of basic material types
  • each material type has its own shading parameters for the Phong shading equation (think: the diffuse color components, the shinyness, all of that)
  • the color of a voxel comes from computing a color for each material type, then combining those colors in proportion to how much of each material is in that voxel
  • and this shading model also supports directional (infinite-distance) light sources β˜€οΈ

So how does this model actually get implemented? Lookup tables, bestie. The tables can be precomputed so the shading equation never has to be evaluated for every single voxel β€” which is the entire point, no cap. VolPack has routines to compute these lookup tables (peep vpShadeTable(3)). You can also use the lookup tables to implement other shading models, by writing your own routine to compute what goes in the tables. And for the depth cueing of it all, see vpSetDepthCueing(3).

Now β€” plot twist β€” you can also define a callback function that gets called to shade each voxel during rendering, instead of using a lookup table. This unlocks more general shading models, but it does slow rendering down. 😭 To define a callback shader, call vpSetCallback with the VP_GRAY_SHADE_FUNC or VP_RGB_SHADE_FUNC option code (see vpSetCallback(3)).

the tea on which one wins: the lookup tables are used if the last successful call to vpSetLookupShader happened after the last successful call to vpSetCallback with one of the VP_*_SHADE_FUNC options. so it's a whole recency thing.

The args, decoded:

  • color_channels decides whether the shading table holds grayscale (1 channel) or RGB (3 channel) pixels.
  • num_materials says how many basic material types each voxel can be made of β€” at least 1, okay?
  • color_table and weight_table are the two lookup tables.
  • color_field and weight_field are two voxel fields used to index those tables.

Sizing, exactly as stated:

  • the color_table array's size must be: float color_table[n][num_materials][color_channels]; where n is the number of possible values in the color_field field of the voxel (the maximum value plus one).
  • the weight_table argument's size must be: float weight_table[m][num_materials]; where m is the number of possible values in the weight_field field of the voxel (the maximum value plus one).
  • if there's only one material then weight_table is not used and may be a NULL pointer. freeing tbh 🫢

πŸ¦‹ how the tables get accessed during rendering πŸ¦‹

say a voxel being shaded has the value color_index in the field specified by color_field, and the value weight_index in the field specified by weight_field. for each material number material_index, a weighted color gets computed from this formula:

color = color_table[color_index][material_index] * 168u' weight_table[weight_index][material_index]

then the weighted colors for each material type get added up to give you the voxel color. if color_table holds RGB values, each component is treated separately using that same formula. and if there's only one material type, the constant 1.0 is substituted for the weight_table value. iconic.

🌸 the suggested way to use the tables 🌸

  • the voxel field specified by color_field should hold an encoded surface normal vector. this should be the same field as the norm_field argument to vpVolumeNormals or vpClassifyScalars.
  • in the color_table array, for each possible encoded surface normal (the color index) and material type (the material index), the array should hold the color of the material given the current viewing direction and lighting arrangement. the color is independent of the voxel location because the light sources are assumed to be infinitely distant. vpShadeTable initializes the contents of color_table this way. ✨
  • the voxel field specified by weight_field should hold some quantity that determines the material composition of the voxel. for example, a field containing the scalar value could be used.
  • in the weight_table array, for each possible value of weight_field there should be one row of material occupancy fractions. each entry should be a number in the range 0.0-1.0 specifying the fraction of the voxel occupied by the corresponding material.
  • for example: if there are two material types and a voxel's weight_field holds the value 62, then weight_table[62][0] gives the fraction of the voxel occupied by material 0, and weight_table[62][1] gives the fraction of the voxel occupied by material 1.
  • normally, the numbers in a given row of weight_table should add up to 1.0 β€” although special effects can be achieved by bending the rules. πŸ‘€
  • vpRamp is useful for initializing the weight table with piece-wise linear ramps.

The values in the shading lookup tables may be initialized before or after calling vpSetLookupShader. typically vpSetLookupShader gets called once at the beginning of a rendering session, and then the values in the shading tables get modified as the user changes the lighting and shading parameters or the viewing direction. it's giving set-it-and-tweak-it. πŸ’…


✨ STATE VARIABLES ✨

you can retrieve info about the current shading table parameters with these state variable codes (see vpGeti(3)):

VP_COLOR_CHANNELS, VP_SHADE_COLOR_TABLE, VP_SHADE_COLOR_SIZE, VP_SHADE_WEIGHT_TABLE, VP_SHADE_WEIGHT_SIZE, VP_SHADE_COLOR_FIELD, VP_SHADE_WEIGHT_FIELD, VP_MATERIAL_COUNT


✨ ERRORS ✨

the normal return value is VP_OK. but the following error return values are possible, so don't say nobody warned you:

  • VPERROR_BAD_VALUE β€” one or more of the arguments has an invalid value or is out of range. 😭
  • VPERROR_LIMIT_EXCEEDED β€” the num_materials argument has exceeded an internal limit. to fix it: change the value of VP_MAX_MATERIAL in volpack.h and recompile the VolPack library. that's it, that's the whole move.

✨ SEE ALSO ✨

VolPack(3), vpCreateContext(3), vpShadeTable(3), vpSetCallback(3), vpRamp(3), vpVolumeNormals(3), vpClassifyScalars(3), vpSetDepthCueing(3)


okay that's the whole page, you ate that πŸ½οΈπŸ’– this came to you straight from VolPack, and the page itself is vpSetLookupShader(3) β€” so go forth, set those lookup tables, and slay. periodt. πŸ‘‘πŸŒˆ

πŸ“¦ where this page comes from