Каков наиболее эффективный способ перемещения нескольких объектов (, хранящихся в VBO )в пространстве? я должен использовать glTranslatef или шейдер?

Я пытаюсь освоить движущиеся объекты (вообще )и линейные полосы (в частности )наиболее эффективно в opengl и поэтому я пишу приложение, где несколько отрезков движутся с постоянной скоростью справа налево. В каждый момент времени самая левая точка будет удалена, вся линия будет смещена влево, а новая точка будет добавлена ​​в самом правом углу линии (эта новая точка данных передается/получается/вычисляется муха, каждые 10 мс или около того ). Чтобы проиллюстрировать, что я имею в виду, посмотрите это изображение :

example showing line strip

. Поскольку я хочу работать со многими объектами, я решил использовать объекты буфера вершин, чтобы свести к минимуму количество вызовов gl*. Мой текущий код выглядит примерно так:

A )настройка начальных вершин:

# calculate my_func(x) in range [0, n]
# (could also be random data)
data = my_func(0, n)

# create & bind buffer
vbo_id = GLuint()
glGenBuffers(1, vbo_id);
glBindBuffer(GL_ARRAY_BUFFER, vbo_id)

# allocate memory & transfer data to GPU
glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_DYNAMIC_DRAW)

B )обновление вершин:

draw():

  # get new data and update offset
  data = my_func(n+dx, n+2*dx)

  # update offset 'n' which is the current absolute value of x.
  n = n + 2*dx

  # upload data 
  glBindBuffer(GL_ARRAY_BUFFER, vbo_id)
  glBufferSubData(GL_ARRAY_BUFFER, n, sizeof(data), data)

  # translate scene so it looks like line strip has moved to the left.
  glTranslatef(-local_shift, 0.0, 0.0)

  # draw all points from offset
  glVertexPointer(2, GL_FLOAT, 0, n)
  glDrawArrays(GL_LINE_STRIP, 0, points_per_vbo)

где my_funcбудет делать что-то вроде этого:

my_func(start_x, end_x):

  # generate the correct x locations.
  x_values = range(start_x, end_x, STEP_SIZE)

  # generate the y values. We could be getting these values from a sensor.
  y_values = []
  for j in x_values:
      y_values.append(random())

  data = []
  for i, j in zip(x_values, y_values):
     data.extend([i, j])

  return data

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

1 )должен ли я использовать glMapBuffer для привязки буфера к графическому процессору и непосредственного заполнения данных (вместо использования glBufferSubData )? Или это не повлияет на производительность?

2 )Должен ли я использовать шейдер для перемещения объектов (здесь линейная полоса )вместо вызова glTranslatef? Если да, то как будет выглядеть такой шейдер? (Я подозреваю, что шейдер — это неправильный путь, так как моя линейная полоса НЕ является функцией периода, а скорее содержит случайные данные ).

3 )что произойдет, если размер окна изменится?как мне сохранить соотношение сторон и соответственно масштабировать вершины? glViewport ()помогает масштабировать только в направлении Y, но не в направлении X. Если окно масштабируется в направлении x -, то в моей текущей реализации мне пришлось бы пересчитывать положение всей линейной полосы (, вызывая my_func, чтобы получить новые координаты x )и загружать их в ГП. Я думаю, это можно было бы сделать более элегантно? Как бы я это сделал?

4 )Я заметил, что когда я использую glTranslatefс нецелым значением, экран начинает мерцать, если полоса линии состоит из тысяч точек. Скорее всего, это связано с тем, что точное разрешение, которое я использую для расчета линейной полосы, не соответствует разрешению экрана в пикселях, и поэтому иногда некоторые точки появляются впереди, а иногда позади других точек (это особенно раздражает, когда вы не визуализировать синусоиду, но некоторые «случайные» данные ). Как я могу предотвратить это (, кроме очевидного решения перевода на целое число, кратное 1 пикселю )? Если размер окна изменяется -с, скажем, первоначальных 800x800 пикселей до 100x100 пикселей, и я все еще хочу визуализировать линейную полосу продолжительностью 20 секунд, тогда смещение в направлении x должно каким-то образом работать без мерцания с субпиксельной точностью, верно?

5 )как видите, я всегда коллируюglTranslatef(-local_shift, 0.0, 0.0)-и никогда не делаю обратного. Поэтому я продолжаю смещать весь вид вправо. И именно поэтому мне нужно отслеживать абсолютную позицию x (, чтобы поместить новые данные в правильное место ). Эта проблема в конечном итоге приведет к артефакту, когда линия перекрывается с краями окна. Я думаю, должен быть лучший способ сделать это, верно? Как сохранить фиксированные значения x и просто переместить и обновить значения y?

РЕДАКТИРОВАТЬ Я удалил пример с синусоидой и заменил его лучшим примером.Мой вопрос обычно о том, как наиболее эффективно перемещать линейные полосы в пространстве (при добавлении к ним новых значений ). Поэтому любые предложения типа «предварительно вычислить значения для t -> бесконечность» здесь не помогут (. Я мог бы также просто нарисовать текущую температуру, измеренную перед моим домом ).

РЕДАКТИРОВАТЬ2 Рассмотрим этот игрушечный пример, где после каждого временного шага первая точка удаляется и в конец добавляется новая:

t = 0

   * 
  * *    *
 *   **** *

 1234567890

t = 1

  * 
 * *    * *
    **** *

 2345678901

t = 2

 *        * 
  *    * *
   **** *

 3456789012

Я не думаю Я могу использовать шейдер здесь, можно?

РЕДАКТИРОВАТЬ 3:пример с двумя линейными полосами.example showing two line strips

РЕДАКТИРОВАТЬ 4:на основе ответа Тима. Теперь я использую следующий код, который хорошо работает, , но разбивает строку на две (, так как у меня есть два вызова glDrawArrays), см. также следующие два скриншота.

complete line incomplete line

# calculate the difference 
diff_first = x[1] - x[0]


''' first part of the line '''

# push the matrix
glPushMatrix()

move_to = -(diff_first * c)
print 'going to %d ' % (move_to)
glTranslatef(move_to, 0, 0)

# format of glVertexPointer: nbr points per vertex, data type, stride, byte offset
# calculate the offset into the Vertex
offset_bytes = c * BYTES_PER_POINT
stride = 0
glVertexPointer(2, GL_FLOAT, stride, offset_bytes)  

# format of glDrawArrays:  mode, Specifies the starting index in the enabled arrays, nbr of points
nbr_points_to_render = (nbr_points - c)
starting_point_in_above_selected_Vertex = 0
glDrawArrays(GL_POINTS, starting_point_in_above_selected_Vertex, nbr_points_to_render)  

# pop the matrix
glPopMatrix()


''' second part of the line '''

# push the matrix
glPushMatrix()

move_to = (nbr_points - c) * diff_first
print 'moving to %d ' %(move_to)
glTranslatef(move_to, 0, 0)


# select the vertex
offset_bytes = 0
stride = 0
glVertexPointer(2, GL_FLOAT, stride, offset_bytes)

# draw the line
nbr_points_to_render = c
starting_point_in_above_selected_Vertex = 0
glDrawArrays(GL_POINTS, starting_point_in_above_selected_Vertex, nbr_points_to_render)  


# pop the matrix
glPopMatrix()

# update counter
c += 1
if c == nbr_points:
    c = 0

РЕДАКТИРОВАТЬ5 Полученное решение, очевидно, должно отображать одну строку на экране -и не должно быть двух строк, в которых отсутствует связь. Циклический буфер от Тима дает решение о том, как перемещать график, но я получаю две строки вместо одной.

7
задан 17 revs 5 June 2012 в 15:35
поделиться