如何使用sigma.js中的webgl渲染器创建带有边框的节点

时间:2018-06-28 16:26:56

标签: javascript webgl sigma.js

我有一个很大的图,因此有必要使用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(我是用画布渲染器完成的,这真的很容易)

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 :(得分:0)

使用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/