使用三角形重心坐标生成网格内的任意一点

1.重心坐标

三角形重心坐标(Barycentric Coordinates)可以通过alpha、beta、gamma三个权重总和为1的插值系数得到

三角形内任意一点,可以用此求出某点的重心坐标系数,或是给出系数得到一点:

public class Test : MonoBehaviour
{
    public Transform p0;
    public Transform p1;
    public Transform p2;

    [Range(0f, 1f)] public float w1;
    [Range(0f, 1f)] public float w2;
    [Range(0f, 1f)] public float w3;


    private void OnDrawGizmos()
    {
        float sum = w1 + w2 + w3;
        w1 /= sum;
        w2 /= sum;
        w3 /= sum;

        Gizmos.DrawLine(p0.position, p1.position);
        Gizmos.DrawLine(p1.position, p2.position);
        Gizmos.DrawLine(p2.position, p0.position);

        var target = w1 * p0.position + w2 * p1.position + w3 * p2.position;
        Gizmos.DrawWireSphere(target, 0.1f);
    }
}

2.绘制

使用三角形重心坐标生成Mesh内任意一点时,需要将三角形面积纳入考量,进行加权随机选取三角形,

选取三角形后,再通过重心坐标选取随机点即可:

 

using System.Collections.Generic;
using UnityEngine;

public class Scatters : MonoBehaviour
{
    public struct WeightItem
    {
        public float weight;
        public int value;
    }

    private int WeightRandom(WeightItem[] weightItems)
    {
        const float kEps = 0.00001f;

        float sumWeight = 0;
        for (int i = 0; i < weightItems.Length; i++)
            sumWeight += weightItems[i].weight;

        float randomValue = Random.Range(0f, sumWeight);

        float atte = 0f;
        for (int i = 0; i < weightItems.Length; i++)
        {
            float min = atte;
            atte += weightItems[i].weight;
            float max = atte;

            if (randomValue > min && randomValue < max + kEps)
            {
                return weightItems[i].value;
            }
        }

        throw new System.Exception();
    }

    public MeshFilter meshFilter;


    private Vector3 Exec()
    {
        float Area(Vector3 a, Vector3 b, Vector3 c)
        {
            return Vector3.Cross(b - a, c - a).magnitude * 0.5f;
        }

        var triangles = meshFilter.sharedMesh.triangles;
        var vertices = meshFilter.sharedMesh.vertices;

        var weightList = new List<WeightItem>(triangles.Length / 3);
        for (int i = 0; i < triangles.Length; i += 3)
        {
            var triInx0 = triangles[i];
            var triInx1 = triangles[i + 1];
            var triInx2 = triangles[i + 2];

            var a = vertices[triInx0];
            var b = vertices[triInx1];
            var c = vertices[triInx2];
            var area = Area(a, b, c);

            weightList.Add(new WeightItem() { weight = area, value = i });
        }

        var index = WeightRandom(weightList.ToArray());
        var vertIndex = index;
        var selTriA = transform.TransformPoint(vertices[triangles[vertIndex]]);
        var selTriB = transform.TransformPoint(vertices[triangles[vertIndex + 1]]);
        var selTriC = transform.TransformPoint(vertices[triangles[vertIndex + 2]]);

        var w1 = Random.Range(0f, 1f);
        var w2 = Random.Range(0f, 1f);
        var w3 = Random.Range(0f, 1f);
        float sum = w1 + w2 + w3;
        w1 /= sum;
        w2 /= sum;
        w3 /= sum;

        return w1 * selTriA + w2 * selTriB + w3 * selTriC;
    }

    private void OnDrawGizmos()
    {
        Gizmos.color = Color.red;

        for (int i = 0; i < 400; ++i)
        {
            var point = Exec();
            Gizmos.DrawWireSphere(point, 0.02f);
        }
    }
}

 

posted @ 2024-12-10 10:17  HONT  阅读(9)  评论(0编辑  收藏  举报