Download brain_lab/static/cortical-surface.js from Chungulus/brain-lab: direct link, hf CLI and curl.
- Browser
- Download file 4.09 kB
-
https://huggingface.co/spaces/Chungulus/brain-lab/resolve/main/brain_lab/static/cortical-surface.js
- Command line
-
hf download hf://spaces/Chungulus/brain-lab/brain_lab/static/cortical-surface.js
-
curl -L -o cortical-surface.js https://huggingface.co/spaces/Chungulus/brain-lab/resolve/main/brain_lab/static/cortical-surface.js
4.09 kB
| // Anatomical fsaverage surface geometry; colors are the actual model outputs. | |
| export function corticalSurface(canvas,model){ | |
| const gl=canvas.getContext('webgl',{antialias:true,alpha:false}); | |
| if(!gl)throw Error('This browser cannot render the cortical surface. Enable WebGL or use another browser.'); | |
| const vertex=`attribute vec3 position;attribute vec3 normal;attribute float value;uniform float angle;uniform float amplitude;uniform float aspect;varying vec3 shade;void main(){float c=cos(angle),s=sin(angle);mat3 r=mat3(c,0.,-s,0.,1.,0.,s,0.,c);vec3 p=r*position;vec3 n=normalize(r*normal);float v=clamp(value/amplitude,-1.,1.);vec3 pale=vec3(.86,.88,.82);vec3 color=v<0.?mix(pale,vec3(.22,.54,.72),-v):mix(pale,vec3(.91,.40,.20),v);float light=.48+.52*abs(dot(n,normalize(vec3(-.4,.7,1.))));shade=color*light;float depth=2.6-p.z;gl_Position=vec4(p.x*2.5/aspect,p.y*2.5,depth-1.,depth);gl_PointSize=2.;}`; | |
| const fragment=`precision mediump float;varying vec3 shade;void main(){gl_FragColor=vec4(shade,1.);}`; | |
| const shader=(type,text)=>{const s=gl.createShader(type);gl.shaderSource(s,text);gl.compileShader(s);if(!gl.getShaderParameter(s,gl.COMPILE_STATUS))throw Error('Surface shader compilation failed.');return s}; | |
| const program=gl.createProgram();gl.attachShader(program,shader(gl.VERTEX_SHADER,vertex));gl.attachShader(program,shader(gl.FRAGMENT_SHADER,fragment));gl.linkProgram(program);gl.useProgram(program); | |
| const vertices=model.vertices,n=vertices.length;const mins=[Infinity,Infinity,Infinity],maxs=[-Infinity,-Infinity,-Infinity];for(const p of vertices)for(let i=0;i<3;i++){mins[i]=Math.min(mins[i],p[i]);maxs[i]=Math.max(maxs[i],p[i])}const center=mins.map((v,i)=>(v+maxs[i])/2),extent=Math.max(...maxs.map((v,i)=>v-mins[i]))/2; | |
| const pos=new Float32Array(n*3);vertices.forEach((p,i)=>{pos[i*3]=(p[0]-center[0])/extent;pos[i*3+1]=(p[2]-center[2])/extent;pos[i*3+2]=-(p[1]-center[1])/extent}); | |
| const normals=new Float32Array(n*3);for(const face of model.faces||[]){const[a,b,c]=face.map(i=>i*3),u=[pos[b]-pos[a],pos[b+1]-pos[a+1],pos[b+2]-pos[a+2]],v=[pos[c]-pos[a],pos[c+1]-pos[a+1],pos[c+2]-pos[a+2]],cross=[u[1]*v[2]-u[2]*v[1],u[2]*v[0]-u[0]*v[2],u[0]*v[1]-u[1]*v[0]];for(const k of [a,b,c])for(let j=0;j<3;j++)normals[k+j]+=cross[j]} | |
| for(let i=0;i<n;i++){const k=i*3,d=Math.hypot(normals[k],normals[k+1],normals[k+2])||1;for(let j=0;j<3;j++)normals[k+j]/=d} | |
| const buffers=[];function attribute(name,data,size,dynamic=false){const buffer=gl.createBuffer();buffers.push(buffer);gl.bindBuffer(gl.ARRAY_BUFFER,buffer);gl.bufferData(gl.ARRAY_BUFFER,data,dynamic?gl.DYNAMIC_DRAW:gl.STATIC_DRAW);const a=gl.getAttribLocation(program,name);gl.enableVertexAttribArray(a);gl.vertexAttribPointer(a,size,gl.FLOAT,false,0,0);return buffer} | |
| attribute('position',pos,3);attribute('normal',normals,3);const values=attribute('value',new Float32Array(n),1,true); | |
| let index=null,count=n;if(model.faces?.length){index=gl.createBuffer();buffers.push(index);gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,index);const indices=new Uint16Array(model.faces.flat());gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,indices,gl.STATIC_DRAW);count=indices.length} | |
| gl.enable(gl.DEPTH_TEST);gl.clearColor(.12,.20,.17,1);const uAngle=gl.getUniformLocation(program,'angle'),uAmplitude=gl.getUniformLocation(program,'amplitude'),uAspect=gl.getUniformLocation(program,'aspect');let lastFrame=-1; | |
| return {draw(frame,angle,range){gl.useProgram(program);gl.viewport(0,0,canvas.width,canvas.height);gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT);gl.uniform1f(uAngle,angle);gl.uniform1f(uAmplitude,Math.max(Math.abs(range[0]),Math.abs(range[1]),1e-8));gl.uniform1f(uAspect,canvas.width/canvas.height);if(frame!==lastFrame){gl.bindBuffer(gl.ARRAY_BUFFER,values);gl.bufferSubData(gl.ARRAY_BUFFER,0,new Float32Array(model.frames[Math.min(frame,model.frames.length-1)]));lastFrame=frame}if(index){gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,index);gl.drawElements(gl.TRIANGLES,count,gl.UNSIGNED_SHORT,0)}else gl.drawArrays(gl.POINTS,0,count)},destroy(){for(const b of buffers)gl.deleteBuffer(b);gl.deleteProgram(program)}} | |
| } | |