Constructive Solid Geometry Tool

calendar_today

27.03.2023

label

Modeling

mouse

Houdini 19.5

1 Introduction

In Development: A simple CSG tool which stacks smooth boolean operations such as union, subtract and intersect on solid geometries, ie. boxes and spheres.

2 Components

Solid objects: Sphere, Box, Tube, Capsule, Torus, Cone.
Boolean operations: Union, Subtract, Intersect.
Shapes: Sharp, Round, Chamfer, Columns, Stairs, Pipe.
Transformation: Size, Position, Rotation.
Repetition: None, Line, Grid, Radial, Mirror.

3 Code

Volume wrangle on a SDF volume. A loop is feeding menu input from a multiparm block into signed distance functions and combines them using boolean operations. `sd` and `op` are wrapper functions.

``````// SIGNED-DISTANCE FUNCTIONS
function float sd_sphere(vector xyz, pos; float r){
float dist = length(xyz - pos) - r;
return dist;
}

function float sd_box(vector xyz, pos, size){
vector q = abs(xyz - pos) - size;
float dist = length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0);
return dist;
}

function float sd_capsule(vector xyz, pos, size){
pos = xyz - pos;
pos.y -= clamp(pos.y, 0.0, size[1]);
return length(pos) - size[0];
}

function float sd(int type; vector xyz, pos, size){
float dist = 0.0;
if(type == 0)      dist = sd_sphere(xyz, pos, size[0]);
else if(type == 1) dist = sd_box(xyz, pos, size);
else               dist = sd_capsule(xyz, pos, size);
return dist;
}

// BOOLEAN OPERATIONS
function float op_union(     float d1, d2) { return min(d1,  d2); }
function float op_subtract(  float d1, d2) { return max(-d1, d2); }
function float op_intersect( float d1, d2) { return max(d1,  d2); }

function float op_union_sm( float d1, d2, k ) {
float h = clamp( 0.5 + 0.5*(d2-d1)/k, 0.0, 1.0 );
return lerp( d2, d1, h ) - k*h*(1.0-h); }

function float op_subtract_sm( float d1,  d2, k ) {
float h = clamp( 0.5 - 0.5*(d2+d1)/k, 0.0, 1.0 );
return lerp( d2, -d1, h ) + k*h*(1.0-h); }

function float op_intersect_sm( float d1, d2, k ) {
float h = clamp( 0.5 - 0.5*(d2-d1)/k, 0.0, 1.0 );
return lerp( d2, d1, h ) + k*h*(1.0-h); }

function float op(int comb; float d_0, d_1, r){
float dist = 0.0;
if(r < 1e-3){
if      (comb == 0) dist = op_union     (d_0, d_1);
else if (comb == 1) dist = op_subtract  (d_0, d_1);
else                dist = op_intersect (d_0, d_1);
}
else{
if      (comb == 0) dist = op_union_sm     (d_0, d_1, r);
else if (comb == 1) dist = op_subtract_sm  (d_0, d_1, r);
else                dist = op_intersect_sm (d_0, d_1, r);
}
return dist;
}

// SCENE ASSEMBLY
float dist_scene = 0.0;
for(int i = 0; i <= chi('objects'); i++){
string num = itoa(i);
int type_obj = chi('type_obj' + num);
int type_op = chi('type_op' + num);

vector rot = set(chf('rx' + num), chf('ry' + num), chf('rz' + num));
vector xyz = v@P * maketransform(0, rot);
vector size = set(chf('sx' + num), chf('sy' + num), chf('sz' + num));
vector pos = set(chf('px' + num), chf('py' + num), chf('pz' + num));

float r_sm = chf('sm' + num);

float d = sd(type_obj, xyz, pos, size);
if(i == 0) dist_scene = d;
else       dist_scene = op(type_op, d, dist_scene, r_sm);
}

f@d = dist_scene;``````

4 Sources

Distance functions by Inigo Quilez: https://iquilezles.org/articles/distfunctions/