Created
February 17, 2013 19:35
-
-
Save RichardMN/4973013 to your computer and use it in GitHub Desktop.
LatheMesh - a factory class for creating rotated solids in Codea.
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
--# LatheMesh | |
-- LatheMesh | |
-- A factory class for creating solids based on rotating an outline series of points around | |
-- an axis. | |
-- Richard Martin-Nielsen, 2013 | |
LatheMesh = class() | |
-- LatheMesh | |
outputVertices = false | |
LatheMesh = class() | |
LatheMesh.FLAT = 1 | |
LatheMesh.SMOOTH = 2 | |
function LatheMesh:buildMesh(segs) | |
local vlist = self.vlist | |
local col = self.color | |
local plist = {} | |
local clist = {} | |
local nlist = {} | |
local vcount = 0 | |
local roti = math.pi*2 / segs | |
print ("roti",roti) | |
local lastv | |
for i,v in ipairs(vlist) do | |
if i ~= 1 then | |
local lp = v | |
local tl,tr,bl,br,normal,intensity, trc, trn | |
for s=1,segs do | |
local crs, crsn, srs, srsn | |
crs = math.cos(roti*s) | |
crsn = math.cos(roti*(s+1)) | |
srs = math.sin(roti*s) | |
srsn = math.sin(roti*(s+1)) | |
tl = vec3(lastv.x*crs-lastv.y*srs, | |
lastv.x*srs-lastv.y*crs,lastv.z) | |
tr = vec3(lastv.x*crsn-lastv.y*srsn, | |
lastv.x*srsn-lastv.y*crsn,lastv.z) | |
bl = vec3(v.x*crs-v.y*srs, | |
v.x*srs-v.y*crs,v.z) | |
br = vec3(v.x*crsn-v.y*srsn, | |
v.x*srsn-v.y*crsn,v.z) | |
--tr = vec3(lastv.x,lastv.y*math.cos(roti*(s+1)),lastv.y*math.sin(roti*(s+1))) | |
--bl = vec3(v.x,v.y*math.cos(roti*s),v.y*math.sin(roti*s)) | |
--br = vec3(v.x,v.y*math.cos(roti*(s+1)),v.y*math.sin(roti*(s+1))) | |
table.insert(plist,tl) | |
table.insert(plist,tr) | |
table.insert(plist,bl) | |
if self.lighting == LatheMesh.FLAT then | |
normal = tr-tl | |
normal = normal:cross (tl-bl) | |
normal = normal:normalize () | |
intensity = (normal:dot(self.lightd)*80 + 125) /255 | |
local gl = color(intensity*col.r,intensity*col.g,intensity*col.b) | |
for i=1,3 do | |
table.insert(clist,gl) | |
table.insert(nlist,normal) | |
end | |
else | |
if vlist[i+1] == nil then | |
normal = vlist[i-1]-v | |
-- y' = y*cos q - z*sin q | |
--z' = y*sin q + z*cos q | |
--x' = x | |
normal = -vec3(normal.x,-normal.z,normal.y) | |
elseif vlist[i-1] == nil then | |
normal = vlist[i+1]-v | |
--normal = vec3(normal.y,-normal.x,0) | |
normal = vec3(normal.x,-normal.z,normal.y) | |
else | |
local v1,v2 | |
v1 = (v-vlist[i-1]) | |
--v1 = vec3(v1.y,-v1.x,0) | |
v1 = vec3(v1.x,-v1.z,v1.y) | |
v1 = v1:normalize() | |
v2 = (vlist[i+1]-v) | |
v2 = vec3(v2.x,-v2.z,v2.y) | |
v2 = v2:normalize() | |
-- print("v1,v2",v1,v2) | |
normal = v1+ v2 | |
end | |
--normal = vec3(normal.x, normal.y*math.cos(roti*s),normal.y*math.sin(roti*s)) | |
local rotnormal = -vec3(normal.x*crs-normal.y*srs,normal.x*srs-normal.y*crs, | |
normal.z) | |
rotnormal = rotnormal:normalize() | |
intensity = (rotnormal:dot(self.lightd)*80 + 125) /255 | |
-- if intensity == 0 or intensity == math.huge then | |
-- print("inten=0",i,intensity,normal) | |
--end | |
local gl = color(intensity*col.r,intensity*col.g,intensity*col.b) | |
table.insert(clist, gl) | |
table.insert(nlist, rotnormal) | |
rotnormal = -vec3(normal.x*crsn-normal.y*srsn,normal.x*srsn-normal.y*crsn, | |
normal.z) | |
rotnormal = rotnormal:normalize() | |
intensity = (rotnormal:dot(self.lightd)*80 + 125) /255 | |
if intensity == 0 then | |
print("inten=0",i,normal) | |
end | |
trc = color(intensity*col.r,intensity*col.g,intensity*col.b) | |
table.insert(clist, trc) | |
table.insert(nlist, rotnormal) | |
trn = rotnormal | |
-- leave bottom right colour to do in next set with next row of normals | |
-- save top right colour (trc) to reuse then | |
end | |
table.insert(plist,tr) | |
table.insert(plist,br) | |
table.insert(plist,bl) | |
if self.lighting == LatheMesh.FLAT then | |
normal = tr-br | |
normal = normal:cross (bl-br) | |
normal = normal:normalize () | |
intensity = (normal:dot(self.lightd)*80 + 125) /255 | |
local gl = color(intensity*col.r,intensity*col.g,intensity*col.b) | |
for i=1,3 do | |
table.insert(clist,gl) | |
table.insert(nlist,normal) | |
end | |
else | |
normal = v | |
if vlist[i+1] == nil then | |
normal = vlist[i]-vlist[i-1] | |
normal = vec3(normal.x,-normal.z,normal.y) | |
elseif vlist[i+2] == nil then | |
normal = vlist[i+1]-v | |
normal = vec3(normal.x,-normal.z,normal.y) | |
else | |
local v1,v2 | |
--v1 = (vlist[i]-vlist[i+1]) | |
v1 = (vlist[i+1]-vlist[i]) | |
v1 = vec3(v1.x,-v1.z,v1.y) | |
v1 = v1:normalize() | |
v2 = (vlist[i+2]-vlist[i+1]) | |
v2 = vec3(v2.x,-v2.z,v2.y) | |
v2 = v2:normalize() | |
normal = v1+ v2 | |
--normal = vlist[i]-2*vlist[i+1]+vlist[i+2] | |
--normal = normal + vlist[i+2]-vlist[i+1] | |
--print("c",normal) | |
end | |
-- print(i,s,vlist[i-1],vlist[i],vlist[i+1],vlist[i+2]) | |
local rotnormal = -vec3(normal.x*crs-normal.y*srs,normal.x*srs-normal.y*crs, | |
normal.z) | |
rotnormal = rotnormal:normalize() | |
intensity = (rotnormal:dot(self.lightd)*80 + 125) /255 | |
if intensity == 0 then | |
print("blc:inten=0",i,normal) | |
end | |
local blc = color(intensity*col.r,intensity*col.g,intensity*col.b) | |
local bln = rotnormal | |
table.insert(clist,blc) | |
table.insert(nlist,rotnormal) | |
table.insert(clist,trc) | |
table.insert(nlist,trn) | |
rotnormal = -vec3(normal.x*crsn-normal.y*srsn,normal.x*srsn-normal.y*crsn, | |
normal.z) | |
rotnormal = rotnormal:normalize() | |
intensity = (rotnormal:dot(self.lightd)*80 + 125) /255 | |
if intensity == 0 then | |
print("gl:inten=0",i,normal) | |
end | |
local gl = color(intensity*col.r,intensity*col.g,intensity*col.b) | |
table.insert(clist,gl) | |
table.insert(nlist,rotnormal) | |
table.insert(clist,blc) | |
table.insert(nlist,bln) | |
end | |
--print(vcount,lp) | |
vcount = vcount + 1 | |
--rp.x = v.x | |
--rp.y = v.y*math.cos(roti*(s+1)) | |
--rp.z = v.y*math.sin(roti*(s+1)) | |
end | |
end | |
lastv = v | |
end | |
self.lmesh.vertices =plist | |
self.lmesh.colors = clist | |
self.lmesh.normals = nlist | |
print(table.maxn(plist),table.maxn(nlist)) | |
local vmax = table.maxn(plist) | |
--print(vmax,table.maxn (self.lmesh.vertices)) | |
end | |
function LatheMesh:init(vlist,col,segs) | |
self.lmesh= mesh() | |
--self.lv = vec3(1,1,1) | |
self.lighting = LatheMesh.SMOOTH | |
--self.lighting = LatheMesh.FLAT | |
self.lightd = vec3(1,1,1) | |
self.lightd = self.lightd:normalize() | |
self.color = col or color(255, 255, 255, 255) | |
self.vlist = vlist | |
self:buildMesh(segs) | |
--self.lmesh:setColors(color(255,0,0)) | |
-- for i=1,vmax do | |
--self.lmesh:color(i,clist[i]) | |
end | |
function LatheMesh:draw() | |
self.lmesh:draw() | |
end | |
function printVertexList(vl) | |
print("lm = {") | |
for i,v in ipairs(vl) do | |
print(string.format("\tvec3(%.2f,%.2f,%.2f),",v.x,v.y,v.z)) | |
end | |
print("}") | |
end | |
function printVertexColors(vc) | |
print("lc = {") | |
for i,v in ipairs(vc) do | |
print(string.format("\tcolor(%.2f,%.2f,%.2f,%.2f),",v.r,v.g,v.b,v.a)) | |
end | |
print("}") | |
end | |
--# Main | |
-- LatheMesh demonstration code | |
-- LatheMesh is a factory class for creating solids based on rotating an | |
-- outline series of points around an axis. | |
-- Richard Martin-Nielsen, 2013 | |
-- Use this function to perform your initial setup | |
function setup() | |
parameter.integer("Size",50,500,150) | |
parameter.number("CamHeight", -500, 1000, 300) | |
parameter.number("Angle",-360, 360, 0) | |
parameter.number("FieldOfView", 10, 140, 45) | |
--iparameter("Lighting",1,2) | |
parameter.integer("Segments",3,36,12,rebuildMeshes) | |
parameter.boolean("useDiffuseShader",true) | |
outlines = {} | |
p = {vec3(0,25,0),vec3(0,50,25),vec3(0,100,50)} | |
table.insert(outlines,p) | |
p={} | |
for i=1,20 do | |
table.insert(p,vec3(0,5+25*math.sin(math.rad(i*15)),0+i*50)) | |
end | |
table.insert(outlines,p) | |
p={} | |
for i = 0,10 do | |
table.insert(p,vec3(0,math.sin(i*math.pi/10)*50,math.cos(i*math.pi/10)*50)) | |
end | |
table.insert(outlines,p) | |
p = {vec3(0,25,0),vec3(0,25,25),vec3(0,25,50),vec3(0,25,75)} | |
table.insert(outlines,p) | |
p={} | |
for i = 0,8 do | |
table.insert(p,vec3(0,math.sin(i*math.pi/10)*50,math.cos(i*math.pi/10)*50)) | |
end | |
table.insert(p,vec3(0,50,-175)) | |
table.insert(p,vec3(0,0,-175)) | |
table.insert(outlines,p) | |
parameter.integer("Outline",1,table.maxn(outlines),rebuildMeshes) | |
-- p = {} | |
--p = {vec3(0,5,0),vec3(25,55,0)} | |
oldLighting = Lighting | |
oldOutline = Outline | |
--segs = 12 | |
lm = LatheMesh(outlines[Outline],color(255,255,0),Segments) | |
lmf = LatheMesh(outlines[Outline],color(255,255,0),Segments) | |
lms = LatheMesh(outlines[Outline],color(255,255,0),Segments) | |
if useDiffuseShader then | |
lms.shader = shader("Documents:Diffuse Shader1") | |
end | |
lmf.lighting = LatheMesh.FLAT | |
lmf:buildMesh(Segments) | |
if outputVertices then | |
printVertexList(lm.lmesh.vertices) | |
end | |
--rebuildMeshes() | |
print(lm.lmesh.valid) | |
end | |
function rebuildMeshes() | |
if outlines ~= nil then | |
lm = LatheMesh(outlines[Outline],color(255,255,0),Segments) | |
lmf = LatheMesh(outlines[Outline],color(255,255,0),Segments) | |
lms = LatheMesh(outlines[Outline],color(255,255,0),Segments) | |
lmf.lighting = LatheMesh.FLAT | |
lmf:buildMesh(Segments) | |
end | |
end | |
-- This function gets called once every frame | |
function draw() | |
-- This sets a dark background color | |
background(40, 40, 50) | |
--FieldOfView = 140 | |
perspective(FieldOfView, WIDTH/HEIGHT) | |
scale(Size/150,Size/150,Size/150) | |
rotate(Angle) | |
-- Position the camera up and back, look at origin | |
camera(0,CamHeight,-300, 0,0,0, 0,1,0) | |
-- This sets the line thickness | |
strokeWidth(5) | |
if false then -- outline ~= oldOutline then | |
lm = LatheMesh(outlines[Outline],color(255,255,0),Segments) | |
lmf = LatheMesh(outlines[Outline],color(255,255,0),Segments) | |
lms = LatheMesh(outlines[Outline],color(255,255,0),Segments) | |
lmf.lighting = LatheMesh.FLAT | |
lmf:buildMesh(Segments) | |
oldOutline = outline | |
end | |
stroke(255, 0, 0, 255) | |
-- Do your drawing here | |
--translate(WIDTH/2,HEIGHT/2) | |
--scale(2 | |
translate(-50,0,0) | |
lm:draw() | |
translate(100,0,0) | |
lmf:draw() | |
if useDiffuseShader then | |
translate(-50,50,0) | |
--lms.lmesh.shader = shader("Documents:Diffuse Shader1") | |
lms.lmesh.shader = shader(DiffuseShader1.Vertex, | |
DiffuseShader1.Fragment) | |
lms.lmesh.shader.m = modelMatrix() | |
local mit = modelMatrix() | |
mit = mit:transpose() | |
mit = mit:inverse() | |
lms.lmesh.shader.m_3x3_inv_transp = mit | |
lms.lmesh.shader.v = viewMatrix() | |
lms.lmesh.shader.p = projectionMatrix() | |
lms:draw() | |
end | |
end | |
DiffuseShader1 = { | |
Vertex = [[ | |
// | |
// A basic vertex shader | |
// | |
//This is the current model * view * projection matrix | |
// Codea sets it automatically | |
uniform mat4 modelViewProjection; | |
//This is the current mesh vertex position, color and tex coord | |
// Set automatically | |
attribute vec4 position; | |
attribute vec4 color; | |
attribute vec2 texCoord; | |
attribute vec3 normal; | |
//This is an output variable that will be passed to the fragment shader | |
varying lowp vec4 vColor; | |
varying highp vec2 vTexCoord; | |
uniform mat4 m, v, p; | |
uniform mat3 m_3x3_inv_transp; | |
varying vec4 mycolor; | |
struct lightSource | |
{ | |
vec4 position; | |
vec4 diffuse; | |
}; | |
lightSource light0 = lightSource( | |
vec4(-1.0, 1.0, -1.0, 0.0), | |
vec4(1.0, 1.0, 1.0, 1.0) | |
); | |
struct material | |
{ | |
vec4 diffuse; | |
}; | |
material mymaterial = material(vec4(1.0, 0.8, 0.8, 1.0)); | |
void main(void) | |
{ | |
mat4 mvp = p*v*m; | |
vec3 normalDirection = normalize(m_3x3_inv_transp * normal); | |
vec3 lightDirection = normalize(vec3(light0.position)); | |
vec3 diffuseReflection | |
= vec3(light0.diffuse) * vec3(mymaterial.diffuse) | |
* max(0.0, dot(normalDirection, lightDirection)); | |
mycolor = vec4(diffuseReflection, 1.0); | |
gl_Position = mvp * position; | |
} | |
]], | |
Fragment = [[ | |
// | |
// A basic fragment shader | |
// | |
//Default precision qualifier | |
precision highp float; | |
//This represents the current texture on the mesh | |
uniform lowp sampler2D texture; | |
//The interpolated vertex color for this fragment | |
varying lowp vec4 vColor; | |
//The interpolated texture coordinate for this fragment | |
varying highp vec2 vTexCoord; | |
varying vec4 mycolor; | |
void main(void) | |
{ | |
gl_FragColor = mycolor; | |
} | |
]] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment