Hi!
I wanted to share this (biased) implementation of path tracing. It’s slow, so you might need a strong device!
function setup()
sin,cos,rad=math.sin,math.cos,math.rad
spriteMode(CORNER)
parameter.watch("1/DeltaTime")
parameter.number("Moving",0,0.1,0)
RES=4
Screen=image(WIDTH/RES,HEIGHT/RES)
M=mesh()
M.vertices={vec2(0,0),vec2(Screen.width,0),vec2(Screen.width,Screen.height),
vec2(Screen.width,Screen.height),vec2(0,Screen.height),vec2(0,0)}
M.texCoords={vec2(0,0),vec2(1,0),vec2(1,1),vec2(1,1),vec2(0,1),vec2(0,0)}
M.shader=shader(PTverts,PTfrag)
M.shader.SColors={vec3(1,1,1),vec3(0.6,0.6,1),vec3(0.8,0.8,0.8),vec3(1,1,1),vec3(1,1,1),vec3(1,0.3,0.3),vec3(0.3,0.3,1)}
M.shader.Spheres={vec4(0,0.3,0,0.3),vec4(0.8,0.3,-1,0.3),
vec4(0,-100,0,100),vec4(0,104,0,100),vec4(0,0,-102,100),vec4(-102,0,0,100),vec4(102,0,0,100)}
M.shader.Lights={vec4(-0.3,1,0,0.15),vec4(0,1,6,0.15)}
M.shader.LColors={vec3(1,1,1),vec3(0,1,1)}
--Variabler
Angle=vec2(180,0)
Eye=vec3(0,0,1)
Pos=vec3(0,1.6,3)
end
function draw()
Eye=vec3(sin(rad(Angle.x)),Angle.y,cos(rad(Angle.x))):normalize()
_TRay=Eye:cross(vec3(0,1,0))
Pos=Pos+Eye*Moving
--Draw
noSmooth()
setContext(Screen)
M.shader.Ray=Eye
M.shader.TRay=_TRay:normalize()
M.shader.BRay=_TRay:cross(Eye):normalize()
M.shader.Position=Pos
M.shader.Time=ElapsedTime
M:draw()
setContext()
background(0, 0, 0, 255)
sprite(Screen,0,0,WIDTH,HEIGHT)
end
function touched(t)
if t.state==BEGAN then
fpos=vec2(t.x,t.y)
fangle=vec2(Angle.x,Angle.y)
end
if t.state==MOVING then
Angle.x=fangle.x-(t.x-fpos.x)/2
Angle.y=(t.y-fpos.y)/80
end
if t.state==ENDED then
fpos=vec2(t.prevX,t.prevY)
fangle=vec2(Angle.x,Angle.y)
end
end
PTverts=[[
uniform mat4 modelViewProjection;
attribute vec4 position;
attribute vec2 texCoord;
uniform vec3 Ray;
uniform vec3 TRay;
uniform vec3 BRay;
varying mat3 Eye;
varying highp vec2 vt;
#define Aspect 749./768.
void main() {
vt=texCoord;
Eye=mat3(TRay.x,BRay.x,Ray.x,TRay.y,BRay.y,Ray.y,TRay.z,BRay.z,Ray.z);
gl_Position=modelViewProjection*position;
}
]]
PTfrag=[[
precision highp float;
varying highp vec2 vt;
varying mat3 Eye;
uniform vec3 Position;
#define NSpheres 7
#define NLights 2
uniform vec4 Spheres[NSpheres];
uniform vec3 SColors[NSpheres];
uniform vec4 Lights[NLights];
uniform vec3 LColors[NLights];
uniform float Time;
//Quali
#define Far 200.
#define GLSamples 8
//Const
#define IGLS 1./max(float(GLSamples),1.)
#define PI 3.14159
#define Aspect 749./768.
//#define Aspect 1024./768.
vec2 seed=vt*vec2(Time*34.69467);
vec2 noise() {
seed+=vec2(-1.,1.);
return vec2(fract(sin(dot(seed.xy,vec2(12.9898,78.233)))*43758.5453),
fract(cos(dot(seed,vec2(4.898,7.23)))*23421.631));
}
float sphere(vec3 pos, vec3 dir, vec4 sph) {
vec3 co=pos-sph.xyz;
float b=dot(co,dir);
float c=dot(co,co)-sph.w*sph.w;
float h=b*b-c;
//if (h<0.) return -1.;
return -b-sqrt(h);
}
int Trace(vec3 pos, vec3 ray, out vec3 col, out vec3 cpos, out vec3 norm) {
float d=Far; float dd; int result=0;
for (int i=0; i<NSpheres; i++) {
dd=sphere(pos,ray,Spheres[i]);
if (dd<0. || dd>d) continue;
result=1;
d=dd; cpos=pos+ray*dd;
col=SColors[i]; norm=normalize(cpos-Spheres[i].xyz);
}
for (int i=0; i<NLights; i++) {
dd=sphere(pos,ray,Lights[i]);
if (dd<0. || dd>d) continue;
d=dd;
col=LColors[i];
return 2;
}
return result;
}
mat3 TBN(vec3 N) {
vec3 Nt,Nb;
if (abs(N.x)>abs(N.y)) Nt=vec3(N.z,0.,-N.x)/sqrt(N.x*N.x+N.z*N.z);
else Nt=vec3(0.,-N.z,N.y)/sqrt(N.y*N.y+N.z*N.z);
Nb=normalize(cross(N,Nt));
return mat3(Nt.x,Nb.x,N.x,Nt.y,Nb.y,N.y,Nt.z,Nb.z,N.z);
}
vec3 NewSample() {
vec2 v=noise();
float theta=sqrt(v.x);
float phi=2.*PI*v.y;
float x=theta*cos(phi);
float z=theta*sin(phi);
return vec3(x,z,sqrt(max(0.,1.-v.x)));
}
float Shadow(vec3 pos, vec3 ray, float dist) {
for (int i=0; i<2; i++) {
float d=sphere(pos,ray,Spheres[i]);
if (d>0. && d<dist) return 0.;
}
return 1.;
}
vec3 Light(vec3 cpos, vec3 norm, int rays) {
vec3 Col=vec3(0.00001);
//AreaLight
for (int i=0; i<NLights; i++) {
mat3 lm=TBN(normalize(Lights[i].xyz-cpos));
for (int r=0; r<rays; r++) {
vec3 RandPos=Lights[i].xyz+(NewSample()*lm)*Lights[i].w;
vec3 ltp=normalize(RandPos-cpos);
float len=length(RandPos-cpos);
float ll=max(0.,1.-len/5.);
Col+=LColors[i]*max(0.,dot(norm,ltp)*Shadow(cpos,ltp,len)*ll);
}
}
return Col/float(rays);
}
vec3 background(vec3 dir) {
return vec3(0.,0.7,1.)*0.7;//*max(dot(dir,vec3(0.,1.,0.)),0.);
}
vec3 Radiance(vec3 pos, in mat3 NM, vec3 PCol) {
vec3 Color=vec3(0.); vec3 norm,sample,gcol,gpos,cpos; mat3 dnm;
for (int i=0; i<GLSamples; i++) {
sample=NewSample();
sample=normalize(sample*NM);
int gpr=Trace(pos,sample,gcol,gpos,norm);
if (gpr==0) { Color+=PCol*background(sample); continue; }
else if (gpr==2) { Color+=gcol; }
Color+=PCol*gcol*Light(gpos,norm,1);
}
return Color*IGLS*0.5;
}
void main() {
vec2 uv=(vt*2.-1.)*vec2(Aspect,1.);
vec3 Ray=normalize(vec3(uv,1.)*Eye);
//vec3 eye=vec3(Eye[0][2],Eye[1][2],Eye[2][2]);
vec3 Final=vec3(0.);
vec3 PPos,PCol,PNorm;
int pr=Trace(Position,Ray,PCol,PPos,PNorm);
if (pr==0) gl_FragColor=vec4(background(Ray),1.);
else if (pr==2) gl_FragColor=vec4(PCol,1.);
else {
vec3 Pixel=PCol*Light(PPos,PNorm,4);
Final+=Pixel*0.4+Radiance(PPos+PNorm*0.001,TBN(PNorm),PCol);
gl_FragColor=vec4(Final.xyz,1.);
}
}
]]