Skip to content

Instantly share code, notes, and snippets.

@dermotbalson
Created April 9, 2013 14:38
Show Gist options
  • Save dermotbalson/5346193 to your computer and use it in GitHub Desktop.
Save dermotbalson/5346193 to your computer and use it in GitHub Desktop.
15. Mesh
--[[
This demo is where it starts to get more complicated, even though we'll only create
a 3D block with just 8 triangles. There are several parts to this
1. creating 3D objects
2. placing them in 3D space
3. choosing our viewpoint in 3D space
CREATING THE BLOCK
I've put the code that creates the block in its own class underneath, so you can use it easily
in your own projects. (Trust me, you will never want to write this code yourself. It took me
about four hours just to understand it!).
Creation of the block is explained in that class. In this section, I'm going to talk about everything else
THE SCREEN CO-ORDINATES
First, when you draw in 3D, your screen no longer starts at 0,0 at lower left. Instead, the zero point,
or (0,0,0) - 3D, remember - is in the middle of your screen.
First, we need to set our own viewpoint.
PERSPECTIVE
Perspective is about what you can see, and has two parts
* Field of view is about how much of the scene you can see at once, in degrees. A setting of 20 zooms right in, while 90 takes you further out and see much more. Think of it as the width of your view. A good setting is 45.
* Aspect is the width to height ratio, and is normally set to the same ratio as the screen, WIDTH/HEIGHT
Having decided this, we set it like so
perspective(45, WIDTH/HEIGHT)
CAMERA
Having decided what we can see, we need to choose where we're going to see it from.
The camera function has three sets of x,y,z values
First, the location of your "eye" in space
x - Typically, you want to be looking straight at your screen, so you want x to be in the middle, which is 0
y - If you want to look down on your picture, set y to a positive value, and vice versa
z - You won't want to be in the picture, so you should probably make z negative so it moves towards you
Next, what you are looking at, as a point in space. We'll use 0,0,0
Finally, the viewer's stance. The normal position would be standing, ie vertical in the y direction, so you'd set 0,1,0. If you wanted to see it from a lying down position you could set 1,0,0.
So here is an example of the final settings
camera(0,300,-300, 0,0,0, 0,1,0)
DRAWING THE BLOCK
Having created the block, if we just draw it, it will appear in the middle of the screen, front face forward.
And that's what we'll do initially.
CHANGING THE OBJECT
There is something else you can alter as well, and that is rotating the object through any of the x,y or z axes, during the drawing process. This is done below to illustrate.
MAKING IT CHANGE AS YOU TOUCH THE SCREEN
The code at the bottom reacts to touches. If you touch left or right, it changes the angle of rotation (which rotates the block). If you touch high or low, it changes the camera height (y axis).
--]]
function setup()
FieldOfView=45
CamHeight=300
Angle=0
--I'm using some art, and it has rounded edges, which will make my block look funny
--so I'll leave out the first and last 5% along the x and y axis
blk=Block(150,100,50,"Platformer Art:Block Brick",{.05,.05,.95,.95})
end
function draw()
background(0)
-- First arg is FOV, second is aspect
perspective(FieldOfView, WIDTH/HEIGHT)
-- Position the camera up and back, look at origin
camera(0,CamHeight,-300, 0,0,0, 0,1,0)
pushMatrix()
rotate(Angle,0,1,0)
blk:draw()
-- Restore orthographic projection
ortho()
-- Restore the view matrix to the identity
viewMatrix(matrix())
output.clear()
print("We play with one 3D block")
print("Touching left/right rotates block\nTouching high/low changes camera height")
popMatrix()
end
function touched(touch)
local xx,yy=math.floor(touch.x*3/WIDTH),math.floor(touch.y*3/HEIGHT)
if xx==0 then Angle=Angle-15 elseif xx==2 then Angle=Angle+15 end
if yy==0 then CamHeight=CamHeight-50 elseif yy==2 then CamHeight=CamHeight+50 end
end
--Block
--[[
This class creates a rectangular 3D block with 12 triangles covered with a single texture
This is about as simple as it gets, and there is still a lot of code
We tell the class how big we want the block to be, ie width, depth and height
We also give it a texture based on an image, so it is visible
We don't always want to use the whole image, so we provide an optional array (parameter r below)
that lets the user specify the start and end x,y position
eg if you only want to use the part of the image from x=0.2 to .6, and y=0.1 to .9, then you
pass in an array {0.2,0.1,0.6,0.9} ie starting x,y position, then ending x,y position
If you omit this array then the range 0,1 will be used
--]]
Block = class() --taken from 3D lab project
function Block:init(w,h,d,t,r) --width,height,depth,texture, (optional) texture range (see above)
self.width=w
self.height=h
self.depth=d
self.tex=t --string name of an image in the library
--if no limits specified on which part of image to draw, set to 0,1
if r~=nil then self.texR=r else self.texR={0,0,1,1} end
self.blk=self:createBlock()
end
function Block:createBlock()
-- all the unique vertices that make up a block
--There are only 8 corners in a cube - we define them as vertices
--all measurements are taken from the centre of the block
--so bottom left front has x of -1/2 width, y of -1/2 height, and z of 1/2 depth
local w,h,d=self.width,self.height,self.depth
local v = {
vec3(-0.5*w, -0.5*h, 0.5*d), -- Left bottom front
vec3( 0.5*w, -0.5*h, 0.5*d), -- Right bottom front
vec3( 0.5*w, 0.5*h, 0.5*d), -- Right top front
vec3(-0.5*w, 0.5*h, 0.5*d), -- Left top front
vec3(-0.5*w, -0.5*h, -0.5*d), -- Left bottom back
vec3( 0.5*w, -0.5*h, -0.5*d), -- Right bottom back
vec3( 0.5*w, 0.5*h, -0.5*d), -- Right top back
vec3(-0.5*w, 0.5*h, -0.5*d), -- Left top back
}
-- now construct a block out of the vertices above
--there are 6 sides, each made up of 2 triangles, each with 3 vertices
--so we need to assign 36 vertices in total
--the 8 vectors are assigned to the 8 corners as follows
--1,2,3,4 anticlockwise round front starting bottom left
--5,6,7,8 clockwise round back starting bottom right (assuming you are looking at the back)
--the first three vectors below use vectors 1,2 and 3. If you look above, you'll
--see those are for left and right of bottom front, plus right top of front
--so this is the right hand triangle for the front side
local cubeverts = {
-- Front, Right, Back, Left, Top, Bottom
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],
}
-- add texture
--create vectors to be assigned to four corners of each face
local BL=vec2(self.texR[1],self.texR[2]) --bottom left
local BR=vec2(self.texR[3],self.texR[2]) --bottom right
local TR=vec2(self.texR[3],self.texR[4]) --top right
local TL=vec2(self.texR[1],self.texR[4]) --top left
-- apply the texture coordinates to each triangle
--we need to add them to each of the vertexes in the same order as above
--that means on each face we need to add them in the order BL, BR, TR, BL, TR, TL
local cubetexCoords = {}
for i=1,6 do
table.insert(cubetexCoords,BL)
table.insert(cubetexCoords,BR)
table.insert(cubetexCoords,TR)
table.insert(cubetexCoords,BL)
table.insert(cubetexCoords,TR)
table.insert(cubetexCoords,TL)
end
--put it all together
local ms = mesh()
ms.vertices = cubeverts
ms.texture = self.tex
ms.texCoords = cubetexCoords
ms:setColors(255,255,255,255)
return ms
end
function Block:draw()
self.blk:draw()
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment