Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save dermotbalson/c6002726de6c6d55bc979b1ab924f5f3 to your computer and use it in GitHub Desktop.
Save dermotbalson/c6002726de6c6d55bc979b1ab924f5f3 to your computer and use it in GitHub Desktop.
3D box 3
--# Main
--# Main
displayMode(FULLSCREEN)
function setup()
size,radius=200,10
CreateScene()
end
function CreateScene() --size is size of 3D box
local img=readImage("SpaceCute:Background")--:copy(4,4,62,62)
box=CreateBlock(size,size,size,color(255),vec3(0,0,0),img)
balls={}
for i=1,12 do
local b=CreateSphere(radius,readImage("Cargo Bot:Starry Background"),color(255))
--create random position but check they dont overlap
local p
while true do
p=(vec3(.2,.2,.2)+0.5*vec3(math.random()-0.5,math.random()-0.5,math.random()-0.5))*size
local overlap=false
for j=1,i-1 do
if p:dist(balls[j].pos)<radius*2 then overlap=true end
end
if not overlap then break end
end
local v=vec3(math.random()-0.5,math.random()-0.5,math.random()-0.5)*5
balls[i]={ball=b,pos=p,vel=v}
end
end
function DrawBalls()
NewVals={}
for i,b in pairs(balls) do
AdjustPos(i)
end
for i,b in pairs(balls) do
b.pos=NewVals[i][1]
b.vel=NewVals[i][2]
pushMatrix()
translate(b.pos:unpack())
b.ball:draw()
popMatrix()
end
end
function AdjustPos(i)
local b=balls[i]
local p=b.pos+b.vel
local v1=vec3(b.vel.x,b.vel.y,b.vel.z)
--check for collisions with each axis wall
local f=0
local d=size/2-radius
--x
local xd=math.abs(p.x)
if xd>d then --collided with x wall
f=(xd-d)/math.abs(b.vel.x) --backtrack by this fraction of the last movement
v1.x=-b.vel.x --reverse x velocity
end
--y
local yd=math.abs(p.y)
if yd>d then --collided with y wall
f=(yd-d)/math.abs(b.vel.y) --backtrack by this fraction of the last movement
v1.y=-b.vel.y --reverse y velocity
end
--z
local zd=math.abs(p.z)
if zd>d then --collided with z wall
f=(zd-d)/math.abs(b.vel.z) --backtrack by this fraction of the last movement
v1.z=-b.vel.z --reverse z velocity
end
--check for collisions with other balls
if f==0 then
for j=1,#balls do
if j~=i then
local b2=balls[j]
local d=p:dist(b2.pos)-radius*2 --distance between centres
if d<0 then
--calculate normal vector from b2 to b
local n=(b.pos-b2.pos):normalize()
local g=n*(b.vel:dot(n)*2)
v1=vec3(b.vel.x-g.x,b.vel.y-g.y,b.vel.z-g.z)
--reflect to reverse embedding
local d0=b.pos:dist(b2.pos)-radius*2
f=d/(d-d0) --fraction of distance to reverse
end
end
end
end
NewVals[i]={b.pos+b.vel*(1-f)+v1*f,v1}
end
function draw()
background(220)
perspective(90)
camera(0,0,size/2-1,0,-size/3,0)
box:draw()
DrawBalls()
end
--# Utility
function CreateBlock(w,h,d,col,pos,tex) --width,height,depth,colour,position,texture
local x,X,y,Y,z,Z=pos.x-w/2,pos.x+w/2,pos.y-h/2,pos.y+h/2,pos.z-d/2,pos.z+d/2
local v={vec3(x,y,Z),vec3(X,y,Z),vec3(X,Y,Z),vec3(x,Y,Z),vec3(x,y,z),vec3(X,y,z),vec3(X,Y,z),vec3(x,Y,z)}
local vert={v[1],v[2],v[3],v[1],v[3],v[4],v[2],v[6],v[7],v[2],v[7],v[3],v[6],v[5],v[8],v[6],v[8],v[7],
v[5],v[1],v[4],v[5],v[4],v[8],v[4],v[3],v[7],v[4],v[7],v[8],v[5],v[6],v[2],v[5],v[2],v[1]}
local texCoords
if tex then
local t={vec2(0,0),vec2(1,0),vec2(0,1),vec2(1,1)}
texCoords={t[1],t[2],t[4],t[1],t[4],t[3],t[1],t[2],t[4],t[1],t[4],t[3],t[1],t[2],t[4],t[1],t[4],t[3],
t[1],t[2],t[4],t[1],t[4],t[3],t[1],t[2],t[4],t[1],t[4],t[3],t[1],t[2],t[4],t[1],t[4],t[3]}
end
local n={vec3(0,0,1),vec3(1,0,0),vec3(0,0,-1),vec3(-1,0,0),vec3(1,0,0),vec3(-1,0,0)}
local norm={}
for i=1,6 do for j=1,6 do norm[#norm+1]=n[i] end end
local ms = mesh()
ms.vertices = vert
ms.normals=norm
if tex then ms.texture,ms.texCoords = tex,texCoords end
ms:setColors(col or color(255))
return ms
end
function CreateSphere(r,tex,col,nx,ny)
local vertices,tc = Sphere_OptimMesh(nx or 40,ny or 20)
vertices = Sphere_WarpVertices(vertices)
for i=1,#vertices do vertices[i]=vertices[i]*r end
local ms = mesh()
ms.vertices=vertices
if tex then ms.texture,ms.texCoords=tex,tc end
ms:setColors(col or color(255))
return ms
end
function Sphere_OptimMesh(nx,ny)
local v,t={},{}
local k,s,x,y,x1,x2,i1,i2,sx,sy=0,1,0,0,{},{},0,0,nx/ny,1/ny
local c = vec3(1,0.5,0)
local m1,m2
for y=0,ny-1 do
local nx1 = math.floor( nx * math.abs(math.cos(( y*sy-0.5)*2 * math.pi/2)) )
if nx1<6 then nx1=6 end
local nx2 = math.floor( nx * math.abs(math.cos(((y+1)*sy-0.5)*2 * math.pi/2)) )
if nx2<6 then nx2=6 end
x1,x2 = {},{}
for i1 = 1,nx1 do x1[i1] = (i1-1)/(nx1-1)*sx end x1[nx1+1] = x1[nx1]
for i2 = 1,nx2 do x2[i2] = (i2-1)/(nx2-1)*sx end x2[nx2+1] = x2[nx2]
local i1,i2,n,nMax,continue=1,1,0,0,true
nMax = nx*2+1
while continue do
m1,m2=(x1[i1]+x1[i1+1])/2,(x2[i2]+x2[i2+1])/2
if m1<=m2 then
v[k+1],v[k+2],v[k+3]=vec3(x1[i1],sy*y,1)-c,vec3(x1[i1+1],sy*y,1)-c,vec3(x2[i2],sy*(y+1),1)-c
t[k+1],t[k+2],t[k+3]=vec2(-x1[i1]/2,sy*y) ,vec2(-x1[i1+1]/2,sy*y),vec2(-x2[i2]/2,sy*(y+1))
if i1<nx1 then i1 = i1 +1 end
else
v[k+1],v[k+2],v[k+3]=vec3(x1[i1],sy*y,1)-c,vec3(x2[i2],sy*(y+1),1)-c,vec3(x2[i2+1],sy*(y+1),1)-c
t[k+1],t[k+2],t[k+3]=vec2(-x1[i1]/2,sy*y),vec2(-x2[i2]/2,sy*(y+1)),vec2(-x2[i2+1]/2,sy*(y+1))
if i2<nx2 then i2 = i2 +1 end
end
if i1==nx1 and i2==nx2 then continue=false end
k,n=k+3,n+1
if n>nMax then continue=false end
end
end
return v,t
end
function Sphere_WarpVertices(verts)
local m = matrix(0,0,0,0, 0,0,0,0, 1,0,0,0, 0,0,0,0)
local vx,vy,vz,vm
for i,v in ipairs(verts) do
vx,vy = v[1], v[2]
vm = m:rotate(180*vy,1,0,0):rotate(180*vx,0,1,0)
vx,vy,vz = vm[1],vm[5],vm[9]
verts[i] = vec3(vx,vy,vz)
end
return verts
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment