Skip to content

Instantly share code, notes, and snippets.

@howiemnet
Last active July 11, 2022 18:04
Show Gist options
  • Save howiemnet/d9bae48fb1547edfe6b43d81308bccb4 to your computer and use it in GitHub Desktop.
Save howiemnet/d9bae48fb1547edfe6b43d81308bccb4 to your computer and use it in GitHub Desktop.
Houdini Particle distance resizer
// NOTE: ignore the .cpp extension on the filename - this is VEX
// but I couldn't find a gist-friendly way to syntax-hilight it
// ¯\_(ツ)_/¯
//
// h's magic adaptive point resizer for optimal
// rendering of tiny points/particles/wires
//
// 1/2/2018 [email protected]
// CC-0 - use and abuse
// -----------------------------------
//
// Sanity checks
//
// -----------------------------------
// Gotta have a camera!
if (chs("parm_cam_obj")=="") {
error("Need a camera object!");
}
// Make sure there are pscale
// and Alpha attribs on the points
if (!haspointattrib(0, "pscale")) {
@pscale = 1.0;
}
if (!haspointattrib(0, "Alpha")) {
f@Alpha = 1.0;
}
// -----------------------------------
//
// Pre-scaling
//
// -----------------------------------
f@pscale *= chf("parm_pre_scale");
// -----------------------------------
//
// Get camera information
//
// -----------------------------------
vector camPos = cracktransform(0,0,0,{0,0,0},optransform(chs("parm_cam_obj")));
float resx = ch("`chs("parm_cam_obj")`/resx");
float focal = ch("`chs("parm_cam_obj")`/focal");
float filmwidth = ch("`chs("parm_cam_obj")`/aperture");
// Per point, first transform it into world-space:
vector myP = ptransform("space:object","space:world",@P);
// get the distance between point and camera:
float dist_to_cam = abs(length(myP-camPos));
// calculate resultant pixel size of the point:
float pixelSize;
if (chi("parm_use_dome_projection")) {
// dome projection
pixelSize = (atan(2*@pscale / dist_to_cam) * (resx/2.0));
} else {
// perspective projection
pixelSize = ((2*@pscale / dist_to_cam) * ((resx * focal) / filmwidth));
}
// now we know how big it'll be, we can calculate what
// factor it'd take to make it exactly the size (in pixels) specified
// by the user
if ((pixelSize == 0.0) || (@Alpha == 0.0)) {
// No point in dealing with things you
// can't see
@Alpha = 0.0;
} else {
// Calculate how much the particle needs
// to be embiggened to end up large enough
// to hit the minimum threshold:
float multFac = chf("parm_min_pixels")/pixelSize;
// If Visualise is enabled, don't change any sizes -
// just change the colour.
if (chi("parm_visualise")) {
@Cd = {0,1,0};
if (pixelSize < chf("parm_min_pixels")) {
@Cd = {1,0,0};
}
} else {
// Not in Visualise mode, so do the scaling and fading.
//
// If we're dealing with wires, Alpha needs to
// be reduced by the same factor as the width increase.
// For round points, the Alpha needs to be reduced by
// the square of the radius increase instead
if (pixelSize < chf("parm_min_pixels")) {
// Tiny points:
@pscale *= multFac;
if (chi("parm_col_not_alpha")) {
@Cd /= chi("parm_wires") ? multFac : pow(multFac,2);
} else {
@Alpha /= chi("parm_wires") ? multFac : pow(multFac,2);
}
} else {
// Big points:
if (chi("parm_brighten_near_ones")) {
// No point in providing an Alpha option
// here: only practical to brighten them
@pscale *= multFac;
@Cd /= chi("parm_wires") ? multFac : pow(multFac,2);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment