Search Unity

Random.between two unit spheres?

Discussion in 'Scripting' started by QuantumCalzone, Oct 20, 2010.

  1. QuantumCalzone

    QuantumCalzone

    Joined:
    Jan 9, 2010
    Posts:
    262
    Hey, so here's an odd one I can't wrap my head around. I'm comfortable with the insideUnitSphere script, but what I want to do is get and object to spawn in the space between two spheres. Any ideas?
     
  2. cannon

    cannon

    Joined:
    Jun 5, 2009
    Posts:
    751
    Here's a quick and dirty one:

    Take the difference between the centers of your two spheres, this will give you a Vector3. Multiply this by a random number between 0 and 1 to give you another Vector3.

    Now, use insideUnitSphere to get a point inside one of the spheres. Now add your Vector3 from above.

    This will give you a random point inside a capsule or swept sphere. If you really just want the space and don't want to include the spheres, include a check to see if the point is inside either sphere. If the point is inside, go back to the first step.
     
  3. QuantumCalzone

    QuantumCalzone

    Joined:
    Jan 9, 2010
    Posts:
    262
    I was planning on the two sphere being placed at the origin of the scene. I wanted a different radius for the two. I should've made that clearer on the initial post. My baad.
     
  4. TerXIII

    TerXIII

    Joined:
    Sep 4, 2010
    Posts:
    184
    You are going to have to randomize a normalized vector, and then randomize a radius.

    I assume you are trying to randomize the location of a point outside of Sphere 1 and inside Sphere 2.

    In order to acheive this, you have to get a random vector on three axes:

    A random point WITHIN a sphere can be any point in any direction from 0,0,0 at a maximum radius of the sphere. Since you want to create a point within a strata between two spheres, your point will be a point in any direction with a minimum radius of the smallest Sphere, and a maximum radius of the larger sphere.

    Code (csharp):
    1.  
    2. float minRad; //set this to the radius of the smallest sphere
    3. float maxRad; //set this to the radius of the largest sphere
    4. float rx = rand() * 2f * Mathf.PI; //rand() is a generic pseudofunction that should generate a value between 0.0f and 1.0f
    5. float ry = rand() * 2f * Mathf.PI;
    6. float rz = rand() * 2f * Mathf.PI;
    7. Vector3 angle = new Vector3(rx,ry,rz);
    8. float radius = minRad + rand()*(maxRad-minRad);
    9.  
    10. Vector3 rpos = angle*radius;
    11.  
    Of course, I very well could have misinterpreted what you are saying, as your geometric description is severely lacking in detail, but I gather that's what you meant.
     
    Last edited: Oct 21, 2010
  5. The-IT664

    The-IT664

    Joined:
    Jul 28, 2009
    Posts:
    29
    Hi GreekDude!

    How's Greece these days? :D

    Code (csharp):
    1.  
    2. float angle1 = Random.value * 2.0f * Mathf.PI;
    3. float angle2 = Random.value * 2.0f * Mathf.PI;
    4. Vector3 pointOnUnitSphere = new Vector3(Mathf.Sin(angle1) * Mathf.Cos(angle2), Mathf.Cos(angle1) * Mathf.Cos(angle2), Mathf.Cos(angle2));
    5. float distance = Random.value;
    6. float radius1 = 1.5f;
    7. float radius2 = 3.0f;
    8. Vector3 pointBetweenSpheres = pointOnUnitSphere * (radius1 * (distance) + radius2 * (1 - distance));
    9.  
    That should give you a random position in between two spheres at the origin with radius radius1 and radius2.
     
    Last edited: Oct 22, 2010
  6. The-IT664

    The-IT664

    Joined:
    Jul 28, 2009
    Posts:
    29
    Hey TerXIII,

    I must have started writing up my post just before you posted yours :p

    I must admit that I was too lazy to actually test my function for which I just noticed there was an error (I'm sorry if there are still errors in it, let me know if it doesn't work and I'll stop being lazy and actually test it).

    When calculating the point on a unit sphere, you cant use 3 random angles for the different axis as there is an intrinsic relationship between the x and y axis (the relationship between the (x and z) and (y and z) is taken care of my multiplying both x and y by Cos(zAngle).

    I hope you don't take this personally but I'll just correct a couple of things I noticed were wrong with your function:
    1) If you're going to use random numbers [0, 1] for each of the elements of your unit vector, you'll need to normalize the vector after you've assigned the random values otherwise you could end up with (0,0,0) or (1, 1, 1).
    2) If you do use random numbers for the elements you'll get an uneven distribution of points, mainly there will be higher probability of a point being near one of the 8 corners of the cube projected onto the sphere.
     
  7. TerXIII

    TerXIII

    Joined:
    Sep 4, 2010
    Posts:
    184
    You do bring up a valid point. Never was much good at first-pass code, usually have to fiddle with it, and I'm a little rusty with 3D garbage at the moment, as I've been working exclusively on Pseudo-2D business for the last two years. =/ Probably would have noticed it had I been paying attention while writing it.

    Thanks for the correction. I really dislike it when I forget something critical while writing up a simple system. Makes ya look real dumb sometimes, don't it?
     
    Last edited: Oct 22, 2010
  8. QuantumCalzone

    QuantumCalzone

    Joined:
    Jan 9, 2010
    Posts:
    262
    Ok...please tell me if this is stupid. But did I do it?

    Code (csharp):
    1. function Clone () {
    2.     Negative1 = Random.Range(-1, 2);
    3.     Negative2 = Random.Range(-1, 2);
    4.     if (Amount < MaxAmount) {
    5.         Instantiate(Prefab, Vector3(Random.Range((6.587849 * Negative1), (7 * Negative2)), Random.Range((6.587849 * Negative1), (7 * Negative2)), Random.Range((6.587849 * Negative1), (7 * Negative2))), Random.rotation);
    6.         Amount += 1;
    7.     }
    8. }
     
  9. Vicenti

    Vicenti

    Joined:
    Feb 10, 2010
    Posts:
    664
    What's with all the magic numbers?

    If you need it in the shell between two spheres, you can use

    Code (csharp):
    1. var diff : float = sphereOuter.radius - sphereInner.radius;
    2. while ( point == Vector3.zero ) point = Random.insideUnitSphere;
    3. point = point.normalized * ( Random.value * diff + sphereInner.radius );
    or the code above by theIT. I'm not sure if one or another has performance benefits, but I like to do away with magic numbers (2, 6.5, 7, etc) wherever possible.

    It looks like the code you posted just chooses a random position in a rectangular box centered on [-1,2]ish.
     
  10. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    Generating random positions in space is actually more difficult than it seems at first. The main issue with a sphere is that generating a random angle and then sliding a random distance along that radius doesn't give a uniform distribution but concentrates more of the points near the inner sphere. I've attached a package that contains a correct function in a script along with a particle system that demonstrates (hopefully) the spread of the particles. In the script, there is a line commented out which returns the uneven distribution you get when you just scale linearly along an angled line. It's probably worth having a look at that to see the difference.
     

    Attached Files:

  11. sama-van

    sama-van

    Joined:
    Jun 2, 2009
    Posts:
    1,734
    Found this topic very interesting but a bit everything and nothing here....

    Below some c# code tested into Unity 2018.3.6f1

    Code (CSharp):
    1.  
    2. Vector3 RandomBetweenRadius3D(float minRad, float maxRad)
    3. {
    4.     float diff = maxRad - minRad;
    5.     Vector3 point = Vector3.zero;
    6.     while(point == Vector3.zero)
    7.     {
    8.         point = Random.insideUnitSphere;
    9.     }
    10.     point = point.normalized * (Random.value * diff + minRad);
    11.     return point;  
    12. }
    13.  
    Code (CSharp):
    1.  
    2. Vector3 RandomBetweenRadius2D(float minRad, float maxRad)
    3. {
    4.     float radius = Random.Range(minRad, maxRad);
    5.     float angle = Random.Range(0, 360);
    6.  
    7.     float x = Mathf.Sin(Mathf.Deg2Rad * angle) * radius;
    8.     float y = Mathf.Cos(Mathf.Deg2Rad * angle) * radius;
    9.  
    10.     return new Vector3(x, y, 0);
    11. }
    12.  
     
  12. andrewhdall

    andrewhdall

    Joined:
    May 5, 2019
    Posts:
    1
    I used Random.onUnitSphere then set sphere size to a Random.Range(maxSize,minSize)
    Maxsize and minSize are both floats
     
    AlxAlxAlx likes this.