PageSourceSearch

https://georgluif.at/assets/painterly-pass.js?v=729d28de

js georgluif.at collected 2026-10-09 21:26:05 UTC 5,151 bytes, 3 lines download raw bytes

1/*! © 2011–2026 Georg Luif · georgluif.at · All rights reserved. */
2import*as a from"./three.module.min.js";export const MAX_RADIUS=35,POST_VERT="varying vec2 vUv; void main(){ vUv = uv; gl_Position = vec4(position, 1.0); }",KUWAHARA_GAUSSIAN_FRAG=["precision highp float;","#define SECTOR_COUNT 8","uniform float radius;","uniform sampler2D inputBuffer;","uniform vec4 resolution;","varying vec2 vUv;","#ifdef GRADE","uniform float uGrade;","uniform vec3 uShadowTint;","uniform vec3 uLightTint;","uniform float uSat;","uniform float uVignette;","vec3 goldenGrade(vec3 c) {","  float l = dot(c, vec3(0.299, 0.587, 0.114));","  vec3 g = c * mix(uShadowTint, uLightTint, smoothstep(0.05, 0.85, l));","  g = mix(vec3(dot(g, vec3(0.299, 0.587, 0.114))), g, uSat);","  vec2 q = (vUv - 0.5) * vec2(1.15, 1.0);","  g *= 1.0 - uVignette * smoothstep(0.35, 0.85, length(q));","  return mix(c, clamp(g, 0.0, 1.0), uGrade);","}","#endif","vec4 fromLinear(vec4 linearRGB) {","  bvec3 cutoff = lessThan(linearRGB.rgb, vec3(0.0031308));","  vec3 higher  = vec3(1.055) * pow(linearRGB.rgb, vec3(1.0 / 2.4)) - vec3(0.055);","  vec3 lower   = linearRGB.rgb * vec3(12.92);","  return vec4(mix(higher, lower, cutoff), linearRGB.a);","}","vec3 sampleColor(vec2 offset) {","  vec2 coord = (gl_FragCoord.xy + offset) / resolution.xy;","  return texture2D(inputBuffer, coord).rgb;","}","float gaussianWeight(float dist, float sigma) {","  return exp(-(dist * dist) / (2.0 * sigma * sigma));","}","void getSectorVarianceAndAverageColor(float angle, float radiusVal, out vec3 avgColor, out float variance) {","  vec3 weightedColorSum = vec3(0.0);","  vec3 weightedSquaredColorSum = vec3(0.0);","  float totalWeight = 0.0;","  float sigma = radiusVal / 3.0;","  for (float r = 1.0; r <= 35.0; r += 1.0) {","    if (r > radiusVal) break;","    for (float a = -0.392699; a <= 0.392699; a += 0.196349) {","      vec2 sampleOffset = r * vec2(cos(angle + a), sin(angle + a));","      vec3 color = sampleColor(sampleOffset);","      float weight = gaussianWeight(length(sampleOffset), sigma);","      weightedColorSum += color * weight;","      weightedSquaredColorSum += color * color * weight;","      totalWeight += weight;","    }","  }","  avgColor = weightedColorSum / totalWeight;","  vec3 varianceRes = (weightedSquaredColorSum / totalWeight) - (avgColor * avgColor);","  variance = dot(varianceRes, vec3(0.299, 0.587, 0.114));","}","void main() {","  vec3 sectorAvgColors[SECTOR_COUNT];","  float sectorVariances[SECTOR_COUNT];","  for (int i = 0; i < SECTOR_COUNT; i++) {","    float angle = float(i) * 6.28318 / float(SECTOR_COUNT);","    getSectorVarianceAndAverageColor(angle, radius, sectorAvgColors[i], sectorVariances[i]);","  }","  float minVariance = sectorVariances[0];","  vec3 finalColor = sectorAvgColors[0];","  for (int i = 1; i < SECTOR_COUNT; i++) {","    if (sectorVariances[i] < minVariance) {","      minVariance = sectorVariances[i];","      finalColor = sectorAvgColors[i];","    }","  }","#ifdef PRESERVE_ALPHA","  float outAlpha = texture2D(inputBuffer, gl_FragCoord.xy / resolution.xy).a;","#else","  float outAlpha = 1.0;","#endif","#ifdef LINEAR_OUTPUT","  gl_FragColor = vec4(finalColor, outAlpha);","#else","  gl_FragColor = fromLinear(vec4(finalColor, outAlpha));","#ifdef GRADE","  gl_FragColor.rgb = goldenGrade(gl_FragColor.rgb);","#endif","#endif","}"].join(`
3`);function S(t){return Math.max(1,Math.min(MAX_RADIUS,t||1))}export function createPainterlyPass(t){t=t||{};let u=S(t.radius==null?15:t.radius),g=t.resolutionScale||1,c=2,f=2;const n=new a.WebGLRenderTarget(2,2,{minFilter:a.LinearFilter,magFilter:a.LinearFilter,format:a.RGBAFormat}),l=new a.Mesh(new a.PlaneGeometry(2,2)),d=new a.Scene;d.add(l);const m=new a.OrthographicCamera(-1,1,1,-1,0,1),o=t.grade||null,v={};
3t.preserveAlpha&&(v.PRESERVE_ALPHA=""),o&&(v.GRADE="");const r={radius:{value:u},inputBuffer:{value:null},resolution:{value:new a.Vector4}};o&&(r.uGrade={value:0},r.uShadowTint={value:new a.Vector3().fromArray(o.shadow||[1,1,1])},r.uLightTint={value:new a.Vector3().fromArray(o.light||[1,1,1])},r.uSat={value:o.sat!=null?o.sat:1},r.uVignette={value:o.vignette||0});const i=new a.ShaderMaterial({defines:v,uniforms:r,vertexShader:POST_VERT,fragmentShader:KUWAHARA_GAUSSIAN_FRAG,depthTest:!1,depthWrite:!1}),h=new a.MeshBasicMaterial({map:n.texture,depthTest:!1,depthWrite:!1});function p(){n.setSize(Math.max(1,Math.round(c*g)),Math.max(1,Math.round(f*g)))}const C={enabled:!0,setSize:function(e,s){c=Math.max(1,e|0),f=Math.max(1,s|0),p()},setRadius:function(e){u=S(e),i.uniforms.radius.value=u},getRadius:function(){return u},setGrade:function(e){r.uGrade&&(r.uGrade.value=Math.max(0,Math.min(1,e||0)))},setResolutionScale:function(e){g=Math.max(.1,Math.min(1,e||1)),p()},render:function(e,s,R){const T=e.getRenderTarget();e.setRenderTarget(n),e.render(s,R),C.enabled?(i.uniforms.inputBuffer.value=n.texture,i.uniforms.resolution.value.set(c,f,1/c,1/f),l.material=i):l.material=h,e.setRenderTarget(T),e.render(d,m)},precompile:function(e,s){return l.material=i,s(e,d,m)},dispose:function(){i.dispose(),h.dispose(),n.dispose(),l.geometry.dispose()}};return C}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.