void CollisionVolume::Init(const float3& scales, const float3& offsets, int vType, int tType, int pAxis) { // assign these here, since we can be // called from outside the constructor primaryAxis = std::max(pAxis, 0) % COLVOL_NUM_AXES; volumeType = std::max(vType, 0) % COLVOL_NUM_SHAPES; testType = std::max(tType, 0) % COLVOL_NUM_HITTESTS; // allow defining a custom volume without using it for coldet disabled = (scales.x < 0.0f || scales.y < 0.0f || scales.z < 0.0f); axisOffsets = offsets; // make sure none of the scales are ever negative // or zero; if the resulting vector is <1, 1, 1>, // then the unit / feature loaders will override // the (clone) scales with the model's radius SetAxisScales(std::max(1.0f, scales.x), std::max(1.0f, scales.y), std::max(1.0f, scales.z)); if (volumeType == COLVOL_TYPE_ELLIPSOID) { // if all axes (or half-axes) are equal in scale, // volume is a sphere (a special-case ellipsoid) if ((streflop::fabsf(axisHScales.x - axisHScales.y) < EPS) && (streflop::fabsf(axisHScales.y - axisHScales.z) < EPS)) { logOutput.Print(LOG_COLVOL, "auto-converting spherical COLVOL_TYPE_ELLIPSOID to COLVOL_TYPE_SPHERE"); volumeType = COLVOL_TYPE_SPHERE; } } // secondaryAxes[0] = (primaryAxis + 1) % COLVOL_NUM_AXES; // secondaryAxes[1] = (primaryAxis + 2) % COLVOL_NUM_AXES; switch (primaryAxis) { case COLVOL_AXIS_X: { secondaryAxes[0] = COLVOL_AXIS_Y; secondaryAxes[1] = COLVOL_AXIS_Z; } break; case COLVOL_AXIS_Y: { secondaryAxes[0] = COLVOL_AXIS_X; secondaryAxes[1] = COLVOL_AXIS_Z; } break; case COLVOL_AXIS_Z: { secondaryAxes[0] = COLVOL_AXIS_X; secondaryAxes[1] = COLVOL_AXIS_Y; } break; } SetBoundingRadius(); }
void CollisionVolume::InitShape( const float3& scales, const float3& offsets, const int vType, const int tType, const int pAxis) { float3 clampedScales; // make sure none of the scales are ever negative or zero // // if the clamped vector is <1, 1, 1> (ie. all scales were <= 1.0f) // then we assume a "default volume" is wanted and the unit/feature // instances will be assigned spheres (of size model->radius) clampedScales.x = std::max(1.0f, scales.x); clampedScales.y = std::max(1.0f, scales.y); clampedScales.z = std::max(1.0f, scales.z); // assign these here, since we can be // called from outside the constructor volumeType = std::max(vType, 0) % (COLVOL_TYPE_SPHERE + 1); volumeAxes[0] = std::max(pAxis, 0) % (COLVOL_AXIS_Z + 1); axisOffsets = offsets; useContHitTest = (tType == COLVOL_HITTEST_CONT); switch (volumeAxes[0]) { case COLVOL_AXIS_X: { volumeAxes[1] = COLVOL_AXIS_Y; volumeAxes[2] = COLVOL_AXIS_Z; } break; case COLVOL_AXIS_Y: { volumeAxes[1] = COLVOL_AXIS_X; volumeAxes[2] = COLVOL_AXIS_Z; } break; case COLVOL_AXIS_Z: { volumeAxes[1] = COLVOL_AXIS_X; volumeAxes[2] = COLVOL_AXIS_Y; } break; } // NOTE: // ellipses are now ALWAYS auto-converted to boxes or // to spheres depending on scale values, cylinders to // base cylinders (ie. with circular cross-section) // // we assume that if the volume-type is set to ellipse // then its shape is largely anisotropic such that the // conversion does not create too much of a difference // if (volumeType == COLVOL_TYPE_ELLIPSOID) { const float dxyAbs = math::fabsf(clampedScales.x - clampedScales.y); const float dyzAbs = math::fabsf(clampedScales.y - clampedScales.z); const float d12Abs = math::fabsf(clampedScales[volumeAxes[1]] - clampedScales[volumeAxes[2]]); if (dxyAbs < COLLISION_VOLUME_EPS && dyzAbs < COLLISION_VOLUME_EPS) { volumeType = COLVOL_TYPE_SPHERE; } else { if (d12Abs < COLLISION_VOLUME_EPS) { volumeType = COLVOL_TYPE_CYLINDER; } else { volumeType = COLVOL_TYPE_BOX; } } } if (volumeType == COLVOL_TYPE_CYLINDER) { clampedScales[volumeAxes[1]] = std::max(clampedScales[volumeAxes[1]], clampedScales[volumeAxes[2]]); clampedScales[volumeAxes[2]] = clampedScales[volumeAxes[1]]; } SetAxisScales(clampedScales); SetBoundingRadius(); }