{"id":1549,"date":"2013-01-15T19:26:42","date_gmt":"2013-01-15T16:26:42","guid":{"rendered":"http:\/\/unitycoder.com\/blog\/?p=1549"},"modified":"2013-01-15T19:29:30","modified_gmt":"2013-01-15T16:29:30","slug":"bounding-sphere-for-3d-points","status":"publish","type":"post","link":"https:\/\/unitycoder.com\/blog\/2013\/01\/15\/bounding-sphere-for-3d-points\/","title":{"rendered":"Bounding Sphere for 3D Points"},"content":{"rendered":"<p><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" data-attachment-id=\"1550\" data-permalink=\"https:\/\/unitycoder.com\/blog\/2013\/01\/15\/bounding-sphere-for-3d-points\/smallest_sphere_for_points\/\" data-orig-file=\"https:\/\/i0.wp.com\/unitycoder.com\/blog\/wp-content\/uploads\/2013\/01\/smallest_sphere_for_points.jpg?fit=680%2C361&amp;ssl=1\" data-orig-size=\"680,361\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;}\" data-image-title=\"smallest_sphere_for_points\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/unitycoder.com\/blog\/wp-content\/uploads\/2013\/01\/smallest_sphere_for_points.jpg?fit=680%2C361&amp;ssl=1\" class=\"alignnone size-full wp-image-1550\" alt=\"smallest_sphere_for_points\" src=\"https:\/\/i0.wp.com\/unitycoder.com\/blog\/wp-content\/uploads\/2013\/01\/smallest_sphere_for_points.jpg?resize=680%2C361\" width=\"680\" height=\"361\" srcset=\"https:\/\/i0.wp.com\/unitycoder.com\/blog\/wp-content\/uploads\/2013\/01\/smallest_sphere_for_points.jpg?w=680&amp;ssl=1 680w, https:\/\/i0.wp.com\/unitycoder.com\/blog\/wp-content\/uploads\/2013\/01\/smallest_sphere_for_points.jpg?resize=300%2C159&amp;ssl=1 300w\" sizes=\"auto, (max-width: 680px) 100vw, 680px\" \/><\/p>\n<p>While looking into this <a title=\"http:\/\/forum.unity3d.com\/threads\/165283-2D-Dynamic-Shadows\" href=\"http:\/\/forum.unity3d.com\/threads\/165283-2D-Dynamic-Shadows\" target=\"_blank\">2D shadows topic<\/a>, converted this <a title=\"http:\/\/tesla-engine.googlecode.com\/svn-history\/r234\/trunk\/Source\/Tesla\/Bounding\/BoundingSphere.cs\" href=\"http:\/\/tesla-engine.googlecode.com\/svn-history\/r234\/trunk\/Source\/Tesla\/Bounding\/BoundingSphere.cs\" target=\"_blank\">BoundingSphere code<\/a> to unity (actually it wouldnt need to be in 3D..)<br \/>\nThis could be also useful for creating &amp; resizing sphere colliders..<\/p>\n<p>It resizes the sphere, so that all the vertices fit inside. (for some reason, some objects fail still, see image below)<br \/>\n<img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" data-attachment-id=\"1551\" data-permalink=\"https:\/\/unitycoder.com\/blog\/2013\/01\/15\/bounding-sphere-for-3d-points\/smallest_sphere_for_points_bound_fail\/\" data-orig-file=\"https:\/\/i0.wp.com\/unitycoder.com\/blog\/wp-content\/uploads\/2013\/01\/smallest_sphere_for_points_bound_fail.jpg?fit=300%2C356&amp;ssl=1\" data-orig-size=\"300,356\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;}\" data-image-title=\"smallest_sphere_for_points_bound_fail\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/unitycoder.com\/blog\/wp-content\/uploads\/2013\/01\/smallest_sphere_for_points_bound_fail.jpg?fit=300%2C356&amp;ssl=1\" class=\"alignnone size-full wp-image-1551\" alt=\"smallest_sphere_for_points_bound_fail\" src=\"https:\/\/i0.wp.com\/unitycoder.com\/blog\/wp-content\/uploads\/2013\/01\/smallest_sphere_for_points_bound_fail.jpg?resize=300%2C356\" width=\"300\" height=\"356\" srcset=\"https:\/\/i0.wp.com\/unitycoder.com\/blog\/wp-content\/uploads\/2013\/01\/smallest_sphere_for_points_bound_fail.jpg?w=300&amp;ssl=1 300w, https:\/\/i0.wp.com\/unitycoder.com\/blog\/wp-content\/uploads\/2013\/01\/smallest_sphere_for_points_bound_fail.jpg?resize=252%2C300&amp;ssl=1 252w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/p>\n<p><strong>Version 1.0 source:<\/strong><\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nusing UnityEngine;\r\nusing System.Collections;\r\n\r\npublic class SmallestSphere : MonoBehaviour {\r\nprivate float _radius;\r\nprivate Vector3 _center;\r\n\/\/For welzl calculations\r\nprivate const float RadiusEpsilon = 1.00001f;\r\nprivate GameObject sphere;\r\n\r\nvoid Start () {\r\nMesh mesh = GetComponent&lt;MeshFilter&gt;().mesh;\r\nVector3&#x5B;] vertices = mesh.vertices;\r\nint&#x5B;] indices = mesh.triangles;\r\n\r\nsphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);\r\n\r\nComputeFromPrimitives(vertices, indices);\r\n}\r\npublic float Radius {\r\nget {\r\nreturn _radius;\r\n}\r\nset {\r\n_radius = value;\r\n\/\/\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0Debug.Log(&quot;Set r=&quot;+value);\r\n}\r\n}\r\n\r\nvoid ComputeFromPrimitives(Vector3&#x5B;] vertices, int&#x5B;] indices)\r\n{\r\nVector3&#x5B;] copy = new Vector3&#x5B;indices.Length];\r\n\r\nfor(int i = 0; i &lt; indices.Length; i++) {\r\ncopy&#x5B;i] = transform.TransformPoint(vertices&#x5B;indices&#x5B;i]]); \/\/ test\r\n\/\/copy&#x5B;i] = vertices&#x5B;indices&#x5B;i]];\r\n}\r\n\r\nCalculateWelzl(copy, copy.Length, 0, 0);\r\n}\r\n\r\n\/\/Welzl minimum bounding sphere algorithm\r\nvoid CalculateWelzl(Vector3&#x5B;] points, int length, int supportCount, int index) {\r\nswitch(supportCount) {\r\ncase 0:\r\n_radius = 0;\r\n_center = Vector3.zero;\r\nbreak;\r\ncase 1:\r\n_radius = 1.0f - RadiusEpsilon;\r\n_center = points&#x5B;index-1];\r\nbreak;\r\ncase 2:\r\n\r\nSetSphere(points&#x5B;index-1], points&#x5B;index-2]);\r\n\r\nbreak;\r\n\r\ncase 3:\r\nSetSphere(points&#x5B;index-1], points&#x5B;index-2], points&#x5B;index-3]);\r\nbreak;\r\ncase 4:\r\nSetSphere(points&#x5B;index-1], points&#x5B;index-2], points&#x5B;index-3], points&#x5B;index-4]);\r\nreturn;\r\n}\r\n\r\nfor(int i = 0; i &lt; length; i++)\r\n{\r\nVector3 comp = points&#x5B;i + index];\r\nfloat distSqr;\r\n\r\ndistSqr = (comp-_center).sqrMagnitude;\r\n\r\nif(distSqr - (_radius * _radius) &gt; RadiusEpsilon - 1.0f) {\r\nfor(int j = i; j &gt; 0; j--) {\r\nVector3 a = points&#x5B;j + index];\r\nVector3 b = points&#x5B;j - 1 + index];\r\npoints&#x5B;j + index] = b;\r\npoints&#x5B;j - 1 + index] = a;\r\n}\r\nCalculateWelzl(points, i, supportCount + 1, index + 1);\r\n}\r\n}\r\n}\r\n\r\n\/\/For Welzl calc - 2 support points\r\nvoid SetSphere(Vector3 O, Vector3 A)\r\n{\r\nRadius = (float) System.Math.Sqrt(((A.x - O.x) * (A.x - O.x) + (A.y - O.y)\r\n* (A.y - O.y) + (A.z - O.z) * (A.z - O.z)) \/ 4.0f) + RadiusEpsilon - 1.0f;\r\nfloat x = (1 - .5f) * O.x + .5f * A.x;\r\nfloat y = (1 - .5f) * O.y + .5f * A.y;\r\nfloat z = (1 - .5f) * O.z + .5f * A.z;\r\n\r\n\/\/ TODO:\r\nSetCenter(x, y, z);\r\n\r\n}\r\n\r\n\/\/For Welzl calc - 3 support points\r\nvoid SetSphere(Vector3 O, Vector3 A, Vector3 B) {\r\nVector3 a = A - O;\r\nVector3 b = B - O;\r\nVector3 aCrossB = Vector3.Cross(a, b);\r\nfloat denom = 2.0f * Vector3.Dot(aCrossB, aCrossB);\r\nif(denom == 0) {\r\n_center = Vector3.zero;\r\n_radius = 0;\r\n} else {\r\n\r\nVector3 o = ((Vector3.Cross(aCrossB, a) * b.sqrMagnitude)+ (Vector3.Cross(b, aCrossB) * a.sqrMagnitude)) \/ denom;\r\n_radius = o.magnitude * RadiusEpsilon;\r\n_center = O + o;\r\n}\r\n}\r\n\r\n\/\/For Welzl calc - 4 support points\r\nvoid SetSphere(Vector3 O, Vector3 A, Vector3 B, Vector3 C) {\r\nVector3 a = A - O;\r\nVector3 b = B - O;\r\nVector3 c = C - O;\r\n\r\nfloat denom = 2.0f * (a.x * (b.y * c.z - c.y * b.z) - b.x\r\n* (a.y * c.z - c.y * a.z) + c.x * (a.y * b.z - b.y * a.z));\r\nif(denom == 0) {\r\n_center = Vector3.zero;\r\n_radius = 0;\r\n} else {\r\nVector3 o = ((Vector3.Cross(a, b) * c.sqrMagnitude)\r\n+ (Vector3.Cross(c, a) * b.sqrMagnitude)\r\n+ (Vector3.Cross(b, c) * a.sqrMagnitude)) \/ denom;\r\n_radius = o.magnitude * RadiusEpsilon;\r\n_center = O + o;\r\n}\r\n}\r\n\r\nvoid SetCenter(float x,float y,float z)\r\n{\r\nsphere.transform.localScale = new Vector3(_radius*2,_radius*2,_radius*2);\r\nsphere.transform.position = new Vector3(x,y,z);\r\n}\r\n}\r\n\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>While looking into this 2D shadows topic, converted this BoundingSphere code to unity (actually it wouldnt need to be in 3D..) This could be also useful for creating &amp; resizing sphere colliders.. It resizes the sphere, so that all the vertices fit inside. (for some [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1550,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[4,3],"tags":[390,392,391],"class_list":["post-1549","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-demos","category-unity3d","tag-bounding-sphere","tag-enclosing-sphere","tag-smallest-sphere"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/unitycoder.com\/blog\/wp-content\/uploads\/2013\/01\/smallest_sphere_for_points.jpg?fit=680%2C361&ssl=1","jetpack_shortlink":"https:\/\/wp.me\/p1KTaT-oZ","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/unitycoder.com\/blog\/wp-json\/wp\/v2\/posts\/1549","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/unitycoder.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/unitycoder.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/unitycoder.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/unitycoder.com\/blog\/wp-json\/wp\/v2\/comments?post=1549"}],"version-history":[{"count":5,"href":"https:\/\/unitycoder.com\/blog\/wp-json\/wp\/v2\/posts\/1549\/revisions"}],"predecessor-version":[{"id":1556,"href":"https:\/\/unitycoder.com\/blog\/wp-json\/wp\/v2\/posts\/1549\/revisions\/1556"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/unitycoder.com\/blog\/wp-json\/wp\/v2\/media\/1550"}],"wp:attachment":[{"href":"https:\/\/unitycoder.com\/blog\/wp-json\/wp\/v2\/media?parent=1549"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/unitycoder.com\/blog\/wp-json\/wp\/v2\/categories?post=1549"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/unitycoder.com\/blog\/wp-json\/wp\/v2\/tags?post=1549"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}