Skip to content

Add #1

@GotyMeister

Description

@GotyMeister

Здравствуйте я добавил на основе вашего скрипта генерацию по длине модели, и деление по чанкам с генерацией GameObject при достижении 60000 вершин. Делал все через ChatGPT. Но вы дали мне большую базу для работы. Спасибо

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

namespace SplineMeshTools.Core
{
[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer), typeof(SplineContainer)), ExecuteInEditMode, DisallowMultipleComponent]
public class SplineMeshResolution : SplineMesh
{
[Space]
[Header("Mesh Resolution Settings")]
[SerializeField] private int[] meshResolution;

    [Header("Debug Info")]
    [SerializeField] private Vector3 segmentMeshSize; // удален ReadOnly

    private readonly Vector3 debugVerticalOffset = new Vector3(0, 0.01f, 0); // добавлен вертикальный оффсет

    public override void GenerateMeshAlongSpline()
    {
        if (CheckForErrors()) return;

        const int MaxVertexCount = 60000;
        var segmentMeshNormalized = segmentMesh.NormalizeMesh(rotationAdjustment, scaleAdjustment);
        segmentMeshSize = segmentMeshNormalized.bounds.size;
        Debug.Log($"Segment mesh normalized size: {segmentMeshSize}");

        float meshLength = Mathf.Abs(SplineMeshUtils.GetRequiredAxis(segmentMeshSize, forwardAxis));

        meshResolution = new int[splineContainer.Splines.Count];
        for (int i = 0; i < splineContainer.Splines.Count; i++)
        {
            float splineLength = splineContainer.Splines[i].GetLength();
            meshResolution[i] = Mathf.Max(1, Mathf.CeilToInt(splineLength / meshLength));
        }

        int splineCounter = 0;
        int chunkIndex = 0;

        var chunkVertices = new List<Vector3>();
        var chunkNormals = new List<Vector3>();
        var chunkUVs = new List<Vector2>();
        var chunkTangents = new List<Vector4>();
        var chunkTriangles = new List<int>[segmentMeshNormalized.subMeshCount];
        for (int i = 0; i < chunkTriangles.Length; i++)
            chunkTriangles[i] = new List<int>();

        int chunkVertexOffset = 0;

        foreach (var spline in splineContainer.Splines)
        {
            var knots = new List<BezierKnot>(spline.Knots);
            var knotRotations = new List<Quaternion>();
            foreach (var knot in knots) knotRotations.Add(knot.Rotation);

            int segmentCount = spline.Closed ? knots.Count : knots.Count - 1;

            var segmentRatios = new List<float>();
            for (int i = 0; i < segmentCount; i++)
            {
                float dist = splineContainer.GetDistanceAlongSpline(splineCounter, knots[i % knots.Count].Position);
                segmentRatios.Add(dist / spline.GetLength());
            }
            segmentRatios.Add(1f);

            for (int i = 0; i < meshResolution[splineCounter]; i++)
            {
                if (chunkVertices.Count + segmentMeshNormalized.vertexCount > MaxVertexCount)
                {
                    CreateChunkGameObject(segmentMeshNormalized.subMeshCount, chunkVertices, chunkNormals, chunkUVs, chunkTangents, chunkTriangles, chunkIndex++);
                    ResetChunkLists(ref chunkVertices, ref chunkNormals, ref chunkUVs, ref chunkTangents, ref chunkTriangles, segmentMeshNormalized.subMeshCount);
                    chunkVertexOffset = 0;
                }

                var vertexRatios = new List<float>();
                var vertexOffsets = new List<Vector3>();

                foreach (var vertex in segmentMeshNormalized.vertices)
                {
                    float ratio = Mathf.Abs(SplineMeshUtils.GetRequiredAxis(vertex, forwardAxis)) / meshLength;
                    vertexRatios.Add(ratio);
                    vertexOffsets.Add(SplineMeshUtils.GetRequiredOffset(vertex, forwardAxis));
                }

                int counter = 0;
                foreach (var vertex in segmentMeshNormalized.vertices)
                {
                    float t = (i + vertexRatios[counter]) / meshResolution[splineCounter];
                    t = Mathf.Clamp01(t);
                    int segIndex = FindSegmentIndexFromRatios(segmentRatios, t);
                    int nextIndex = Mathf.Min(segIndex + 1, knotRotations.Count - 1);
                    float localT = Mathf.InverseLerp(segmentRatios[segIndex], segmentRatios[nextIndex], t);
                    Quaternion twist = Quaternion.Slerp(knotRotations[segIndex], knotRotations[nextIndex], localT);

                    Vector3 tangent = spline.EvaluateTangent(t);
                    Quaternion rot = Quaternion.LookRotation(tangent.normalized, shouldTwistMesh ? twist * Vector3.up : Vector3.up);
                    Vector3 position = (Vector3)spline.EvaluatePosition(t) + rot * vertexOffsets[counter] + positionAdjustment + debugVerticalOffset;

                    chunkVertices.Add(position);

                    Vector3 tan = rot * Vector3.right;
                    chunkTangents.Add(new Vector4(tan.x, tan.y, tan.z, 1f));

                    counter++;
                }

                for (int j = 0; j < segmentMeshNormalized.normals.Length; j++)
                {
                    float t = (i + vertexRatios[j]) / meshResolution[splineCounter];
                    t = Mathf.Clamp01(t);
                    int segIndex = FindSegmentIndexFromRatios(segmentRatios, t);
                    int nextIndex = Mathf.Min(segIndex + 1, knotRotations.Count - 1);
                    float localT = Mathf.InverseLerp(segmentRatios[segIndex], segmentRatios[nextIndex], t);
                    Quaternion twist = Quaternion.Slerp(knotRotations[segIndex], knotRotations[nextIndex], localT);

                    Vector3 tangent = spline.EvaluateTangent(t);
                    Quaternion rot = Quaternion.LookRotation(tangent.normalized, shouldTwistMesh ? twist * Vector3.up : Vector3.up);
                    chunkNormals.Add(rot * segmentMeshNormalized.normals[j]);
                }

                for (int j = 0; j < segmentMeshNormalized.uv.Length; j++)
                {
                    float t = uniformUVs ? (i + vertexRatios[j]) / meshResolution[splineCounter] : (i + vertexRatios[j]) / segmentCount;
                    var uv = segmentMeshNormalized.uv[j];
                    var newUV = SplineMeshUtils.MakeUVs(uv, t, splineCounter, uvAxis, uvResolutions);
                    chunkUVs.Add(newUV);
                }

                for (int sub = 0; sub < segmentMeshNormalized.subMeshCount; sub++)
                {
                    var indices = segmentMeshNormalized.GetTriangles(sub);
                    for (int k = 0; k < indices.Length; k += 3)
                    {
                        chunkTriangles[sub].Add(indices[k] + chunkVertexOffset);
                        chunkTriangles[sub].Add(indices[k + 2] + chunkVertexOffset);
                        chunkTriangles[sub].Add(indices[k + 1] + chunkVertexOffset);
                    }
                }

                chunkVertexOffset = chunkVertices.Count;
            }

            splineCounter++;
        }

        if (chunkVertices.Count > 0)
            CreateChunkGameObject(segmentMeshNormalized.subMeshCount, chunkVertices, chunkNormals, chunkUVs, chunkTangents, chunkTriangles, chunkIndex);
    }

    private void ResetChunkLists(ref List<Vector3> v, ref List<Vector3> n, ref List<Vector2> u, ref List<Vector4> tan, ref List<int>[] t, int subMeshCount)
    {
        v = new List<Vector3>();
        n = new List<Vector3>();
        u = new List<Vector2>();
        tan = new List<Vector4>();
        t = new List<int>[subMeshCount];
        for (int i = 0; i < subMeshCount; i++) t[i] = new List<int>();
    }

    private void CreateChunkGameObject(int subMeshCount, List<Vector3> v, List<Vector3> n, List<Vector2> u, List<Vector4> tan, List<int>[] t, int chunkIndex)
    {
        if (v.Count != n.Count || v.Count != u.Count || v.Count != tan.Count)
        {
            Debug.LogError($"Mismatch in vertex data counts: vertices={v.Count}, normals={n.Count}, uvs={u.Count}, tangents={tan.Count}");
            return;
        }

        foreach (var triangleList in t)
        {
            foreach (int index in triangleList)
            {
                if (index >= v.Count)
                {
                    Debug.LogError($"Triangle index {index} is out of bounds (vertex count: {v.Count})");
                    return;
                }
            }
        }

        Mesh mesh = new Mesh();
        mesh.name = $"SplineChunk_{chunkIndex}";
        mesh.vertices = v.ToArray();
        mesh.normals = n.ToArray();
        mesh.uv = u.ToArray();
        mesh.tangents = tan.ToArray();
        mesh.subMeshCount = subMeshCount;

        for (int i = 0; i < subMeshCount; i++)
            mesh.SetTriangles(t[i].ToArray(), i);

        mesh.RecalculateBounds();
        mesh.RecalculateNormals();   // 💡 добавлено
        mesh.RecalculateTangents(); // 💡 добавлено

        GameObject go = new GameObject($"SplineMesh_Chunk_{chunkIndex}");
        go.transform.SetParent(transform, false);

        var mf = go.AddComponent<MeshFilter>();
        var mr = go.AddComponent<MeshRenderer>();

        mf.sharedMesh = mesh;
        mr.sharedMaterials = GetComponent<MeshRenderer>().sharedMaterials;

        // 💡 Временно убрано отключение теней
        // mr.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
        // mr.receiveShadows = false;
    }


    private int FindSegmentIndexFromRatios(List<float> segmentRatios, float t)
    {
        for (int i = 0; i < segmentRatios.Count - 1; i++)
        {
            if (t >= segmentRatios[i] && t <= segmentRatios[i + 1])
                return i;
        }
        return segmentRatios.Count - 2;
    }

    protected override bool CheckForErrors()
    {
        if (base.CheckForErrors()) return true;
        if (segmentMesh == null)
        {
            Debug.LogError("Segment mesh is missing");
            return true;
        }
        return false;
    }
}

}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions