Pull to refresh

Comments 48

Чем это лучше существующих решений? В чём смысл статьи? Где код работы со скелетной анимацией, почему не используется GPU, и тп.

Ваш текст выглядит как отчёт по лабораторной работе на 1 курсе колледжа.

спасибо, возможно будет в будущем по анимациям. Анимация на С покачто в процессе. Здесь упомянул вскользь, потомучто вектор общего повествования связан с анимацией и в дальнейшем если будет возможность, будут продолжения.

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

Вы забыли ответить на главный вопрос: в чём смысл вашей статьи на Хабре?

Зачем вы упомянули скелетную анимацию, если ни строчки про неё не написали?

Зачем отладка через вывод в консоль, когда уже более четверти века есть нормальные отладчики?

а как вы сделаете скелетную анимацию представленную через код с математикой, скажите пожалуйста ход действий? ну тоесть не пропуская все этапы, как вы поймёте что использовать из математики, и как вы поймёте что то что берем из файла валидно? по гайдам, но ведь это надо проверить, в гайдах математика на глм, сделайте шаг от глм и вот уже всё надо проверять

Это вы должны были сделать, раз уж с этого началась статья. И, пожалуйста, не игнорируйте остальные вопросы. Я понимаю, что на них вам неудобно отвечать, но всё же постарайтесь.

спасибо, конкретно анимации будет в следующей статье если будет такая возможность.

в статье написано

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

сомневаюсь что через дебагер сразу скопом с участием ГПУ вы разберетесь и с математикой и с листами и со всеми нюансами

тоесть тема статьи про лист, в контексте разработки своего не движка, соотв из-за того что сразу всё отладить сложно, надо создавать условия для последовательной отладки разных составляющих и граффическая составляющая включается в конце, когда +- происходит то что должно происходить, на отладочном окружении, и это может быть не только дебагер, в качестве пути был пройден путь всех тестов до анимаций на С++ не задумываясь. Но изза того что было принято решение уходить от некоторых библиотек пришлось переходить на С, и из-за ввода математики разбираться во всём, и последовательно создавать условия для всех ключевых нюансов.

в статье указан пример анимации, указано что это такое, и то почему не массивы

Ну то есть написать printf, подсунуть туда нужные переменные - это по вашему проще чем 1 раз кликнуть мышкой (или хоткеем) для установки breakpoint?

И всё таки - у вас ни слова про анимации. Какие будете использовать? Скелетные? Велосипед изобретёте? Функции работы с матрицами свои напишете? GPU будете использовать для матриц? Обосновать написание велосипедов, вместо использования готового сможете? Если нет, то мы возвращаемся к тому, что ваша статья - это лаба по спискам на си, которую вы почему-то решили оформить на Хабре.

Это вот всё - очень большие темы, по ним люди книжки пишут. А у вас даже банальных примеров нет.

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

В статьях всё охватить невозможно, или в гайдах всегда, идёт описание не глубокое, чтобы не решить даже возможно, а чтобы читатель сам понял что и как он будет использовать, рано или поздно придётся же разбираться что и почему вы делаете. А статья и гайд где охвачено всё это нечитаемо и не интересно, так как всё это надо же изучать правильно?

Как пример: 10 часов видео гайда конвертируется в реальное обучение к примеру и это реальность осваивания/обучения и придётся еще обучаться смежным вопросам

тоесть 10 часов гайда видео придётся еще понять, и попробовать разные моменты, чтобы придти к реализации комплексной, то что вы спрашиваете надо иметь реализацию, тоесть, как сделать модельку вас не волнует, вас волнует только анимация. то что на контент потратиться время вас тоже не волнует, ну а анимация, на С++ попроще может быть все сущности известны, пара гайдов есть, в том числе начиная с консоли тоже, тут как кому удобно изучать. А и потом разве есть единственное решение анимаций? есть тема в 3д что можно анимировать, как не крути это придётся изучать, и даже те люди кто пишет книги или гайды учаться.

Интересное у вас «вскользь», аж 2/3 текста «статьи».

Кем и какая поставлена задача?

Почему вы решили что ваш «гайд» по написанию односвязных списков имеет какую-то ценность по сравнению с существующими? Проведите сравнение эталонных реализаций и вашей, расскажите о преимуществах- это вот и будет статья.

Повторюсь - пока что весь ваш код и статья выглядят как лаба 1 курса, да и то средненькая. Впрочем, оценки за статью как бы не это намекают.

воспользуйтесь успешной реализацией которую вы считаете более успешной и подходлящей вам, моя реализация успешно справляется с моей задачью

Чо-то нет консистентности: ни PascalCase, ни camelCase, ни snake_case… что-то все время промежуточное и смешанное.

typedef struct NodeL_t NodeL;
struct NodeL_t //структура списка
{
    enum typeElements T;
    void* data;
    NodeL* Next;
};
typedef struct VNodeL_t VNodeL;

struct VNodeL_t//структура хендлера
{
  long NodeSz;
  NodeL *head;
};

Не знаю, на какой архитектуре сидите, но если на x64 у вас вероятно будет паддинг в 4 байта на экземпляр каждой из этих структур. Кроме того, в Win64 long обычно 32-битный.

Если не знали про выравнивание структур, то можете почитать, например, перевод статьи Эрика Реймонда "The Lost Art of C Structure Packing".

спасибо, код несет исключительно применительный характер, все изменения будут производиться на проигранной анимации, когда будет видна нагрузка ключевая

проверил да паддинг есть (NodeL 4 байта), инта хватит конечно )

structure-member-alignment-padding-and-data-packing/

Скрытый текст
struct Meshes_t
{
  vec3 *vertices;
  vec3 *colors;
  vec3 *normals;
  vec4 *boneIDs;
  vec4 *weights;
  unsigned int *indices;
};
typedef struct Meshes_t Meshes;

struct Model_t
{
  Meshes *meshes;
  VNodeL *vNodel;
};
typedef struct Model_t Model;

чтото около рабочего всё равно будет что-то наподобии такого

mat4 весит 64 - да кстати а их например с варешкой и скрепленным мешем - цельным 50 в сумме , спасибо что про паддинги напомнили

тестовый код без анимаций, всё равно мягче работает по моим наблюдениям, чем на С++ или 1 в 1, плюс на С у меня почти готова процедурная генерация там масштабы уже побольше чем на С++, хочу посмотреть как будет вести себя анимация, будет ли мягче чем на С++, сейчас анимация на С++ чуть грузит проц - толи от самой анимации, толи там расчеты, ну а математика у меня реализована, надеюсь будет мягче, ну в худшем случае будет так же как в С++ сейчас по анимации

расти есть куда по анимациям можно будет еще изучить двойные кватернионы если похуже будет, хотя по процессору должно быть чуть мягче

UFO landed and left these words here
 case CHARLINE:
            char* dd=d;
            tmp->data=malloc(sizeof(char)*strlen(dd));
            memcpy(tmp->data, dd, sizeof(char)*strlen(dd));
            vNodeL->NodeSz++;
            break;

/*...*/
case EPICLEGENDARYNODES:
                EpicLEgendaryNodes *temp=(EpicLEgendaryNodes*)cur->data;
                printf("%s\n",temp->name);
                printf("%d\n",temp->Num);
                printf("%f\n",temp->weights);
                break;

Это C23 что ли? В C за метками должны следовать операторы, тогда как объявления переменных не являются операторами, и в православных стандартах это вообще компилироваться недолжно. В С++ тоже - там в пределах одной области видимости запрещен переход минуя инициализацию, т.е. блок {} так и так нужен.

вы про фигурные скобочки?

Скрытый текст
.L3:
        mov     edi, 16
        call    malloc
        movdqu  xmm0, XMMWORD PTR [r13+0]
        add     QWORD PTR [r12], 1
        mov     QWORD PTR [rbp+4], rax
        movups  XMMWORD PTR [rax], xmm0
        jmp     .L2

там 2 свитча, в свитчах кейсы, первая часть что вы показали из стадии получения ноды, вторая часть после троеточия в стадии вывода ноды в консоль

у меня не компилируется на кланге 19 версии, выше O1 - проблема в установке ноды, что-то урезается при этом компилируется ассемблерная часть, по тому что я заметил

я клангом не пользуюсь, кланг стоит только для clangd, а создавал на gcc 14.2

а извиняюсь. обнуление индекса при инициализации хендлера фиксит-тут пофиксил, просто в тесте не было. На обоих компилируется (clang 19/gcc 14.2)

Скрытый текст
case EPICLEGENDARYNODES:
{
  EpicLEgendaryNodes *temp=(EpicLEgendaryNodes*)cur->data;
  printf("%s\n",temp->name);
  printf("%d\n",temp->Num);
  printf("%f\n",temp->weights);
  break;
}

вас понял да скобочки, спасибо пофикшу

Лучше перед публикацией скомпилировать код, который приводите в статье, с флагами -Wall -pedantic и исправить его, чтобы не было таких эксцессов.

У вас еще, например, из кучи этих переменных:

int t=4,i=1,q=2,w=3,e=5,r=6,y=7,u=8;

часть вообще не используется.

В setByAfterIndex() NodeL *tmp тоже не используется, строкой ниже вы пишете NodeL *tmp1=cur->Next;.

Про неправильные спецификаторы типа в print() тоже покажет.

Инициализацию NodeSz нулем вы исправили, тоже ее заметил. При компиляции MSVC программа просто упадет.

Кстати, вот что он выводит, когда я ошибки с размером long`а, метками и NodeSz немного поправил:

Скрытый текст
CHARLINE¤¤¤¤
CHARLINE1¤¤¤¤
CHARLINE2¤¤¤¤
CHARLINE3¤¤¤¤▌▌▌EУ░ж


getByIndex
SearchIndex > SizeNodeLists
4

Searched element
CHARLINE3¤¤¤¤▌▌▌OТ╣↓Еж

CHARLINE111111
3
1.100000
CHARLINE22221
4
2.100000
CHARLINE23333
5
3.100000
CHARLINE34444
6
4.100000

Думаю, перед использованием вам его еще много придется дебажить.

тоесть вы скопировали то что в статье и у вас вывелось так да?, платформа Linux извините.

Да. Вот что выдает при версии, что вы исправили сейчас:

Скрытый текст

CHARLINE¤¤¤¤
CHARLINE1¤¤¤¤
CHARLINE2¤¤¤¤
CHARLINE3¤¤¤¤

getByIndex
SearchIndex > SizeNodeLists
4

Searched element
CHARLINE3¤¤¤¤

CHARLINE111111
3
1.100000
CHARLINE22221
4
2.100000
CHARLINE23333
5
3.100000
CHARLINE34444
6
4.100000

Windows 10 x64. Visual Studio 2019. Стандарт С17.

Сборка с Release тоже выдает всякий мусор

Скрытый текст
CHARLINEP☺Л     М☺
CHARLINE1
CHARLINE2
CHARLINE3


getByIndex
SearchIndex > SizeNodeLists
4

Searched element
CHARLINE3

CHARLINE111111
3
1.100000
CHARLINE22221
4
2.100000
CHARLINE23333
5
3.100000
CHARLINE34444
6
4.100000

На первую строчку взгляните. Читаем что-то из неинициализированной памяти.

Небольшая подсказка. Взгляните на getNode()

        case CHARLINE:
            //char* dd=d;
            //tmp->data=malloc(sizeof(char)*strlen(dd));
            //memcpy(tmp->data, dd, sizeof(char)*strlen(dd));
            //vNodeL->NodeSz++;
            tmp->data=malloc(sizeof(char)*strlen((char*)d));
            memcpy(tmp->data, d, sizeof(char)*strlen((char*)d));
            vNodeL->NodeSz++;
            break;

Вы аллоцируете память для строки размером в ее длину, а под завершающий ноль места уже нет.

        case CHARLINE:
            char* dd=d;
            size_t szS=(size_t)strlen(dd)+1;
            tmp->data=malloc(sizeof(char)*szS));
            memcpy(tmp->data, d, sizeof(char)*szS);
            dd[szS]='\0'; /* WTF??? */
            vNodeL->NodeSz++;
            break;

Вы куда терминальный ноль записали, а главное для чего?

Какой у вас размер списка (сколько элементов в типовых сценариях)?

Я про поиск по индексу перебором - не будет ли это слишком долго?

Может стоит присмотреться к алгоритму SkipList

https://15721.courses.cs.cmu.edu/spring2018/papers/08-oltpindexes1/pugh-skiplists-cacm1990.pdf

и его расширениям

https://webdiis.unizar.es/asignaturas/APD/skip_list_cookbook.pdf

спасибо большое посмотрю, первичная проборка 50(на меш 25 костей - упрощенный скелет без пальцев ) - этот этап пока не проверял, далее надо будет загнать веса и посмотреть, толи 4*вершины, толи 1 в 1 если учесть что вектор-веса xyzw, в гифке чтото около грубого расчета по вершинам, очень грубого в большую сторону 2к

Скрытый текст
1310 Vertices
1310 Colors
1310 Normals
1314 Indices
1310 BoneIDS
1310 Weights

Num Bones 25#list

2128 Vertices
2128 Colors
2128 Normals
2216 Indices
2128 BoneIDS
2128 Weights

Num Bones 25#list
LIST NUMBER ELEMENTS: 50
mixamorig:Hips
100.000000 0.000001 -0.000000 0.000000
-0.000000 -0.000004 -100.000000 0.000000
0.000001 100.000015 -0.000004 0.000000
0.000002 -413.847046 13.272202 1.000000
mixamorig:Spine
100.000000 0.000001 0.000000 0.000000
-0.000000 3.754293 -99.929504 0.000000
0.000001 99.929504 3.754293 0.000000
0.000002 -458.326569 -2.274207 1.000000
mixamorig:Spine1
...

Ну это немного... Я привык работать со списками в сотни тысяч элементов.

В вашем случае, возможно, перебором будет достаточно.

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

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

А возможно тут вообще не список нужен а динамический массив. Но тут, опять, типовые сценарии использования. Если элементы постоянно добавляются-удаляются - это список. А если вы один раз заполняете его, а потом многократно используете - это однозначно массив.

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

Не всегда. Дерево хорошо для поиска. И то при условии что оно сбалансировано (что при постоянном добавлении-удалении элементов будет требовать дополнительных затрат).

Но вот при обходе "от первого до последнего элемента" дерево будет хуже списка.

Кстати попробовал - обход обычного std::map тормознее std::list раз в пять (в одних конкретно взятых условиях). Не думал, что разница настолько большая.

Ну я за свою специфику могу говорить - большие объемы данных + HiLoad (все что делаем проходит через нагрузочное тестирование).

В моей специфике деревья как-то не прижились. Два основных сценария

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

  2. Справочники в памяти. Тут справочник один раз заполняется при старте, потом многократно используется для поиска нужных данных. Здесь лучше всего работает отсортированный массив с двоичным поиском по нему (самый быстрый поиск). Заполнили, один раз отсортировали и потом пользуемся. Тут, в принципе, деревья тоже неплохи, но они сложнее в реализации и накладных расходов там немного больше.

Тут даже смысла особого нет, и так всё понятно ) Но если смотреть list vs map - и там и там pointer chasing, в мапе всё посложнее, но казалось бы можно сделать похоже.

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

А список - это именно упорядоченная последовательность элементов. Там каждый элемент содержит указатель на следующий. Но там сложнее реализовать поиск элемента по значению (кроме перебора). Потому и придумали SkipList список с возможностью быстрого не такого быстрого как по дереву, но быстрее чем перебором) поиска. Именно для тех ситуаций когда нужно потом с ним работать как со списком и "гулять" по нему вперед-назад.

Затем и нужно понимание "что под капотом" таких сущностей как list, vector, map... чтобы под конкретный сценарий использования выбирать наиболее эффективный подход.

на фрибсд классно работает я тест С++ глянул(но нагрузку не посмотрел на CPU linux от фряхи отличаются некоторыми функциями- на линуксе были всплески по частоте на анимации, которая на гифке тут. а на бсд вроде не было всплесков, потом посмотрю внимательнее ), и фрибсд стал дружелюбнее прям не верится, возможно не в тему, ставится быстрее чем раньше, все доки поправили до текущих, он настраивается прям из хендбука минут за 5, подвезли блендер ассимп вулкан, на гноме красота

по итогу 3 списка, но будет около 10, вообщем до 100 чтоли как я понял будет. я эти моменты еще посмотрю, ну грубо говоря 10 списков по 100 елементов это по максимуму - фантазирую, но на самом деле грубо прикинул, потомучто 2 комплекта бонов, и трансформации - это только начало, там еще сами анимации - так сказать в анимациях, то на чем посмотрел быстро вроде работает, ключевая нагрузка всё равно будет в цикле при обновлении, там будет видно

Sign up to leave a comment.

Articles