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;
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.
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.
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.
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.
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”