Два слоя с разными формами точек - PullRequest
1 голос
/ 05 мая 2020

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

[lat, lng, r, g, b, a, id, lat, lng, r, g, b, a, id, etc...] //where id is used for selecting the marker.

Точки нарисованы с использованием:

this.delegate.gl.drawArrays(this.delegate.gl.POINTS, 0, numPoints);

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

[lat, lng, r, g, b, a, id, code, lat, lng, r, g, b, a, id, code etc...]

Код шейдера затем решает, нарисовать ли круг или квадрат. Это возможно? Я не знаю, как передать шейдеру атрибут кода формы, чтобы определить, какую форму рисовать. Вот код шейдера, в настоящее время существует две программы шейдера фрагментов. Один dr aws круги, один рисовать квадраты.

 <script id="vshader" type="x-shader/x-vertex">
      uniform mat4 u_matrix;
      attribute vec4 a_vertex;
      attribute float a_pointSize;
      attribute vec4 a_color;
      varying vec4 v_color;

      void main() {
        gl_PointSize =  a_pointSize;
        gl_Position = u_matrix * a_vertex;
        v_color = a_color;
      }
    </script>

    <script id="fshader" type="x-shader/x-fragment">
      precision mediump float;
      varying vec4 v_color;

      void main() {
        float border = 0.05;
        float radius = 0.5;

        vec2 m = gl_PointCoord.xy - vec2(0.5, 0.5);
        float dist = radius - sqrt(m.x * m.x + m.y * m.y);

        float t = 0.0;
        if (dist > border)
        t = 1.0;
        else if (dist > 0.0)
        t = dist / border;
        gl_FragColor = mix(vec4(0), v_color, t);

      }
    </script>
      <script id="fshader-square" type="x-shader/x-fragment">
        precision mediump float;
        varying vec4 v_color;
        void main() {
          gl_FragColor = v_color;  
        }

    </script>

Мои указатели атрибутов настроены следующим образом:

this.gl.vertexAttribPointer(vertLoc, 2, this.gl.FLOAT, false, fsize*7, 0); // вершина

this.gl.vertexAttribPointer(colorLoc, 4, this.gl.FLOAT, true, fsize*7, fsize*2); / / цвет

1 Ответ

1 голос
/ 05 мая 2020

Самый распространенный способ рисования точек различной формы - использовать текстуру, таким образом ваши дизайнеры могут сделать маркеры et c ..

Также часто не рисуют POINTS, но вместо этого рисовать квадраты, сделанные из TRIANGLES. Ни Google Maps, ни Mapbox не используют POINTS (что вы можете проверить самостоятельно )

POINTS имеют 2 проблемы

  1. SP c говорит, что самый большой размер, который вы можете нарисовать ТОЧКУ, зависит от реализации и может составлять всего 1 пиксель

  2. * 1020 не является частью SP c, но, к сожалению, это правда)
  3. ТОЧКИ могут быть только выровненными квадратами.

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

Что касается реализации, все зависит от вас. Некоторые случайные идеи

  • Используйте POINTS, добавляйте imageId за точку. Используйте imageId и gl_PointCoord, чтобы выбрать изображение из текстурного атласа.

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

    uniform vec2 textureAtlasSize;  // eg 64x32
    uniform vec2 imageSize;         // eg 16x16
    
    float imagesAcross = floor(textureAtlasSize.x / imageSize.x);
    vec2 imageCoord = vec2(mod(imageId, imagesAcross), floor(imageId / imagesAcross));
    vec2 uv = (imageCoord + imageSize * gl_PointCoord) / textureAtlasSize;
    
    gl_FragColor = texture2D(textureAtlas, uv);
    

обратите внимание, что если вы сделаете ваш imageIds a vec2 вместо float и просто передайте идентификатор как imageCoord, тогда вам не нужна математика imageCoord в шейдере.

  • Используйте POINTS, атлас текстуры , и смещение vec2, диапазон vec2 для каждой точки

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

    gl_FragColor = texture2D(textureAtlas, offset + range * gl_PointCoord);
    
  • Используйте TRIANGLES и экземпляр чертежа

    Это действительно не отличается от приведенного выше, за исключением того, что вы создаете один квадрат с двумя треугольниками и используете drawArrayInstanced или drawElementsInstanced. Вам нужно изменить ссылки на gl_PointCoord с вашими собственными координатами текстуры, и вам нужно вычислить точки в вершинном шейдере

    attribute vec2 reusedPosition;  // the 6 points (1, -1)
    
    ... all the attributes you had before ...
    
    uniform vec2 outputResolution;  // gl.canvas.width, gl.canvas.height
    
    varying vec2 ourPointCoord;
    
    void main() {
       ... -- insert code that you had before above this line -- ...
    
       // now take gl_Position and convert to point
       float ourPointSize = ???
       gl_Position.xy += reusedPosition * ourPointSize / outputResolution * gl_Position.w;
    
       ourPointCoord = reusedPosition * 0.5 + 0.5;
    
  • Используйте TRIANGLES с объединенной геометрией.

    Это просто означает, что вместо одной вершины на точку вам нужно 4 (если проиндексировано) или 6.

  • Используйте TRIANGLES только с идентификатором, помещайте данные в текстуры.

    Если обновление 4–6 вершин для перемещения точки - это слишком много работы (подсказка: вероятно, это не так). Затем вы можете поместить свои данные в текстуру и искать данные для каждой точки на основе идентификатора. Итак, вы помещаете 4 идентификатора на точку плюс идентификатор вершины в некотором буфере (ie, идентификаторы 0,0,0,0,1,1,1,1,2,2,2,2,3,3,3, 3,4,4,4,4, идентификаторы вершин 0,1,2,3,0,1,2,3,0,1,2,3,0,1,2,3) вы можете затем использовать их для вычислить координаты квадрата, координаты текстуры и uvs для поиска данных точки в текстуре. Преимущество: вам нужно обновить только одно значение на точку вместо 4-6 значений на точку, если вы хотите переместить точку.

Примечание: все вышеперечисленное предполагает, что вы хотите нарисовать 1000 очков за один вызов отрисовки. Если вы рисуете 250 или меньше точек, может быть, даже 1000-2000 точек, рисование их по одной точке за вызов отрисовки обычным способом, возможно, будет вполне приемлемым. например,

for each point
  setup uniforms
  gl.drawXXX

Не указывает, а просто в качестве примера WebGL Aquarium использует это l oop. Он никоим образом не использует создание экземпляров или слияние геометрии. Вот еще один пример просто отрисовка 1 квадрата за вызов отрисовки

...