llphysshapebuilderutil.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. /**
  2. * @file llphysshapebuilderutil.cpp
  3. * @brief Generic system to convert LL(Physics)VolumeParams to physics shapes
  4. *
  5. * $LicenseInfo:firstyear=2001&license=viewergpl$
  6. *
  7. * Copyright (c) 2010, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "linden_common.h"
  33. #include "llphysshapebuilderutil.h"
  34. //static
  35. void LLPhysShapeBuilderUtil::getPhysShape(const LLPhysicsVolumeParams& vparams,
  36. const LLVector3& scale,
  37. bool has_decomp,
  38. ShapeSpec& spec_out)
  39. {
  40. const LLProfileParams& profile_params = vparams.getProfileParams();
  41. const LLPathParams& path_params = vparams.getPathParams();
  42. spec_out.mScale = scale;
  43. constexpr F32 ONETHIRD = 1.f / 3.f;
  44. F32 avg_scale = (scale[VX] + scale[VY] + scale[VZ]) * ONETHIRD;
  45. if (avg_scale == 0.f)
  46. {
  47. avg_scale = F32_MIN; // Paranoia: avoid divide by zero
  48. }
  49. F32 scaler = 1.f / avg_scale;
  50. // Count the scale elements that are small
  51. S32 min_size_counts = 0;
  52. for (S32 i = 0; i < 3; ++i)
  53. {
  54. if (scale[i] < SHAPE_BUILDER_CONVEXIFICATION_SIZE)
  55. {
  56. ++min_size_counts;
  57. }
  58. }
  59. F32 path_cut_limit = SHAPE_BUILDER_IMPLICIT_THRESHOLD_PATH_CUT * scaler;
  60. bool profile_complete = profile_params.getBegin() <= path_cut_limit &&
  61. profile_params.getEnd() >= 1.f - path_cut_limit;
  62. bool path_complete = path_params.getBegin() <= path_cut_limit &&
  63. path_params.getEnd() >= 1.f - path_cut_limit;
  64. F32 hollow_limit = SHAPE_BUILDER_IMPLICIT_THRESHOLD_HOLLOW * scaler;
  65. F32 shear_limit = SHAPE_BUILDER_IMPLICIT_THRESHOLD_SHEAR * scaler;
  66. bool simple_params = vparams.getHollow() <= hollow_limit &&
  67. fabs(path_params.getShearX()) <= shear_limit &&
  68. fabs(path_params.getShearY()) <= shear_limit &&
  69. !vparams.isMeshSculpt() &&
  70. !vparams.isSculpt();
  71. if (simple_params && profile_complete)
  72. {
  73. // Try to create an implicit shape or convexified
  74. F32 taper_limit = SHAPE_BUILDER_IMPLICIT_THRESHOLD_TAPER * scaler;
  75. bool no_taper = fabs(path_params.getScaleX() - 1.f) <= taper_limit &&
  76. fabs(path_params.getScaleY() - 1.f) <= taper_limit;
  77. F32 twist_limit = SHAPE_BUILDER_IMPLICIT_THRESHOLD_TWIST * scaler;
  78. bool no_twist = fabs(path_params.getTwistBegin()) <= twist_limit &&
  79. fabs(path_params.getTwistEnd()) <= twist_limit;
  80. // Box
  81. if (no_taper && no_twist &&
  82. profile_params.getCurveType() == LL_PCODE_PROFILE_SQUARE &&
  83. path_params.getCurveType() == LL_PCODE_PATH_LINE)
  84. {
  85. spec_out.mType = ShapeSpec::BOX;
  86. if (!path_complete)
  87. {
  88. // Side lengths
  89. spec_out.mScale[VX] = llmax(scale[VX],
  90. SHAPE_BUILDER_MIN_GEOMETRY_SIZE);
  91. spec_out.mScale[VY] = llmax(scale[VY],
  92. SHAPE_BUILDER_MIN_GEOMETRY_SIZE);
  93. spec_out.mScale[VZ] = llmax(scale[VZ] *
  94. (path_params.getEnd() -
  95. path_params.getBegin()),
  96. SHAPE_BUILDER_MIN_GEOMETRY_SIZE);
  97. spec_out.mCenter.set(0.f, 0.f,
  98. 0.5f * scale[VZ] *
  99. (path_params.getEnd() +
  100. path_params.getBegin() - 1.f));
  101. }
  102. return;
  103. }
  104. // Sphere
  105. if (path_complete && no_twist &&
  106. profile_params.getCurveType() == LL_PCODE_PROFILE_CIRCLE_HALF &&
  107. path_params.getCurveType() == LL_PCODE_PATH_CIRCLE &&
  108. fabs(vparams.getTaper()) <= taper_limit)
  109. {
  110. if (scale[VX] == scale[VZ] && scale[VY] == scale[VZ])
  111. {
  112. // Perfect sphere
  113. spec_out.mType = ShapeSpec::SPHERE;
  114. spec_out.mScale = scale;
  115. return;
  116. }
  117. else if (min_size_counts > 1)
  118. {
  119. // Small or narrow sphere: we can boxify
  120. for (S32 i = 0; i < 3; ++i)
  121. {
  122. if (spec_out.mScale[i] <
  123. SHAPE_BUILDER_CONVEXIFICATION_SIZE)
  124. {
  125. // Reduce each small dimension size to split the
  126. // approximation errors
  127. spec_out.mScale[i] *= 0.75f;
  128. }
  129. }
  130. spec_out.mType = ShapeSpec::BOX;
  131. return;
  132. }
  133. }
  134. // Cylinder
  135. if (no_taper && scale[VX] == scale[VY] &&
  136. profile_params.getCurveType() == LL_PCODE_PROFILE_CIRCLE &&
  137. path_params.getCurveType() == LL_PCODE_PATH_LINE &&
  138. vparams.getBeginS() <= path_cut_limit &&
  139. vparams.getEndS() >= 1.f - path_cut_limit)
  140. {
  141. if (min_size_counts > 1)
  142. {
  143. // Small or narrow sphere; we can boxify
  144. for (S32 i = 0; i < 3; ++i)
  145. {
  146. if (spec_out.mScale[i] <
  147. SHAPE_BUILDER_CONVEXIFICATION_SIZE)
  148. {
  149. // Reduce each small dimension size to split the
  150. // approximation errors
  151. spec_out.mScale[i] *= 0.75f;
  152. }
  153. }
  154. spec_out.mType = ShapeSpec::BOX;
  155. }
  156. else
  157. {
  158. spec_out.mType = ShapeSpec::CYLINDER;
  159. F32 length = (vparams.getPathParams().getEnd() -
  160. vparams.getPathParams().getBegin()) *
  161. scale[VZ];
  162. spec_out.mScale[VY] = spec_out.mScale[VX];
  163. spec_out.mScale[VZ] = length;
  164. // The minus one below fixes the fact that begin and end range
  165. // from 0 to 1 not -1 to 1.
  166. spec_out.mCenter.set(0.f, 0.f,
  167. 0.5f * scale[VZ] *
  168. (vparams.getPathParams().getBegin() +
  169. vparams.getPathParams().getEnd() -
  170. 1.f));
  171. }
  172. return;
  173. }
  174. }
  175. if (min_size_counts == 3 ||
  176. // Possible dead code here: who wants to take it out ?
  177. (path_complete && profile_complete && min_size_counts > 1 &&
  178. path_params.getCurveType() == LL_PCODE_PATH_LINE))
  179. {
  180. // It is not simple but we might be able to convexify this shape if the
  181. // path and profile are complete or the path is linear and both path
  182. // and profile are complete --> we can boxify it
  183. spec_out.mType = ShapeSpec::BOX;
  184. spec_out.mScale = scale;
  185. return;
  186. }
  187. // Special case for big, very thin objects: bump the small dimensions up to
  188. // the COLLISION_TOLERANCE
  189. if (min_size_counts == 1 && // One dimension is small
  190. avg_scale > 3.f) // ... but others are fairly large
  191. {
  192. for (S32 i = 0; i < 3; ++i)
  193. {
  194. spec_out.mScale[i] = llmax(spec_out.mScale[i],
  195. COLLISION_TOLERANCE);
  196. }
  197. }
  198. if (vparams.shouldForceConvex())
  199. {
  200. spec_out.mType = ShapeSpec::USER_CONVEX;
  201. }
  202. // Make a simpler convex shape if we can.
  203. else if (vparams.isConvex() || // is convex
  204. min_size_counts > 1) // two or more small dimensions
  205. {
  206. spec_out.mType = ShapeSpec::PRIM_CONVEX;
  207. }
  208. else if (vparams.isSculpt())
  209. {
  210. if (vparams.isMeshSculpt())
  211. {
  212. // Check if one dimension is smaller than min
  213. if (!has_decomp &&
  214. (scale[0] < SHAPE_BUILDER_CONVEXIFICATION_SIZE_MESH ||
  215. scale[1] < SHAPE_BUILDER_CONVEXIFICATION_SIZE_MESH ||
  216. scale[2] < SHAPE_BUILDER_CONVEXIFICATION_SIZE_MESH))
  217. {
  218. spec_out.mType = ShapeSpec::PRIM_CONVEX;
  219. }
  220. else
  221. {
  222. spec_out.mType = ShapeSpec::USER_MESH;
  223. }
  224. }
  225. else
  226. {
  227. spec_out.mType = ShapeSpec::SCULPT;
  228. }
  229. }
  230. else
  231. {
  232. // Resort to mesh
  233. spec_out.mType = ShapeSpec::PRIM_MESH;
  234. }
  235. }