After lunch, I want to replicate the sketch shader I wrote for the Pencil-vs-Camera project. Additionally, I wrote a one-pass shader for dotted drawing / sketch post processing effect, which I think is more aesthetically pleasing. Dotted Drawing Demo Click on the play button in the left bottom corner of the embedded ShaderToy window below, to…
Unified Gnomonic and Stereographic Projections
Gnomonic projection, or rectilinear projection, together with stereographic projection, are two most commonly used projection in rendering 360 degree videos, or other VR applications. Recently, I found the inverse converting function from screen coordinates to the two projections can be unified within a single function. It’s not really surprising since both projection uses spherical lens,…
Equirectangular Projection, Gnomonic Projection, and Cubemaps
Gnomonic Projection Background According to MathWorld, the gnomonic projection is a nonconformal map projection obtained by projecting points (or ) on the surface of sphere from a sphere’s center O to point P in a plane that is tangent to a point S (Coxeter 1969, p. 93). In a gnomonic projection, great circles are mapped…
Yet another shader for image fade-In effect
Taken iq’s background transparent code and Dr. Neyret’s advice: This shader can be used for rendering pop-up images in a 3D environment.
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 |
// Image Fade-In Effect, CC0 // Forked from iq's invisible shader with transparent background: [url]https://www.shadertoy.com/view/XljSRK[/url] float backgroundPattern( in vec2 p ) { vec2 uv = p + 0.1*texture2D( iChannel2, 0.05*p ).xy; return texture2D( iChannel1, 16.0*uv ).x; } vec3 getBackground(in vec2 coord) { float fa = backgroundPattern( (coord + 0.0) / iChannelResolution[0].xy ); float fb = backgroundPattern( (coord - 0.5) / iChannelResolution[0].xy ); return vec3( 0.822 + 0.4*(fa-fb) ); } float getFadeInWeight(vec2 uv) { float edge = 0.3 * abs(sin(0.5)); // taken FabriceNeyret2's advice vec4 v = smoothstep(0., edge, vec4(uv, 1. - uv) ); return v.x * v.y * v.z * v.w; } void mainImage( out vec4 fragColor, in vec2 fragCoord ) { vec2 uv = fragCoord.xy / iResolution.xy; vec3 bg = getBackground(fragCoord); vec3 col = texture2D(iChannel0, uv).rgb; float alpha = getFadeInWeight(uv); fragColor = vec4(mix(bg, col, alpha), 1.0); } |
Foveated Rendering via Quadtree
Today, I wrote a shader for foveated rendering uisng Prof. Neyret’s QuadTree: https://www.shadertoy.com/view/Ml3SDf The basic idea is: Calculate the depth of the QuadTree using the distance between the current coordinate to the foveat region Use the depth as the mipmap level to sample from the texture Code below:
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 |
// forked and remixed from Prof. Neyret's https://www.shadertoy.com/view/ltBSDV // Foveated Rendering via Quadtree: https://www.shadertoy.com/view/Ml3SDf# void mainImage( out vec4 o, vec2 U ) { float r = 0.1, t = iGlobalTime, H = iResolution.y; vec2 V = U.xy / iResolution.xy; U /= H; // foveated region : disc(P,r) vec2 P = .5 + .5 * vec2(cos(t), sin(t * 0.7)), fU; U *= .5; P *= .5; // unzoom for the whole domain falls within [0,1]^n float mipmapLevel = 4.0; for (int i = 0; i < 7; ++i) { // to the infinity, and beyond ! :-) //fU = min(U,1.-U); if (min(fU.x,fU.y) < 3.*r/H) { o--; break; } // cell border if (length(P - vec2(0.5)) - r > 0.7) break; // cell is out of the shape // --- iterate to child cell fU = step(.5, U); // select child U = 2.0 * U - fU; // go to new local frame P = 2.0 * P - fU; r *= 2.0; mipmapLevel -= 0.5; } o = texture2D(iChannel0, V, mipmapLevel); } |
Bilateral Filter to Look Younger on GPU
Bilateral filter can be used to smooth the texture while preserving significant edges / contrast. Below shows a live demo in ShaderToy. Press mouse for comparison. Thanks to mrharicot’s awesome bilateral filter: https://www.shadertoy.com/view/4dfGDH With performance improvement proposed by athlete. With gamma correction by iq: https://www.shadertoy.com/view/XtsSzH Skin detection forked from carlolsson’s Skin Detection https://www.shadertoy.com/view/MlfSzn#
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 92 93 94 |
// Bilateral Filter for Younger. starea. // URL: https://www.shadertoy.com/view/XtVGWG // Press mouse for comparison. // Filter forked from mrharicot: https://www.shadertoy.com/view/4dfGDH // Skin detection forked from carlolsson's Skin Detection https://www.shadertoy.com/view/MlfSzn# // With performance improvement by athlete #define SIGMA 10.0 #define BSIGMA 0.1 #define MSIZE 15 #define USE_CONSTANT_KERNEL #define SKIN_DETECTION const bool GAMMA_CORRECTION = true; float kernel[MSIZE]; float normpdf(in float x, in float sigma) { return 0.39894 * exp(-0.5 * x * x/ (sigma * sigma)) / sigma; } float normpdf3(in vec3 v, in float sigma) { return 0.39894 * exp(-0.5 * dot(v,v) / (sigma * sigma)) / sigma; } float normalizeColorChannel(in float value, in float min, in float max) { return (value - min)/(max-min); } void mainImage( out vec4 fragColor, in vec2 fragCoord ) { vec3 c = texture2D(iChannel0, (fragCoord.xy / iResolution.xy)).rgb; const int kSize = (MSIZE - 1) / 2; vec3 final_colour = vec3(0.0); float Z = 0.0; #ifdef USE_CONSTANT_KERNEL // unfortunately, WebGL 1.0 does not support constant arrays... kernel[0] = kernel[14] = 0.031225216; kernel[1] = kernel[13] = 0.033322271; kernel[2] = kernel[12] = 0.035206333; kernel[3] = kernel[11] = 0.036826804; kernel[4] = kernel[10] = 0.038138565; kernel[5] = kernel[9] = 0.039104044; kernel[6] = kernel[8] = 0.039695028; kernel[7] = 0.039894000; float bZ = 0.2506642602897679; #else //create the 1-D kernel for (int j = 0; j <= kSize; ++j) { kernel[kSize+j] = kernel[kSize-j] = normpdf(float(j), SIGMA); } float bZ = 1.0 / normpdf(0.0, BSIGMA); #endif vec3 cc; float factor; //read out the texels for (int i=-kSize; i <= kSize; ++i) { for (int j=-kSize; j <= kSize; ++j) { cc = texture2D(iChannel0, (fragCoord.xy+vec2(float(i),float(j))) / iResolution.xy).rgb; factor = normpdf3(cc-c, BSIGMA) * bZ * kernel[kSize+j] * kernel[kSize+i]; Z += factor; if (GAMMA_CORRECTION) { final_colour += factor * pow(cc, vec3(2.2)); } else { final_colour += factor * cc; } } } if (GAMMA_CORRECTION) { fragColor = vec4(pow(final_colour / Z, vec3(1.0/2.2)), 1.0); } else { fragColor = vec4(final_colour / Z, 1.0); } bool isSkin = true; #ifdef SKIN_DETECTION isSkin = false; vec4 rgb = fragColor * 255.0; vec4 ycbcr = rgb; ycbcr.x = 16.0 + rgb.x*0.257 + rgb.y*0.504 + rgb.z*0.098; ycbcr.y = 128.0 - rgb.x*0.148 - rgb.y*0.291 + rgb.z*0.439; ycbcr.z = 128.0 + rgb.x*0.439 - rgb.y*0.368 - rgb.z*0.071; if (ycbcr.y > 100.0 && ycbcr.y < 118.0 && ycbcr.z > 121.0 && ycbcr.z < 161.0) { isSkin = true; } #endif if (iMouse.z > 0.0 || !isSkin) { fragColor = vec4(texture2D(iChannel0, fragCoord.xy / iResolution.xy).xyz, 1.0); } } |
…
Interactive Poisson Blending on GPU
Recently, I have implemented two fragment shaders for interactive Poisson Blending (seamless blending). Here is my real-time demo and code on ShaderToy: Press 1 for normal mode, press 2 for mixed gradients, press space to clear the canvas. Technical Brief I followed a simplified routine of the Poisson Image Editing paper [P. Pérez, M. Gangnet,…
Libraries, Textbooks, Courses, Tutorials for WebGL
WebGL (Web Graphics Library) is a JavaScript API for rendering interactive 3D computer graphics and 2D graphics within any compatible web browser without the use of plug-ins. WebGL is a great tool for quick demos and video rendering. In the past year, I have created Social Street View, Video Fields, and VRSurus using WebGL. Additionally,…
404 Not Found in Two Triangles
Inspred by 104 from ShaderToy, I made a new 404 Not Found page with two triangles in GLSL using calligraphic strokes. Live Demo Please visit: http://duruofei.com/404 or Code
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 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 |
// Ruofei Du // 404 Not Found Page // Forked and mixed from 104's Brush Experiments: https://www.shadertoy.com/view/ltj3Wc // Free to use and share vec2 mouse; //////////////////////////////////////////////////////////////// // BOILERPLATE UTILITIES................... const float pi = 3.14159265359; const float pi2 = pi * 2.; float opU( float d1, float d2 ){ return min(d1,d2); } float opS( float d2, float d1 ){ return max(-d1,d2); } float opI( float d1, float d2) { return max(d1,d2); } // from "Magic Fractal" by dgreensp // https://www.shadertoy.com/view/4ljGDd float magicBox(vec3 p) { const int MAGIC_BOX_ITERS = 13; const float MAGIC_BOX_MAGIC = 0.55; // The fractal lives in a 1x1x1 box with mirrors on all sides. // Take p anywhere in space and calculate the corresponding position // inside the box, 0<(x,y,z)<1 p = 1.0 - abs(1.0 - mod(p, 2.0)); float lastLength = length(p); float tot = 0.0; // This is the fractal. More iterations gives a more detailed // fractal at the expense of more computation. for (int i=0; i < MAGIC_BOX_ITERS; i++) { // The number subtracted here is a "magic" paremeter that // produces rather different fractals for different values. p = abs(p)/(lastLength*lastLength) - MAGIC_BOX_MAGIC; float newLength = length(p); tot += abs(newLength-lastLength); lastLength = newLength; } return tot; } float magicBox(vec2 uv){ // A random 3x3 unitary matrix, used to avoid artifacts from slicing the // volume along the same axes as the fractal's bounding box. const mat3 M = mat3(0.28862355854826727, 0.6997227302779844, 0.6535170557707412, 0.06997493955670424, 0.6653237235314099, -0.7432683571499161, -0.9548821651308448, 0.26025457467376617, 0.14306504491456504); vec3 p = 0.5*M*vec3(uv, 0.0); return magicBox(p); } mat2 rot2D(float r) { float c = cos(r), s = sin(r); return mat2(c, s, -s, c); } float nsin(float a){return .5+.5*sin(a);} float ncos(float a){return .5+.5*cos(a);} vec3 saturate(vec3 a){return clamp(a,0.,1.);} float rand(vec2 co){ return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); } float rand(float n){ return fract(cos(n*89.42)*343.42); } float dtoa(float d, float amount) { return clamp(1.0 / (clamp(d, 1.0/amount, 1.0)*amount), 0.,1.); } float sdAxisAlignedRect(vec2 uv, vec2 tl, vec2 br) { vec2 d = max(tl-uv, uv-br); return length(max(vec2(0.0), d)) + min(0.0, max(d.x, d.y)); } float sdCircle(vec2 uv, vec2 origin, float radius) { return length(uv - origin) - radius; } // 0-1 1-0 float smoothstep4(float e1, float e2, float e3, float e4, float val) { return min(smoothstep(e1,e2,val), 1.-smoothstep(e3,e4,val)); } // hash & simplex noise from https://www.shadertoy.com/view/Msf3WH vec2 hash( vec2 p ) { p = vec2( dot(p,vec2(127.1,311.7)), dot(p,vec2(269.5,183.3)) ); return -1.0 + 2.0*fract(sin(p)*43758.5453123); } // returns -.5 to 1.5. i think. float noise( in vec2 p ) { const float K1 = 0.366025404; // (sqrt(3)-1)/2; const float K2 = 0.211324865; // (3-sqrt(3))/6; vec2 i = floor( p + (p.x+p.y)*K1 ); vec2 a = p - i + (i.x+i.y)*K2; vec2 o = (a.x>a.y) ? vec2(1.0,0.0) : vec2(0.0,1.0); //vec2 of = 0.5 + 0.5*vec2(sign(a.x-a.y), sign(a.y-a.x)); vec2 b = a - o + K2; vec2 c = a - 1.0 + 2.0*K2; vec3 h = max( 0.5-vec3(dot(a,a), dot(b,b), dot(c,c) ), 0.0 ); vec3 n = h*h*h*h*vec3( dot(a,hash(i+0.0)), dot(b,hash(i+o)), dot(c,hash(i+1.0))); return dot( n, vec3(70.0) ); } float noise01(vec2 p) { return clamp((noise(p)+.5)*.5, 0.,1.); } // debug function to convert distance to color, revealing sign. vec3 dtocolor(vec3 inpColor, float dist) { vec3 ret; if(dist > 0.) ret = mix(vec3(0,0,.5), vec3(.5,.5,1), sin(dist * pi2 * 50.));// red = negative / inside geometry. else ret = mix(vec3(1.,.5,.5), vec3(.5,0,0), sin(dist * pi2 * 50.));// blue = positive, of of geometry. ret = mix(ret, vec3(0), clamp(abs(dist),0.,1.));// falloff return ret; } float smooth(float x) { return x*x*x*(x*(x*6. - 15.) + 10.); } //////////////////////////////////////////////////////////////// // APP CODE ................... // this function will produce a line with brush strokes. the inputs are such // that you can apply it to pretty much any line; the geometry is separated from this function. vec3 colorBrushStroke(vec2 uvLine, vec2 uvPaper, vec2 lineSize, float sdGeometry, vec3 inpColor, vec4 brushColor) { float posInLineY = (uvLine.y / lineSize.y);// position along the line. in the line is 0-1. if(iMouse.z > 0.) { // return mix(inpColor, vec3(0), dtoa(sdGeometry, 1000.));// reveal geometry. // return mix(inpColor, dtocolor(inpColor, uvLine.y), dtoa(sdGeometry, 1000.));// reveal Y // return mix(inpColor, dtocolor(inpColor, posInLineY), dtoa(sdGeometry, 1000.));// reveal pos in line. // return mix(inpColor, dtocolor(inpColor, uvLine.x), dtoa(sdGeometry, 1000.));// reveal X float okthen = 42.;// NOP } // warp the position-in-line, to control the curve of the brush falloff. if(posInLineY > 0.) { float mouseX = iMouse.x == 0. ? 0.2 : (iMouse.x / iResolution.x); //float mouseX = 1.0; posInLineY = pow(posInLineY, (pow(mouseX,2.) * 15.) + 1.5); } // brush stroke fibers effect. float strokeBoundary = dtoa(sdGeometry, 300.);// keeps stroke texture inside the geometry. float strokeTexture = 0. + noise01(uvLine * vec2(min(iResolution.y,iResolution.x)*0.2, 1.))// high freq fibers + noise01(uvLine * vec2(79., 1.))// smooth brush texture. lots of room for variation here, also layering. + noise01(uvLine * vec2(14., 1.))// low freq noise, gives more variation ; strokeTexture *= 0.333 * strokeBoundary;// 0 to 1 (take average of above) strokeTexture = max(0.008, strokeTexture);// avoid 0; it will be ugly to modulate // fade it from very dark to almost nonexistent by manipulating the curve along Y float strokeAlpha = pow(strokeTexture, max(0.,posInLineY)+0.09);// add allows bleeding // fade out the end of the stroke by shifting the noise curve below 0 const float strokeAlphaBoost = 1.09; if(posInLineY > 0.) strokeAlpha = strokeAlphaBoost * max(0., strokeAlpha - pow(posInLineY,0.5));// fade out else strokeAlpha *= strokeAlphaBoost; strokeAlpha = smooth(strokeAlpha); // paper bleed effect. float paperBleedAmt = 60. + (rand(uvPaper.y) * 30.) + (rand(uvPaper.x) * 30.); // amt = 500.;// disable paper bleed // blotches (per stroke) //float blotchAmt = smoothstep(17.,18.5,magicBox(vec3(uvPaper, uvLine.x))); //blotchAmt *= 0.4; //strokeAlpha += blotchAmt; float alpha = strokeAlpha * brushColor.a * dtoa(sdGeometry, paperBleedAmt); alpha = clamp(alpha, 0.,1.); return mix(inpColor, brushColor.rgb, alpha); } vec3 colorBrushStrokeLine(vec2 uv, vec3 inpColor, vec4 brushColor, vec2 p1_, vec2 p2_, float lineWidth) { // flatten the line to be axis-aligned. float lineAngle = pi-atan(p1_.x - p2_.x, p1_.y - p2_.y); mat2 rotMat = rot2D(lineAngle); float lineLength = distance(p2_, p1_); // make an axis-aligned line from this line. vec2 tl = (p1_ * rotMat);// top left vec2 br = tl + vec2(0,lineLength);// bottom right vec2 uvLine = uv * rotMat; // make line slightly narrower at end. lineWidth *= mix(1., .9, smoothstep(tl.y,br.y,uvLine.y)); // wobble it around, humanize float res = min(iResolution.y,iResolution.x); uvLine.x += (noise01(uvLine * 1.)-0.5) * 0.02; uvLine.x += cos(uvLine.y * 3.) * 0.009;// smooth lp wave uvLine.x += (noise01(uvLine * 5.)-0.5) * 0.005;// a sort of random waviness like individual strands are moving around // uvLine.x += (noise01(uvLine * res * 0.18)-0.5) * 0.0035;// HP random noise makes it look less scientific // calc distance to geometry. actually just do a straight line, then we will round it out to create the line width. float d = sdAxisAlignedRect(uvLine, tl, br) - lineWidth / 2.; uvLine = tl - uvLine; vec2 lineSize = vec2(lineWidth, lineLength); vec3 ret = colorBrushStroke(vec2(uvLine.x, -uvLine.y), uv, lineSize, d, inpColor, brushColor); return ret; } // returns: // xy = uvLine // z = radius vec3 humanizeBrushStrokeDonut(vec2 uvLine, float radius_, bool clockwise, float lineLength) { vec2 humanizedUVLine = uvLine; // offsetting the circle along its path creates a twisting effect. float twistAmt = .24; float linePosY = humanizedUVLine.y / lineLength;// 0 to 1 scale humanizedUVLine.x += linePosY * twistAmt; // perturb radius / x float humanizedRadius = radius_; float res = min(iResolution.y,iResolution.x); humanizedRadius += (noise01(uvLine * 1.)-0.5) * 0.04; humanizedRadius += sin(uvLine.y * 3.) * 0.019;// smooth lp wave humanizedUVLine.x += sin(uvLine.x * 30.) * 0.02;// more messin humanizedUVLine.x += (noise01(uvLine * 5.)-0.5) * 0.005;// a sort of random waviness like individual strands are moving around // humanizedUVLine.x += (noise01(uvLine * res * 0.18)-0.5) * 0.0035;// HP random noise makes it look less scientific return vec3(humanizedUVLine, humanizedRadius); } // there's something about calling an Enso a "donut" that makes me giggle. // TODO: sweepAmt is 0 to 1, the amount of the circle to cover by the brush stroke. 1=whole circle. 0=just a point. vec3 colorBrushStrokeDonut(vec2 uv, vec3 inpColor, vec4 brushColor, vec2 o, float radius_, float angleStart, float sweepAmt, float lineWidth, bool clockwise) { vec2 uvLine = uv - o; float angle = atan(uvLine.x, uvLine.y) + pi;// 0-2pi angle = mod(angle-angleStart+pi, pi2); if(!clockwise) angle = pi2 - angle; float lineLength = radius_ * pi2;// this is calculated before any humanizing/perturbance. so it's possible that it's slightly inaccurate, but in ways that will never matter uvLine = vec2( radius_ - length(uvLine), angle / pi2 * lineLength ); // make line slightly narrower at end. float lineWidth1 = lineWidth * mix(1., .9, smoothstep(0.,lineLength,uvLine.y)); vec3 hu = humanizeBrushStrokeDonut(uvLine, radius_, clockwise, lineLength); vec2 humanizedUVLine = hu.xy; float humanizedRadius = hu.z; float d = opS(sdCircle(uv, o, humanizedRadius), sdCircle(uv, o, humanizedRadius)); d -= lineWidth1 * 0.5;// round off things just like in the line routine. vec3 ret = colorBrushStroke(humanizedUVLine, uv, vec2(lineWidth1, lineLength), d, inpColor, brushColor); // do the same but for before the beginning of the line. distance field is just a single point vec3 ret2 = vec3(1); if(angle > pi) { uvLine.y -= lineLength; hu = humanizeBrushStrokeDonut(uvLine, radius_, clockwise, lineLength); humanizedUVLine = hu.xy; humanizedRadius = hu.z; vec2 strokeStartPos = o + vec2(sin(angleStart), cos(angleStart)) * humanizedRadius; d = distance(uv, strokeStartPos); d -= lineWidth * 0.5 * 1.;// round off things just like in the line routine. ret2 = colorBrushStroke(humanizedUVLine, uv, vec2(lineWidth, lineLength), d, inpColor, brushColor); } return min(ret, ret2); } vec2 getuv_centerX(vec2 fragCoord, vec2 newTL, vec2 newSize) { vec2 ret = vec2(fragCoord.x / iResolution.x, (iResolution.y - fragCoord.y) / iResolution.y);// ret is now 0-1 in both dimensions ret *= newSize;// scale up to new dimensions float aspect = iResolution.x / iResolution.y; ret.x *= aspect;// orig aspect ratio float newWidth = newSize.x * aspect; return ret + vec2(newTL.x - (newWidth - newSize.x) / 2.0, newTL.y); } void main() { mouse = getuv_centerX(iMouse.xy, vec2(-1,-1), vec2(2,2));// (iMouse.xy / iResolution.y * 2.0) - 1.; vec2 uv = getuv_centerX(fragCoord, vec2(-1,-1), vec2(2,2));// 0-1 centered vec3 col = vec3(1.,1.,0.875);// bg float dist; // geometry on display... float yo = sin(-uv.x*pi*0.5)*0.2; vec4 colFour = vec4(vec3(.8,.1,0),.9); float widFour = 0.15; // 4 col = colorBrushStrokeLine(uv, col, colFour, vec2(-1.0, -0.6+yo), vec2(-1.6, 0.2+yo), widFour); col = colorBrushStrokeLine(uv, col, colFour, vec2(-1.45, 0.05+yo), vec2(-0.5, 0.35-yo), widFour); col = colorBrushStrokeLine(uv, col, colFour, vec2(-1.0, -0.6+yo), vec2(-1.0, 0.6+yo), widFour); // 0 col = colorBrushStrokeDonut(uv, col, vec4(0,0,0,.9), vec2(0,0),// origin 0.4,// radius 3.4,// angle of brush start 0.5,// sweep amt 0-1 0.2,// width true);// clockwise // 4 colFour = vec4(vec3(.8,.1,0),.8); float dt = 2.3; widFour = 0.15; col = colorBrushStrokeLine(uv, col, colFour, vec2(-1.0+dt+yo, -0.4), vec2(-1.6+dt+yo, 0.2), widFour); col = colorBrushStrokeLine(uv, col, colFour, vec2(-1.6+dt, -0.0-yo), vec2(-0.5+dt+yo, 0.25+yo), widFour); col = colorBrushStrokeLine(uv, col, colFour, vec2(-1.0+dt+yo, -0.4), vec2(-1.0+dt+yo, 0.8), widFour); // paint blotches float blotchAmt = smoothstep(20.,50.,magicBox((uv+12.)*2.));// smoothstep(40.,40.5, magicBox((uv+9.4)*2.)); blotchAmt = pow(blotchAmt, 3.);// attenuate blotchAmt = .7*smoothstep(.2,.4,blotchAmt);// sharpen col *= 1.-blotchAmt; // grain col.rgb += (rand(uv)-.5)*.08; col.rgb = saturate(col.rgb); // vignette vec2 uvScreen = (fragCoord / iResolution.xy * 2.)-1.; float vignetteAmt = 1.-dot(uvScreen*0.5,uvScreen* 0.62); col *= vignetteAmt; gl_FragColor = vec4(col, 1.); } |
Social Street View wins the Best Paper Award in Web3D 2016
I am thrilled to announce that Social Street View has won the Best Paper Award at Web3D 2016, which was held next to SIGGRAPH 2016 in late August! Please visit the project website for more details: http://www.socialstreetview.com I also published my slides and videos.
March 2021 M T W T F S S « Nov 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 Clock
World
Random Posts
- Tianqi Chen published WebGL-based deep learning…
- [Summary] Oculus Press Event · June 11 – Consumer Rift Spec Revealed
- [Summary] DynamicFusion: Reconstruction and Tracking of Non-rigid Scenes in Real-Time – CVPR 2015 Best Paper
- [Summary] Computer Graphics for Next Generation Displays, Input Devices, and Data
- SIGGRAPH Asia 2014 Course Materials from iq/rgba
Share
Slideshow
-
Recent Posts
- Wearable Interactions Using Touch without a Touchscreen
- [Talk Summary] HandSight: A Touch-Based Wearable System to Increase Information Accessibility for People with Visual Impairments
- [Talk Summary] A large-scale analysis of YouTube videos depicting everyday thermal camera use
- [Summary] Google I/O and Microsoft Build 2018
- [Summary] StackGAN: Text to Photo-realistic Image Synthesis
Twitter
My TweetsRecent Comments
- CS475 Algorithm Analysis and Design – Course | Ruofei Du on Treap in 45 lines of C++
- MA066 Advanced Algebra I – Course | Ruofei Du on Gradient, Circulation, Laplacian, Divergence, Jacobian, Hessian, and Trace
- Mr Zhu (@834144373zhu) on Tutorial of Ray Casting, Ray Tracing, Path Tracing and Ray Marching
- サンプリングレンダリングの解説記事 – Tech masuk on Tutorial of Ray Casting, Ray Tracing, Path Tracing and Ray Marching
- starea on Estimated Cost of Per Atom Function in Real-time Shaders on the GPU
Archives
- November 2018
- August 2018
- May 2018
- April 2018
- March 2018
- November 2017
- October 2017
- August 2017
- July 2017
- April 2017
- March 2017
- February 2017
- January 2017
- December 2016
- November 2016
- October 2016
- September 2016
- June 2016
- April 2016
- March 2016
- February 2016
- December 2015
- November 2015
- October 2015
- September 2015
- August 2015
- July 2015
- June 2015
- May 2015
- September 2014
- September 2012
- October 2010
- May 2010
- July 2008
Categories
Meta