以下の内容はhttps://redhologerbera.hatenablog.com/entry/2024/07/21/221248より取得しました。


Unityでスムースを試す。 その② メッシュの破断の原因

本日はUnity枠です。

〇環境

・Untiy2022.3.26f1

・Windows11PC

〇メッシュのスムースと破断

 前回のコードではメッシュの頂点から平均的な座標を割り出し、バイアスに応じて平均的に配置するアプローチを行いました。

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

namespace SODA3DART.HoloMoto
{
    public class SmoothMesh : MonoBehaviour
    {
        public int iterations = 10; // スムージングの反復回数
        public float alpha = 0.5f; // 元の頂点位置と新しい頂点位置のブレンド率(0.0 - 1.0)

        void Start()
        {
            MeshFilter meshFilter = GetComponent<MeshFilter>();
            if (meshFilter != null)
            {
                Mesh mesh = meshFilter.mesh;
                sMesh(mesh, iterations, alpha);
            }
        }
        void sMesh(Mesh mesh, int iterations, float alpha)
        {
            Vector3[] vertices = mesh.vertices;
            int[] triangles = mesh.triangles;
            Dictionary<int, List<int>> vertexNeighbors = new Dictionary<int, List<int>>();

            // 頂点の隣接関係を構築
            for (int i = 0; i < triangles.Length; i += 3)
            {
                AddNeighbor(vertexNeighbors, triangles[i], triangles[i + 1]);
                AddNeighbor(vertexNeighbors, triangles[i], triangles[i + 2]);
                AddNeighbor(vertexNeighbors, triangles[i + 1], triangles[i]);
                AddNeighbor(vertexNeighbors, triangles[i + 1], triangles[i + 2]);
                AddNeighbor(vertexNeighbors, triangles[i + 2], triangles[i]);
                AddNeighbor(vertexNeighbors, triangles[i + 2], triangles[i + 1]);
            }

            // スムージングの反復処理
            for (int iter = 0; iter < iterations; iter++)
            {
                Vector3[] newVertices = new Vector3[vertices.Length];

                for (int i = 0; i < vertices.Length; i++)
                {
                    Vector3 sum = Vector3.zero;
                    List<int> neighbors = vertexNeighbors[i];
                    foreach (int neighbor in neighbors)
                    {
                        sum += vertices[neighbor];
                    }

                    Vector3 average = sum / neighbors.Count;
                    newVertices[i] = Vector3.Lerp(vertices[i], average, alpha);
                }

                vertices = newVertices;
            }

            mesh.vertices = vertices;
            mesh.RecalculateNormals();
            mesh.RecalculateBounds();
        }

        void AddNeighbor(Dictionary<int, List<int>> vertexNeighbors, int vertex, int neighbor)
        {
            if (!vertexNeighbors.ContainsKey(vertex))
            {
                vertexNeighbors[vertex] = new List<int>();
            }

            if (!vertexNeighbors[vertex].Contains(neighbor))
            {
                vertexNeighbors[vertex].Add(neighbor);
            }
        }
    }
}

このコードの問題としてSphereのような閉じたジオメトリであっても、破断が生じました。

今回はこの原因と改善に取り組みます。

今回考えられる原因としては大きく2つあります。

①頂点の重複:

Unityでは、頂点が同じ位置にあっても異なる法線やUV座標を持つ場合、別々の頂点として扱われます。そのため、頂点インデックスが異なるため、スムージングの際に隣接する頂点として考慮されないことがあります。

②法線のリセット:

スムージング処理後に法線を再計算しているので、頂点の位置が変わった後の法線が正しく再計算されていない場合があります。

この2つの問題を改善することで破断を抑えることができます。

改めて破断個所を見てみると、UV展開でのシームに対応していることがわかります。

まずはUV情報を削除して同じ処理を行ってみます。

しかしながらUVを削除しても結果は変わらず破断が生じてしまいました。

次に考えられるのは頂点のインデックスです。

すべてのオブジェクトは頂点3つによってポリゴンが形成されていますが、この頂点は3Dデータ上で配列として格納されています。

メッシュを構成するためには重複している頂点が形成されている可能性があります。

次回は3DCGの頂点座標を見比べていきます。本日は以上です。




以上の内容はhttps://redhologerbera.hatenablog.com/entry/2024/07/21/221248より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14