Find A Random Point On A Plane Using Barycentric Coordinates in Unity

Randomness brings excitement and expectation to any experience. And games are no different. With a random point, we can spawn new enemies or valuable items to players. We can even transport the player to different places in unexpected moments.

In my previous post, I suggested a way to find corners of a Unity plane. In this post, I will be using these corner points and barycentric coordinates to find random points in any given plane.

Barycentric Coordinates

For a quick introduction, Barycentric coordinates are special coordinates that help to define a point in convex shapes. Moreover, the summation value of these coordinates leads to 1. For n-dimensional shape, there are n points in the coordinate. As for the triangle, it is (u, v, w).  A point on the triangle can be represented with the other corner points and barycentric coordinates. For a triangle with corners A, B, C and a point P with barycentric coordinates (u, v, w), P is defined as;

barycentric equationAsset 1

I really liked the explanation here, I suggest reading up to the first gray part.

Using Barycentric Coordinates To Find A Random Point On A Plane

As we will get help from the barycentric coordinates of a triangle to find a random point inside the plane, we can simply divide the plane into two triangles using two of the opposing corners. We start the calculation by first choosing which triangle of the plane is used.

int randomCornerIdx = Random.Range(0, 2) == 0 ? 0 : 2; 
CalculateEdgeVectors(randomCornerIdx);

randomCornerIdx is either 0 or 1, but to get opposing points we need to transform this value to indexes in the corner points array.

İnitShapeAsset 4
Edge vectors of a plane, we only calculate one side with the random index variable
void CalculateEdgeVectors(int VectorCorner)
{
EdgeVectors.Clear();
EdgeVectors.Add(Corners[3] - Corners[VectorCorner]);
EdgeVectors.Add(Corners[1] - Corners[VectorCorner]);
}

In case the transform of the plane has been changed, edge vectors are calculated each time, first clearing up the previous values. It is done as the common corner of the edges is being substracted by the other corners of the edges, this way we get the directions aka vectors of the edges.

randomPointShapeAsset 3
Sum of random weights should be 1 to have the point not overflow from the triangle

The edge vectors move the common corner in their direction but not so far that the common corner moves out of the triangle. To meet this criterion the sum of weights should be smaller than 1. Therefore, already randomly decided weights r1 and r2 is subtracted from 1 to have new random weight values.

float u = Random.Range(0.0f, 1.0f); 
float v = Random.Range(0.0f, 1.0f);

if (v + u > 1) //sum of coordinates should be smaller than 1 for the point be inside the triangle
{
v = 1 - v;
u = 1 - u;
}

In the code, random valued weights r1 and r2 are represented as u and v as a part of the coordinates of the random point’s barycentric coordinate. To calculate w, we only need to subtract u + v from 1, but we will not need to calculate it to define a random point.

RandomPointEqAsset 2
 RandomPoint = Corners[randomCornerIdx] + u * EdgeVectors[0] + v * EdgeVectors[1];

Random point P is calculated by moving common corner A by the direction of u1 by r1 and then moving it by the direction of r2 by v1.

2019-08-07-22-24-40.gif
Here is a demo of using the calculations made in this post.

The code used in demo:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FindRandomPoint : MonoBehaviour
{

    List<Vector3> VerticeList = new List<Vector3>(); //List of local vertices on the plane
    List<Vector3> Corners = new List<Vector3>();
    public int sphereSize = 1;
    Vector3 RandomPoint;
    List<Vector3> EdgeVectors = new List<Vector3>();

    void OnDrawGizmos()
    {
        if (VerticeList.Count > 0)
            for (int a = 0; a < Corners.Count; a++)
            {
                Gizmos.color = Color.yellow;
                Gizmos.DrawSphere(Corners[a], sphereSize); //show coordinate as a sphere on editor
            }

        Gizmos.color = Color.magenta;
        Gizmos.DrawSphere(RandomPoint, sphereSize); //show coordinate of the random point as a sphere on editor

    }


    // Start is called before the first frame update
    void Start()
    {
        VerticeList = new List<Vector3>(GetComponent<MeshFilter>().sharedMesh.vertices); //get vertice points from the mesh of the object
        CalculateCornerPoints();        
    }

    void Update()
    {
        CalculateCornerPoints(); //To show corner points with transform change
    }

    void CalculateEdgeVectors(int VectorCorner)
    {
        EdgeVectors.Clear();

        EdgeVectors.Add(Corners[3] - Corners[VectorCorner]);
        EdgeVectors.Add(Corners[1] - Corners[VectorCorner]);
    }

   public void CalculateRandomPoint()
    {
        int randomCornerIdx = Random.Range(0, 2) == 0 ? 0 : 2; //there is two triangles in a plane, which tirangle contains the random point is chosen
                                                           //corner point is chosen for triangles as the variable
        CalculateEdgeVectors(randomCornerIdx); //in case of transform changes edge vectors change too

        float u = Random.Range(0.0f, 1.0f); 
        float v = Random.Range(0.0f, 1.0f);

        if (v + u > 1) //sum of coordinates should be smaller than 1 for the point be inside the triangle
        {
            v = 1 - v;
            u = 1 - u;
        }

        RandomPoint = Corners[randomCornerIdx] + u * EdgeVectors[0] + v * EdgeVectors[1];
    }
    public void CalculateCornerPoints()
    {
        Corners.Clear(); //in case of transform changes corner points are reset

        Corners.Add(transform.TransformPoint(VerticeList[0])); //corner points are added to show  on the editor
        Corners.Add(transform.TransformPoint(VerticeList[10]));
        Corners.Add(transform.TransformPoint(VerticeList[110]));
        Corners.Add(transform.TransformPoint(VerticeList[120]));
    }
}

You can find the whole project here.

One thought on “Find A Random Point On A Plane Using Barycentric Coordinates in Unity

Leave a comment