public float scale = 1; // Scale of the instantiated objects
public int pointCount = 10; // Number of points to generate
private Vector3[] vertices; // Array storing mesh vertices
private int[] triangleIndices; // Array storing triangle indices
private List<GameObject> instantiatedPrefabs = new List<GameObject>(); // List to store created prefabs
public Vector3[] pts; // Array storing generated points
public Vector3[] norms; // Array storing corresponding normals
// Get mesh data from the MeshFilter
var sharedMesh = mf.sharedMesh;
vertices = sharedMesh.vertices;
triangleIndices = sharedMesh.triangles;
instantiatedPrefabs = new List<GameObject>(); // Initialise the prefab list
// Check if the trigger key is pressed
if (Input.GetKeyDown(trigger))
// Initialise point and normal arrays
pts = new Vector3[pointCount];
norms = new Vector3[pointCount];
// Clear any previously instantiated prefabs
ClearInstantiatedPrefabs();
// Generate and place new prefabs
for (int i = 0; i < pointCount; i++)
// Select a random triangle
var triangle = Random.Range(0, triangleIndices.Length / 3) * 3;
// Generate a random point on the selected triangle
var (pt, norm) = Generate(vertices, triangleIndices, mf.transform, triangle);
// Create a random rotation along the Y-axis
var rot = Quaternion.Euler(0, Random.Range(-180f, 180f), 0);
// Instantiate the prefab at the generated position with proper rotation
var go = Instantiate(prefab, pt, Quaternion.FromToRotation(Vector3.up, -norm) * rot, container);
// Set the scale of the instantiated object
go.transform.localScale = new Vector3(scale, scale, scale);
// Store the created object and generated values
instantiatedPrefabs.Add(go);
private void OnDrawGizmos()
if (pts == null) return; // Avoid errors if no points exist
// Draw rays at each generated point to visualize normals
for (int i = 0; i < pts.Length; i++)
Gizmos.DrawRay(pts[i], norms[i]);
private void ClearInstantiatedPrefabs()
// Remove and destroy all instantiated prefabs
foreach (var obj in instantiatedPrefabs)
instantiatedPrefabs.Clear(); // Clear the list
// Generates a random point on a triangle and calculates the normal
private static (Vector3, Vector3) Generate(Vector3[] verts, int[] tris, Transform xform, int triangleIndex)
// Get the vertex indices of the triangle
var i_A = tris[triangleIndex];
var i_B = tris[triangleIndex + 1];
var i_C = tris[triangleIndex + 2];
// Retrieve the actual vertex positions
// Compute two edges of the triangle
// Generate a random point inside the triangle
var newPointOnMesh = GetRandomPointInTriangle(v_A, v_B, v_C);
// Compute the normal of the triangle using cross product
var normal = Vector3.Cross(AB.normalized, CB.normalized);
// Convert local space positions to world space
newPointOnMesh = xform.TransformPoint(newPointOnMesh);
normal = xform.TransformDirection(normal);
return (newPointOnMesh, normal);
// Computes a random point inside a triangle using barycentric coordinates
private static Vector3 GetRandomPointInTriangle(Vector3 v0, Vector3 v1, Vector3 v2)
// Ensure the point is inside the triangle
// Compute the final position
return v0 + u * (v1 - v0) + v * (v2 - v0);