Last active
December 17, 2015 11:58
-
-
Save sp4cemonkey/5605858 to your computer and use it in GitHub Desktop.
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
--# Main | |
-- RayTracer 3Balls | |
-- Use this function to perform your initial setup | |
function setup() | |
displayMode(FULLSCREEN) | |
myMesh = mesh() | |
--myMesh.shader = shader("Documents:ray") | |
myMesh.shader = shader(rayShader.vertexShader, rayShader.fragmentShader) | |
aVPosBuffer = myMesh:buffer("aVertexPosition") | |
aPPosBuffer = myMesh:buffer("aPlotPosition") | |
aVPosBuffer:resize(6) | |
aPPosBuffer:resize(6) | |
size = 1.0 -- 1.0 is fullscreen | |
aVPosBuffer[1] = vec2(size,size) | |
aVPosBuffer[2] = vec2(-size,size) | |
aVPosBuffer[3] = vec2(size,-size) | |
aVPosBuffer[4] = vec2(size,-size) | |
aVPosBuffer[5] = vec2(-size,size) | |
aVPosBuffer[6] = vec2(-size,-size) | |
t=0 | |
s1 = vec3(0,0,0) | |
s2 = vec3(0,0,0) | |
s3 = vec3(0,0,0) | |
sphere = Primitive:Sphere(3) | |
end | |
function calcCamera() | |
cameraFrom = vec3(math.sin(t*0.4)*28, math.sin(t*0.13)*5+5, math.cos(t*0.4)*28) | |
cameraTo = vec3(0,0,0) | |
cameraPersp = 6 | |
up = vec3(0,1,0) | |
cameraDir = (cameraTo - cameraFrom):normalize() | |
cameraLeft = cameraDir:cross(up):normalize() | |
cameraUp = cameraLeft:cross(cameraDir):normalize() | |
cameraCenter = cameraFrom + cameraDir * cameraPersp | |
ratio = WIDTH/HEIGHT | |
cameraTopLeft = cameraCenter + cameraUp + cameraLeft * ratio | |
cameraBotLeft = cameraCenter - cameraUp + cameraLeft * ratio | |
cameraTopRight = cameraCenter + cameraUp - cameraLeft * ratio | |
cameraBotRight = cameraCenter - cameraUp - cameraLeft * ratio | |
aPPosBuffer[1] = cameraTopLeft | |
aPPosBuffer[2] = cameraTopRight | |
aPPosBuffer[3] = cameraBotLeft | |
aPPosBuffer[4] = cameraBotLeft | |
aPPosBuffer[5] = cameraTopRight | |
aPPosBuffer[6] = cameraBotRight | |
end | |
function calcBalls() | |
s1.x = math.sin(t * 1.1) * 1.5 | |
s1.y = math.cos(t * 1.3) * 1.5 | |
s1.z = math.sin(t + math.pi/3) * 1.5 | |
s2.x = math.cos(t * 1.2) * 1.5 | |
s2.y = math.sin(t * 1.4) * 1.5 | |
s2.z = math.sin(t*1.25 - math.pi/3) * 1.5 | |
s3.x = math.cos(t * 1.15) * 1.5 | |
s3.y = math.sin(t * 1.37) * 1.5 | |
s3.z = math.sin(t*1.27) * 1.5 | |
end | |
-- This function gets called once every frame | |
function draw() | |
noSmooth() | |
strokeWidth(0) | |
calcBalls() | |
calcCamera() | |
myMesh.shader.cameraPos = cameraFrom | |
myMesh.shader.sphere1Center = s1 | |
myMesh.shader.sphere2Center = s2 | |
myMesh.shader.sphere3Center = s3 | |
background(0, 0, 0) | |
camera(cameraFrom.x, cameraFrom.y, cameraFrom.z, cameraTo.x, cameraTo.y, cameraTo.z) | |
perspective(19) | |
translate(s1.x, s1.y, s1.z) | |
fill(0,0,255,255) | |
sphere:draw() | |
resetMatrix() | |
translate(s2.x, s2.y, s2.z) | |
fill(255,0,0,255) | |
sphere:draw() | |
resetMatrix() | |
translate(s3.x, s3.y, s3.z) | |
fill(0,255,0,255) | |
sphere:draw() | |
resetMatrix() | |
translate(0, -2.7, 0) | |
rotate(90, 1, 0, 0) | |
fill(255,255,0,255) | |
ellipse(0, 0, 10.95464) | |
myMesh:draw() | |
t = t + 0.03 | |
if t> math.pi * 200 then | |
t = t - math.pi * 200 | |
end | |
--output.clear() | |
--print(1/DeltaTime) | |
end | |
rayShader = { | |
vertexShader = [[ | |
attribute vec2 aVertexPosition; | |
attribute vec3 aPlotPosition; | |
varying vec3 vPosition; | |
void main(void) | |
{ | |
gl_Position = vec4(aVertexPosition, 1.0, 1.0); | |
vPosition = aPlotPosition; | |
} | |
]], | |
fragmentShader = [[ | |
#extension GL_EXT_shader_framebuffer_fetch : require | |
precision highp float; | |
const vec3 lightDir = vec3(0.577350269, 0.577350269, -0.577350269); | |
varying vec3 vPosition; | |
uniform vec3 cameraPos; | |
uniform vec3 sphere1Center; | |
uniform vec3 sphere2Center; | |
uniform vec3 sphere3Center; | |
uniform lowp sampler2D texture; | |
bool intersectSphere(vec3 center, vec3 lStart, vec3 lDir, out float dist) { | |
vec3 c = center - lStart; | |
float b = dot(lDir, c); | |
float d = b*b - dot(c, c) + 1.0; | |
if (d < 0.0) { | |
dist = 10000.0; | |
return false; | |
} | |
dist = b - sqrt(d); | |
if (dist < 0.0) { | |
dist = 10000.0; | |
return false; | |
} | |
return true; | |
} | |
vec3 lightAt(vec3 N, vec3 V, vec3 color, vec3 p) { | |
vec3 L = lightDir; | |
vec3 R = reflect(-L, N); | |
float spec = max(dot(R,V), 0.0); | |
float diff = max(dot(L,N), 0.0); | |
float c, d; | |
bool h1, h2, h3; | |
if (spec > 0.0 || diff > 0.0) { | |
h1 = intersectSphere(sphere1Center, p, L, d); | |
h2 = intersectSphere(sphere2Center, p, L, d); | |
h3 = intersectSphere(sphere3Center, p, L, d); | |
if (h1 || h2 || h3) { | |
c = 0.3; | |
} | |
else { | |
c = 0.3 + 0.4 * pow(spec, 30.0) + 0.7 * diff; | |
} | |
} | |
else { | |
c = 0.3; | |
} | |
if (c > 1.0) { | |
return mix(color, vec3(1.6, 1.6, 1.6), c - 1.0); | |
} | |
return c * color; | |
} | |
bool intersectWorld(vec3 lStart, vec3 lDir, out vec3 pos, out vec3 normal, out vec3 color) { | |
float d1, d2, d3; | |
bool h1, h2, h3; | |
h1 = intersectSphere(sphere1Center, lStart, lDir, d1); | |
h2 = intersectSphere(sphere2Center, lStart, lDir, d2); | |
h3 = intersectSphere(sphere3Center, lStart, lDir, d3); | |
if (h1 && d1 < d2 && d1 < d3) { | |
pos = lStart + d1 * lDir; | |
normal = pos - sphere1Center; | |
color = vec3(0.0, 0.0, 0.9); | |
} | |
else if (h2 && d2 < d3) { | |
pos = lStart + d2 * lDir; | |
normal = pos - sphere2Center; | |
color = vec3(0.9, 0.0, 0.0); | |
} | |
else if (h3) { | |
pos = lStart + d3 * lDir; | |
normal = pos - sphere3Center; | |
color = vec3(0.0, 0.9, 0.0); | |
} | |
else if (lDir.y < -0.01) { | |
pos = lStart + ((lStart.y + 2.7) / -lDir.y) * lDir; | |
if ((pos.x + pos.z) > 20.0) { | |
return false; | |
} | |
if (pos.x*pos.x + pos.z*pos.z > 30.0) { | |
return false; | |
} | |
normal = vec3(0.0, 1.0, 0.0); | |
if (fract(pos.x / 5.0) > 0.5 == fract(pos.z / 5.0) > 0.5) { | |
color = vec3(1.0); | |
} | |
else { | |
color = vec3(0.0); | |
} | |
} | |
else { | |
return false; | |
} | |
return true; | |
} | |
void main(void) | |
{ | |
vec3 cameraDir = normalize(vPosition - cameraPos); | |
float d; | |
vec3 p1, norm, p2; | |
vec3 col, colT, colM, col3; | |
lowp vec4 curCol = gl_LastFragData[0]; | |
bool hit; | |
hit = false; | |
if (curCol.r > 0.1 && curCol.g > 0.1) { | |
p1 = cameraPos + ((cameraPos.y + 2.7) / -cameraDir.y) * cameraDir; | |
norm = vec3(0.0, 1.0, 0.0); | |
if (fract(p1.x / 5.0) > 0.5 == fract(p1.z / 5.0) > 0.5) { | |
colT = vec3(1.0); | |
} | |
else { | |
colT = vec3(0.0); | |
} | |
hit = true; //intersectWorld(cameraPos, cameraDir, p1, norm, colT); | |
} | |
else if (curCol.b > 0.1) { | |
intersectSphere(sphere1Center, cameraPos, cameraDir, d); | |
p1 = cameraPos + d * cameraDir; | |
norm = p1 - sphere1Center; | |
colT = vec3(0.0, 0.0, 0.9); | |
hit = true; | |
} | |
else if (curCol.r > 0.1) { | |
intersectSphere(sphere2Center, cameraPos, cameraDir, d); | |
p1 = cameraPos + d * cameraDir; | |
norm = p1 - sphere2Center; | |
colT = vec3(0.9, 0.0, 0.0); | |
hit = true; | |
} | |
else if (curCol.g > 0.1) { | |
intersectSphere(sphere3Center, cameraPos, cameraDir, d); | |
p1 = cameraPos + d * cameraDir; | |
norm = p1 - sphere3Center; | |
colT = vec3(0.0, 0.9, 0.0); | |
hit = true; | |
} | |
if (hit) { | |
col = lightAt(norm, -cameraDir, colT, p1); | |
colM = (colT + vec3(0.7)) / 1.7; | |
cameraDir = reflect(cameraDir, norm); | |
if (intersectWorld(p1, cameraDir, p2, norm, colT)) { | |
col += lightAt(norm, -cameraDir, colT, p2) * colM; | |
colM *= (colT + vec3(0.7)) / 1.7; | |
cameraDir = reflect(cameraDir, norm); | |
if (intersectWorld(p2, cameraDir, p1, norm, colT)) { | |
col += lightAt(norm, -cameraDir, colT, p1) * colM; | |
} | |
} | |
gl_FragColor = vec4(col, 1.0); | |
} | |
else { | |
discard; | |
//gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); | |
} | |
}]] | |
} | |
--# Primitive | |
Primitive = class() | |
--primitves gives basic mesh building for cubes and isospheres | |
--triangles are wound consistently to avoid gl_facing issues | |
function Primitive:Cube() | |
m = mesh() | |
local vertices = { | |
vec3(-0.5, -0.5, 0.5), -- Left bottom front | |
vec3( 0.5, -0.5, 0.5), -- Right bottom front | |
vec3( 0.5, 0.5, 0.5), -- Right top front | |
vec3(-0.5, 0.5, 0.5), -- Left top front | |
vec3(-0.5, -0.5, -0.5), -- Left bottom back | |
vec3( 0.5, -0.5, -0.5), -- Right bottom back | |
vec3( 0.5, 0.5, -0.5), -- Right top back | |
vec3(-0.5, 0.5, -0.5), -- Left top back | |
} | |
-- now construct a cube out of the vertices above | |
m.vertices = { | |
-- Front | |
vertices[1], vertices[2], vertices[3], | |
vertices[1], vertices[3], vertices[4], | |
-- Right | |
vertices[2], vertices[6], vertices[7], | |
vertices[2], vertices[7], vertices[3], | |
-- Back | |
vertices[6], vertices[5], vertices[8], | |
vertices[6], vertices[8], vertices[7], | |
-- Left | |
vertices[5], vertices[1], vertices[4], | |
vertices[5], vertices[4], vertices[8], | |
-- Top | |
vertices[4], vertices[3], vertices[7], | |
vertices[4], vertices[7], vertices[8], | |
-- Bottom | |
vertices[5], vertices[6], vertices[2], | |
vertices[5], vertices[2], vertices[1], | |
} | |
return m | |
end | |
function Primitive:Sphere(depth) | |
m = mesh() | |
local t = (1 + math.sqrt(5)) / 2 | |
--all the vertices of an icosohedron | |
local vertices = { | |
vec3(-1 , t, 0):normalize(), | |
vec3(1 , t, 0):normalize(), | |
vec3(-1 , -t, 0):normalize(), | |
vec3(1 , -t, 0):normalize(), | |
vec3(0 , -1, t):normalize(), | |
vec3(0 , 1, t):normalize(), | |
vec3(0 , -1, -t):normalize(), | |
vec3(0 , 1, -t):normalize(), | |
vec3(t , 0, -1):normalize(), | |
vec3(t , 0, 1):normalize(), | |
vec3(-t , 0, -1):normalize(), | |
vec3(-t , 0, 1):normalize() | |
} | |
--20 faces | |
icovertices = { | |
-- 5 faces around point 0 | |
vertices[1], vertices[12], vertices[6], | |
vertices[1], vertices[6], vertices[2], | |
vertices[1], vertices[2], vertices[8], | |
vertices[1], vertices[8], vertices[11], | |
vertices[1], vertices[11], vertices[12], | |
-- 5 adjacent faces | |
vertices[2], vertices[6], vertices[10], | |
vertices[6], vertices[12], vertices[5], | |
vertices[12], vertices[11], vertices[3], | |
vertices[11], vertices[8], vertices[7], | |
vertices[8], vertices[2], vertices[9], | |
-- 5 faces around point 3 | |
vertices[4], vertices[10], vertices[5], | |
vertices[4], vertices[5], vertices[3], | |
vertices[4], vertices[3], vertices[7], | |
vertices[4], vertices[7], vertices[9], | |
vertices[4], vertices[9], vertices[10], | |
--5 adjacent faces | |
vertices[5], vertices[10], vertices[6], | |
vertices[3], vertices[5], vertices[12], | |
vertices[7], vertices[3], vertices[11], | |
vertices[9], vertices[7], vertices[8], | |
vertices[10], vertices[9], vertices[2] | |
} | |
local finalVertices = {} | |
--divide each triangle into 4 sub triangles to make an isosphere | |
--this can be repeated (based on depth) for higher res spheres | |
for j=1,depth do | |
for i=1,#icovertices/3 do | |
midpoint1 = ((icovertices[i*3-2] + icovertices[i*3-1])/2):normalize() | |
midpoint2 = ((icovertices[i*3-1] + icovertices[i*3])/2):normalize() | |
midpoint3 = ((icovertices[i*3] + icovertices[i*3-2])/2):normalize() | |
--triangle 1 | |
table.insert(finalVertices,icovertices[i*3-2]) | |
table.insert(finalVertices,midpoint1) | |
table.insert(finalVertices,midpoint3) | |
--triangle 2 | |
table.insert(finalVertices,midpoint1) | |
table.insert(finalVertices,icovertices[i*3-1]) | |
table.insert(finalVertices,midpoint2) | |
--triangle 3 | |
table.insert(finalVertices,midpoint2) | |
table.insert(finalVertices,icovertices[i*3]) | |
table.insert(finalVertices,midpoint3) | |
--triangle 4 | |
table.insert(finalVertices,midpoint1) | |
table.insert(finalVertices,midpoint2) | |
table.insert(finalVertices,midpoint3) | |
end | |
icovertices = finalVertices | |
finalVertices = {} | |
end | |
m.vertices = icovertices | |
return m | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment