Я пытаюсь создать многогранники Голдберга, но код, который должен отрисовывать их на моем экране, работает слишком медленно (около 22 секунд, чтобы отрисовать 6-й уровень детализации)
Stopwatch sw = new Stopwatch();
var hexes = sphere.hexes.ToArray();
sw.Start();
for (int j = 0; j < hexes.Length; j++)
{
MeshGeometry3D myMeshGeometry3D = new MeshGeometry3D();
Vector3DCollection myNormalCollection = new Vector3DCollection();
foreach (var verts in hexes[j].Normals)
{
myNormalCollection.Add(verts);
}
myMeshGeometry3D.Normals = myNormalCollection;
Point3DCollection myPositionCollection = new Point3DCollection();
foreach (var verts in hexes[j].Normals)
{
myPositionCollection.Add(new Point3D(verts.X, verts.Y, verts.Z));
}
myMeshGeometry3D.Positions = myPositionCollection;
Int32Collection myTriangleIndicesCollection = new Int32Collection();
foreach (var triangle in hexes[j].Tris)
{
myTriangleIndicesCollection.Add(triangle);
}
myMeshGeometry3D.TriangleIndices = myTriangleIndicesCollection;
Material material = new DiffuseMaterial(
new SolidColorBrush(Colors.Black)); ;
if (switcher)
{
material = new DiffuseMaterial(
new SolidColorBrush(Colors.BlueViolet));
}
switcher = !switcher;
GeometryModel3D model = new GeometryModel3D(
myMeshGeometry3D, material);
myGeometryModel.Geometry = myMeshGeometry3D;
myModel3DGroup.Children.Add(model);
myModel3DGroup.Children.Add(myGeometryModel);
}
sw.Stop();
Я пытался сделать свой цикл параллельным, но myGeometryModel и myModel3DGroup находятся в основном потоке, поэтому я не могу их изменить.
Пробовали ли вы создать для этого профиль производительности в Visual Studio, чтобы точно определить, вызовы каких методов занимают больше всего времени? Хотите верьте, хотите нет, но иногда ДЕЙСТВИТЕЛЬНО выдает полезную информацию. Затем вы можете сосредоточиться на их устранении или сокращении.





Редактировать:
Экспериментируйте с кодом.
Я добавил следующий код в конец генерации:
myViewport3D.Children.Add(myModelVisual3D);
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
XmlWriter writer = XmlWriter.Create(@"e:\temp\3dg.xaml", settings);
XamlWriter.Save(myViewport3D, writer);
Это приводит к файлу размером примерно 79 мегабайт и, конечно, совсем не ускоряет генерацию.
Затем я загружаю этот файл вместо его создания:
private void CreateHexaSphere(object sender, RoutedEventArgs e)
{
using (FileStream fs = new FileStream(@"e:\temp\3dg.xaml", FileMode.Open))
{
myViewport3D = (Viewport3D)XamlReader.Load(fs);
}
this.Content = myViewport3D;
return;
Это занимает примерно 7 секунд, чтобы показать сферу. Ага. Небольшая разница.
Если вы готовы просто загрузить этот файл с диска, то 7 секунд кажутся намного лучше, чем 52 секунды.
Если вам нужно сгенерировать эту вещь на лету, я бы нашел способ работать со строками и построить строку, аналогичную той, что вы получаете в этом файле.
Неудачная теория:
Я думаю, что все, что там имеет значение, — это заморозки.
.Freeze() замораживается, и вы увеличиваете производительность, но также можете передавать его из одного потока в другой.
Вы можете сделать большую часть этого в нескольких параллельных фоновых потоках.
Например, каждый гекс может быть построен на наборе параллельных рабочих потоков. Каждый строит свой собственный myMeshGeometry3D, который был заморожен и возвращен вызывающему потоку.
Грубо говоря, у вас будет Task DoMeshGeom3D(int j), который возвращает одну из ваших трехмерных геометрий.
Вы можете использовать plinq или task.whenall или parallel.foreach
Грубо
var taskList = new List<Task<MeshGeometry3D>>();
for (int j = 0; j < hexes.Length; j++)
{
taskList.Add(DoMeshGeom3D(j));
}
var result = await Task.WhenAll(taskList.ToList());
Возьмите свой список многочисленных MeshGeometry3D и соберите их все вместе.
И вы можете ожидать этого в фоновом потоке в другой задаче.
Вы также можете попробовать построить свою 3dgroup, используя список или перечисление этих вещей, созданных в отдельных потоках, а не добавляя по одному за раз.
https://briancaos.wordpress.com/2020/09/11/run-tasks-in-parallel-using-net-core-c-and-async-coding/
https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.whenall?view=netcore-3.1
myGeometryModel.Geometry=myMeshGeometry3D;``myModel3DGroup.Children.Add(model);``myModel3DGroup.Children.Add(myGeometryModel); самые дорогие операции, я пробовал ваше решение, но оно не помогло
@goner243 goner243 вы пробовали конструктор 3dgroup, который принимает ienumerable? Параллельно создавайте MeshGeometry3D. создайте группу, используя список или перечисление всех сразу, а не добавляя по одному.
пробовал, но нужен Model3D, а у меня GeometryModel3D
Не могли бы вы опубликовать полный код?
Полный код здесь github.com/goner243/3dRender2
Я понимаю что ты имеешь ввиду. 58 секунд на моем i5. Ой!
да, это действительно дорого, и из-за этого я хочу как-то сделать его многопоточным. И будьте осторожны, я не установил лимит потоков на шестнадцатеричную генерацию
Я думаю, что было бы намного быстрее построить это как строку, а затем xamlreader.parse() в объект wpf за один раз.
Ваш код не проблема.
Я попробовал это (спасибо за публикацию ссылки) и, основываясь на том, что я видел в инструментах производительности Visual Studio, попытался использовать конструктор Model3DCollection, который принимает IEnumerable<Model3D>, вместо того, чтобы добавлять их один за другим, что, как я вижу, также предложил Энди. (Во время цикла сборки я добавил все модели в свой собственный List<Model3D>, что почти не заняло времени, и получил Model3DCollection с помощью этого списка, на котором все остановилось.)
Хотя это примерно вдвое сократило время, на моей продвинутой машине в режиме отладки все еще оставалось 20 с лишним секунд. Конструктор Model3DCollection с IEnumerable — одной строкой кода — занимал почти все время.
Для чего бы это ни стоило — и я полагаю, вы это знаете, но для пользы всех остальных — уровень детализации 5 отрисовывался примерно в 4 раза быстрее для меня, с 20 485 элементами в коллекции против 81 925 на уровне 6, в то время как уровень 4 был практически мгновенным на 5125. элементы. Таким образом, очевидно, что каждый уровень детализации в четыре раза увеличивает количество ваших моделей и, в свою очередь, время на создание Model3DCollection. Дело в том, что если вы можете обойтись более низким уровнем детализации, время рендеринга значительно улучшится.
Но если вам нужен такой уровень детализации, вам действительно нужно смотреть на другую платформу IMO. Сам по себе С# не является проблемой, но узкое место находится в WPF, так что вы скорее застряли. Если вам нужно придерживаться WPF, вы можете попробовать изучить D3DImage и SharpDX. С++ не требуется. Конечно, это будет существенная переработка, но вы практически уверены, что получите желаемую производительность.
У меня достаточно мощный компьютер, поэтому мой 7-й уровень генерируется всего за 50 секунд. Основная идея этого проекта состоит в том, чтобы сгенерировать наиболее детализированные многогранники Гольдберга и сохранить все эти данные в базе данных, чтобы другие люди могли использовать эти данные не в своих проектах. Поэтому мне нужен WPF только для того, чтобы увидеть результат триангуляции.
А, ну ладно. Тогда да, этого кажется достаточно для вашего приложения.
Я попробовал другой подход, который может показаться вам интересным. Обновил мой ответ.