Created
July 27, 2013 05:35
-
-
Save dermotbalson/6093875 to your computer and use it in GitHub Desktop.
Reflect
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
--# 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