-
Notifications
You must be signed in to change notification settings - Fork 2
Open
Description
Здравствуйте я добавил на основе вашего скрипта генерацию по длине модели, и деление по чанкам с генерацией 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;
}
}
}
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels