// Vertex Shader: Calcula tamaño y posición export const vertexShader = ` attribute float intensity; attribute float vertexIndex; varying float vIntensity; varying float vIsHighlight; uniform float highlightIndex; uniform float pointSpacing; uniform float dotSize; // Tamaño visual independiente del spacing void main() { vIntensity = intensity; // Use explicit attribute for index float index = vertexIndex; // Si este punto es el seleccionado, marcamos highlight if (abs(index - highlightIndex) < 0.1) vIsHighlight = 1.0; else vIsHighlight = 0.0; vec4 mvPosition = modelViewMatrix * vec4(position, 1.0); float dist = length(mvPosition.xyz); // Tamaño dinámico basado en dotSize (independiente del pointSpacing) float size = dotSize; if (vIsHighlight > 0.5) size *= 2.5; gl_PointSize = clamp(size * (300.0 / dist), 3.0, 120.0); gl_Position = projectionMatrix * mvPosition; } `; // Fragment Shader: Colormap perceptual Viridis export const fragmentShader = ` varying float vIntensity; varying float vIsHighlight; uniform float opacity; uniform vec3 color; // Base color from Uniform vec3 sampleViridis(float t) { float clampedT = clamp(t, 0.0, 1.0); float scaled = clampedT * 8.0; int idx = int(floor(scaled)); float frac = fract(scaled); vec3 c0 = vec3(0.267004, 0.004874, 0.329415); vec3 c1 = vec3(0.282327, 0.160431, 0.457811); vec3 c2 = vec3(0.253935, 0.265254, 0.529983); vec3 c3 = vec3(0.191090, 0.364218, 0.548574); vec3 c4 = vec3(0.127568, 0.456911, 0.550996); vec3 c5 = vec3(0.121148, 0.547463, 0.506309); vec3 c6 = vec3(0.236780, 0.636730, 0.420680); vec3 c7 = vec3(0.460673, 0.723062, 0.303117); vec3 c8 = vec3(0.993248, 0.906157, 0.143936); if (idx == 0) return mix(c0, c1, frac); if (idx == 1) return mix(c1, c2, frac); if (idx == 2) return mix(c2, c3, frac); if (idx == 3) return mix(c3, c4, frac); if (idx == 4) return mix(c4, c5, frac); if (idx == 5) return mix(c5, c6, frac); if (idx == 6) return mix(c6, c7, frac); return mix(c7, c8, frac); } vec4 getActivationColor(float v) { float clampedV = clamp(v, -1.0, 1.0); float t01 = (clampedV + 1.0) * 0.5; vec3 col = sampleViridis(t01); return vec4(col, 1.0); } void main() { vec2 coord = gl_PointCoord - vec2(0.5); if (length(coord) > 0.5) discard; // Círculo perfecto vec4 activation = getActivationColor(vIntensity); vec3 finalColor = activation.rgb * opacity; float alpha = 1.0; // Si está seleccionado, brilla en BLANCO PURO if (vIsHighlight > 0.5) { finalColor = vec3(1.0, 1.0, 1.0); } gl_FragColor = vec4(finalColor, alpha); } `;