Created
August 21, 2018 15:13
-
-
Save diska/cbd01ce8f7f88e6a4b0abe29fdd08fbf to your computer and use it in GitHub Desktop.
三葉レイ動画の25:10時点のコードのGLSL化。
This file contains 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
<meta charset="utf-8"><br/> | |
<canvas id="CNVS"></canvas><hr/> | |
<input id="CAM" type="range" step="0.02" min="0" max="6.3"> | |
<script> | |
const vsrc=`attribute vec4 p;void main(){gl_Position=p;}`; | |
const fsrc=`precision mediump float; | |
struct Ray{ vec3 o, d;}; | |
struct Sph{ vec3 o; float r; vec3 ref; vec3 le;}; | |
const float width=120., height=80.; | |
float intersect(Sph sph, Ray ray, float tmin, float tmax){ | |
vec3 op=sph.o-ray.o; | |
float bo=dot(op, ray.d); | |
float det=bo*bo-dot(op,op)+sph.r*sph.r; | |
if(det<0.){return -1.;} | |
float t1=bo-sqrt(det); | |
if(tmin<t1&&t1<tmax){return t1;} | |
float t2=bo+sqrt(det); | |
if(tmin<t2&&t2<tmax){return t2;} | |
return -1.; | |
} | |
vec3 tonemap(vec3 c){ | |
float r=pow(c.r, 1./2.2); | |
float g=pow(c.g, 1./2.2); | |
float b=pow(c.b, 1./2.2); | |
return vec3(r,g,b); | |
} | |
void getSphs1(out Sph[2] sphs){// "2 spheres" scene | |
sphs[0].o=vec3( .5,0,0), sphs[0].r=1., sphs[0].ref=vec3(1,0,0); | |
sphs[1].o=vec3(-.5,0,0), sphs[1].r=1., sphs[1].ref=vec3(0,1,0); | |
} | |
void getSphs2(out Sph[8] sphs){// Cornell Box scene | |
const float bnum=1e5; | |
sphs[0].o=vec3( bnum+1., 40.8, 81.6), sphs[0].r=bnum, sphs[0].ref=vec3(.75,.25,.25); | |
sphs[1].o=vec3(-bnum+99., 40.8, 81.6), sphs[1].r=bnum, sphs[1].ref=vec3(.25,.25,.75); | |
sphs[2].o=vec3(50., 40.8, bnum), sphs[2].r=bnum, sphs[2].ref=vec3(.75); | |
sphs[3].o=vec3(50., bnum, 81.6), sphs[3].r=bnum, sphs[3].ref=vec3(.75); | |
sphs[4].o=vec3(50., -bnum+81.6, 81.6), sphs[4].r=bnum, sphs[4].ref=vec3(.75); | |
sphs[5].o=vec3(27., 16.5, 47.), sphs[5].r=16.5, sphs[5].ref=vec3(.999); | |
sphs[6].o=vec3(73., 16.5, 78.), sphs[6].r=16.5, sphs[6].ref=vec3(.999); | |
sphs[7].o=vec3(50., 681.6-.27, 81.6), sphs[7].r=600., sphs[7].ref=vec3(0); | |
sphs[7].le=vec3(12); | |
} | |
uniform vec3 uDir; | |
void main(){ | |
const float PI=3.141592; | |
float fov=30.*PI/180., aspect=width/height; | |
// camera parameters for "2 spheres" scene | |
// vec3 eye=vec3(5,5,5), center=vec3(0,0,0); | |
// camera parameters for Cornell Box scene | |
// vec3 eye=vec3(50.,52.,295.6), center=eye+vec3(0.,-0.042612,-1.); | |
vec3 eye=vec3(50.,52.,295.6), center=eye+uDir; | |
vec3 up=vec3(0,1,0); | |
// basis vectors for camera coordinates | |
vec3 wE=normalize(eye-center); | |
vec3 uE=normalize(cross(up, wE)); | |
vec3 vE=cross(wE, uE); | |
// | |
float tf=tan(fov*.5); | |
vec2 rp=vec2(2.*gl_FragCoord.x/width-1., 2.*gl_FragCoord.y/height-1.); | |
vec3 wo=normalize(vec3(aspect*tf*rp.x, tf*rp.y, -1)); | |
Ray ray; | |
// ray.o=vec3(vec2(rp), 5); ray.d=vec3(0,0,-1); | |
ray.o=eye; | |
ray.d=uE*wo.x+vE*wo.y+wE*wo.z; | |
// | |
vec3 color=vec3(1,0,1); | |
Sph sph; | |
// Sph sphs[2]; getSphs1(sphs); | |
Sph sphs[8]; getSphs2(sphs); | |
float h, minh=-1., tmax=1000.; | |
for(int i=0; i<8; i++){ | |
h=intersect(sphs[i], ray, 0., tmax); | |
if(h<0.){continue;} | |
sph=sphs[i]; | |
minh=h; | |
tmax=h; | |
} | |
vec3 p, n, c; | |
if(minh>0.){ | |
p=ray.o+ray.d*minh; // 交点 | |
n=(p-sph.o)/sph.r; // 法線 | |
c=sph.ref; // 球の色 | |
} | |
if(minh>0.){ | |
c*=dot(n, -ray.d); // カメラ向いてる面はよく反射する。 | |
gl_FragColor=vec4(color,1); | |
gl_FragColor=vec4(tonemap(abs(c)),1); | |
}else{ | |
gl_FragColor=vec4(0,0,0,1); | |
} | |
}`; | |
// ポリゴン描画するだけであとの処理はFragmentShaderに任せる。 | |
var cx, uDir; | |
function draw(){ | |
const width=120, height=80; // Image size | |
CNVS.width=width, CNVS.height=height; | |
cx=CNVS.getContext("webgl"); | |
var vs=cx.createShader(cx.VERTEX_SHADER);cx.shaderSource(vs,vsrc); | |
var fs=cx.createShader(cx.FRAGMENT_SHADER);cx.shaderSource(fs,fsrc); | |
var pg=cx.createProgram();cx.attachShader(pg,vs);cx.attachShader(pg,fs); | |
cx.compileShader(vs);cx.compileShader(fs);cx.linkProgram(pg); | |
console.log(`vs:${cx.getShaderInfoLog(vs)}\nfs:${cx.getShaderInfoLog(fs)}\n`); | |
console.log(`pg:${cx.getProgramInfoLog(pg)}\n`); | |
cx.enableVertexAttribArray(0); | |
uDir=cx.getUniformLocation(pg, "uDir"); | |
cx.useProgram(pg); | |
var abuf=cx.createBuffer(cx.ARRAY_BUFFER); | |
var data=new Float32Array([-1,-1, 1,-1, -1,1, 1,1]); | |
cx.bindBuffer(cx.ARRAY_BUFFER,abuf); | |
cx.bufferData(cx.ARRAY_BUFFER, data, cx.STATIC_DRAW); | |
cx.vertexAttribPointer(0, 2,cx.FLOAT, false, 0,0); | |
cx.bindBuffer(cx.ARRAY_BUFFER,null); | |
}; draw(); | |
function update(){ | |
var x=0,y=-0.042612,z=-1; | |
x=Math.sin(CAM.value), z=Math.cos(CAM.value); | |
cx.uniform3fv(uDir, [x,y,z]); | |
cx.drawArrays(cx.TRIANGLE_STRIP,0,4); | |
} update(); | |
CAM.addEventListener("input", update); | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment