如何在 sigmajs 中使用 webgl 渲染器创建带边框的节点
How to create nodes with a border with the webgl renderer in sigmajs
我有一个相当大的图表,所以有必要使用 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)
);
},
来自无国界
使用边框(我用 canvas 渲染器做到了,这真的很简单)
这是日志。可以看到只有前3块循环了(只有颜色值为7864320
的块)
如果你们知道另一种实现边框的方法,我很想知道。
使用 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/
我有一个相当大的图表,所以有必要使用 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)
);
},
来自无国界
使用边框(我用 canvas 渲染器做到了,这真的很简单)
这是日志。可以看到只有前3块循环了(只有颜色值为7864320
的块)如果你们知道另一种实现边框的方法,我很想知道。
使用 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/