Skip to content

Instantly share code, notes, and snippets.

@dermotbalson
Last active August 29, 2015 14:13
Show Gist options
  • Save dermotbalson/11696d0b6bd4600bf6de to your computer and use it in GitHub Desktop.
Save dermotbalson/11696d0b6bd4600bf6de to your computer and use it in GitHub Desktop.
Touch code plane - ver 4
function setup()
--set up details for a couple of pictures
pics={
{name="red",pos=vec3(-100,-200,-250),size=vec3(400,600,1),rotation=vec3(45,0,20),colr=color(255,0,0)},
{name="yellow",pos=vec3(100,-100,-400),size=vec3(400,600,1),rotation=vec3(-45,30,0),colr=color(255,255,0)}
}
--add them to the Touch class (so we can detect touches)
for _,p in pairs(pics) do
--we need to provide some kind of id, so the Touch class can tell us which object was touched
--we also need to provide the position (of the centre of the picture), and its size, both vec3
--the Touch class gives us back a reference which we need to store, for each picture
--because we'll need it in draw
p.tch=Touch(p,p.pos,p.size)
end
end
function draw()
background(50)
perspective()
camera(0,0,1000,0,0,-1)
for _,p in pairs(pics) do
pushMatrix()
--you can translate and rotate any way you want
translate(p.pos.x,p.pos.y,p.pos.z)
if p.rotation.x~=0 then rotate(p.rotation.x,1,0,0) end
if p.rotation.y~=0 then rotate(p.rotation.y,0,1,0) end
if p.rotation.z~=0 then rotate(p.rotation.z,0,0,1) end
--draw the image any way you want
fill(p.colr)
rect(-p.size.x/2,-p.size.y/2,p.size.x,p.size.y)
--next, is why we had to store the reference received back from Touch, because now
--we need to tell the Touch class about the translations and rotations for this picture
--this must be done for each picture
--you only really need to do this when something changes, not necessarily every frame
p.tch:storeMatrix()
popMatrix()
end
end
function touched(t)
local touches={}
if t.state==ENDED then
--this is all you need to find out which object was touched
--it returns the picture id (which you provided initially)
--as well as the touch position (x,y)
--and the z value of the touch, if you want it
local id,tc,d=Touch:PictureIsTouchedBy(t)
if id then print(id.name,tc) end
end
end
------ touch code below ----
Touch=class()
Touch.list={}
function Touch:init(id,pos,size)
self.id=id --string or number (optional)
self.pos=pos --vec3
self.size=size --vec2
end
function Touch:storeMatrix()
self.model=modelMatrix()
self.matrix=modelMatrix() * viewMatrix() * projectionMatrix()
if Touch.list[self.id] then Touch.list={} end
Touch.list[self.id]=self
end
function Touch:PictureIsTouchedBy(t)
local item, tc, dist, d
for _,L in pairs(Touch.list) do
local p,s=L.pos,L.size
tc = screentoplane(t, vec3(0,0,0), vec3(1,0,0), vec3(0,1,0), L.matrix)
tc=vec2(tc.x+0.5*s.x,tc.y+0.5*s.y)
if tc.x<0 or tc.x>s.x or tc.y<0 or tc.y>s.y then --didn't touch, do nothing
else
L.tc=tc --store touch position
--now get z value of touch
local a=L.model:translate(tc.x-s.x/2,tc.y-s.y/2,0)
d=a[15]
--keep track of closest picture
if not item or dist>d then item,dist=L,d end
end
end
if item then return item.id,item.tc,d end
end
-- Compute the cofactor matrix of a 3x3 matrix, entries
-- hard-coded for efficiency.
-- The cofactor differs from the inverse by a scale factor, but
-- as our matrices are only well-defined up to scale, this
-- doen't matter.
function cofactor3(m)
return {
vec3(
m[2].y * m[3].z - m[3].y * m[2].z,
m[3].y * m[1].z - m[1].y * m[3].z,
m[1].y * m[2].z - m[2].y * m[1].z
),
vec3(
m[2].z * m[3].x - m[3].z * m[2].x,
m[3].z * m[1].x - m[1].z * m[3].x,
m[1].z * m[2].x - m[2].z * m[1].x
),
vec3(
m[2].x * m[3].y - m[3].x * m[2].y,
m[3].x * m[1].y - m[1].x * m[3].y,
m[1].x * m[2].y - m[2].x * m[1].y
)
}
end
-- Given a plane in space, this computes the transformation
-- matrix from that plane to the screen
function __planetoscreen(o,u,v,A)
A = A or modelMatrix() * viewMatrix() * projectionMatrix()
o = o or vec3(0,0,0)
u = u or vec3(1,0,0)
v = v or vec3(0,1,0)
-- promote to 4-vectors
o = vec4(o.x,o.y,o.z,1)
u = vec4(u.x,u.y,u.z,0)
v = vec4(v.x,v.y,v.z,0)
local oA, uA, vA
oA = A*o
uA = A*u
vA = A*v
oA = applymatrix4(o,A)
uA = applymatrix4(u,A)
vA = applymatrix4(v,A)
return { vec3(uA[1], uA[2], uA[4]),
vec3(vA[1], vA[2], vA[4]),
vec3(oA[1], oA[2], oA[4])}
end
-- Given a plane in space, this computes the transformation
-- matrix from the screen to that plane
function screentoplane(t,o,u,v,A)
A = A or modelMatrix() * viewMatrix() * projectionMatrix()
o = o or vec3(0,0,0)
u = u or vec3(1,0,0)
v = v or vec3(0,1,0)
t = t or CurrentTouch
local m = __planetoscreen(o,u,v,A)
m = cofactor3(m)
local ndc = vec3((t.x/WIDTH - .5)*2,(t.y/HEIGHT - .5)*2,1)
local a
a = applymatrix3(ndc,m)
if (a[3] == 0) then return end
a = vec2(a[1], a[2])/a[3]
return o + a.x*u + a.y*v
end
-- This computes a frame in which the first vector is along
-- the "touch ray" and the other two are in the orthogonal plane
-- (but the whole frame is not guaranteed to be orthogonal)
function screenframe(t,A)
A = A or modelMatrix() * viewMatrix() * projectionMatrix()
t = t or CurrentTouch
local u,v,w,x,y
u = vec3(A[1],A[5],A[9])
v = vec3(A[2],A[6],A[10])
w = vec3(A[4],A[8],A[12])
x = (t.x/WIDTH - .5)*2
y = (t.y/HEIGHT - .5)*2
u = u - x*w
v = v - y*w
return u:cross(v),u,v
end
-- Apply a 3-matrix to a 3-vector
function applymatrix3(v,m)
return v.x * m[1] + v.y * m[2] + v.z * m[3]
end
-- Apply a 4-matrix to a 4-vector
function applymatrix4(v,m)
return vec4(
m[1]*v[1] + m[5]*v[2] + m[09]*v[3] + m[13]*v[4],
m[2]*v[1] + m[6]*v[2] + m[10]*v[3] + m[14]*v[4],
m[3]*v[1] + m[7]*v[2] + m[11]*v[3] + m[15]*v[4],
m[4]*v[1] + m[8]*v[2] + m[12]*v[3] + m[16]*v[4]
)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment