Created
June 16, 2018 21:02
-
-
Save Daniel-Abrecht/873253bdedb0a9fbcb91c6744a96c623 to your computer and use it in GitHub Desktop.
Fur inequality rendering
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
</head> | |
<body> | |
<canvas id="canvas" width="512" height="512"></canvas> | |
<script type="x-shader/x-vertex"> | |
uniform vec3 direction, ucamera; | |
attribute vec3 coordinates; | |
varying vec3 ray; | |
varying vec3 vcamera; | |
const vec3 up = vec3(0,1,0); | |
void main(void){ | |
mat3 rotation = mat3( | |
-1,0,0, | |
0,0,1, | |
0,1,0 | |
); | |
vec3 forward = normalize(direction); | |
if(forward != up){ | |
vec3 left = normalize(cross(forward,up)); | |
vec3 top = normalize(cross(left,forward)); | |
rotation = mat3(left,top,forward); | |
} | |
ray = rotation * vec3(coordinates.xy,1); | |
vcamera = ucamera; | |
gl_Position = vec4(coordinates, 1.0); | |
} | |
</script> | |
<script type="x-shader/x-fragment"> | |
precision mediump float; | |
varying vec3 ray; | |
varying vec3 vcamera; | |
const vec3 up = vec3(0,1,0); | |
const float depth = 5.; | |
const int resolution = 1000; | |
const int backtrack = 30; | |
const float displacement = 1.5; | |
const int overtrace = 2; | |
const float step = depth / float(resolution); | |
const float backtrack_step = step / float(backtrack); | |
bool fur(vec3 p){ | |
const float n = 10.; | |
const float d = 0.75; | |
const float r = 0.5; | |
const float m = 3.; | |
const vec2 t = vec2(-0.6, 1.4); | |
p.xyz = p.zxy; | |
if(p.z < 0.) | |
return false; | |
p.xy += vec2(cos(p.z*m*3.14*2.),sin(p.z*m*3.14*2.))/(n*2.); | |
p.xy += p.z*p.z * t; | |
p.xy = mod(abs(p.xy) * n, 2.) - 1.; | |
return 1. > ( dot(p.xy,p.xy) + p.z/d*r) + (1.-r); | |
} | |
bool sphere(vec3 p){ | |
return dot(p,p) < 1.; | |
} | |
bool plotfunc(vec3 p){ | |
return fur(p); | |
} | |
float finetune_distance(vec3 ray, vec3 viewpoint, float distance){ | |
float res = distance; | |
for(int i=0; i<backtrack*overtrace; i++){ | |
float bdist = float(i)*backtrack_step; | |
vec3 position = ray * (distance-bdist); | |
if(plotfunc(position-viewpoint)){ | |
res = distance-bdist; | |
}else{ | |
return res; | |
} | |
} | |
return res; | |
} | |
float finetune_surface_distance(vec3 ray, vec3 viewpoint){ | |
for(int i=0; i<backtrack*overtrace; i++){ | |
float bdist = float(i)*backtrack_step; | |
vec3 position = ray * bdist; | |
if(plotfunc(position+viewpoint)) | |
return bdist; | |
} | |
return 1000.; | |
} | |
float getDisplacement(vec3 ray, vec3 viewpoint){ | |
if(plotfunc(viewpoint)){ | |
return finetune_distance(ray,-viewpoint,0.); | |
}else{ | |
return finetune_surface_distance(ray,viewpoint); | |
} | |
} | |
void main(void){ | |
vec3 viewpoint = vcamera; | |
vec3 zray = normalize(ray); | |
vec3 xray = ray == up ? vec3(1,0,0) : normalize(cross(zray,up)); | |
vec3 yray = normalize(cross(zray,xray)); | |
float distance; | |
vec3 position; | |
bool found = false; | |
for(int i=0; i<resolution; i++){ | |
distance = float(i)*step; | |
position = zray * distance; | |
if(plotfunc(position-viewpoint)){ | |
found = true; | |
break; | |
} | |
} | |
if(!found) | |
discard; | |
distance = finetune_distance(zray,viewpoint,distance); | |
position = zray * distance; | |
float ld = getDisplacement(zray,position - viewpoint + xray * backtrack_step * displacement); | |
float rd = getDisplacement(zray,position - viewpoint - xray * backtrack_step * displacement); | |
float td = getDisplacement(zray,position - viewpoint + yray * backtrack_step * displacement); | |
float bd = getDisplacement(zray,position - viewpoint - yray * backtrack_step * displacement); | |
vec3 dir = vec3(ld-rd,td-bd,0) * float(backtrack) / ( float(step) * displacement); | |
if(dir.xy == vec2(0,0)){ | |
dir.z = 1.; | |
}else{ | |
dir.z = 1. / length(dir.xy); | |
} | |
dir = normalize(dir); | |
gl_FragColor = vec4(dir, 1); | |
} | |
</script> | |
<script> | |
var canvas = document.getElementById("canvas"); | |
var gl = canvas.getContext("webgl"); | |
var rx=0.14, ry=-0.15, x=0, y=-1.25, z=0, keys=[]; | |
var vertices = [ | |
-1, 1, 0, | |
-1,-1, 0, | |
1,-1, 0, | |
-1, 1, 0, | |
1,-1, 0, | |
1, 1, 0, | |
]; | |
indices = [0,1,2,3,4,5]; | |
var vertex_buffer = gl.createBuffer(); | |
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer); | |
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); | |
gl.bindBuffer(gl.ARRAY_BUFFER, null); | |
var Index_Buffer = gl.createBuffer(); | |
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, Index_Buffer); | |
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW); | |
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); | |
var vertCode = document.querySelector('script[type="x-shader/x-vertex"]').textContent; | |
var fragCode = document.querySelector('script[type="x-shader/x-fragment"]').textContent; | |
var vertShader = gl.createShader(gl.VERTEX_SHADER); | |
gl.shaderSource(vertShader, vertCode); | |
gl.compileShader(vertShader); | |
var compiled = gl.getShaderParameter(vertShader, gl.COMPILE_STATUS); | |
if(!compiled){ | |
var compilationLog = gl.getShaderInfoLog(vertShader); | |
console.log('Vertex shader compile error: ' + compilationLog); | |
} | |
var fragShader = gl.createShader(gl.FRAGMENT_SHADER); | |
gl.shaderSource(fragShader, fragCode); | |
gl.compileShader(fragShader); | |
var compiled = gl.getShaderParameter(fragShader, gl.COMPILE_STATUS); | |
if(!compiled){ | |
var compilationLog = gl.getShaderInfoLog(fragShader); | |
console.log('Fragment shader compile error: ' + compilationLog); | |
} | |
var shaderProgram = gl.createProgram(); | |
gl.attachShader(shaderProgram, vertShader); | |
gl.attachShader(shaderProgram, fragShader); | |
gl.linkProgram(shaderProgram); | |
gl.useProgram(shaderProgram); | |
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer); | |
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, Index_Buffer); | |
var coord = gl.getAttribLocation(shaderProgram, "coordinates"); | |
gl.vertexAttribPointer(coord, 3, gl.FLOAT, false, 0, 0); | |
gl.enableVertexAttribArray(coord); | |
gl.disable(gl.DEPTH_TEST); | |
var direction = gl.getUniformLocation(shaderProgram, 'direction'); | |
var ucamera = gl.getUniformLocation(shaderProgram, 'ucamera'); | |
gl.viewport(0,0,canvas.width,canvas.height); | |
function draw(){ | |
var dx = -Math.cos(ry*Math.PI*2)*Math.sin(rx*Math.PI*2), | |
dy = Math.sin(ry*Math.PI*2), | |
dz = Math.cos(rx*Math.PI*2)*Math.cos(ry*Math.PI*2); | |
if(keys[89]){ | |
x += dx * 0.01; | |
y += dy * 0.01; | |
z += dz * 0.01; | |
} | |
if(keys[88]){ | |
x -= dx * 0.01; | |
y -= dy * 0.01; | |
z -= dz * 0.01; | |
} | |
if(keys[37]) rx -= 0.01; | |
if(keys[39]) rx += 0.01; | |
if(keys[38]) ry -= 0.01; | |
if(keys[40]) ry += 0.01; | |
if(ry>0.25) ry=0.25; | |
if(ry<-0.25) ry=-0.25; | |
gl.clearColor(0.0, 0.0, 0.3, 1); | |
gl.clear(gl.COLOR_BUFFER_BIT); | |
gl.uniform3f(ucamera,x,y,z); | |
gl.uniform3f(direction,dx,dy,dz); | |
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0); | |
requestAnimationFrame(draw); | |
} | |
draw(); | |
addEventListener("keydown",function(event){ | |
keys[event.which] = true; | |
}); | |
addEventListener("keyup",function(event){ | |
keys[event.which] = false; | |
}); | |
</script> | |
</body></html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
</head> | |
<body> | |
<canvas id="ra" width="512" height="512"></canvas> | |
<canvas id="rb" width="512" height="512"></canvas><br/> | |
<canvas id="rc" width="512" height="512"></canvas> | |
<br/> | |
<canvas id="rd" width="512" height="512"></canvas> | |
<canvas id="re" width="512" height="512"></canvas><br/> | |
<canvas id="rf" width="512" height="512"></canvas> | |
<script> | |
var rae = document.getElementById("ra"); | |
var rac = rae.getContext("2d"); | |
var rbe = document.getElementById("rb"); | |
var rbc = rbe.getContext("2d"); | |
var rce = document.getElementById("rc"); | |
var rcc = rce.getContext("2d"); | |
var rde = document.getElementById("rd"); | |
var rdc = rde.getContext("2d"); | |
var ree = document.getElementById("re"); | |
var rec = ree.getContext("2d"); | |
var rfe = document.getElementById("rf"); | |
var rfc = rfe.getContext("2d"); | |
function plot(f,w,h,x,y){ | |
x = x || 0; | |
y = y || 0; | |
w = w || rae.width; | |
h = h || rae.height; | |
for(let j=0;j<h;j++){ | |
let ry = j / h * 2 - 1; | |
for(let i=0;i<w;i++){ | |
let rx = i / w * 2 - 1; | |
let green1 = 0; | |
let red1 = 0; | |
let green2 = 0; | |
let red2 = 0; | |
let green3 = 0; | |
let red3 = 0; | |
let d1 = -1; | |
let d2 = -1; | |
let d3 = -1; | |
for(let k=0;k<w;k++){ | |
let rz = k / w * 2 - 1; | |
let r1 = Math.max(-1,Math.min(1,+f([rx,ry,-rz]))); | |
let r2 = Math.max(-1,Math.min(1,+f([rz,ry,rx]))); | |
let r3 = Math.max(-1,Math.min(1,+f([rx,rz,ry]))); | |
if(r1 > 0){ | |
green1 += r1; | |
if(d1 == -1) | |
d1 = 1-k/w; | |
}else{ | |
red1 -= r1; | |
} | |
if(r2 > 0){ | |
green2 += r2; | |
if(d2 == -1) | |
d2 = 1-k/w; | |
}else{ | |
red2 -= r2; | |
} | |
if(r3 > 0){ | |
green3 += r3; | |
if(d3 == -1) | |
d3 = 1-k/w; | |
}else{ | |
red3 -= r3; | |
} | |
} | |
green1 /= w; | |
red1 /= w; | |
green2 /= w; | |
red2 /= w; | |
green3 /= w; | |
red3 /= w; | |
rac.fillStyle="rgb("+Math.round(red1*220+35)+","+Math.round(green1*220+35)+",0)"; | |
rac.fillRect(i+x,j+y,1,1); | |
rbc.fillStyle="rgb("+Math.round(red2*220+35)+","+Math.round(green2*220+35)+",0)"; | |
rbc.fillRect(i+x,j+y,1,1); | |
rcc.fillStyle="rgb("+Math.round(red3*220+35)+","+Math.round(green3*220+35)+",0)"; | |
rcc.fillRect(i+x,j+y,1,1); | |
let c = x=>Math.max(Math.round((x*0.9+0.1)*255),0); | |
rdc.fillStyle="rgb("+c(d1)+","+c(d1)+","+c(d1)+")"; | |
rdc.fillRect(i+x,j+y,1,1); | |
rec.fillStyle="rgb("+c(d2)+","+c(d2)+","+c(d2)+")"; | |
rec.fillRect(i+x,j+y,1,1); | |
rfc.fillStyle="rgb("+c(d3)+","+c(d3)+","+c(d3)+")"; | |
rfc.fillRect(i+x,j+y,1,1); | |
} | |
} | |
} | |
function q(x){return x*x;} | |
function fur([x,y,z],n,f,r,d){ | |
if(z < -1) return; | |
z = z * 0.5 + 0.5; | |
x += Math.cos(z*f*Math.PI*2)/(n*2) * (1-r); | |
y += Math.sin(z*f*Math.PI*2)/(n*2) * (1-r); | |
x += z*z * 1; | |
y += z*z * -2; | |
x = Math.abs(x) * n % 2 - 1; | |
y = Math.abs(y) * n % 2 - 1; | |
return 1 > ( x*x + y*y + z/d*r) + (1-r); | |
} | |
function smile([x,y,z]){ | |
x *= 6; | |
y *= 6; | |
y = -y; | |
return q(x)+q(y)<36 && q(x+2.5)+q(y-2.5)>2.25 && q(x-2.5)+q(y-2.5)>2.25 && q((y+3.5)/1.5-q(x/4))+q(x/4)>1; | |
} | |
plot(x=>fur(x,15,5,0.5,3/4)); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment