Génération de points aléatoires dans un maillage via les coordonnées barycentriques d'un triangle

Coordonnées barycentriques

Les coordonnées barycentriques d'un triengle permettent d'exprimer un point intérieur comme une combinaison linéaire des sommets, avec des poids alpha, bêta et gamma dont la somme est égale à 1. Cette méthode facilite l'interpolation de positions au sein d'une surface triangulaire, que ce soit pour obtenir les coefficients d'un point donné ou pour calculer un point à partir de coefficients spécifiés.

[Range(0f, 1f)] public float poidsAlpha;
[Range(0f, 1f)] public float poidsBeta;
[Range(0f, 1f)] public float poidsGamma;

private void OnDrawGizmos()
{
    float total = poidsAlpha + poidsBeta + poidsGamma;
    poidsAlpha /= total;
    poidsBeta /= total;
    poidsGamma /= total;

    Gizmos.DrawLine(sommetA.position, sommetB.position);
    Gizmos.DrawLine(sommetB.position, sommetC.position);
    Gizmos.DrawLine(sommetC.position, sommetA.position);

    Vector3 pointCible = poidsAlpha * sommetA.position + poidsBeta * sommetB.position + poidsGamma * sommetC.position;
    Gizmos.DrawWireSphere(pointCible, 0.1f);
}

}


</div>Génération de points sur un maillage
------------------------------------

Pour générer un point aléatoire à l'intérieur d'un mailllage, il convient d'abord de sélectionner un triangle proportionnellement à son aire, en utilisant une méthode de tirage pondéré. Une fois le triangle choisi, les coordonnées barycantriques sont appliquées avec des poids aléatoires pour déterminer un point final.

<div>```
using System.Collections.Generic;
using UnityEngine;

public class GenerateurPointsMaillage : MonoBehaviour
{
    public struct ElementPondere
    {
        public float poids;
        public int indice;
    }

    private int SelectionAleatoirePonderee(ElementPondere[] elements)
    {
        const float epsilon = 0.00001f;
        float sommePoids = 0f;
        for (int i = 0; i < elements.Length; i++)
            sommePoids += elements[i].poids;

        float valeurAleatoire = Random.Range(0f, sommePoids);
        float cumul = 0f;

        for (int i = 0; i < elements.Length; i++)
        {
            float borneInferieure = cumul;
            cumul += elements[i].poids;
            float borneSuperieure = cumul;

            if (valeurAleatoire > borneInferieure && valeurAleatoire < borneSuperieure + epsilon)
                return elements[i].indice;
        }
        throw new System.InvalidOperationException("Aucun élément sélectionné");
    }

    public MeshFilter filtreMaillage;

    private Vector3 CalculerPointAleatoire()
    {
        float CalculerAire(Vector3 v1, Vector3 v2, Vector3 v3)
        {
            return Vector3.Cross(v2 - v1, v3 - v1).magnitude * 0.5f;
        }

        Mesh maillage = filtreMaillage.sharedMesh;
        int[] triangles = maillage.triangles;
        Vector3[] sommets = maillage.vertices;

        List<elementpondere> listePoids = new List<elementpondere>(triangles.Length / 3);
        for (int i = 0; i < triangles.Length; i += 3)
        {
            Vector3 sommet1 = sommets[triangles[i]];
            Vector3 sommet2 = sommets[triangles[i + 1]];
            Vector3 sommet3 = sommets[triangles[i + 2]];
            float aire = CalculerAire(sommet1, sommet2, sommet3);
            listePoids.Add(new ElementPondere { poids = aire, indice = i });
        }

        int indiceTriangle = SelectionAleatoirePonderee(listePoids.ToArray());
        Vector3 pointA = transform.TransformPoint(sommets[triangles[indiceTriangle]]);
        Vector3 pointB = transform.TransformPoint(sommets[triangles[indiceTriangle + 1]]);
        Vector3 pointC = transform.TransformPoint(sommets[triangles[indiceTriangle + 2]]);

        float a = Random.Range(0f, 1f);
        float b = Random.Range(0f, 1f);
        float c = Random.Range(0f, 1f);
        float sommeCoeffs = a + b + c;
        a /= sommeCoeffs;
        b /= sommeCoeffs;
        c /= sommeCoeffs;

        return a * pointA + b * pointB + c * pointC;
    }

    private void OnDrawGizmos()
    {
        Gizmos.color = Color.red;
        for (int i = 0; i < 500; i++)
        {
            Vector3 point = CalculerPointAleatoire();
            Gizmos.DrawWireSphere(point, 0.02f);
        }
    }
}</elementpondere></elementpondere>

Étiquettes: Unity Maillage Coordonnées barycentriques C# Triangle

Publié le 15 juillet à 07h06