When simulating projectile impacts, calculating the angle between incoming trajectory and surface orientation determines whether the object adheres to the surface or rebounds. By comparing the normalized dot product against a configurable threshold, we can trigger a reflection sequence.
vector trajectory = @v;
vector surf_normal = normalize(@hitnml);
float impact_cos = dot(normalize(trajectory), surf_normal);
if (impact_cos < ch("incidence_limit")) {
@has_bounced = 1;
@v = reflect(trajectory, surf_normal) * ch("velocity_damp");
}
Achieving surface relaxation with out dedicated geometry nodes can be handled efficiently through attribute manipulation. This method computes a centroid based on adjacent vertices and repositions the current point toward that average.
int adjacent_pts[] = neighbours(0, @ptnum);
vector centroid = @P;
foreach(int idx; adjacent_pts) {
vector neighbor_pos = point(0, "P", idx);
centroid += neighbor_pos;
}
centroid /= (len(adjacent_pts) + 1);
@P = centroid;
While matrix transformations are common, quaternions offer a robust alternative for avoiding gimbal lock during dynamic rotations. The following snippet constructs a rotation quaternion from an axis-angle pair and applies it directly to a position vector.
float spin_radians = radians(ch("rotation_deg"));
vector axis = normalize(chv("spin_axis"));
vector4 quat_rot = quaternion(spin_radians, axis);
vector transformed_pos = qrotate(quat_rot, @P);
@P = transformed_pos;
Bending a polyline sequential requires storing historical positions to maintain structural integrity during recursive transformatiosn. This approach iterates through the curve, applying incremental rotations around preceding pivot points.
vector sampled_positions[];
int total_pts = @numpt;
for (int i = 0; i < total_pts; i++) {
append(sampled_positions, point(0, "P", i));
}
for (int i = 1; i < total_pts; i++) {
float bend_angle = point(0, "bend_amt", i) * ch("global_scale");
vector pivot = sampled_positions[i-1];
vector prev_normal = point(0, "N", i-1);
for (int j = i; j < total_pts; j++) {
vector current = sampled_positions[j] - pivot;
vector4 local_quat = quaternion(-bend_angle, prev_normal);
current = qrotate(local_quat, current);
sampled_positions[j] = current + pivot;
}
}
for (int k = 0; k < total_pts; k++) {
setpointattrib(0, "P", k, sampled_positions[k]);
}
The bending magnitude typically scales with point index, allowing for smooth, organic curves. A ramp parameter can be mapped to the angle attribute for precise control.
Adjusting point density along a resampled curve relies on remapping the curveu attribute. By applying a power function to the linear parameter, we can cluster or distribute vertices non-uniformly before interpolating new coordinates.
vector position_samples[] = detail(1, "stored_positions");
float raw_param = @curveu;
float exponent = ch("density_curve");
float mapped_param = pow(raw_param, exponent);
@P = spline("catmull-rom", mapped_param, position_samples);
When the exponent equals one, distribution remains linear. Increasing the value compresses vertices toward the curve's origin, while values below one expand them toward the terminal end.