Как создать узлы с рамкой с помощью рендерера webgl в sigmajs - PullRequest
0 голосов
/ 28 июня 2018

У меня довольно большой график, поэтому необходимо использовать webgl вместо canvas. Я попытался изменить средство рендеринга узла webgl, пытаясь обмануть его, чтобы нарисовать два круга, внешний из которых был бы немного больше, создав тем самым границу. К сожалению, это не сработало. В массиве данных дополнительный код полностью игнорируется. Если у кого-то есть идея, она будет оценена! Ниже приведен код, который отображает узлы для рендерера webgl.

    sigma.webgl.nodes.def = {
POINTS: 3,
ATTRIBUTES: 5,
addNode: function(node, data, i, prefix, settings) {
  var color = sigma.utils.floatColor(
    node.color || settings('defaultNodeColor')
  );

  data[i++] = node[prefix + 'x'];
  data[i++] = node[prefix + 'y'];
  data[i++] = node[prefix + 'size'];
  data[i++] = 7864320;
  data[i++] = 0;

  data[i++] = node[prefix + 'x'];
  data[i++] = node[prefix + 'y'];
  data[i++] = node[prefix + 'size'];
  data[i++] = 7864320;
  data[i++] = 2 * Math.PI / 3;

  data[i++] = node[prefix + 'x'];
  data[i++] = node[prefix + 'y'];
  data[i++] = node[prefix + 'size'];
  data[i++] = 7864320;
  data[i++] = 4 * Math.PI / 3;

  /*  This below was my idea to create another node which is slightly bigger 
  and white. The parameters for that are not the issue. The issue is that the 
  log seems to skip this after 12 indexes of the array data for every node. I 
  wasn't able to find how they define this. */
data[i++] = node[prefix + 'x'];
  data[i++] = node[prefix + 'y'];
  data[i++] = node[prefix + 'size'];
  data[i++] = color;
  data[i++] = 0;

  data[i++] = node[prefix + 'x'];
  data[i++] = node[prefix + 'y'];
  data[i++] = node[prefix + 'size'];
  data[i++] = color;
  data[i++] = 2 * Math.PI / 3;

  data[i++] = node[prefix + 'x'];
  data[i++] = node[prefix + 'y'];
  data[i++] = node[prefix + 'size'];
  data[i++] = color;
  data[i++] = 4 * Math.PI / 3;
 */
  //The log is in the picture below
 console.log(data);
},
render: function(gl, program, data, params) {
  var buffer;

  // Define attributes:


   // I guess they define the location and the attributes here.
  var positionLocation =
        gl.getAttribLocation(program, 'a_position'),
      sizeLocation =
        gl.getAttribLocation(program, 'a_size'),
      colorLocation =
        gl.getAttribLocation(program, 'a_color'),
      angleLocation =
        gl.getAttribLocation(program, 'a_angle'),
      resolutionLocation =
        gl.getUniformLocation(program, 'u_resolution'),
      matrixLocation =
        gl.getUniformLocation(program, 'u_matrix'),
      ratioLocation =
        gl.getUniformLocation(program, 'u_ratio'),
      scaleLocation =
        gl.getUniformLocation(program, 'u_scale');

  buffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  gl.bufferData(gl.ARRAY_BUFFER, data, gl.DYNAMIC_DRAW);

 // I don't know what happens here

  gl.enableVertexAttribArray(positionLocation);
  gl.enableVertexAttribArray(sizeLocation);
  gl.enableVertexAttribArray(colorLocation);
  gl.enableVertexAttribArray(angleLocation);

  gl.vertexAttribPointer(
    positionLocation,
    2,
    gl.FLOAT,
    false,
    this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
    0
  );
  gl.vertexAttribPointer(
    sizeLocation,
    1,
    gl.FLOAT,
    false,
    this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
    8
  );
  gl.vertexAttribPointer(
    colorLocation,
    1,
    gl.FLOAT,
    false,
    this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
    12
  );
  gl.vertexAttribPointer(
    angleLocation,
    1,
    gl.FLOAT,
    false,
    this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT,
    16
  );

  gl.drawArrays(
    gl.TRIANGLES,
    params.start || 0,
    params.count || (data.length / this.ATTRIBUTES)
  );
},

Из-за границы

From Without Border

To с Border (я сделал это с рендером Canvas, где это было действительно легко)

To with Border(I did this with the canvas renderer, where it was really easy)

Это журнал. Вы можете видеть, что только первые 3 блока зациклены (только те со значением цвета 7864320

This is the log. You can see that only the first 3 blocks are looped(only the ones with the color value 7864320)

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

1 Ответ

0 голосов
/ 17 июля 2018

Простой способ построения кругов с помощью WebGL - использовать gl.POINTS вместо gl.TRIANGLES . С помощью этого трюка одна вершина используется для одного круга, каким бы большим ни был радиус. Кроме того, у вас может быть рамка нужного вам размера.

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

attribute vec2 attCoords;
attribute float attRadius;
attribute float attBorder;
attribute vec3 attColor;

varying float varR1;
varying float varR2;
varying float varR3;
varying float varR4;
varying vec4 varColor;

const float fading = 0.5;

void main() {
  float r4 = 1.0;
  float r3 = 1.0 - fading / attRadius;
  float r2 = 1.0 - attBorder / attRadius;
  float r1 = r2 - fading / attRadius;

  varR4 = r4 * r4 * 0.25;
  varR3 = r3 * r3 * 0.25;
  varR2 = r2 * r2 * 0.25;
  varR1 = r1 * r1 * 0.25;

  varColor = vec4( attColor.rgb, 1.0 );

  gl_PointSize = 2.0 * attRadius;
  gl_Position = vec4( attCoords.xy, 0, 1 );
}

В фрагментном шейдере вы можете узнать, какой из пикселей POINT вы обрабатываете. Вы получите координаты этого пикселя в gl_PointCoord . (0,0) - это верхний левый пиксель, а (1,1) - нижний правый пиксель. Кроме того, вы можете использовать ключевое слово discard , которое эквивалентно return , но сообщая WebGL, что текущий фрагмент не должен быть нарисован.

precision mediump float;
varying float varR1;
varying float varR2;
varying float varR3;
varying float varR4;
varying vec4 varColor;

const vec4 WHITE = vec4(1, 1, 1, 1);
const vec4 TRANSPARENT = vec4(1, 1, 1, 0);

void main() {
  float x = gl_PointCoord.x - 0.5;
  float y = gl_PointCoord.y - 0.5;
  float radius = x * x + y * y;

  if( radius > 1.0 ) discard;

  if( radius < varR1 )
    gl_FragColor = varColor;
  else if( radius < varR2 )
    gl_FragColor = mix(varColor, WHITE, (radius - varR1) / (varR2 - varR1));
  else if( radius < varR3 )
    gl_FragColor = WHITE;
  else
    gl_FragColor = mix(WHITE, TRANSPARENT, (radius - varR3) / (varR4 - varR3));
}

По сути, если пиксель находится на расстоянии более чем attRadius от центра, вы отбрасываете пиксель. Если он внутри attRadius - attBorder , вы используете цвет. А между ними вы используете белый.

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

Вот полный рабочий пример: https://jsfiddle.net/7rh2eog1/2/

...