#### Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

# Pipe and Tunnel: experiments with meshes

edited August 2012 Posts: 489

I have been experimenting with meshes with the following code, inspired by the Roller Coaster example project:

``````--
-- Pipe
--
supportedOrientations(LANDSCAPE_ANY)
function setup()
local randomColours = false -- True for different shading option
local pointNo = 30          -- No. of points in cross-section
local radius = 30           -- Cross-section radius
local path = Pipe.knot -- Choose path for pipe

parameter("r", 10, 1600, 1200)
parameter("theta", 0, 360, 0)
parameter("phi", 5, 175, 90) -- Avoid the discontinuity at poles

light = vec3(1, 0, 0) -- Direction to light source
ambient =0.25         -- Ambient light factor (0 to 1)
local c = rCol()      -- A random colour
local dt = 1/400      -- No of cross-sections in pipe
m = mesh()            -- Create a mesh
local ver = {}        -- Table for vertices
local col = {}        -- Table for their colours
for j = 0, 1 - dt, dt do -- For each cross-section in the pipe
p1 = circle(path(j),
tangent(dt, path, j), radius, pointNo)
p2 = circle(path(j+dt),
tangent(dt, path, j+dt), radius, pointNo)
for i = 1, pointNo do -- For each point in cross-section
local t1 = p1[i]
local t2 = p1[(i % pointNo)+1]
local t3 = p2[i]
local t4 = p2[(i % pointNo)+1]
table.insert(ver, t1) -- First triangle
table.insert(ver, t2)
table.insert(ver, t3)
table.insert(ver, t3) -- Second triangle
table.insert(ver, t2)
table.insert(ver, t4)
local c1, c2
if not randomColours then
local n1 = (t2 - t1):cross(t3 - t1)
n1 = n1:normalize()
local n2 = (t2 - t3):cross(t4 - t3)
n2 = n2:normalize()
local i1 = (math.max(n1:dot(light), 0) *
(1 - ambient) + ambient)
local i2 = (math.max(n2:dot(light), 0) *
(1 - ambient) + ambient)
c1 = color(c.r*i1, c.g*i1, c.b*i1)
c2 = color(c.r*i1, c.g*i1, c.b*i1)
else
c1 = rCol() -- A random colour
c2 = rCol() -- Another random colour
end
table.insert(col, c1) -- First triangle
table.insert(col, c1)
table.insert(col, c1)
table.insert(col, c2) -- Second triangle
table.insert(col, c2)
table.insert(col, c2)
end
end
m.vertices = ver -- Set vertices
m.colors = col   -- Set their colours
end

function draw()
background(0)
local eye = eye(r, theta, phi) -- Get position of the eye
pushMatrix()
perspective() -- Set the default perspective
camera(eye.x, eye.y, eye.z, 0, 0, 0, 0, 1, 0) -- Set camera
m:draw()                                      -- Draw mesh
popMatrix()
end

Pipe = {}

-- Function to define a path of the pipe
function Pipe.rollerCoaster(t)
local a = t * 2 * math.pi
local r = 300
local y = r/2 * math.sin(3*a)
local x = r * math.cos(a)
local z = r * math.sin(2*a)
return vec3(x, y, z)
end

-- Function to define a path of the pipe
function Pipe.knot(t)
local a = t * 2 * math.pi * 3
local r = 200 * (1 + math.cos(5 * a / 3))
local y = 100 * math.sin(5 * a / 3)
local x = r * math.cos(a)
local z = r * math.sin(a)
return vec3(x, y, z)
end

-- Function to estimate tangent of f(t) at t
function tangent(delta, f, t)
local u = t - delta/2
local v = t + delta/2
local df = f(v) - f(u)
return df:normalize()
end

-- Function returns points of next cross-section
local ov2 = nil
function circle(origin, dir, radius, pointNo)
local points = {}
local v1 = dir:cross(ov2 or vec3(1, 0, 0))
local v2 = dir:cross(v1)
v1 = v1:normalize()
v2 = v2:normalize()
ov2 = -v2
for i = 0, pointNo - 1 do
local a = i/pointNo * 2 * math.pi
local p = origin +
(v1 * math.cos(a) + v2 * math.sin(a)) * radius
table.insert(points, p)
end
return points
end

-- Returns a random colour
function rCol()
local red = math.random(255)
local green = math.random(255)
local blue = math.random(255)
return color(red, green, blue)
end

-- Returns position of eye
function eye(r, thetaDeg, phiDeg)
local deg2rad = math.pi/180 -- Conversion factor
local theta = thetaDeg * deg2rad
local phi = phiDeg * deg2rad
local x = r * math.cos(theta)*math.sin(phi)
local z = r * math.sin(theta)*math.sin(phi)
local y = r * math.cos(phi)
return vec3(x, y, z)
end
``````
Tagged:

## Comments

• Posts: 9,260

Nice example of meshes. I like how you can go thru a tube and look at it from the inside. Is there anyway you can change the eye x,y,z location and viewing direction to allow the illusion that you're moving along the inside of the tubes. It would be interesting to work your way along the inside of the tubes and see the inside of where they come together.

• Posts: 489

Hello @dave1707. Below is a variation - Tunnel - inspired by your suggestion. (Warning: this involves rapidly moving coloured elements.)

``````--
-- Tunnel
--
supportedOrientations(LANDSCAPE_ANY)
displayMode(FULLSCREEN)
function setup()
local randomColours = true -- False for different shading option
local pointNo = 30         -- No. of points in cross-section
local radius = 30          -- Cross-section radius
path = Pipe.rollerCoaster  -- Choose path for pipe
speed = 1/20               -- Speed of animation

light = vec3(1, 0, 0) -- Direction to light source
ambient =0.25         -- Ambient light factor (0 to 1)
local c = rCol()      -- A random colour
dt = 1/400            -- No of cross-sections in pipe
m = mesh()            -- Create a mesh
local ver = {}        -- Table for vertices
local col = {}        -- Table for their colours
for j = 0, 1 - dt, dt do -- For each cross-section in the pipe
p1 = circle(path(j),
tangent(dt, path, j), radius, pointNo)
p2 = circle(path(j+dt),
tangent(dt, path, j+dt), radius, pointNo)
for i = 1, pointNo do -- For each point in cross-section
local t1 = p1[i]
local t2 = p1[(i % pointNo)+1]
local t3 = p2[i]
local t4 = p2[(i % pointNo)+1]
table.insert(ver, t1) -- First triangle
table.insert(ver, t2)
table.insert(ver, t3)
table.insert(ver, t3) -- Second triangle
table.insert(ver, t2)
table.insert(ver, t4)
local c1, c2
if not randomColours then
local n1 = (t2 - t1):cross(t3 - t1)
n1 = n1:normalize()
local n2 = (t2 - t3):cross(t4 - t3)
n2 = n2:normalize()
local i1 = (math.max(n1:dot(light), 0) *
(1 - ambient) + ambient)
local i2 = (math.max(n2:dot(light), 0) *
(1 - ambient) + ambient)
c1 = color(c.r*i1, c.g*i1, c.b*i1, 255)
c2 = color(c.r*i1, c.g*i1, c.b*i1, 255)
else
c1 = rCol() -- A random colour
c2 = rCol() -- Another random colour
end
table.insert(col, c1) -- First triangle
table.insert(col, c1)
table.insert(col, c1)
table.insert(col, c2) -- Second triangle
table.insert(col, c2)
table.insert(col, c2)
end
end
m.vertices = ver -- Set vertices
m.colors = col   -- Set their colours
end

function draw()
t = ElapsedTime * speed
background(0)
local eye = eye(t) -- Get position of the eye
local dir = eye + tangent(dt, path, t)
pushMatrix()
perspective() -- Set the default perspective
camera(eye.x, eye.y, eye.z, -- Set eye location
dir.x, dir.y, dir.z,    -- Set direction of eye
0, 1, 0)                -- Set orientation of eye
m:draw()                    -- Draw mesh
popMatrix()
end

Pipe = {}

-- Function to define a path of the pipe
function Pipe.rollerCoaster(t)
local a = t * 2 * math.pi
local r = 300
local y = r/2 * math.sin(3*a)
local x = r * math.cos(a)
local z = r * math.sin(2*a)
return vec3(x, y, z)
end

-- Function to define a path of the pipe
function Pipe.knot(t)
local a = t * 2 * math.pi * 3
local r = 200 * (1 + math.cos(5 * a / 3))
local y = 100 * math.sin(5 * a / 3)
local x = r * math.cos(a)
local z = r * math.sin(a)
return vec3(x, y, z)
end

-- Function to estimate tangent of f(t) at t
function tangent(delta, f, t)
local u = t - delta/2
local v = t + delta/2
local df = f(v) - f(u)
return df:normalize()
end

-- Function returns points of next cross-section
local ov2 = nil
function circle(origin, dir, radius, pointNo)
local points = {}
local v1 = dir:cross(ov2 or vec3(1, 0, 0))
local v2 = dir:cross(v1)
v1 = v1:normalize()
v2 = v2:normalize()
ov2 = -v2
for i = 0, pointNo - 1 do
local a = i/pointNo * 2 * math.pi
local p = origin +
(v1 * math.cos(a) + v2 * math.sin(a)) * radius
table.insert(points, p)
end
return points
end

-- Returns a random colour
function rCol()
local red = math.random(255)
local green = math.random(255)
local blue = math.random(255)
return color(red, green, blue)
end

-- Returns position of eye
function eye(t)
return path(t)
end
``````
• edited August 2012 Posts: 9,260

@mpilgrem

Fantastic. That's what I had in mind. It makes me dizzy just watching it. Another great example of using meshes. I can't tell, but are you following just one loop or is it going thru a different loop each time.

• Posts: 2,161

That's great. Very fluid motion.

I put a half-tunnel track into the latest version of the roller coaster (so you can still see the stars).

• Posts: 5,614

Just posting a picture of your project, @mpilgrem, it's very good. • edited August 2012 Posts: 154

Wow

• Posts: 489

Thank you for your kind words. I should emphasise the debt that this code owes to the existence of @Andrew_Stacey's Roller Coaster example project, and to @dave1707's encouragement.

• edited August 2012 Posts: 437

I found quite interesting this prototype, i have changed the rCol() function to give a solid look to the tunnel, give it a try!!

``````-- Returns a random colour
red = math.random(255)
green = math.random(255)
blue = math.random(255)
function rCol()
local r = math.random(1,3)
if r == 2 then
inc = -1
elseif r == 3 then
inc = 1
else
inc = 0
end
if inc~=0 then
red = morecolor(red,inc)
blue = morecolor(blue,inc)
green = morecolor(green,inc)
end
return color(red, green, blue)
end

function morecolor(c,inc)
c = c + inc
if c>255 or c<0 then
c = math.random(255)
end
return c
end

`````` Your skills with meshes blow my mind @mpilgrem

• Posts: 179

That is fairly awesome, @mpilgrem. And in less than 150 lines of code, impressive.

• edited August 2012 Posts: 489

Hello @juaxix. Did you mean the following (so that each circular 'segment' of the tunnel is, more a less, a single random colour)?

``````-- Returns a random colour
local red   = math.random(255)
local green = math.random(255)
local blue  = math.random(255)
function rCol()
local inc = math.random(1, 3)
if r == 2 then
inc = -1
elseif r == 3 then
inc = 1
else
inc = 0
end
if inc~=0 then
red = morecolor(red,inc)
blue = morecolor(blue,inc)
green = morecolor(green,inc)
end
return color(red, green, blue)
end

function morecolor(c,inc)
c = c + inc
if c>255 or c<0 then
c = math.random(255)
end
return c
end
``````

That is certainly less disorienting than every triangle being a random colour!

• Posts: 437

Yes @mpilgrem ,red,green,blue as globals , i have just reedit the code.

• Posts: 871

A slightly different take - adding a texture to each pair of triangles.

``````--
-- Tunnel
--
supportedOrientations(LANDSCAPE_ANY)
displayMode(FULLSCREEN)
function setup()
local randomColours = false -- False for different shading option
local pointNo = 30         -- No. of points in cross-section
local radius = 30          -- Cross-section radius
red   = math.random(255)
green = math.random(255)
blue  = math.random(255)
path = Pipe.rollerCoaster  -- Choose path for pipe
speed = 1/20               -- Speed of animation
c=0
light = vec3(1, 0, 0) -- Direction to light source
ambient =0.25         -- Ambient light factor (0 to 1)
local c = rCol()      -- A random colour
dt = 1/400            -- No of cross-sections in pipe
m = mesh()            -- Create a mesh
m.texture="Cargo Bot:Command Grab"  --set a texture
local ver = {}        -- Table for vertices
local col = {}        -- Table for their colours
for j = 0, 1 - dt, dt do -- For each cross-section in the pipe
p1 = circle(path(j),
tangent(dt, path, j), radius, pointNo)
p2 = circle(path(j+dt),
tangent(dt, path, j+dt), radius, pointNo)
local c1, c2
c1 = rCol() -- A random colour
c2=c1
for i = 1, pointNo do -- For each point in cross-section
local t1 = p1[i]
local t2 = p1[(i % pointNo)+1]
local t3 = p2[i]
local t4 = p2[(i % pointNo)+1]
table.insert(ver, t3) -- First triangle
table.insert(ver, t1)
table.insert(ver, t2)
table.insert(ver, t3) -- Second triangle
table.insert(ver, t2)
table.insert(ver, t4)

