DalerLiss
@DalerLiss
Ребенок в большом теле

Unity3d: Как сгладить нормали созданного меша?

В Unity процедурно генерирую меш локации, однако мне нужен угол затенения от векторов, а не от граней, восьмой час рою в дебрях интернета, и за это время нашел только пару мелких деталей по необходимой теме, в итоге плюнул и методом тыка выяснил что мне нужно делать, однако то что у меня получилось и дало результат довольно тяжеловато в выполнении, я конечно и не рассчитывал получить моментальную загрузку, но работать в редакторе стало невозможно, когда сцена загружается секунд тридцать при тысяче полигонов (проверял зависимость быстродействия от количества полигонов, результат удручающий) , вместо двух-трех на полноценной локации без выполнения этой функции.
В общем ищу способы либо удалить этот говнокод и использовать нормальный, продуманный разработчиками Unity функционал для такого же результата, либо облегчить то что есть. Во втором варианте по идее можно использовать Linq, он как минимум должен быстрее выполнятся чем цикл в цикле для поиска похожих координат вершин, но я с этим совершенно не знаком и пока не разобрался с документацией чтобы получить нужный результат, поэтому обращаюсь за помощью.

Сделал скриншоты для понимания необходимого действия и на второй экран вывел код.
637c4cd32f305613021441.png637c4cd6d7e09421382589.png

void SmoothingNormalsNotOptimize()			/// Не оптимизированное сглаживание нормалей
	{
		List<int> verticesNumber = new List<int>();				// создать лист с индексами повторяющихся вершин
		Vector3[] ns = chunkMesh.normals;						// создать список с углами нормалей и заполнить его имеющимися нормалями
		
		for(int vertList1 = 0; vertList1 < chunkMesh.vertices.Length; vertList1++)		// цикл переборки вершин
		{	
			verticesNumber.Add(vertList1);			// добавить индекс проверяемой вершины в список
			
			for(int vertList2 = 0; vertList2 < chunkMesh.vertices.Length; vertList2++)	// второй цикл переборки вершин
			{
				if(vertList2 != vertList1 && chunkMesh.vertices[vertList2] == chunkMesh.vertices[verticesNumber[0]])	// проверить не является ли сравниваемая вершина проверяемой и одинаковы ли координаты с проверяемой
				{
					verticesNumber.Add(vertList2);	// если равна, то добавить её в список
				}
			}
			if(verticesNumber.Count > 1)			// если список индексов одинаковых координат вершине содержит больше одной вершины
			{
				Vector3 newVector = new Vector3();	// создать новый верктор для усредненой нормали
				
				/// Найти среднее арифметическое нормалей на стыке граней
				for(int n = 0; n < verticesNumber.Count; n++)	// цикл переборки количества одинаковых вершин
				{
					newVector.x += ns[verticesNumber[n]].x;		// приплюсовать направление меша по X
					newVector.y += ns[verticesNumber[n]].y;		// приплюсовать направление меша по Y
					newVector.z += ns[verticesNumber[n]].z;		// приплюсовать направление меша по Z
				}
				
				newVector.x = newVector.x / verticesNumber.Count;	// разделить значение X на количество одинаковых нормалей
				newVector.y = newVector.y / verticesNumber.Count;	// разделить значение Y на количество одинаковых нормалей
				newVector.z = newVector.z / verticesNumber.Count;	// разделить значение Z на количество одинаковых нормалей
				
				for(int un = 0; un < verticesNumber.Count; un++)	// цикл переборки количества одинаковых вершин	
				{
					ns[verticesNumber[un]] = newVector;				// изменить координаты в списке по индексу на усредненное значение
				}
			}
			verticesNumber.Clear();		// очистить список с индексами одинаковых вершин		
		}
		chunkMesh.normals = ns;			// заменить список нормалей в меше на измененный
	}
  • Вопрос задан
  • 139 просмотров
Решения вопроса 1
DalerLiss
@DalerLiss Автор вопроса
Ребенок в большом теле
В общем проторчав почти весь день на зарубежных форумах и по разному составляя этот вопрос, я в итоге наткнулся на необходимый мне ответ, пока только тупо скопировал код и проверил что он выдает нужный результат при полной нагрузке за секунду, но сейчас буду сидеть изучать как оно работает на самом деле (Отсылка к Конору)

Оставляю ссылку с ответом, надеюсь кому-нибудь и когда-нибудь это поможет и он не потратит почти сутки в поисках и попытках разобраться в нерабочих способах.

schemingdeveloper.com/2017/03/26/better-method-rec...

Уточню для новичков, которые полезут в такую муть вместо изучения основ (как я поступал лет шесть назад), этот код нужно просто скопировать в пустой скрипт C# с названием NormalSolver.cs, а в функции Mesh.RecalculateNormals() нужно указать угол при котором сглаживание будет срабатывать, в моем случае, чтобы вершина пирамиды сглаживалась нужно 90 градусов, то есть Mesh.RecalculateNormals(90);
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы