UNPKG

@jonobr1/force-directed-graph

Version:

GPU supercharged attraction-graph visualizations for the web built on top of Three.js

140 lines (112 loc) 4.18 kB
/** * Renders points of all nodes as a * single draw call. */ const points = { vertexShader: ` #include <fog_pars_vertex> uniform float sizeAttenuation; uniform float frustumSize; uniform float is2D; uniform float nodeRadius; uniform float nodeScale; uniform float uBeginning; uniform float uEnding; uniform float uNodeAmount; uniform sampler2D texturePositions; uniform sampler2D textureTargetPositions; varying vec3 vColor; varying float vImageKey; varying float vDistance; varying float vViewZ; varying vec3 vTargetPosition; varying float vHasTarget; attribute float imageKey; attribute float pointSize; void main() { float nodeIndex = position.z - 1.0; float rangeStart = uBeginning * uNodeAmount; float rangeEnd = uEnding * uNodeAmount; float inRange = step( rangeStart, nodeIndex ) * ( 1.0 - step( rangeEnd, nodeIndex ) ); vec4 texel = texture2D( texturePositions, position.xy ); vec3 vPosition = texel.xyz; vPosition.z *= 1.0 - is2D; vec4 targetTexel = texture2D( textureTargetPositions, position.xy ); vTargetPosition = targetTexel.xyz; vHasTarget = targetTexel.w; vec4 mvPosition = modelViewMatrix * vec4( vPosition, 1.0 ); gl_PointSize = nodeRadius * pointSize * nodeScale; gl_PointSize *= mix( 1.0, frustumSize / - mvPosition.z, sizeAttenuation ); gl_PointSize *= inRange; vDistance = 1.0 / - mvPosition.z; vViewZ = mvPosition.z; vColor = color; vImageKey = imageKey; gl_Position = projectionMatrix * mvPosition; #include <fog_vertex> } `, fragmentShader: ` #include <fog_pars_fragment> uniform float sizeAttenuation; uniform float frustumSize; uniform vec3 uColor; uniform float opacity; uniform float imageDimensions; uniform sampler2D textureAtlas; uniform float inheritColors; varying vec3 vColor; varying float vImageKey; varying float vDistance; varying float vViewZ; void main() { // Calculate distance from center for circular shape and depth vec2 cxy = 2.0 * gl_PointCoord - 1.0; float r = length(cxy); // Antialiased circle using fwidth for automatic edge smoothing float delta = fwidth(r); float t = 1.0 - smoothstep(1.0 - delta, 1.0, r); // Calculate custom depth to fix z-fighting with transparent points // For fragments inside the circle, offset depth proportionally #if defined(GL_EXT_frag_depth) if (r <= 1.0) { // Keep the center of the node slightly closer so coincident links // do not leak through overlapping nodes. float depthOffset = (1.0 - r) * 0.0001; gl_FragDepthEXT = gl_FragCoord.z - depthOffset; } else { gl_FragDepthEXT = gl_FragCoord.z; } #elif __VERSION__ >= 300 if (r <= 1.0) { // Keep the center of the node slightly closer so coincident links // do not leak through overlapping nodes. float depthOffset = (1.0 - r) * 0.0001; gl_FragDepth = gl_FragCoord.z - depthOffset; } else { gl_FragDepth = gl_FragCoord.z; } #endif // Calculate texture atlas coordinates for image sprites float col = mod( vImageKey, imageDimensions ); float row = floor( vImageKey / imageDimensions ); vec2 uv = vec2( 0.0 ); uv.x = mix( 0.0, 1.0 / imageDimensions, gl_PointCoord.x ); uv.y = mix( 0.0, 1.0 / imageDimensions, gl_PointCoord.y ); uv = vec2( gl_PointCoord ) / imageDimensions; uv.x += col / imageDimensions; uv.y += row / imageDimensions; vec4 texel = texture2D( textureAtlas, uv ); float useImage = step( 0.0, vImageKey ); t = mix( t, texel.a, useImage ); vec3 layer = mix( vec3( 1.0 ), texel.rgb, useImage ); float alpha = opacity * t; if ( alpha <= 0.0 ) { discard; } gl_FragColor = vec4( layer * mix( vec3( 1.0 ), vColor, inheritColors ) * uColor, alpha ); #include <fog_fragment> } `, }; export default points;