local idx = m:addRect(0,0,50,50) -- not sure what difference changing these values makes
m:setRectTex(idx, 0, 0, 1, 1)

if not randomColours then
local n1 = (t2 - t1):cross(t3 - t1)
n1 = n1:normalize()
local n2 = (t2 - t3):cross(t4 - t3)
n2 = n2:normalize()
local i1 = (math.max(n1:dot(light), 0) *
(1 - ambient) + ambient)
local i2 = (math.max(n2:dot(light), 0) *
(1 - ambient) + ambient)
c1 = color(c.r*i1, c.g*i1, c.b*i1, 255)
c2 = color(c.r*i1, c.g*i1, c.b*i1, 255)
else
--already taken care of
end
table.insert(col, c1) -- First triangle
table.insert(col, c1)
table.insert(col, c1)
table.insert(col, c2) -- Second triangle
table.insert(col, c2)
table.insert(col, c2)
end
end
m.vertices = ver -- Set vertices
m.colors = col   -- Set their colours

end

function draw()
t = ElapsedTime * speed
background(0)
local eye = eye(t) -- Get position of the eye
local dir = eye + tangent(dt, path, t)
pushMatrix()
perspective() -- Set the default perspective
camera(eye.x, eye.y, eye.z, -- Set eye location
dir.x, dir.y, dir.z,    -- Set direction of eye
0, 1, 0)                -- Set orientation of eye
m:draw()                    -- Draw mesh
popMatrix()
end

Pipe = {}

-- Function to define a path of the pipe
function Pipe.rollerCoaster(t)
local a = t * 2 * math.pi
local r = 300
local y = r/2 * math.sin(3*a)
local x = r * math.cos(a)
local z = r * math.sin(2*a)
return vec3(x, y, z)
end

-- Function to define a path of the pipe
function Pipe.knot(t)
local a = t * 2 * math.pi * 3
local r = 200 * (1 + math.cos(5 * a / 3))
local y = 100 * math.sin(5 * a / 3)
local x = r * math.cos(a)
local z = r * math.sin(a)
return vec3(x, y, z)
end

-- Function to estimate tangent of f(t) at t
function tangent(delta, f, t)
local u = t - delta/2
local v = t + delta/2
local df = f(v) - f(u)
return df:normalize()
end

-- Function returns points of next cross-section
local ov2 = nil
function circle(origin, dir, radius, pointNo)
local points = {}
local v1 = dir:cross(ov2 or vec3(1, 0, 0))
local v2 = dir:cross(v1)
v1 = v1:normalize()
v2 = v2:normalize()
ov2 = -v2
for i = 0, pointNo - 1 do
local a = i/pointNo * 2 * math.pi
local p = origin +
(v1 * math.cos(a) + v2 * math.sin(a)) * radius
table.insert(points, p)
end
return points
end

-- Returns a random colour
function rCol()
local red = math.random(255)
local green = math.random(255)
local blue = math.random(255)
return color(red, green, blue)
end

-- Returns position of eye
function eye(t)
return path(t)
end

``````
• edited August 2012 Posts: 563

@mpilgrem - absolutely brilliant! What about turning this into a game with a Fantastic Voyage (http://en.wikipedia.org/wiki/Fantastic_Voyage) theme? You just need to add some bacteria and virus to shoot at and blood cells to avoid.

• Posts: 2,161

Something along these lines?:

• Posts: 437

Is not that a little dark, @West?

• Posts: 871

Increase the value of ambient to lighten @juaxix

Make randomColours true to get back to the more colourful version

These are part of @mpilgrem's original posting

• edited August 2012 Posts: 437

Thanks @West , i have not started yet with meshes, Btw, here is the video with the colors stuff

http://yfrog.us/n1gd9lnjbcxgdevjqutajonfz

• Posts: 643

Trippy

Sign In or Register to comment.