用1009字节的JavaScript适应WebGL上的繁星点点的天空

两件事总是让灵魂充满新的,越来越强烈的惊喜和崇敬,我们对它们的思考越来越频繁和漫长-这是我头顶的星空和我的道德律。 伊曼纽尔·康德

JS1k是一项年度竞赛,您需要在JavaScript中以1024个字符容纳演示,游戏或任何其他内容。 今年,我的演示名列第四(直到第三名得分不足两分)。 您可以在JS1k网站上观看演示。 谁不开放或不工作,应该看起来像这样:



完整而完整的源代码位于github上 。 重点是分析如何在此类竞赛中最小化JavaScript。


免责声明


该演示的主要优点 Pablo Roman Andrioli制作的片段着色器 。 Pablo是一位从事分形工作的艺术家,在fractalforums论坛上, 提供了一些计算细节。 我的任务是打包一个1024字节的着色器和WebGL代码。


WebGL初始化


演示开始时的JS1k包装器在全局变量g中提供了WebGL上下文。 尽管如此,使用WebGL还是很冗长的。 例如,要将顶点着色器添加到程序中,需要159个字符:


// Define a new program p=g.createProgram(); // Basic vertex shader s=g.createShader(VERTEX_SHADER); g.shaderSource(s,"attribute vec2 p;void main(){gl_Position=vec4(p,0,1);}"); // Compile and attach it to the program g.compileShader(s); g.attachShader(p,s); 

为了解决这个问题,最近几年的所有JS1k解决方案都使用了带有函数同义词的技巧:


 for(i in g){ g[i[0] + i[6]] = g[i]; } 

循环为WebGL上下文的每个功能(以及任何成员)添加了同义词,该同义词由首字母和7个字母组成。 例如,创建项目将变成cP ,更高级的源代码等。 另外, with(g)构造(在这些项目中不能使用with(g)构造所有代码,我们得到:


 with(g){ p=cP(); sS(s=cS(35633),'attribute vec2 p;void main(){gl_Position=vec4(p,1,1);}'); ce(s); aS(p,s); } 

着色器缩小


原始着色器需要1100个字符。 主要缩写:删除不必要的变量,并组合相似的片段。 毕竟,我是通过在线minifier传递代码的。 结果,着色器仅剩500多个字节。


JSCrush


JSCrush是在此类比赛中压缩代码的事实标准。 该实用程序将代码转换为大约以下顺序:


_ ='(i a.style = ...
 _='(i a.style="widMj%;hEjvh;:left",g)g[i[0]+i[6]]=g[i];wiMO.u=g.G1f,x=y=k=g)p=cP(35633"tribute 2 p gl_Posit=4?FN"precis mediump ;G Zt,a,x,y Uf`ord.rg/64!-.f.=a;Zc=+xz,v=+yz;m2 m$cc-cc)s$vv-vv)fJf#Ur`Q,,r+`t*2.,t,-2.rJr#Zg=.1,b=Q;Ui`!Kl=Rl<2Rl++){Uo=r+f*;oQ)-mod(o,2.))Ze,n=e=!;Kd=Rd<2Rd++)oo)/dot(o,o)-3,n+o)-ee=oif(l>6)Q-max(!,.3-i+=b+g,g,g)*n*5*b;.73;g+=.1;}i=mix(i)i,.85lor=4(i*.01.lo?ug?bfO=34962,cB()eV(0vA(2,5120bDO,Tw Int8Array([|,|]35044o=,(Lt@-oa@TrHE/TrWidMx@xy@ydr(6,3requestAnimFrame(L)})(down=upk^=1},movek&&(xX,yY)};),3=funct(e){uOf?,"flo}@ce(saS?,slengM(onmouse ;void ma(){Tw De/1e5);incos(for=abs(gl_FragCo,1g*(sS(s=cS(n*n*.001at.5vecionb*=s(=e.page0,!0.#.r=s;$=m2(?(p@"EeightGunimJ.rm;K(t MthO(gQ1.R0;TneU Z `=j:100z/50!|-3';for(Y in $='|zj`ZUTRQOMKJGE@?$#! ')with(_.split($[Y]))_=join(pop());eval(_) 

JSCrush的原理可以在用于反向代码转换工具中直观地查看。 或在文章中详细阅读。 通常,这是使用字典进行编码的:


  1. 我们发现代码中未使用的字符
  2. 我们在代码中发现重复的片段,并将其替换为第一段中的字符
  3. 用字符替换字符串
  4. 重复1-3,直到结果小于源代码。

最佳化


完成所有操作后,我仍然剩下大约30个字符,可以用来优化性能。 加载演示时,您可以指定画布大小:全屏或固定大小。 全屏启动很漂亮,但是片段着色器会为每个像素调用,并且运行缓慢。 解决方案是从JS1k canvas请求固定大小(我选择640x640),然后在代码中将其增加到全屏显示:


 a.style='width:100%;height:100vh;float:left'; 

然后,图像占据了整个屏幕,但是仅对原始画布大小的每个像素执行着色器。

Source: https://habr.com/ru/post/zh-CN462115/


All Articles