Skip to content

Instantly share code, notes, and snippets.

@dermotbalson
Created July 27, 2013 05:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dermotbalson/6093875 to your computer and use it in GitHub Desktop.
Save dermotbalson/6093875 to your computer and use it in GitHub Desktop.
Reflect
--# Main
-- Display a few parametric surfaces
VERSION = "1.0.3"
PROJECTNAME = "ParaSurf"
function setup()
displayMode(FULLSCREEN)
sphere = ParaSphere(1)
sphere.color = color(253, 255, 0, 255)
torus = ParaTorus(1)
torus.color = color(242, 116, 27, 255)
supersphere = ParaSuperellipsoid(1)
supersphere.color = color(170, 220, 45, 255)
supertorus = ParaSupertoroid(1)
supertorus.color = color(60,150,240,255)
supersphere2 = ParaSuperellipsoid(1)
supersphere2.n1 = 1.7
supersphere2.n2 = 1.7
supersphere2.color = color(59, 240, 209, 255)
trefoil = ParaTrefoil(1)
trefoil.color = color(240,60,150,255)
cyl1 = ParaCylinder(0.75)
cyl1.color = color(39, 217, 155, 255)
cyl2 = ParaSupercylinder(0.75)
cyl2.color = color(119, 44, 158, 255)
cyl3 = ParaSupercylinder(0.75)
cyl3.n = 1.7
cyl3.color = color(231, 25, 36, 255)
grid = {
{ cyl3, supersphere2, trefoil },
{ cyl2, supersphere, supertorus },
{ cyl1, sphere, torus },
}
shadr = shader([[
attribute vec4 position;
attribute vec3 normal;
attribute vec3 color;
uniform mat4 modelViewProjection;
varying vec3 eyenormal;
varying vec3 diffuse;
void main(void)
{
eyenormal = mat3(modelViewProjection) * normal;
diffuse = color;
gl_Position = modelViewProjection * position;
}
]], [[
uniform highp vec3 light;
varying mediump vec3 eyenormal;
varying lowp vec3 diffuse;
void main(void)
{
highp vec3 N = normalize(eyenormal);
highp vec3 L = normalize(light);
highp vec3 E = vec3(0, 0, 1);
highp vec3 H = normalize(L + E);
highp float df = max(0.0, dot(N, L)) * 0.3;
highp float sf = max(0.0, dot(N, H));
sf = pow(sf, 250.0);
if(abs(N.z) < 0.2) sf = sf + (1.0 - abs(N.z)*(1.0/0.2));
sf = sf * 0.5;
lowp vec3 color = vec3(1,1,1) * 0.7 * diffuse + df * diffuse + sf * vec3(1,1,1);
gl_FragColor = vec4(min(1.0,color.x), min(1.0,color.y), min(1.0,color.z), 1.0);
}
]]
)
shadr.light = vec3(0,1500,1000)
rx, ry = 0, 0
end
function draw()
background(49, 49, 49, 255)
pushMatrix()
resetMatrix()
perspective(90, WIDTH/HEIGHT)
camera(0,0,-2, 0,0,0, 0,1,0)
rotate(rx, 1, 0, 0)
rotate(ry, 0, 1, 0)
frame = (frame or 0) + 1
for y = 1, #grid do
for x = 1, #grid[y] do
pushMatrix()
translate(x-1-(#grid[y]-1)/2, y-1-(#grid-1)/2, 0)
scale(0.75)
rotate(frame, 0, 1, 0)
local p = grid[y][x]
local m = p:paramesh()
m.shader = shadr
m:draw()
popMatrix()
end
end
popMatrix()
end
function touched(touch)
if tid then
if touch.state == ENDED then
tid = nil
tweenid = tween(0.2, _G, {rx=0,ry=0})
else
ry = ry - (tx - touch.x)*0.1
rx = rx - (ty - touch.y)*0.1
tx = touch.x
ty = touch.y
end
elseif touch.state == BEGAN then
tid = touch.id
tx = touch.x
ty = touch.y
if tweenid then
tween.stop(tweenid)
tweenid = nil
end
end
end
--# Parametric
-- Generate meshes for parametric surfaces
--
-- Parts adapted from code in
-- iPhone 3D Programming by Philip Rideout, O’Reilly, ISBN 978-0-596-80482-4.
ParaSurf = class()
function ParaSurf:init()
self.divx = 32
self.divy = 32
self.maxx = 100
self.maxy = 100
end
function ParaSurf:sgn(x)
if x < 0 then return -1
elseif x > 0 then return 1
end
return 0
end
function ParaSurf:eval(x, y, wrap)
if wrap then
if x < 0 then x = x + self.maxx end
if y < 0 then y = y + self.maxy end
if x > self.maxx then x = x - self.maxx end
if y > self.maxy then y = y - self.maxy end
end
return self:calculate(x,y)
end
function ParaSurf:calculate(x, y)
return vec3(x,y,0)
end
function ParaSurf:normal(x, y)
local v, v1, v2
local s = 0.001
if x + s >= self.maxx then x = x - s end
if y + s >= self.maxy then y = y - s end
if x <= s then x = x + s end
if y <= s then y = y + s end
v = self:eval(x, y, true)
v1 = self:eval(x+s, y, true)-v
v2 = self:eval(x, y+s, true)-v
return v1:cross(v2):normalize()
end
function ParaSurf:paramesh(rebuild)
local m
if rebuild or not self.mesh then m = mesh()
else return self.mesh end
local v = {}
local n = {}
for y = 0, self.divy-2 do
for x = 0, self.divx-2 do
x1 = ((x+self.divx)%(self.divx) * self.maxx)/(self.divx-1)
y1 = ((y+self.divy)%(self.divy) * self.maxy)/(self.divy-1)
x2 = ((x+1)%(self.divx) * self.maxx)/(self.divx-1)
y2 = ((y+self.divy)%(self.divy) * self.maxy)/(self.divy-1)
x3 = ((x+1)%(self.divx) * self.maxx)/(self.divx-1)
y3 = ((y+1)%(self.divy) * self.maxy)/(self.divy-1)
x4 = ((x+self.divx)%(self.divx) * self.maxx)/(self.divx-1)
y4 = ((y+1)%(self.divy) * self.maxy)/(self.divy-1)
v1 = self:eval(x1, y1, x, y)
v2 = self:eval(x2, y2, x, y)
v3 = self:eval(x3, y3, x, y)
v4 = self:eval(x4, y4, x, y)
table.insert(v, v1)
table.insert(v, v2)
table.insert(v, v3)
table.insert(v, v1)
table.insert(v, v3)
table.insert(v, v4)
n1 = self:normal(x1, y1, x, y)
n2 = self:normal(x2, y2, x, y)
n3 = self:normal(x3, y3, x, y)
n4 = self:normal(x4, y4, x, y)
table.insert(n, n1)
table.insert(n, n2)
table.insert(n, n3)
table.insert(n, n1)
table.insert(n, n3)
table.insert(n, n4)
end
end
m.vertices = v
m.normals = n
m:setColors(self.color or color(200))
self.mesh = m
return m
end
ParaSphere = class(ParaSurf)
function ParaSphere:init(radius)
ParaSurf.init(self)
self.maxx = math.pi
self.maxy = math.pi*2
self.radius = (radius or 1)/2
end
function ParaSphere:calculate(u, v)
local x = self.radius * math.sin(u) * math.cos(v)
local y = self.radius * math.cos(u)
local z = self.radius * -math.sin(u) * math.sin(v)
return vec3(x,y,z)
end
ParaSuperellipsoid = class(ParaSphere)
function ParaSuperellipsoid:init(radius)
ParaSphere.init(self, radius)
self.n1 = 0.5
self.n2 = 0.5
end
function ParaSuperellipsoid:calculate(u, v)
local x = self.radius * math.pow(math.abs(math.sin(u)),self.n1) * math.pow(math.abs(math.cos(v)),self.n2) * self:sgn(math.sin(u)) * self:sgn(math.cos(v))
local y = self.radius * math.pow(math.abs(math.cos(u)),self.n1) * self:sgn(math.cos(u))
local z = self.radius * -math.pow(math.abs(math.sin(u)),self.n1) * math.pow(math.abs(math.sin(v)),self.n2) * self:sgn(math.sin(u)) * self:sgn(math.sin(v))
return vec3(x,y,z)
end
ParaTorus = class(ParaSurf)
function ParaTorus:init(radius)
ParaSurf.init(self)
self.maxx = math.pi * 2
self.maxy = math.pi * 2
self.radius = radius/2-radius/6
self.rinner = radius/6
end
function ParaTorus:calculate(u, v)
local x = (self.radius + self.rinner*math.cos(v)) * math.cos(u)
local y = (self.radius + self.rinner*math.cos(v)) * math.sin(u)
local z = self.rinner * math.sin(v)
return vec3(x,y,z)
end
ParaSupertoroid = class(ParaTorus)
function ParaSupertoroid:init(radius)
ParaTorus.init(self, radius)
self.n1 = 0.5
self.n2 = 0.5
end
function ParaSupertoroid:calculate(u, v)
local x = (self.radius + self.rinner*math.pow(math.abs(math.cos(v)),self.n1) * self:sgn(math.cos(v))) * math.pow(math.abs(math.cos(u)),self.n2) * self:sgn(math.cos(u))
local y = (self.radius + self.rinner*math.pow(math.abs(math.cos(v)),self.n1) * self:sgn(math.cos(v))) * math.pow(math.abs(math.sin(u)),self.n2) * self:sgn(math.sin(u))
local z = self.rinner * math.pow(math.abs(math.sin(v)),self.n1) * self:sgn(math.sin(v))
return vec3(x,y,z)
end
ParaTrefoil = class(ParaSurf)
function ParaTrefoil:init(radius)
ParaSurf.init(self)
self.divx = self.divx * 2
self.divy = self.divy / 2
self.maxx = math.pi*2
self.maxy = math.pi*2
self.radius = (radius or 1)/2
end
function ParaTrefoil:calculate(dx, dy)
local a, b, c, d = 0.5, 0.3, 0.5, 0.25
local u = (math.pi*2 - dx) * 2
local v = dy
local r = a + b * math.cos(1.5 * u)
local x = r * math.cos(u)
local y = r * math.sin(u)
local z = c * math.sin(1.5 * u)
local dv = vec3(
-1.5 * b * math.sin(1.5 * u) * math.cos(u) - (a + b * math.cos(1.5 * u)) * math.sin(u),
-1.5 * b * math.sin(1.5 * u) * math.sin(u) + (a + b * math.cos(1.5 * u)) * math.cos(u),
1.5 * c * math.cos(1.5 * u))
local q = dv:normalize()
local qvn = vec3(q.y, -q.x, 0):normalize()
local ww = q:cross(qvn)
local range = vec3(
x + d * (qvn.x * math.cos(v) + ww.x * math.sin(v)),
y + d * (qvn.y * math.cos(v) + ww.y * math.sin(v)),
z + d * ww.z * math.sin(v))
return range * self.radius
end
ParaCylinder = class(ParaSurf)
function ParaCylinder:init(radius)
ParaSurf.init(self)
self.maxx = math.pi
self.divx = 4
self.maxy = math.pi*2
self.radius = (radius or 1)/2
end
function ParaCylinder:normal(u, v, uu, vv)
if uu == 1 then
local n = self:calculate(u,v,uu,vv)
n.y = 0
return n:normalize()
end
return ParaSurf.normal(self, u, v)
end
function ParaCylinder:calculate(u, v)
local x = self.radius * math.sin(u) * math.cos(v)
local y = (self.radius * math.cos(u) < 0) and -self.radius or self.radius
local z = self.radius * -math.sin(u) * math.sin(v)
return vec3(x,y,z)
end
ParaSupercylinder = class(ParaCylinder)
function ParaSupercylinder:init(radius)
ParaCylinder.init(self, radius)
self.n = 0.2
end
function ParaSupercylinder:calculate(u, v)
local x = self.radius * math.pow(math.abs(math.sin(u)),self.n) * math.pow(math.abs(math.cos(v)),self.n) * self:sgn(math.sin(u)) * self:sgn(math.cos(v))
local y = (self.radius * math.cos(u) < 0) and -self.radius or self.radius
local z = self.radius * -math.pow(math.abs(math.sin(u)),self.n) * math.pow(math.abs(math.sin(v)),self.n) * self:sgn(math.sin(u)) * self:sgn(math.sin(v))
return vec3(x,y,z)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment