Операции над комплексными числами в вершинном шейдере

Я разрабатываю гиперболический граф для визуализации деревьев с большим количеством узлов. Вот почему я использую WebGL и библиотеку ThreeJS для повышения производительности. Вы можете проверить, что я разработал до сих пор, здесь: http://hyperbrowser.herokuapp.com/. Идея состоит в том, чтобы иметь возможность взаимодействовать с графом: щелчок по узлу центрирует граф в этом узле, а перетаскивание мыши перемещает граф вокруг него.

Я смог отобразить до 100 000 узлов. Но когда вы перетаскиваете такое большое количество узлов, производительность падает. Я думаю, это потому, что теперь я выполняю все операции с самим JavaScript, а затем обновляю положение вершин моего THREE.PointCloud.

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

  • Правильный это подход или нет
  • И если это так, поскольку преобразования, которые я применяю, являются функциями с комплексными числами, есть ли способ выполнить эти операции в самих шейдерах? Способ состоит в том, чтобы просто выполнить математические преобразования: https://github.com/julesb/glsl-util

Весь код находится в https://github.com/vabada/hyperBrowser/ на случай, если вы захотите чтобы увидеть, как я выполняю какие-либо конкретные операции. Конечно, любые советы, идеи и советы приветствуются.


person vabada    schedule 11.11.2014    source источник
comment
Я не смотрел, как вы построили свой график, но мне кажется, что вы одновременно отображаете на экране только ‹ 1000 объектов? Если так, то маловероятно, что рисование является узким местом. Если у вас есть подходящая структура данных, которая может инкапсулировать все данные, содержащиеся в графе, и извлекать только соответствующие объекты, которые вам нужно нарисовать, этого должно быть достаточно. Если только ваш вопрос не в том, что вы хотите рисовать 100 000 объектов одновременно. Но как это поместится на экране?   -  person WacławJasper    schedule 12.11.2014
comment
Случайный график, отображаемый в героку, как вы говорите, составляет порядка 100 узлов. Но для его создания некоторые переменные могут быть изменены (например, глубина и количество дочерних элементов на узел), чтобы общее количество узлов менялось. Я сделал несколько проб, изменяя эти переменные, и это было в порядке величины 100 000, когда производительность падала ниже 60 кадров в секунду. Идея состоит в том, чтобы после этого сделать некоторую кластеризацию, чтобы граф по-прежнему оставался удобочитаемым для людей, но, таким образом, мне пришлось бы вычислять преобразование для каждого узла после каждого движения. Вот почему я подумал сделать расчеты в шейдере   -  person vabada    schedule 12.11.2014
comment
Думаю, я на пути к решению проблемы. Я уже использую шейдерный материал, а теперь пытаюсь передать трансформацию через юниформу. Для сложных операций я видел здесь примерно так, в основном выполняем операции в декартовых координатах: vec2 c_mult(vec2 a, vec2 b) { return vec2(ax * bx - ay * by, (a.x+ay)*(b.x+by) - axbx - ауby); }   -  person vabada    schedule 12.11.2014
comment
@dabad 1. Во-первых, у вас есть 226 вызовов отрисовки. Погуглите THREE.LinePieces и нарисуйте одну линию. Посмотрите, поможет ли это. 2. Вы создаете новый Raycaster при каждом движении мыши. Создайте один и используйте его повторно. 3. Убедитесь, что вы подумали о том, как бы вы выбрали, если бы вершинный шейдер изменил позиции.   -  person WestLangley    schedule 13.11.2014
comment
Большое спасибо @WestLangley Это было действительно полезно. Теперь я определяю Raycaster только один раз и использую LinePieces. Это заставило меня значительно улучшить производительность. Однако я хотел бы попробовать, сгладит ли выполнение операций в шейдере переходы (если вы сейчас посмотрите на пример, где около 100 000 узлов, он хорошо отображается, но немного уменьшается при перетаскивании мышью: hyperbrowser.herokuapp.com/ Вы также можете увеличить глубину (&depth=12), чтобы отображать больше узлов ). Я не уверен, что понимаю вашу третью идею, что вы подразумеваете под выбором?   -  person vabada    schedule 13.11.2014
comment
Теперь это 3 вызова отрисовки. Намного лучше. Выбор означает выбор элементов с помощью мыши.   -  person WestLangley    schedule 13.11.2014
comment
Ok. Я думаю, что понимаю тебя. Проблема в том, что после изменения точек в шейдерах в javascript нет способа узнать, где точки правильные? Поскольку после вершинного шейдера следующим шагом будет фрагментный шейдер, а затем экран. Значит, нет рейкастинга? Если это так, это будет проблемой, так как я хотел бы иметь возможность щелкнуть каждый узел для отображения информации. Так что это будет окончательное решение. Тем не менее, я собираюсь попробовать сделать преобразования в вершинном шейдере, я просто люблю ThreeJS. Большое спасибо, вы были действительно hepful!   -  person vabada    schedule 13.11.2014
comment
Если вы измените позиции в вершинном шейдере, вы можете попробовать выбор GPU.   -  person WestLangley    schedule 14.11.2014


Ответы (1)


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

Итак, в первую очередь реализованы функции для работы с комплексными числами (спасибо julesb):

Define complex operations
#define product(a, b) vec2(a.x*b.x-a.y*b.y, a.x*b.y+a.y*b.x)
#define conjugate(a) vec2(a.x,-a.y)
#define divide(a, b) vec2(((a.x*b.x+a.y*b.y)/(b.x*b.x+b.y*b.y)),((a.y*b.x-a.x*b.y)/(b.x*b.x+b.y*b.y)))

А затем выполненное преобразование в вершинном шейдере:

uniform vec2 t;

void main(){

  vec2 z = vec2(position.x,position.y);
  vec2 newPos = divide((z+t),(vec2(1.0,0) + product((conjugate(t)),z)));
  gl_Position = projectionMatrix * modelViewMatrix * vec4(newPos, 0, 1.0);

}
person vabada    schedule 16.11.2014