4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

webGLの圧縮

Last updated at Posted at 2019-05-06

JsExe

Revision2019 の 4K Intro 優勝作品のwebGLの圧縮スキルがわかりました。
javascriptをバイナリに変換して、それをを<img>のソースとして読み込んで、そのソースをデコードし、eval()を使ってwebGLをやってるようです。
JsExeというToolを使うみたい。
出力ファイルは、バイナリとデコードのスクリプトが入っていて、そのまま使えます。
この圧縮するスキルは、ここに書いてある事と同等と思われます。

使い方

JsExeをdownloadしてくる。
javascriptだけで表示が出来るfileを用意する。
こんな感じ

var canvas = document.createElement("canvas");
canvas.style.position = "fixed";
canvas.style.cursor = "none";
canvas.style.left = canvas.style.top = 0;

canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
document.body.appendChild(canvas);

var gl = canvas.getContext("webgl2") || canvas.getContext("experimental-webgl2");
var compileShader = function(prog, src, type){
    var sh = gl.createShader(type);
    gl.shaderSource(sh, src.replace(/^\n/, ""));
    gl.compileShader(sh);
    gl.attachShader(prog, sh);
    gl.deleteShader(sh);
};
        
vs = `
# version 300 es
void main()
{ 
    gl_Position = vec4(ivec2(gl_VertexID&1,gl_VertexID>>1)*2-1,0,1);
}
`
fs = `
# version 300 es
precision highp float;
out vec4 fragColor;
uniform vec2 resolution;
uniform float time;
void main() {
  vec2 uv=(gl_FragCoord.xy*2.-resolution)/resolution.y;
  vec3 col=.5+.5*cos(time+uv.xyx+vec3(0,2,4));
  fragColor=vec4(col,1);
}
`

var p = gl.createProgram();
compileShader(p, vs, gl.VERTEX_SHADER);
compileShader(p, fs, gl.FRAGMENT_SHADER);
gl.linkProgram(p);
gl.useProgram(p);
gl.uniform2f(gl.getUniformLocation(p, "resolution"), canvas.width, canvas.height);

var zero = Date.now();
(function () { 
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    gl.uniform1f(gl.getUniformLocation(p, "time"), (Date.now() - zero) * 0.001);
    gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
    requestAnimationFrame(arguments.callee);
})();

この時のポイントは
styleを使ってcanvasを固定する事とcanvasの動的生成。

上のファイル名を test.js として、出力ファイル名を index.html とした場合のコマンドラインは

jsexe.exe -cn test.js index.html

これで、おしまい。
オプションは、-cnだけで良さそう。

このindex.htmlは、localhostを立てないと見れない。
python3を使ってlocalhostを立ててみるには

python -m http.server

これでOK。
http://localhost:8000/
にアクセスしてください。

ここでは、複雑になるのでミニ化については、触れないでJsExeだけの使い方にとどめています。

JsExeを使ってのミニ化は、こちらを参考にすれば良いと思います。
Bercon/CoreCritical

base64を使ってみた

バイナリだと色々と制約があるみたい。なのでbase64を使ってみた。この場合は圧縮効果は無いと思います。利点としてソースを見せたくない時に利用が出来ると思います。
雑だけど、python3でJsExeの出力ファイルから、base64のimgソースを持つhtmlファイルを作るスクリプトを書きました。

import base64
import sys

def convert(inFile, outFile):
    f = open(inFile, "rb")
    data = f.read()
    f.close
    js= "<canvas id=V><img src=# onload=C=V.getContext(\'2d\');for($=_=\'\';C.drawImage(this,$--,0),X=C.getImageData(0,0,1,1).data[0];_+=String.fromCharCode(X));(1,eval)(_)>"
    b64 = base64.encodestring(data)
    js = js.replace("#","'data:image/png;base64,"+b64.decode('utf-8')+"'")
    f = open(outFile, 'w')
    f.write(js)
    f.close()

if __name__ == '__main__':
    args = sys.argv
    convert(args[1],args[2])

これを b64Exe.pyとして保存してもらうとしたら、

python b64Exe.py jsExe_Html out_Html

これでできます。

<canvas id=V><img src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABdYAAAABCAAAAAD25KMnAAAC2UlEQVR4Xn1UXW/aMBTtMxL/wcqk
KaEhDbR9QlRiENZKXYeAdnuYxtzkJrFm7Mx2ANbuv892SgNttzyE+J5zfL85WmGBYsxWWKI+Snhc
LoGpIBaAFUQUzMl1KoLj9ZqNihtItaUQFFwSRTjTUiclG0icl4y4FJILgzPO4BVMIVUaPLApXmhT
qKnP5DVJVK6Na8ISvg4IYyC+GFvtLgeS5eoF59IaNek5sXuebANcFMCSYU5o4lZyz3oztchoHU8G
asiZgo0uwRruM9p1PPT4+BYMmwIEMS4wbe+4verKmC8LQmGW4wRMKdKSxaZqbiF45iMpYh+pbQHe
Q7OB9GM00qSb0aoRT1LXknqWZDBprTNeihhcmdubAgEFxfp88v0bO/GR43h7ioNItGQPwkrhOK+Q
XWD7eAIU1KHyj0WrR2dqBuhHs/FuBUKamTgNQwRSA5wkaIkJc71m4wHtPC4m9fCsID5ziX53XQ3c
gVCwuRq97/h7p4uLjtfqtjt+6Hes92ZDe0v/5bUQEBNryUmWFyilHJtJ4KWy7lAqcDbklAttLBlJ
uVgaoIsESE5LE1mNVHKkyBJ6Bxkh2zOrK1d9E/3Y3stFEmy2rW7Qrq/zTurvYNt7Ep6imNN+cH4c
nLdiLl3j47hcafXm2MBu6Hf9s6qLddB9WzKtrIuxm+Bif3ImgmcCL11DOux+4aOV9A3zLprOo6+L
2eVgFE3fJKYVcTwdfPwU3cz3qNpKCfu5c1M82UoJr0xVJbupq/EM1G11vuYxrpbBR05dH8fz0f7y
21O95/W+/gbBdcIjrCBgfG0TdXcbhkyDUD3+FLAw7oefrz9PFx9ux+NI/1zN0aOBR9Fkfrln3U1/
HXznf8Gbxpmw3ToW1LbxeaiFwiAMO/v7JPB6IATeSnPlfHo1uPl4HS1m+mvio9BHZzuygF8lSDVg
ZGmdjXVVwcUis/9oMogxpQB2Cjy3KszRX33+127r/QzqRT48Y2FudmFzIGlkPVY+PGltZyBzcmM9
IyBvbmxvYWQ9Qz1WLmdldENvbnRleHQoJzJkJyk7Zm9yKCQ9Xz0nJztDLmRyYXdJbWFnZSh0aGlz
LCQtLSwwKSxYPUMuZ2V0SW1hZ2VEYXRhKDAsMCwxLDEpLmRhdGFbMF07Xys9U3RyaW5nLmZyb21D
aGFyQ29kZShYKSk7KDEsZXZhbCkoXyk+
' onload=C=V.getContext('2d');for($=_='';C.drawImage(this,$--,0),X=C.getImageData(0,0,1,1).data[0];_+=String.fromCharCode(X));(1,eval)(_)>

こんなに意味不明のスクリプトが動く絵を出すなんて、楽しすぎです。
ちなみに、https://neort.io/ のhtmlに貼り付けたら動きました。

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?