-
Notifications
You must be signed in to change notification settings - Fork 2
/
npr_build_opt.js
91 lines (91 loc) · 54.9 KB
/
npr_build_opt.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
var NPR=NPR||{};NPR.createInstancedBillboardBuffers=function(a,b){var c=new NPR.Triangles;c.addPoint(-0.5,0.5);c.addPoint(-0.5,-0.5);c.addPoint(0.5,0.5);c.addPoint(0.5,0.5);c.addPoint(-0.5,-0.5);c.addPoint(0.5,-0.5);return c.makeInstancedVertexBuffer(a,b)};NPR=NPR||{};
NPR.Framebuffer=function(a){var b=NPR.gl;a=a||{};var c=a.width||b.viewportWidth,d=a.height||b.viewportHeight,e=a.type||b.UNSIGNED_BYTE,f=a.channelFormat||b.RGBA;a=void 0!==a.hasDepth?a.hasDepth:!0;this.fbo=b.createFramebuffer();b.bindFramebuffer(b.FRAMEBUFFER,this.fbo);this.fbo.width=c;this.fbo.height=d;this.texture=b.createTexture();b.bindTexture(b.TEXTURE_2D,this.texture);b.pixelStorei(b.UNPACK_FLIP_Y_WEBGL,!0);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_S,b.CLAMP_TO_EDGE);b.texParameteri(b.TEXTURE_2D,
b.TEXTURE_WRAP_T,b.CLAMP_TO_EDGE);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MAG_FILTER,b.LINEAR);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MIN_FILTER,b.LINEAR);b.texImage2D(b.TEXTURE_2D,0,f,this.fbo.width,this.fbo.height,0,f,e,null);b.framebufferTexture2D(b.FRAMEBUFFER,b.COLOR_ATTACHMENT0,b.TEXTURE_2D,this.texture,0);a&&(c=b.createRenderbuffer(),b.bindRenderbuffer(b.RENDERBUFFER,c),b.renderbufferStorage(b.RENDERBUFFER,b.DEPTH_COMPONENT16,this.fbo.width,this.fbo.height),b.framebufferRenderbuffer(b.FRAMEBUFFER,
b.DEPTH_ATTACHMENT,b.RENDERBUFFER,c));b.bindFramebuffer(b.FRAMEBUFFER,null)};NPR.Framebuffer.prototype.bind=function(){var a=NPR.gl;a.bindFramebuffer(a.FRAMEBUFFER,this.fbo)};NPR.Framebuffer.prototype.release=function(){var a=NPR.gl;a.bindFramebuffer(a.FRAMEBUFFER,null)};NPR.Framebuffer.prototype.bindTexture=function(){var a=NPR.gl;a.bindTexture(a.TEXTURE_2D,this.texture)};NPR=NPR||{};NPR.Mesh=function(){this.loaded=!1};
NPR.Mesh.prototype.load=function(a,b){var c=this,d=new XMLHttpRequest;d.open("GET",a);d.onreadystatechange=function(){if(4==d.readyState){var a=JSON.parse(d.responseText);c.positions=a.vertexPositions;c.normals=a.vertexNormals;c.texcoords=a.vertexTextureCoords;c.indices=a.indices;c.makeBuffers();c.loaded=!0;b()}};d.overrideMimeType("application/json");d.send()};
NPR.Mesh.prototype.makeBuffers=function(){var a=NPR.gl;this.positions&&(this.VertexPositionBuffer&&a.deleteBuffer(this.VertexPositionBuffer),this.VertexPositionBuffer=a.createBuffer(),a.bindBuffer(a.ARRAY_BUFFER,this.VertexPositionBuffer),a.bufferData(a.ARRAY_BUFFER,new Float32Array(this.positions),a.STATIC_DRAW),this.VertexPositionBuffer.itemSize=3,this.VertexPositionBuffer.numItems=this.positions.length/3);this.normals&&(this.VertexNormalBuffer&&a.deleteBuffer(this.VertexNormalBuffer),this.VertexNormalBuffer=
a.createBuffer(),a.bindBuffer(a.ARRAY_BUFFER,this.VertexNormalBuffer),a.bufferData(a.ARRAY_BUFFER,new Float32Array(this.normals),a.STATIC_DRAW),this.VertexNormalBuffer.itemSize=3,this.VertexNormalBuffer.numItems=this.normals.length/3);this.texcoords&&(this.TextureCoordinateBuffer&&a.deleteBuffer(this.TextureCoordinateBuffer),this.TextureCoordinateBuffer=a.createBuffer(),a.bindBuffer(a.ARRAY_BUFFER,this.TextureCoordinateBuffer),a.bufferData(a.ARRAY_BUFFER,new Float32Array(this.texcoords),a.STATIC_DRAW),
this.TextureCoordinateBuffer.itemSize=2,this.TextureCoordinateBuffer.numItems=this.texcoords.length/2);this.indices&&(this.VertexIndexBuffer&&a.deleteBuffer(this.VertexIndexBuffer),this.VertexIndexBuffer=a.createBuffer(),a.bindBuffer(a.ELEMENT_ARRAY_BUFFER,this.VertexIndexBuffer),a.bufferData(a.ELEMENT_ARRAY_BUFFER,new Uint16Array(this.indices),a.STATIC_DRAW),this.VertexIndexBuffer.itemSize=1,this.VertexIndexBuffer.numItems=this.indices.length)};
NPR.Mesh.prototype.getRandomSamples=function(a){var b=this.positions,c=this.normals,d=this.indices;if(!b||!c||!d)throw[[],[]];for(var e=[],f=[],h=0,g=0;g<b.length/3;g++)f[g]=[b[3*g],b[3*g+1],b[3*g+2]];b=[];for(g=0;g<c.length/3;g++)b[g]=[c[3*g],c[3*g+1],c[3*g+2]];for(g=0;g<d.length;g+=3){var j=c=[d[g],d[g+1],d[g+2]],k;k=f[c[0]];var l=f[c[1]],s=f[c[2]],n=void 0,t=void 0,m=void 0,u=void 0,p=void 0,v=void 0,x=void 0,n=m=void 0,n=l[0]-k[0],t=l[1]-k[1],m=l[2]-k[2],u=s[0]-k[0],p=s[1]-k[1],v=s[2]-k[2],x=
t*v-m*p,m=m*u-n*v,n=n*p-t*u;k=Math.sqrt(x*x+m*m+n*n);j.area=k;e[g/3]=c;h+=c.area}e.sort(function(b,a){return b.area-a.area});d=[];c=[];for(k=j=0;d.length<3*a;){k+=Math.min(a*e[j].area/h,3*a-d.length);l=f[e[j][0]];s=f[e[j][1]];x=f[e[j][2]];n=b[e[j][0]];t=b[e[j][1]];u=b[e[j][2]];j==e.length-1&&(k=3*a-d.length);p=0;if(1<k)for(g=1;g<k;g++){var m=l,v=s,y=x,z=n,A=t,B=u,q=void 0,r=void 0,w=void 0,C=void 0,D=void 0,E=void 0,q=Math.random(),r=Math.random();1<q+r&&(q=1-q,r=1-r);w=1-q-r;C=q*m[0]+r*v[0]+w*y[0];
D=q*m[1]+r*v[1]+w*y[1];E=q*m[2]+r*v[2]+w*y[2];nx=q*z[0]+r*A[0]+w*B[0];ny=q*z[1]+r*A[1]+w*B[1];nz=q*z[2]+r*A[2]+w*B[2];m=[[C,D,E],[nx,ny,nz]];d.push(m[0][0]);d.push(m[0][1]);d.push(m[0][2]);c.push(m[1][0]);c.push(m[1][1]);c.push(m[1][2]);p++}k-=p;j++}return[d,c]};
NPR.Mesh.prototype.getRandomSampleBuffers=function(a,b){var c=NPR.gl,d=this.getRandomSamples(a),e=d[0],d=d[1],f=c.createBuffer();c.bindBuffer(c.ARRAY_BUFFER,f);c.bufferData(c.ARRAY_BUFFER,new Float32Array(e),c.STATIC_DRAW);f.itemSize=3;f.numItems=e.length/3;var h=c.createBuffer();c.bindBuffer(c.ARRAY_BUFFER,h);c.bufferData(c.ARRAY_BUFFER,new Float32Array(d),c.STATIC_DRAW);h.itemSize=3;h.numItems=d.length/3;b&&(b[0]=e,b[1]=d);return[f,h]};
NPR.Mesh.prototype.makeRandomSampleBuffers=function(a,b){this.RandomSampleBuffer&&NPR.gl.deleteBuffer(this.RandomSampleBuffer);this.RandomSampleNormalBuffer&&NPR.gl.deleteBuffer(this.RandomSampleNormalBuffer);var c=this.getRandomSampleBuffers(a,b);this.RandomSampleBuffer=c[0];this.RandomSampleNormalBuffer=c[1]};function handleLoadedModel(a,b){b.model=new objmodel(a)}
function loadModel(a,b){var c=new XMLHttpRequest;c.open("GET",a);c.onreadystatechange=function(){4==c.readyState&&handleLoadedModel(JSON.parse(c.responseText),b)};c.send()}
function objmodel(a){var b,c,d,e;b=gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER,b);gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(a.vertexPositions),gl.STATIC_DRAW);b.itemSize=3;b.numItems=a.vertexPositions.length/3;c=gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER,c);gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(a.vertexNormals),gl.STATIC_DRAW);c.itemSize=3;c.numItems=a.vertexNormals.length/3;d=gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER,d);gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(a.vertexTextureCoords),
gl.STATIC_DRAW);d.itemSize=2;d.numItems=a.vertexTextureCoords.length/2;e=gl.createBuffer();gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,e);gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,new Uint16Array(a.indices),gl.STATIC_DRAW);e.itemSize=1;e.numItems=a.indices.length;this.VertexPositionBuffer=b;this.VertexNormalBuffer=c;this.TextureCoordinateBuffer=d;this.VertexIndexBuffer=e;a.AABBmax&&a.AABBmin&&(this.AABBmax=a.AABBmax,this.AABBmin=a.AABBmin,a=MakeAABBLines(this.AABBmax,this.AABBmin),this.DebugAABBBuffer=gl.createBuffer(),
gl.bindBuffer(gl.ARRAY_BUFFER,this.DebugAABBBuffer),gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(a),gl.STATIC_DRAW),this.DebugAABBBuffer.itemSize=3,this.DebugAABBBuffer.numItems=24);this.draw=drawModel;this.drawAABB=drawAABB}function sampledObjModel(a,b){var c=new objmodel(a),d=makeRandomSampleBuffers(a.vertexPositions,a.vertexNormals,a.indices,b);c.RandomSampleBuffer=d[0];c.RandomSampleNormalBuffer=d[1];return c}
function MakeAABBLines(a,b){lines=[];assignFlatVec3(lines,0,a);assignFlatVec3(lines,1,[a[0],a[1],b[2]]);assignFlatVec3(lines,2,[a[0],b[1],a[2]]);assignFlatVec3(lines,3,[a[0],b[1],b[2]]);assignFlatVec3(lines,4,[b[0],b[1],a[2]]);assignFlatVec3(lines,5,b);assignFlatVec3(lines,6,[b[0],a[1],a[2]]);assignFlatVec3(lines,7,[b[0],a[1],b[2]]);assignFlatVec3(lines,8,[a[0],a[1],b[2]]);assignFlatVec3(lines,9,[b[0],a[1],b[2]]);assignFlatVec3(lines,10,a);assignFlatVec3(lines,11,[b[0],a[1],a[2]]);assignFlatVec3(lines,
12,[a[0],b[1],b[2]]);assignFlatVec3(lines,13,b);assignFlatVec3(lines,14,[a[0],b[1],a[2]]);assignFlatVec3(lines,15,[b[0],b[1],a[2]]);assignFlatVec3(lines,16,[a[0],a[1],b[2]]);assignFlatVec3(lines,17,[a[0],b[1],b[2]]);assignFlatVec3(lines,18,a);assignFlatVec3(lines,19,[a[0],b[1],a[2]]);assignFlatVec3(lines,20,[b[0],a[1],b[2]]);assignFlatVec3(lines,21,b);assignFlatVec3(lines,22,[b[0],a[1],a[2]]);assignFlatVec3(lines,23,[b[0],b[1],a[2]]);return lines}
function assignFlatVec3(a,b,c){b*=3;a[b]=c[0];a[b+1]=c[1];a[b+2]=c[2]}
function drawModel(a){gl.useProgram(a);gl.bindBuffer(gl.ARRAY_BUFFER,this.VertexPositionBuffer);gl.vertexAttribPointer(a.vertexPositionAttribute,this.VertexPositionBuffer.itemSize,gl.FLOAT,!1,0,0);gl.bindBuffer(gl.ARRAY_BUFFER,this.VertexNormalBuffer);gl.vertexAttribPointer(a.vertexNormalAttribute,this.VertexNormalBuffer.itemSize,gl.FLOAT,!1,0,0);gl.bindBuffer(gl.ARRAY_BUFFER,this.TextureCoordinateBuffer);gl.vertexAttribPointer(a.textureCoordinateAttribute,this.TextureCoordinateBuffer.itemSize,gl.FLOAT,
!1,0,0);gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,this.VertexIndexBuffer);setMatrixUniforms(a);gl.drawElements(gl.TRIANGLES,this.VertexIndexBuffer.numItems,gl.UNSIGNED_SHORT,0)}function drawAABB(a){gl.useProgram(a);gl.bindBuffer(gl.ARRAY_BUFFER,this.DebugAABBBuffer);gl.vertexAttribPointer(a.vertexPositionAttribute,this.DebugAABBBuffer.itemSize,gl.FLOAT,!1,0,0);setMatrixUniforms(a);gl.drawArrays(gl.LINES,0,this.DebugAABBBuffer.numItems)}
function triangleArea(a,b,c){var d,e,f,h;d=b[0]-a[0];e=b[1]-a[1];f=b[2]-a[2];b=c[0]-a[0];h=c[1]-a[1];c=c[2]-a[2];a=e*c-f*h;f=f*b-d*c;d=d*h-e*b;return Math.sqrt(a*a+f*f+d*d)}function randomTrianglePoint(a,b,c,d,e,f){var h,g,j,k,l;h=Math.random();g=Math.random();1<h+g&&(h=1-h,g=1-g);j=1-h-g;k=h*a[0]+g*b[0]+j*c[0];l=h*a[1]+g*b[1]+j*c[1];a=h*a[2]+g*b[2]+j*c[2];nx=h*d[0]+g*e[0]+j*f[0];ny=h*d[1]+g*e[1]+j*f[1];nz=h*d[2]+g*e[2]+j*f[2];return[[k,l,a],[nx,ny,nz]]}
function getRandomSamples(a,b,c,d){for(var e=[],f=[],h=0,g=0;g<a.length/3;g++)f[g]=[a[3*g],a[3*g+1],a[3*g+2]];a=[];for(g=0;g<b.length/3;g++)a[g]=[b[3*g],b[3*g+1],b[3*g+2]];for(g=0;g<c.length;g+=3)b=[c[g],c[g+1],c[g+2]],b.area=triangleArea(f[b[0]],f[b[1]],f[b[2]]),e[g/3]=b,h+=b.area;e.sort(function(b,a){return b.area-a.area});c=[];b=[];for(var j=0;c.length<3*d;){for(var k=Math.min(Math.ceil(d*e[j].area/h),3*d-c.length),l=f[e[j][0]],s=f[e[j][1]],n=f[e[j][2]],t=a[e[j][0]],m=a[e[j][1]],u=a[e[j][2]],g=
0;g<k;g++){var p=randomTrianglePoint(l,s,n,t,m,u);c.push(p[0][0]);c.push(p[0][1]);c.push(p[0][2]);b.push(p[1][0]);b.push(p[1][1]);b.push(p[1][2])}j++}return[c,b]}
function makeRandomSampleBuffers(a,b,c,d){b=getRandomSamples(a,b,c,d);a=b[0];b=b[1];c=gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER,c);gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(a),gl.STATIC_DRAW);c.itemSize=3;c.numItems=a.length/3;a=gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER,a);gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(b),gl.STATIC_DRAW);a.itemSize=3;a.numItems=b.length/3;return[c,a]}NPR=NPR||{};
NPR.init=function(a){NPR.gl=a;NPR.frame=0;var b={};b.VertexPositionBuffer=a.createBuffer();a.bindBuffer(a.ARRAY_BUFFER,b.VertexPositionBuffer);a.bufferData(a.ARRAY_BUFFER,new Float32Array([-1,-1,0,1,-1,0,1,1,0,1,1,0,-1,1,0,-1,-1,0]),a.STATIC_DRAW);b.VertexPositionBuffer.itemSize=3;b.VertexPositionBuffer.numItems=6;b.TextureCoordinateBuffer=a.createBuffer();a.bindBuffer(a.ARRAY_BUFFER,b.TextureCoordinateBuffer);a.bufferData(a.ARRAY_BUFFER,new Float32Array([0,1,1,1,1,0,1,0,0,0,0,1]),a.STATIC_DRAW);
b.TextureCoordinateBuffer.itemSize=2;b.TextureCoordinateBuffer.numItems=6;NPR.ScreenQuad=b;NPR.TextureShader=new NPR.Shader(" attribute vec3 aVertexPosition; attribute vec2 aTexureCoordinate; varying vec2 vTexCoord; void main(void) { vTexCoord = aTexureCoordinate; gl_Position = vec4(aVertexPosition, 1.0); } "," #ifdef GL_ES\n precision highp float;\n #endif\n uniform sampler2D uTextureSampler; varying vec2 vTexCoord; uniform float uScale; void main(void) { vec2 tc = vTexCoord; if (uScale < 0.0) tc.t = 1.0 - tc.t; vec4 texcol = texture2D(uTextureSampler, tc); gl_FragColor = texcol; } ");
NPR.DrawTexture=function(b,a){var e=NPR.gl;e.disable(e.DEPTH_TEST);e.enable(e.BLEND);e.blendFunc(e.SRC_ALPHA,e.ONE_MINUS_SRC_ALPHA);e.useProgram(NPR.TextureShader.program);e.bindBuffer(e.ARRAY_BUFFER,NPR.ScreenQuad.TextureCoordinateBuffer);var f=e.getAttribLocation(NPR.TextureShader.program,"aTexureCoordinate");e.enableVertexAttribArray(f);e.vertexAttribPointer(f,NPR.ScreenQuad.TextureCoordinateBuffer.itemSize,e.FLOAT,!1,0,0);e.bindBuffer(e.ARRAY_BUFFER,NPR.ScreenQuad.VertexPositionBuffer);f=e.getAttribLocation(NPR.TextureShader.program,
"aVertexPosition");e.enableVertexAttribArray(f);e.vertexAttribPointer(f,NPR.ScreenQuad.VertexPositionBuffer.itemSize,e.FLOAT,!1,0,0);e.activeTexture(e.TEXTURE0);e.bindTexture(e.TEXTURE_2D,b);e.uniform1i(e.getUniformLocation(NPR.TextureShader.program,"uTextureSampler"),0);e.uniform1f(e.getUniformLocation(NPR.TextureShader.program,"uScale"),a?-1:1);e.drawArrays(e.TRIANGLES,0,NPR.ScreenQuad.VertexPositionBuffer.numItems);e.bindBuffer(e.ARRAY_BUFFER,null);e.enable(e.DEPTH_TEST);e.disable(e.BLEND)};NPR.MakeAttributeTexture=
function(b){var a=b.length;if(a)var e=b[0].length;var f=b[0][0].length;if(3!=f&&4!=f)throw"AttributeTextures must have 3 or 4 channels.";for(var h=a*e,g=1;g*g<h;)g<<=1;for(var h=[],j=0,k=0;k<e;k++)for(var l=0;l<a;l++)for(var s=b[l][k],n=0;n<f;n++)h[j]=s[n],++j;for(k=j;k<g*g*f;k++)h[k]=0.1;b=this.gl;if(!b.getExtension("OES_texture_float"))throw"OES_texture_float required for NPR.MakeAttributeTexture";a=b.createTexture();b.bindTexture(b.TEXTURE_2D,a);f=3==f?b.RGB:b.RGBA;b.texParameteri(b.TEXTURE_2D,
b.TEXTURE_WRAP_S,b.CLAMP_TO_EDGE);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_WRAP_T,b.CLAMP_TO_EDGE);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MAG_FILTER,b.NEAREST);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MIN_FILTER,b.NEAREST);b.pixelStorei(b.UNPACK_FLIP_Y_WEBGL,!1);b.texImage2D(b.TEXTURE_2D,0,f,g,g,0,f,b.FLOAT,new Float32Array(h));b.bindTexture(b.TEXTURE_2D,null);a.dim=g;return a}};NPR.update=function(){NPR.frame++};NPR=NPR||{};
(function(){NPR.start=function(a){document.onkeydown=NPR.handleKeyDown;document.onkeyup=NPR.handleKeyUp;!NPR.gl&&a&&NPR.initGL(a);NPR.init(NPR.gl);(window.drawScene||window.draw)&&window.update&&NPR.requestAnimFrame.call(window,NPR.tick)};NPR.initGL=function(a){try{var b=a.getContext("experimental-webgl",{preserveDrawingBuffer:!0});b.viewportWidth=a.width;b.viewportHeight=a.height;return NPR.gl=b}catch(c){}b||alert("Couldn't initialize WebGL.")};NPR.requestAnimFrame=window.requestAnimationFrame||
window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(a){window.setTimeout(a,1E3/60)};NPR.tick=function(){(window.drawScene||window.draw)&&window.update&&NPR.requestAnimFrame.call(window,NPR.tick);window.drawScene?drawScene():window.draw&&draw();window.update&&update()};NPR.keys={};NPR.handleKeyDown=function(a){NPR.keys[a.keyCode]=!0};NPR.handleKeyUp=function(a){NPR.keys[a.keyCode]=!1};NPR.mvMatrixStack=[];NPR.mvMatrix=
mat4.create();NPR.pMatrix=mat4.create();mat4.identity(NPR.mvMatrix);mat4.identity(NPR.pMatrix);NPR.mvPushMatrix=function(){var a=mat4.create();mat4.set(NPR.mvMatrix,a);NPR.mvMatrixStack.push(a)};NPR.mvPopMatrix=function(){if(0==NPR.mvMatrixStack.length)throw"Invalid popMatrix.";NPR.mvMatrix=NPR.mvMatrixStack.pop()};NPR.loadTexture=function(a,b){var c=NPR.gl.createTexture();c.image=new Image;c.image.onload=b?function(){b(c)}:function(){c.image.loaded=!0;NPR.handleLoadedTexture(c)};c.image.src=a;return c};
NPR.handleLoadedTexture=function(a){var b=NPR.gl;b.pixelStorei(b.UNPACK_FLIP_Y_WEBGL,!0);b.bindTexture(b.TEXTURE_2D,a);b.texImage2D(b.TEXTURE_2D,0,b.RGBA,b.RGBA,b.UNSIGNED_BYTE,a.image);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MAG_FILTER,b.LINEAR);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MIN_FILTER,b.LINEAR_MIPMAP_LINEAR);b.generateMipmap(b.TEXTURE_2D);b.bindTexture(b.TEXTURE_2D,null)};NPR.loadCustomMipmap=function(a){function b(b,a){return function(){f--;if(0==f){c.pixelStorei(c.UNPACK_FLIP_Y_WEBGL,
!0);c.bindTexture(c.TEXTURE_2D,a);c.texParameteri(c.TEXTURE_2D,c.TEXTURE_MAG_FILTER,c.LINEAR);c.texParameteri(c.TEXTURE_2D,c.TEXTURE_MIN_FILTER,c.LINEAR_MIPMAP_LINEAR);for(var b=0;b<a.images.length;b++)c.texImage2D(c.TEXTURE_2D,b,c.RGBA,c.RGBA,c.UNSIGNED_BYTE,a.images[b]),0==b&&c.generateMipmap(c.TEXTURE_2D);c.bindTexture(c.TEXTURE_2D,null)}}}var c=NPR.gl,d=c.createTexture();d.images=[];for(var e=a.length,f=e,h=0;h<e;h++)d.images[h]=new Image,d.images[h].src=a[h],d.images[h].onload=b(h,d);return d};
NPR.canvasTexture=function(a){var b=NPR.gl,c=b.createTexture();b.pixelStorei(b.UNPACK_FLIP_Y_WEBGL,!0);b.bindTexture(b.TEXTURE_2D,c);b.texImage2D(b.TEXTURE_2D,0,b.RGBA,b.RGBA,b.UNSIGNED_BYTE,a);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MAG_FILTER,b.LINEAR);b.texParameteri(b.TEXTURE_2D,b.TEXTURE_MIN_FILTER,b.LINEAR_MIPMAP_LINEAR);b.generateMipmap(b.TEXTURE_2D);b.bindTexture(b.TEXTURE_2D,null);return c}})();NPR=NPR||{};
(function(){NPR.Brush=function(b,a){this.Properties=function(){return new NPR.BrushProperties(this.size,this.color,this.hardness)};b&&(this.dest_ctx=b);a&&this.setBrushImage(a)};var a=NPR.Brush;a.prototype.Draw=function(b,a,d){(d?d:this.dest_ctx).drawImage(this.brush_image,b-this.r/2,a-this.r/2)};a.prototype.DrawLine=function(b,a,d,e,f){f=f?f:this.dest_ctx;b=d-b;a=e-a;for(var h=Math.sqrt(b*b+a*a),g=0;g<2*(h/this.r);g++)f.drawImage(this.brush_image,d-this.r/2-g/h*this.r*b/2,e-this.r/2-g/h*this.r*a/
2)};a.prototype.fromProperties=function(b){this.makeBrushImage(b.size,b.hardness,b.color)};a.prototype.setBrushImage=function(b){this.brush_image=b;this.r=b.width};a.prototype.makeBrushImage=function(b,a,d,e){this.r=b;this.hardness=a;this.color=d;this.setBrushImage(NPR.makeBrushImage(b,a,d,e))};a.prototype.setColor=function(b){this.makeBrushImage(this.r,this.hardness,b)};a.prototype.setSize=function(b){this.makeBrushImage(b,this.hardness,this.color)};a.prototype.setHardness=function(b){this.makeBrushImage(this.r,
b,this.color)};NPR.BrushProperties=function(b,a,d){this.size=b||32;this.color=a||[0,0,0,1];this.hardness=void 0==d?0.9:d};NPR.PaintSession=function(b){this.beginStroke=function(b,a){this.newstroke=[];this.newstroke[0]=[b,a]};this.nextPoint=function(b,a){this.newstroke.push([b,a])};this.endStroke=function(){this.newstroke&&this.actions.push(this.newstroke);this.newstroke=void 0;console.log("Actions:"+this.actions.length)};this.addStroke=function(b){this.actions.push(b)};this.drawStroke=function(b){for(var a=
0;a<b.length;a++)this.brush.Draw(b[a][0],b[a][1])};this.undo=function(){this.actions.pop();ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);for(var b=0;b<this.actions.length;b++)this.actions[b]instanceof Array&&this.drawStroke(this.actions[b])};this.setBrush=function(b){this.brush=b;new_properties=b.Properties();this.brush&&this.actions[this.actions.length-1]instanceof NPR.BrushProperties?this.actions[this.actions.length-1]=new_properties:this.actions.push(b.Properties())};this.actions=[];this.sctx=
b};NPR.makeBrushImage=function(b,a,d,e){e=e?e:document.createElement("canvas");e.width=b;e.height=b;var f=e.getContext("2d");a=Math.max(Math.min(a,0.9999),0);var h=b/2;a=f.createRadialGradient(h,h,a*h,h,h,h);a.addColorStop(0,"rgba("+d[0]+","+d[1]+","+d[2]+","+d[3]+")");a.addColorStop(1,"rgba("+d[0]+","+d[1]+","+d[2]+",0)");f.fillStyle=a;f.clearRect(0,0,b,b);f.fillRect(0,0,b,b);f.fill();return e}})();NPR=NPR||{};NPR.Polygon=function(a){this.points=[];this.ctx=a?a.getContext("2d"):null};
NPR.Polygon.prototype.TRIANGLES=0;NPR.Polygon.prototype.TRIANGLE_STRIP=1;NPR.Polygon.prototype.TRIANGLE_FAN=2;NPR.Polygon.prototype.polyType=-1;NPR.Polygon.prototype.addPoint=function(a,b){this.points.push([a,b])};NPR.Polygon.prototype.makeOutlinePolygon=function(){throw"Abstract Method NPR.Polygon::makeOutlinePolygon() called.";};NPR.Polygon.prototype.draw=function(){throw"Abstract Method NPR.Polygon::draw() called.";};
NPR.Polygon.prototype.drawTriangle=function(a,b,c,d){if(!this.ctx&&!d)throw"NPR.Polygon::drawTriangle called with no canvas context.";d=d?d:this.ctx;d.fillStyle="#fff";d.beginPath();d.moveTo(a[0],a[1]);d.lineTo(b[0],b[1]);d.lineTo(c[0],c[1]);d.lineTo(a[0],a[1]);d.closePath();d.fill();d.stroke()};
NPR.Polygon.prototype.getNormalized=function(){for(var a=[],b=this.points,c=b[0][0],d=b[0][1],e=b[0][0],f=b[0][1],h=0;h<b.length;h++)c=b[h][0]<c?b[h][0]:c,d=b[h][1]<d?b[h][1]:d,e=b[h][0]>e?b[h][0]:e,f=b[h][1]>f?b[h][1]:f;for(var h=Math.abs(e-c),g=Math.abs(f-d),j=Math.min(1,h/g),g=Math.min(1,g/h),h=0;h<b.length;h++)a.push([(b[h][0]-c)/(e-c)*j,(1-(b[h][1]-d)/(f-d))*g]);return a};NPR.Polygon.prototype.flatten=function(a){for(var b=[],c=0;c<a.length;c++)b.push(a[c][0]),b.push(a[c][1]);return b};
NPR.Polygon.prototype.getNormalizedFlattened=function(){return this.flatten(this.getNormalized())};NPR.Polygon.prototype.getNormalizedFlattenedTriangles=function(){return this.getFlattenedTriangles(this.getNormalized())};NPR.Polygon.prototype.getFlattenedTriangles=function(){throw"Abstract Method NPR.Polygon::getFlattenedTriangles() called.";};
NPR.Polygon.prototype.makeVertexBuffer=function(a){var b=a.createBuffer();a.bindBuffer(a.ARRAY_BUFFER,b);a.bufferData(a.ARRAY_BUFFER,new Float32Array(this.getNormalizedFlattened()),a.STATIC_DRAW);b.itemSize=2;b.numItems=this.points.length;return b};
NPR.Polygon.prototype.makeInstancedVertexBuffer=function(a,b,c){var d=c?c:this.getNormalizedFlattenedTriangles();c=[];for(var e=[],f=d.length,h=0;h<b;h++){for(var g=0;g<f;g++)c[g+f*h]=d[g];for(g=0;g<f/2;g++)e[g+f/2*h]=h}b=a.createBuffer();a.bindBuffer(a.ARRAY_BUFFER,b);a.bufferData(a.ARRAY_BUFFER,new Float32Array(c),a.STATIC_DRAW);b.itemSize=2;b.numItems=c.length/2;d=a.createBuffer();a.bindBuffer(a.ARRAY_BUFFER,d);a.bufferData(a.ARRAY_BUFFER,new Float32Array(e),a.STATIC_DRAW);d.itemSize=1;d.numItems=
c.length/2;return{VertexPositionBuffer:b,InstanceIDBuffer:d}};NPR.Polygon.prototype.makeInstancedOutlineBuffer=function(a,b){return this.makeInstancedVertexBuffer(a,b)};NPR.TriStrip=function(a){NPR.Polygon.call(this,a);this.draw=function(b){var a=this.points;if(3>a.length)throw"NPR.TriStrip.draw() called with fewer than 3 points.";for(var d=2;d<a.length;d++)this.drawTriangle(a[d-2],a[d-1],a[d],b)}};NPR.TriStrip.prototype=Object.create(NPR.Polygon.prototype);NPR.TriStrip.prototype.polyType=NPR.Polygon.prototype.TRIANGLE_STRIP;
NPR.TriStrip.prototype.getFlattenedTriangles=function(a){a=a?a:this.points;a=this.flatten(a);for(var b=[],c=4;c<a.length;c+=2)c/3&1?(b.push(a[c-2]),b.push(a[c-1]),b.push(a[c-4]),b.push(a[c-3])):(b.push(a[c-4]),b.push(a[c-3]),b.push(a[c-2]),b.push(a[c-1])),b.push(a[c]),b.push(a[c+1]);return b};
NPR.TriStrip.prototype.makeOutlinePolygon=function(a,b){for(var c=new NPR.TriStrip,d=b?this.getNormalized():this.points,e=[],f=[],h=0;h<d.length;h++)0==(h+1)%2?e.push(d[h]):f.push(d[h]);d=f.concat(e.reverse());for(h=0;h<d.length;h++){e=d[h];if(0==h)f=[0,0];else if(h==d.length-1)f=[0,0];else{var g=d[h-1],j=d[h+1],f=[e[0]-g[0],e[1]-g[1]],k=Math.sqrt(f[0]*f[0]+f[1]*f[1]);f[0]/=k;f[1]/=k;var k=[e[0]-j[0],e[1]-j[1]],l=Math.sqrt(k[0]*k[0]+k[1]*k[1]);k[0]/=l;k[1]/=l;g=(e[0]-g[0])*(j[1]-g[1])-(e[1]-g[1])*
(j[0]-g[0]);1E-5>Math.abs(g-1)?f=[-vp0[1],vp0[0]]:(f=[f[0]+k[0],f[1]+k[1]],j=Math.sqrt(f[0]*f[0]+f[1]*f[1]),f[0]/=j,f[1]/=j)}j=0<g||0==h||h==d.length-1?-1:1;j*=b?1:-1;f[0]=f[0]*a*j;f[1]=f[1]*a*j;c.addPoint(e[0]+f[0],e[1]+f[1]);c.addPoint(e[0],e[1])}return c};NPR.TriFan=function(a){NPR.Polygon.call(this,a);this.draw=function(b){var a=this.points;if(3>a.length)throw"NPR.TriFan.draw() called with fewer than 3 points.";for(var d=2;d<a.length;d++)this.drawTriangle(a[0],a[d-1],a[d],b)}};
NPR.TriFan.prototype=Object.create(NPR.Polygon.prototype);NPR.TriFan.prototype.polyType=NPR.Polygon.prototype.TRIANGLE_FAN;NPR.TriFan.prototype.getFlattenedTriangles=function(a){a=a?a:this.points;a=this.flatten(a);for(var b=[],c=4;c<a.length;c+=2)b.push(a[0]),b.push(a[1]),b.push(a[c-2]),b.push(a[c-1]),b.push(a[c]),b.push(a[c+1]);return b};
NPR.TriFan.prototype.makeOutlinePolygon=function(a,b){var c=new NPR.TriStrip,d=b?this.getNormalized():this.points;d.splice(0,1);for(var e=0;e<d.length;e++){var f,h=d[e];if(0==e)f=[0,0];else if(e==d.length-1)f=[0,0];else{var g=d[e-1],j=d[e+1];f=[h[0]-g[0],h[1]-g[1]];var k=Math.sqrt(f[0]*f[0]+f[1]*f[1]);f[0]/=k;f[1]/=k;var k=[h[0]-j[0],h[1]-j[1]],l=Math.sqrt(k[0]*k[0]+k[1]*k[1]);k[0]/=l;k[1]/=l;g=(h[0]-g[0])*(j[1]-g[1])-(h[1]-g[1])*(j[0]-g[0]);1E-5>Math.abs(g-1)?f=[-vp0[1],vp0[0]]:(f=[f[0]+k[0],f[1]+
k[1]],j=Math.sqrt(f[0]*f[0]+f[1]*f[1]),f[0]/=j,f[1]/=j)}j=0<g||0==e||e==d.length-1?-1:1;j*=b?-1:1;f[0]=f[0]*a*j;f[1]=f[1]*a*j;c.addPoint(h[0]+f[0],h[1]+f[1]);c.addPoint(h[0],h[1])}return c};
NPR.Triangles=function(a){NPR.Polygon.call(this,a);this.draw=function(b){var a=this.points;if(3>a.length)throw"NPR.Triangles.draw() called with fewer than 3 points.";for(var d=2;d<a.length;d+=3)this.drawTriangle(a[d-2],a[d-1],a[d],b);if(d!=a.length)throw"NPR.Triangles.draw() called with an incomplete number of points.";}};NPR.Triangles.prototype=Object.create(NPR.Polygon.prototype);NPR.Triangles.prototype.makeOutlinePolygon=function(){throw"TODO NPR.Triangles.prototype.makeOutlinePolygon";};
NPR.Triangles.prototype.getFlattenedTriangles=function(a){return this.flatten(a?a:this.points)};NPR.Triangles.prototype.polyType=NPR.Polygon.prototype.TRIANGLES;NPR=NPR||{};NPR.RenderPass=function(a){this.shader=a;this.framebuffer=new NPR.Framebuffer};NPR.RenderPass.prototype.draw=function(a){this.lastframe!=NPR.frame&&(this.lastframe=NPR.frame,this.updateFramebuffer(a));NPR.DrawTexture(this.framebuffer.texture)};
NPR.RenderPass.prototype.updateFramebuffer=function(a){var b=NPR.gl;this.framebuffer.bind();b.viewport(0,0,this.framebuffer.fbo.width,this.framebuffer.fbo.height);b.clear(b.COLOR_BUFFER_BIT|b.DEPTH_BUFFER_BIT);this.drawImmediate(a);this.framebuffer.release()};NPR.RenderPass.prototype.drawImmediate=function(a){a?a(this.shader):this.drawCall(this.shader)};NPR.RenderPass.prototype.setDrawCall=function(a){this.drawCall=a};NPR.RenderPass.prototype.setUniforms=function(a){this.shader.setUniforms(a)};
NPR.RenderPass.prototype.setMatrixUniforms=function(a,b,c){this.shader.setMatrixUniforms(a,b,c)};NPR.RenderPass.prototype.bindTexture=function(){this.framebuffer.bindTexture()};NPR.PostProcessPass=function(){};NPR.PostProcessPass.prototype=Object.create(NPR.RenderPass.prototype);NPR=NPR||{};
NPR.Shader=function(a,b){function c(b,a){var c=d.createShader(b);d.shaderSource(c,a);d.compileShader(c);if(!d.getShaderParameter(c,d.COMPILE_STATUS))throw"compile error: "+d.getShaderInfoLog(c);return c}var d=NPR.gl;this.program=d.createProgram();d.attachShader(this.program,c(d.VERTEX_SHADER,a));d.attachShader(this.program,c(d.FRAGMENT_SHADER,b));d.linkProgram(this.program);if(!d.getProgramParameter(this.program,d.LINK_STATUS))throw"link error: "+d.getProgramInfoLog(this.program);this.attributes=
{};for(var e={},f=/uniform\s+sampler(1D|2D|3D|Cube)\s+(\w+)\s*;/g,h=a+b;null!=(result=f.exec(h));)e[result[2]]=1;this.isSampler=e;this.setUniforms=function(b){d.useProgram(this.program);for(var a in b){var c=d.getUniformLocation(this.program,a);if(c){var e=b[a],f=Object.prototype.toString.call(e);if("[object Array]"==f||"[object Float32Array]"==f)switch(e.length){case 1:d.uniform1fv(c,new Float32Array(e));break;case 2:d.uniform2fv(c,new Float32Array(e));break;case 3:d.uniform3fv(c,new Float32Array(e));
break;case 4:d.uniform4fv(c,new Float32Array(e));break;case 9:d.uniformMatrix3fv(c,!1,new Float32Array(e));break;case 16:d.uniformMatrix4fv(c,!1,new Float32Array(e));break;default:throw"don't know how to load uniform \""+a+'" of length '+e.length;}else if(f=Object.prototype.toString.call(e),"[object Number]"==f||"[object Boolean]"==f)(this.isSampler[a]?d.uniform1i:d.uniform1f).call(d,c,e);else throw'attempted to set uniform "'+a+'" to invalid value '+e;}}};d.useProgram(this.program);this.pMatrixUniform=
d.getUniformLocation(this.program,"uPMatrix");this.mvMatrixUniform=d.getUniformLocation(this.program,"uMVMatrix");this.nMatrixUniform=d.getUniformLocation(this.program,"uNMatrix");this.setMatrixUniforms=function(a,b,c){d.useProgram(this.program);this.mvMatrixUniform&&a&&d.uniformMatrix4fv(this.mvMatrixUniform,!1,a);this.pMatrixUniform&&b&&d.uniformMatrix4fv(this.pMatrixUniform,!1,b);this.nMatrixUniform&&c&&d.uniformMatrix3fv(this.nMatrixUniform,!1,c)};this.drawModel=function(a,b,c,e){d.useProgram(this.program);
for(buffer in this.attributes){if(!a[buffer])throw"drawing error: missing buffer: "+buffer;d.bindBuffer(d.ARRAY_BUFFER,a[buffer]);d.vertexAttribPointer(this.attributes[buffer],a[buffer].itemSize,d.FLOAT,!1,0,0);d.enableVertexAttribArray(this.attributes[buffer])}e=!c&&a.VertexIndexBuffer||e;c&&(a[c]&&!e)&&(d.bindBuffer(e?d.ELEMENT_ARRAY_BUFFER:d.ARRAY_BUFFER,a[c]),d.vertexAttribPointer(this.attributes.VertexPositionBuffer,a[c].itemSize,d.FLOAT,!1,0,0),d.enableVertexAttribArray(this.attributes.VertexPositionBuffer));
b=void 0!==b?b:d.TRIANGLES;c=c&&a[c]?c:a.VertexIndexBuffer?"VertexIndexBuffer":"VertexPositionBuffer";e?(d.bindBuffer(d.ELEMENT_ARRAY_BUFFER,a[c]),d.drawElements(b,a[c].numItems,d.UNSIGNED_SHORT,0),d.bindBuffer(d.ELEMENT_ARRAY_BUFFER,null)):(d.bindBuffer(d.ARRAY_BUFFER,a[c]),d.drawArrays(b,0,a[c].numItems),d.bindBuffer(d.ARRAY_BUFFER,null))};this.bind=function(){d.useProgram(this.program)};this.release=function(){d.useProgram(null)}};NPR=NPR||{};
NPR.DepthPass=function(a){NPR.RenderPass.call(this);var b=NPR.gl,c=" #ifdef GL_ES\n \tprecision highp float;\n #endif\n uniform float uNear; uniform float uFar; \n#ifdef PACK_FLOAT\n vec3 pack(float f) { vec3 v = fract(f * vec3(1.0, 256.0, 65536.0)); v = floor(v * 256.0) / 256.0; return v; } \n#endif\n float linearizeDepth(float d) { float n = uNear + 0.00001; return (2.0 * n) / (uFar + n - d * (uFar - n)); } void main(void) { \tfloat depth = linearizeDepth(gl_FragCoord.z); \n#ifdef PACK_FLOAT\n gl_FragColor.rgb = pack(depth); \n#else\n gl_FragColor.r = depth; gl_FragColor.g = gl_FragColor.r; gl_FragColor.b = gl_FragColor.r; \n#endif\n gl_FragColor.a = 1.0; } ";
a&&(c="#define PACK_FLOAT\n"+c);this.shader=new NPR.Shader(" attribute vec3 aVertexPosition; uniform mat4 uMVMatrix; uniform mat4 uPMatrix; uniform mat3 uNMatrix; void main(void) { \tgl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0); } ",c);this.shader.attributes={VertexPositionBuffer:b.getAttribLocation(this.shader.program,"aVertexPosition")}};
NPR.RenderPass.prototype.updateFramebuffer=function(a){var b=NPR.gl;this.framebuffer.bind();b.clearColor(1,1,1,1);b.clear(b.COLOR_BUFFER_BIT|b.DEPTH_BUFFER_BIT);b.viewport(0,0,this.framebuffer.fbo.width,this.framebuffer.fbo.height);b.clear(b.COLOR_BUFFER_BIT|b.DEPTH_BUFFER_BIT);this.drawImmediate(a);this.framebuffer.release()};NPR.DepthPass.prototype=Object.create(NPR.RenderPass.prototype);NPR=NPR||{};
NPR.PainterlyBillboardPass=function(a,b){var c=!1,d=!1;"texture"==b?(c=!0,d=!1):"value"==b?(c=!1,d=!0):(c="none"==b?!1:!0,d=!1);NPR.RenderPass.call(this);var e=NPR.gl,f="";a&&(f+="\n#define DO_SCALE\n");c&&(f+="\n#define ORIENTATION_TEXTURE\n");d&&(f+="\n#define ORIENTATION_UNIFORM\n");!c&&!d&&(f+="\n#define NO_ORIENTATION\n");this.shader=new NPR.Shader(f+" attribute vec3 aVertexPosition; attribute vec3 aVertexNormal; uniform mat4 uMVMatrix; uniform mat4 uPMatrix; uniform mat3 uNMatrix; uniform sampler2D uBrushTexture; uniform sampler2D uColorTexture; /* In this implementation, controls both size and opacity */ uniform sampler2D uSizeTexture; uniform sampler2D uOrientationTexture; uniform vec2 uBaseDimensions; uniform vec2 uOrientation; varying float rdist; /* The radius that must be accomodated for rotation. */ varying vec2 vDim; varying vec3 vColor; varying float nz; varying float size_factor; \n#ifndef NO_ORIENTATION\n varying float angle; \n#endif\n void main(void) { float pi = 3.14159265358; gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0); vec2 screen_coord = gl_Position.xy / 2.0 / gl_Position.w + vec2(0.5, 0.5); vColor = texture2D(uColorTexture, screen_coord).rgb; \n#ifdef ORIENTATION_TEXTURE\n vec2 orientation = texture2D(uOrientationTexture, screen_coord).rg; \n#else\n \n#ifdef ORIENTATION_UNIFORM\n vec2 orientation = uOrientation; \n#endif\n \n#endif\n \n#ifndef NO_ORIENTATION\n angle = atan(orientation.y - 0.5, orientation.x - 0.5) + 3.0 * pi / 4.0; \n#endif\n size_factor = texture2D(uSizeTexture, screen_coord).x; nz = (uNMatrix * aVertexNormal).z; vDim = uBaseDimensions; \n#ifdef DO_SCALE\n vDim = uBaseDimensions * size_factor; \n#endif\n vDim = max(vDim, vec2(0.2,0.2)); rdist = 0.5 * length(vDim); \n#ifdef NO_ORIENTATION\n rdist = max(vDim.x,vDim.y) * 2.0; \n#endif\n /* FYI: On many configurations gl_PointSize is capped at 64. */ gl_PointSize = 2.0 * rdist; /* A hack to hide back-facing points. */ \tif (nz <= 0.5) { gl_PointSize = 0.0; } } ",
f+" #ifdef GL_ES\n \tprecision highp float;\n #endif\n uniform sampler2D uBrushTexture; uniform vec2 uBaseDimensions; varying float rdist; varying vec3 vColor; varying vec2 vDim; varying float nz; varying float size_factor; \n#ifndef NO_ORIENTATION\n varying float angle; \n#endif\n void main(void) { if(nz<=0.5) discard; \n#ifndef NO_ORIENTATION\n /* Here is where we rotate the point sprite. */ vec2 offset = gl_PointCoord - vec2(0.5,0.5); float ox = offset.x; offset.x = offset.x * cos(angle) - offset.y * sin(angle); offset.y = ox * sin(angle) + offset.y * cos(angle); offset = offset / vec2(vDim.x / rdist / 2.0, vDim.y / rdist / 2.0); offset = offset + vec2(0.5, 0.5); \n#else\n vec2 offset = gl_PointCoord; \n#endif\n vec4 texCol = texture2D(uBrushTexture, offset); if (offset.x < 0.0 || offset.y < 0.0 || offset.x > 1.0 || offset.y > 1.0) { texCol = vec4(0.0,0.0,0.0,0.0); } gl_FragColor.a = min(0.9, texCol.a * 1.0); gl_FragColor.rgb = vColor.rgb * gl_FragColor.a; } ");
this.attributes={RandomSampleBuffer:e.getAttribLocation(this.shader.program,"aVertexPosition"),RandomSampleNormalBuffer:e.getAttribLocation(this.shader.program,"aVertexNormal")};this.uniforms={uBaseDimensions:e.getUniformLocation(this.shader.program,"uBaseDimensions"),uBrushTexture:e.getUniformLocation(this.shader.program,"uBrushTexture"),uOrientation:e.getUniformLocation(this.shader.program,"uOrientation")};this.internal_uniforms={uColorTexture:e.getUniformLocation(this.shader.program,"uColorTexture"),
uOrientationTexture:e.getUniformLocation(this.shader.program,"uOrientationTexture"),uSizeTexture:e.getUniformLocation(this.shader.program,"uSizeTexture")};this.shader.attributes=this.attributes;this.shader.uniforms=this.uniforms;e.useProgram(this.shader.program);e.uniform2fv(this.uniforms.uBaseDimensions,[20,20]);e.uniform2fv(this.uniforms.uOrientation,[0.5,0.5]);this.OrientationPass=this.SizePass=this.ColorPass=void 0;this.children={ColorPass:void 0,SizePass:void 0,OrientationPass:void 0};this.drawModel=
function(a){this.shader.drawModel(a,e.POINTS,"RandomSampleBuffer")};this.draw=function(a){this.ColorPass.updateFramebuffer(a);this.SizePass.updateFramebuffer(a);this.OrientationPass.updateFramebuffer(a);e.enable(e.BLEND);e.disable(e.DEPTH_TEST);e.blendFunc(e.ONE,e.ONE_MINUS_SRC_ALPHA);e.activeTexture(e.TEXTURE0);this.ColorPass.framebuffer.bindTexture();e.activeTexture(e.TEXTURE2);this.SizePass.framebuffer.bindTexture();e.activeTexture(e.TEXTURE3);this.OrientationPass.framebuffer.bindTexture();this.shader.setUniforms({uColorTexture:0,
uBrushTexture:1,uSizeTexture:2,uOrientationTexture:3});this.lastframe!=NPR.frame&&(this.lastframe=NPR.frame,this.updateFramebuffer(a));NPR.DrawTexture(this.framebuffer.texture)}};NPR.PainterlyBillboardPass.prototype=Object.create(NPR.RenderPass.prototype);NPR=NPR||{};
NPR.ColorLightDirShader=function(){var a=NPR.gl;NPR.Shader.call(this," attribute vec3 aVertexPosition; attribute vec3 aVertexNormal; uniform mat4 uMVMatrix; uniform mat4 uPMatrix; uniform mat3 uNMatrix; uniform vec3 uLightDir; varying float vLightIntensity; void main(void) { vLightIntensity = dot(uLightDir, uNMatrix * aVertexNormal); \tgl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0); } "," #ifdef GL_ES\n \tprecision highp float;\n #endif\n uniform vec3 uColor; varying float vLightIntensity; void main(void) { gl_FragColor.rgb = mix(vec3(0,0,0), uColor, vLightIntensity); gl_FragColor.a = 1.0; } ");
this.attributes={VertexPositionBuffer:a.getAttribLocation(this.program,"aVertexPosition"),VertexNormalBuffer:a.getAttribLocation(this.program,"aVertexNormal")}};NPR.ColorLightDirShader.prototype=Object.create(NPR.Shader.prototype);NPR=NPR||{};
NPR.ColorShader=function(){var a=NPR.gl;NPR.Shader.call(this," attribute vec3 aVertexPosition; uniform mat4 uMVMatrix; uniform mat4 uPMatrix; uniform mat3 uNMatrix; void main(void) { \tgl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0); } "," #ifdef GL_ES\n \tprecision highp float;\n #endif\n uniform vec4 uColor; void main(void) { gl_FragColor = uColor; } ");this.attributes={VertexPositionBuffer:a.getAttribLocation(this.program,"aVertexPosition")}};
NPR.ColorShader.prototype=Object.create(NPR.Shader.prototype);NPR=NPR||{};
NPR.DepthShader=function(){var a=NPR.gl;NPR.Shader.call(this," attribute vec3 aVertexPosition; uniform mat4 uMVMatrix; uniform mat4 uPMatrix; uniform mat3 uNMatrix; void main(void) { \tgl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0); } "," #ifdef GL_ES\n \tprecision highp float;\n #endif\n uniform float uNear; uniform float uFar; float linearizeDepth(float d) { float n = uNear + 0.00001; return (2.0 * n) / (uFar + n - d * (uFar - n)); } void main(void) { \t float depth = linearizeDepth(gl_FragCoord.z); gl_FragColor.r = depth; gl_FragColor.g = gl_FragColor.r; gl_FragColor.b = gl_FragColor.r; gl_FragColor.a = 1.0; } ");this.attributes=
{VertexPositionBuffer:a.getAttribLocation(this.program,"aVertexPosition")}};NPR.DepthShader.prototype=Object.create(NPR.Shader.prototype);NPR=NPR||{};
NPR.FacingRatioOutlineShader=function(){var a=NPR.gl;NPR.Shader.call(this," attribute vec3 aVertexPosition; attribute vec3 aVertexNormal; uniform mat4 uMVMatrix; uniform mat4 uPMatrix; uniform mat3 uNMatrix; varying float vFacingRatio; void main(void) { /* Facing Ratio */ vec3 mvn = uNMatrix * aVertexNormal; vFacingRatio = dot(normalize(mvn), vec3(0,0,1)); \tgl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0); } "," #ifdef GL_ES\n \tprecision highp float;\n #endif\n uniform vec3 uColor; uniform vec3 uOutlineColor; varying float vFacingRatio; void main(void) { float val = smoothstep(0.0, 0.4, vFacingRatio-0.2); gl_FragColor.rgb = mix(uOutlineColor, uColor, val); gl_FragColor.a = 1.0; } ");
this.attributes={VertexPositionBuffer:a.getAttribLocation(this.program,"aVertexPosition"),VertexNormalBuffer:a.getAttribLocation(this.program,"aVertexNormal")}};NPR.FacingRatioOutlineShader.prototype=Object.create(NPR.Shader.prototype);NPR=NPR||{};
NPR.GraftalShader=function(){var a=NPR.gl;NPR.Shader.call(this,"\t uniform mat4 uMVMatrix;\t uniform mat4 uPMatrix;\t uniform mat3 uNMatrix;\t uniform sampler2D uInstanceAttrTex;\t uniform float uAttrTexDim;\t uniform float uScale;\t uniform vec3 uOffset;\t \t attribute vec2 aVertexPosition;\t attribute float aInstanceID;\t \t varying float vFacingRatio;\t \t /* Function to look up cell from the attribute texture. */\t vec2 attrTexCell(float idx) {\t \tfloat r = floor(idx / uAttrTexDim);\t \tfloat c = mod(idx, uAttrTexDim);\t \tfloat drc = 0.5 / uAttrTexDim;\t \tvec2 attrTc = vec2(c/uAttrTexDim+drc, r/uAttrTexDim+drc);\t \treturn attrTc;\t }\t \t void main(void) {\t \tvec2 attrTc = attrTexCell(2.0 * aInstanceID);\t \tvec4 instpos = texture2D(uInstanceAttrTex, attrTc);\t \tvec3 instnorm = texture2D(uInstanceAttrTex, attrTexCell(2.0 * aInstanceID + 1.0)).xyz;\t \tvec4 mvpos = uMVMatrix * instpos;\t \tmvpos.z = mvpos.z + uOffset.z;\t \tvec4 mvppos = uPMatrix * mvpos;\t \t\t \t/* Project the normal to the screen */ \t \t/*vec4 p1 = mvppos;\t \tvec4 p2 = instpos + vec4(instnorm.xyz, 1.0);\t \tp2 = uPMatrix * uMVMatrix * p2;\t \tvec3 projnorm = (p2 - p1).xyz;\t \tprojnorm = normalize(projnorm);\t projnorm.z = 0.0;\t vFacingRatio = length(projnorm);\t \tprojnorm = normalize(projnorm);*/\t \tvec3 projnorm = uNMatrix * instnorm.xyz;\t \tprojnorm.z = 0.0;\t \tprojnorm = normalize(projnorm);\t \t\t \t/* Facing Ratio */\t \tvec3 mvn = uNMatrix * instnorm;\t \tvFacingRatio = dot(normalize(mvn),vec3(0,0,1));\t \t\t\t/* Get position rotated around screen normal */\t\tvec2 rotpos = aVertexPosition + vec2(-.25, -.1);\t\trotpos = rotpos * uScale;\t\trotpos.xy = rotpos.xy + uOffset.xy;\t\tfloat pi = 3.14159265358;\t\tfloat angle = atan(projnorm.y, projnorm.x) - pi/2.0;\t\tfloat ox = rotpos.x;\t\trotpos.x = rotpos.x * cos(angle) - rotpos.y * sin(angle); rotpos.y = ox * sin(angle) + rotpos.y * cos(angle);\t \t\t \tgl_Position = mvppos;\t \tgl_Position.xy = gl_Position.xy + rotpos;\t }\t","\tprecision mediump float;\t\tuniform vec3 uColor;\tuniform vec3 uFadeColor;\t\tvarying float vFacingRatio;\tvoid main(void) {\t gl_FragColor = vec4(uColor, 1.0);\t if (vFacingRatio > 0.7) {\t float fade = (vFacingRatio-.7)/.3;\t gl_FragColor.rgb = mix(gl_FragColor.rgb, uFadeColor, fade);\t }\t if(vFacingRatio<-0.5) discard;\t}\t");
this.attributes={VertexPositionBuffer:a.getAttribLocation(this.program,"aVertexPosition"),InstanceIDBuffer:a.getAttribLocation(this.program,"aInstanceID")}};NPR.GraftalShader.prototype=Object.create(NPR.Shader.prototype);NPR=NPR||{};
NPR.HatchBillboardShader=function(){var a=NPR.gl;NPR.Shader.call(this," uniform float uYaw; uniform float uPitch; uniform mat4 uMVMatrix; uniform mat4 uPMatrix; uniform mat3 uNMatrix; uniform float uAttrTexDim; uniform vec2 uScale; uniform vec3 uLightDir; uniform sampler2D uLappedMask; uniform sampler2D uTamTex1; uniform sampler2D uTamTex2; uniform sampler2D uInstanceAttrTex; attribute vec2 aVertexPosition; attribute float aInstanceID; varying vec2 vTexCoord; varying float vFacingRatio; varying float vLightIntensity; vec2 attrTexCell(float idx) { float r = floor(idx / uAttrTexDim); float c = mod(idx, uAttrTexDim); float drc = 0.5 / uAttrTexDim; vec2 attrTc = vec2(c/uAttrTexDim+drc, r/uAttrTexDim+drc); return attrTc; } void main(void) { float pi = 3.14159265358; vec2 attrTc = attrTexCell(2.0 * aInstanceID); vec4 instpos = texture2D(uInstanceAttrTex, attrTc); vec3 instnorm = texture2D(uInstanceAttrTex, attrTexCell(2.0 * aInstanceID + 1.0)).xyz; vec4 mvpos = uMVMatrix * instpos; vec4 mvppos = uPMatrix * mvpos; vec2 screen_coord = mvppos.xy / 2.0 / mvppos.w + vec2(0.5, 0.5); vTexCoord = aVertexPosition; /* Project normal to the screen. */ vec4 p1 = mvppos; vec4 p2 = instpos + vec4(instnorm.xyz, 1.0); p2 = uPMatrix * uMVMatrix * p2; vec3 projnorm = (p2 - p1).xyz; float dz = -projnorm.z; projnorm.z=projnorm.y; projnorm.y=dz; projnorm = normalize(projnorm); projnorm.z = 0.0; projnorm = normalize(projnorm); /* Facing Ratio */ vec3 mvn = normalize(uNMatrix * instnorm); vFacingRatio = dot(mvn, vec3(0,0,1)); vLightIntensity = dot(mvn, normalize(uLightDir)); /* Build a rotation matrix so we don't billboard. */ vec3 ra = -cross(vec3(0,0,1.0), mvn); float cA = dot(vec3(0,0,1.0), mvn); float icA = 1.0 - cA; float sA = sin(acos(cA)); mat3 rotMat; float r00 = cA+ra.x*ra.x*icA; float r01 = ra.x*ra.y*icA-ra.z*sA; float r02 = ra.x*ra.z*icA+ra.y*sA; float r10 = ra.y*ra.x*icA+ra.z*sA; float r11 = cA+ra.y*ra.y*icA; float r12 = ra.y*ra.z*icA-ra.x*sA; float r20 = ra.z*ra.x*icA-ra.y*sA; float r21 = ra.z*ra.y*icA+ra.x*sA; float r22 = cA+ra.z*ra.z*icA; rotMat[0] = vec3(r00, r01, r02); rotMat[1] = vec3(r10, r11, r12); rotMat[2] = vec3(r20, r21, r22); vec3 rmp = rotMat * vec3((aVertexPosition-vec2(.5,.5))*uScale, 0); vec4 ppp = mvpos + vec4(rmp, 0); /* Rotation around screen normal. */ vec2 tpos = aVertexPosition - vec2(0.5, 0.5); tpos = tpos * uScale; float angle = atan(projnorm.y, projnorm.x) - pi/2.0; float ox = tpos.x; tpos.x = tpos.x * cos(angle) - tpos.y * sin(angle); tpos.y = ox * sin(angle) + tpos.y * cos(angle); gl_Position = mvppos; gl_Position.xy = gl_Position.xy + tpos; gl_Position = uPMatrix * ppp; } "," precision mediump float; uniform sampler2D uLappedMask; uniform sampler2D uTamTex1; uniform sampler2D uTamTex2; varying float vFacingRatio; varying vec2 vTexCoord; varying float vLightIntensity; void main(void) { if (vFacingRatio < -0.0) discard; float fade = (vFacingRatio-0.25)/0.75; vec4 mask = texture2D(uLappedMask, vTexCoord); float hatchval = 0.0; vec4 hatchSamp1 = texture2D(uTamTex1, vTexCoord); vec4 hatchSamp2 = texture2D(uTamTex2, vTexCoord); if (vLightIntensity > 0.9) { hatchval = mix(1.0, hatchSamp1.x, 1.0-(vLightIntensity - 0.9)/0.1); } else if (vLightIntensity > 0.8) { float v1 = hatchSamp1.x; float v2 = hatchSamp1.y; hatchval = mix(v1, v2, 1.0-(vLightIntensity - 0.8)/0.2); } else if (vLightIntensity > 0.65) { float v1 = hatchSamp1.y; float v2 = hatchSamp1.z; hatchval = mix(v1, v2, 1.0-(vLightIntensity - 0.65)/0.15); } else if (vLightIntensity > 0.5) { float v1 = hatchSamp1.z; float v2 = hatchSamp2.x; hatchval = mix(v1, v2, 1.0-(vLightIntensity - 0.5)/0.15); } else if (vLightIntensity > 0.35) { float v1 = hatchSamp2.x; float v2 = hatchSamp2.y; hatchval = mix(v1, v2, 1.0-(vLightIntensity - 0.35)/0.15); } else if (vLightIntensity > 0.2) { float v1 = hatchSamp2.y; float v2 = hatchSamp2.z; hatchval = mix(v1, v2, 1.0-(vLightIntensity - 0.2)/0.15); } else { hatchval = texture2D(uTamTex2, vTexCoord).z; } gl_FragColor.a = mask.r; if (mask.r < 0.01) discard; gl_FragColor.a = gl_FragColor.a * fade; gl_FragColor.rgb = vec3(hatchval, hatchval, hatchval) * gl_FragColor.a; } ");
this.attributes={VertexPositionBuffer:a.getAttribLocation(this.program,"aVertexPosition"),InstanceIDBuffer:a.getAttribLocation(this.program,"aInstanceID")}};NPR.HatchBillboardShader.prototype=Object.create(NPR.Shader.prototype);NPR=NPR||{};
NPR.OutlineShader=function(){var a=NPR.gl;NPR.Shader.call(this," uniform mat4 uMVMatrix;\t uniform mat4 uPMatrix;\t uniform mat3 uNMatrix;\t uniform vec2 uScreenDim;\t uniform sampler2D uAttrTex; uniform sampler2D uDepthTex;\t uniform float uAttrTexDim; uniform float uNear; uniform float uFar; uniform float uStrokeWidth; uniform float uStrokeRepeat; uniform float uStrokeRepeatDFactor;\t \t attribute vec2 aEdgeIndices;\t \t varying vec2 vTexCoord; varying float ang; varying float depth_disc0; varying float depth_disc1; varying float tex_depth_0; varying float tex_depth_1; varying float geo_depth_0; varying float geo_depth_1;\t \n #define PI 3.14159265358\n \t bool feq(float f1, float f2) {\t \treturn abs(f1-f2)<0.0001;\t }\t \t vec2 attrTexCell(float idx) {\t \t float r = floor(idx / uAttrTexDim);\t \t float c = mod(idx, uAttrTexDim);\t \t float drc = 0.5 / uAttrTexDim;\t \t vec2 attrTc = vec2(c/uAttrTexDim+drc, r/uAttrTexDim+drc);\t \t return attrTc;\t } float linearizeDepth(float d) { float n = uNear + 0.00001; return (2.0 * n) / (uFar + n - d * (uFar - n)); }\t \t void main(void) { /* Main geometric values. */\t \t float eid = aEdgeIndices.y;\t \t float vid = aEdgeIndices.x;\t \t vec3 v0 = texture2D(uAttrTex, attrTexCell(7.0 * eid)).xyz;\t \t vec3 v1 = texture2D(uAttrTex, attrTexCell(7.0 * eid + 1.0)).xyz;\t \t vec3 v2 = texture2D(uAttrTex, attrTexCell(7.0 * eid + 2.0)).xyz;\t \t vec3 v3 = texture2D(uAttrTex, attrTexCell(7.0 * eid + 3.0)).xyz;\t \t vec3 n0 = texture2D(uAttrTex, attrTexCell(7.0 * eid + 4.0)).xyz;\t \t vec3 n1 = texture2D(uAttrTex, attrTexCell(7.0 * eid + 5.0)).xyz;\t \t float r = texture2D(uAttrTex, attrTexCell(7.0 * eid + 6.0)).x;\t \t vec3 tn0 = normalize(cross(v1-v0, v2-v0));\t \t vec3 tn1 = normalize(cross(v3-v0, v1-v0)); /* Screen space and depth testing values */ \t \t vec4 s0 = (uPMatrix * uMVMatrix * vec4(v0, 1.0)); s0 = s0/s0.w; vec2 sc0 = s0.xy / 2.0 + vec2(0.5,0.5); geo_depth_0 = linearizeDepth(s0.z); float depth_discrepancy_0 = (geo_depth_0 - tex_depth_0);\t \t vec4 s1 = (uPMatrix * uMVMatrix * vec4(v1, 1.0)); s1 = s1/s1.w; vec2 sc1 = s1.xy / 2.0 + vec2(0.5,0.5); geo_depth_1 = linearizeDepth(s1.z); float depth_discrepancy_1 = (geo_depth_1 - tex_depth_1); vec2 dScreen = vec2(1.0/uScreenDim.x, 1.0/uScreenDim.y); float vDepthTexVal0 = texture2D(uDepthTex, sc0).r; float vDepthTexVal1 = texture2D(uDepthTex, sc1).r; /* Sample in a small window around the screen point and take the lowest depth */ /* In order to combat the inherent problems of sampling on edges */ for (int dx = -1; dx <= 1; dx++) { for (int dy = -1; dy <= 1; dy++) { vec2 dsc = sc0 + dScreen * vec2(float(dx), float(dy)); float dd = texture2D(uDepthTex, dsc).r; vDepthTexVal0 = min(vDepthTexVal0, dd); dsc = sc1 + dScreen * vec2(float(dx), float(dy)); dd = texture2D(uDepthTex, dsc).r; vDepthTexVal1 = min(vDepthTexVal1, dd); } } depth_discrepancy_0 = abs(geo_depth_0 - (1.0 - vDepthTexVal0)); depth_discrepancy_1 = abs(geo_depth_1 - (1.0 - vDepthTexVal1)); depth_disc0 = depth_discrepancy_0; depth_disc1 = depth_discrepancy_1; tex_depth_0 = vDepthTexVal0; tex_depth_1 = vDepthTexVal1; /* Edge thickness offset values */\t \t vec2 sp = normalize(vec2(s0.y-s1.y, s1.x-s0.x));\t \t vec2 m0 = (uPMatrix * uMVMatrix * vec4(v0+vec3(sp,0), 1.0)).xy - s0.xy;\t \t vec3 offset = vec3(sp*sign(dot(n0.xy, sp)), 0.0) * 1.0; offset = n0 * uStrokeWidth; /* Angle stuff for texture coordinates. */ vec3 objCtr = vec3(0,0,0); vec4 screenCtr = uPMatrix * uMVMatrix * vec4(objCtr, 1.0); screenCtr = screenCtr/screenCtr.w; vec2 screen_ctr_v0 = s0.xy - screenCtr.xy; vec2 screen_ctr_v1 = s1.xy - screenCtr.xy; float ctr_dst_0 = length(screen_ctr_v0); float ctr_dst_1 = length(screen_ctr_v1); float pang0 = (atan(screen_ctr_v0.y, screen_ctr_v0.x) + PI) / (2.0*PI); float pang1 = (atan(screen_ctr_v1.y, screen_ctr_v1.x) + PI) / (2.0*PI); if (abs(pang0-pang1)>0.9) { if (pang0 < pang1) { pang1 = 1.0 - pang1; } else { pang0 = 1.0 - pang0; } } float tex_scale = uStrokeRepeat; ang=pang0;\t \t vec3 siv;\t \t vTexCoord = vec2(0.0, 0.0);\t \t float scale = 0.2;\t \t if (feq(vid, 0.0)) {\t \t \tsiv = v0 - scale*offset;\t \t \tvTexCoord = vec2(pang0*tex_scale+uStrokeRepeatDFactor*ctr_dst_0, 0.0);\t \t } else if (feq(vid, 1.0)) { offset = n1 * uStrokeWidth; ang = pang1;\t \t \tsiv = v1 - scale*offset;\t \t \tvTexCoord = vec2(pang1*tex_scale+uStrokeRepeatDFactor*ctr_dst_1, 0.0);\t \t } else if (feq(vid, 2.0)) { offset = n1 * uStrokeWidth;\t \t \tsiv = v1 + scale*offset; ang = pang1;\t \t \tvTexCoord = vec2(pang1*tex_scale+uStrokeRepeatDFactor*ctr_dst_1, 1.0);\t\t } else if (feq(vid, 3.0)) {\t\t \tsiv = v0 + scale*offset;\t\t \tvTexCoord = vec2(pang0*tex_scale+uStrokeRepeatDFactor*ctr_dst_0, 1.0);\t\t } else {\t\t \tsiv = vec3(-5.0,-5.0,-5.0);\t\t }\t\t if (sign(dot(uNMatrix*tn0, vec3(0,0,1.0)))==sign(dot(uNMatrix*tn1, vec3(0,0,1.0)))) {\t\t \tsiv = vec3(-5.0,-5.0,-5.0);\t\t }\t\t if (dot(uNMatrix*n0, vec3(0,0,1.0))<-0.5 || dot(uNMatrix*n1, vec3(0,0,1.0))<-0.5) {\t\t \tsiv = vec3(-5.0,-5.0,-5.0);\t\t }\t \t gl_Position = uPMatrix * uMVMatrix * vec4(siv, 1.0);\t } "," precision mediump float; varying vec2 vTexCoord; uniform sampler2D uStrokeTex; uniform vec3 uColor; varying float ang; varying float depth_disc0; varying float depth_disc1; varying float tex_depth_0; varying float tex_depth_1; varying float geo_depth_0; varying float geo_depth_1; void main(void) { \tfloat dy = 1.0 - abs(vTexCoord.y - 0.5); float texAlpha = texture2D(uStrokeTex, vTexCoord).a; vec3 col = uColor; if (geo_depth_0 > tex_depth_0-0.05 && geo_depth_1 > tex_depth_1-0.05) { col = vec3(0,1.0,0); discard; } gl_FragColor = vec4(col*texAlpha, texAlpha); } ");
this.attributes={EdgeIndicesBuffer:a.getAttribLocation(this.program,"aEdgeIndices")}};NPR.OutlineShader.prototype=Object.create(NPR.Shader.prototype);NPR=NPR||{};
NPR.PainterlyBillboardShader=function(){var a=NPR.gl;NPR.Shader.call(this," uniform mat4 uMVMatrix; uniform mat4 uPMatrix; uniform mat3 uNMatrix; uniform float uAttrTexDim; uniform vec2 uScale; uniform sampler2D uBrushTexture; uniform sampler2D uColorTexture; uniform sampler2D uDepthTexture; uniform sampler2D uInstanceAttrTex; attribute vec2 aVertexPosition; attribute float aInstanceID; varying vec2 vTexCoord; varying float vFacingRatio; varying vec4 vColor; vec2 attrTexCell(float idx) { float r = floor(idx / uAttrTexDim); float c = mod(idx, uAttrTexDim); float drc = 0.5 / uAttrTexDim; vec2 attrTc = vec2(c/uAttrTexDim+drc, r/uAttrTexDim+drc); return attrTc; } void main(void) { float pi = 3.14159265358; vec2 attrTc = attrTexCell(2.0 * aInstanceID); vec4 instpos = texture2D(uInstanceAttrTex, attrTc); vec3 instnorm = texture2D(uInstanceAttrTex, attrTexCell(2.0 * aInstanceID + 1.0)).xyz; vec4 mvpos = uMVMatrix * instpos; vec4 mvppos = uPMatrix * mvpos; vec2 screen_coord = mvppos.xy / 2.0 / mvppos.w + vec2(0.5, 0.5); vColor = texture2D(uColorTexture, screen_coord); vTexCoord = aVertexPosition; /* Project normal to the screen. */ /*vec4 p1 = mvppos; vec4 p2 = instpos + vec4(instnorm.xyz, 1.0); p2 = uPMatrix * uMVMatrix * p2; vec3 projnorm = (p2 - p1).xyz; projnorm = normalize(projnorm);*/ vec3 projnorm = uNMatrix * instnorm.xyz; float dz = -projnorm.z; projnorm.z=projnorm.y; projnorm.y=dz; projnorm.z = 0.0; projnorm = normalize(projnorm); /* Facing Ratio */ vec3 mvn = uNMatrix * instnorm; vFacingRatio = dot(normalize(mvn), vec3(0,0,1)); /* Rotation around screen normal. */ vec2 tpos = aVertexPosition - vec2(0.5, 0.5); tpos = tpos * uScale; float angle = atan(projnorm.y, projnorm.x) - pi/2.0; float ox = tpos.x; tpos.x = tpos.x * cos(angle) - tpos.y * sin(angle); tpos.y = ox * sin(angle) + tpos.y * cos(angle); gl_Position = mvppos; gl_Position.xy = gl_Position.xy + tpos; } "," precision mediump float; uniform sampler2D uBrushTexture; varying float vFacingRatio; varying vec4 vColor; varying vec2 vTexCoord; void main(void) { /*if (vFacingRatio < 0.5) discard;*/ float fade = (vFacingRatio-0.5)/0.5; vec4 brushTexCol = texture2D(uBrushTexture, vTexCoord); gl_FragColor.a = min(0.9, brushTexCol.a); gl_FragColor.a = gl_FragColor.a * fade; gl_FragColor.rgb = vColor.rgb * gl_FragColor.a; } ");
this.attributes={VertexPositionBuffer:a.getAttribLocation(this.program,"aVertexPosition"),InstanceIDBuffer:a.getAttribLocation(this.program,"aInstanceID")}};NPR.PainterlyBillboardShader.prototype=Object.create(NPR.Shader.prototype);