Created
July 27, 2016 02:39
-
-
Save dermotbalson/a692c5b3d4f35a8a7b5f3c7e848ed580 to your computer and use it in GitHub Desktop.
Step by step mesh
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
--# Notes | |
--[[ | |
** What is a mesh? ** | |
A mesh is a quick way of drawing a shape. It is a set of points which create an outline (or wirefame) of an object | |
It is made up of triangles (groups of three points) | |
Triangles are used because a triangle has the smallest number of points that encloses an area | |
Each triangle corner is known as a VERTEX, and has a position and a colour | |
The colours of all the points inside the triangle are interpolated from the colours of the three corners | |
This means you can draw quite complex shapes without having to say what colour every pixel is going to be - your program will figure that out itself, just from the colours at the corners of each triangle. | |
** Should I learn meshes? ** | |
When you are starting out with Codea, you don't need to worry about "meshes", because for simple 2D projects, | |
sprites are usually the simplest option. | |
But as you develop your skills, you should learn about meshes, because | |
* they are used to draw everything (sprites are meshes), | |
* you can deform or twist meshes more easily than sprites, because you can move any of the vertices | |
* if you have hundreds of sprites to draw, a single mesh may draw much faster than sprites, because there | |
is some setting up before each sprite (which is a mesh) is drawn | |
* meshes are the only way to draw in 3D | |
So the best approach may be to use sprites until you are very comfortable with 2D graphics, and then | |
learn about meshes. | |
This set of demos shows you the basics of meshes for 2D graphics. For 3D meshes, see the 3D demo app. | |
--]] | |
--# Triangle | |
--Triangle | |
--in this demo, we'll draw just one triangle, with a different colour at each corner | |
--so you can see the interpolation | |
function setup() | |
m=mesh() --always start by creating an empty mesh | |
--create a table of three vec2(x,y) positions to make a triangle | |
--vertices must always be in groups of three, making triangles | |
m.vertices={vec2(300,400),vec2(500,400),vec2(400,560)} | |
--we'll make each vertex colour different so you can see the interpolation | |
m.colors={color(255,0,0),color(255,255,0),color(0,255,0)} | |
--if you wanted ALL the colours to be the same, you can just write this | |
--m:setColors(color(255,255,0)) | |
end | |
function draw() | |
background(180) | |
m:draw() --draws the mesh with the positions and fills it with the colour we defined | |
end | |
function PrintExplanation() | |
output.clear() | |
print("All meshes are made up of triangles.\n\nThis demo creates a mesh of just one triangle in a fixed place") | |
print("Look at the code for details") | |
print("When you understand it, choose the next step with the slider at the top, and press the Run button.") | |
end | |
--# Square | |
--Square | |
function setup() | |
m=mesh() | |
--a square is made up of two triangles next to each other | |
--a square has 4 corners, and 2 triangles have 6 corners, so two of the vertices get used twice | |
--the vertices start to get messy, so it's easiest to first define the corners of the square | |
--I'm doing it in the order - bottom left, bottom right, top left, top right | |
local bL, bR, tR, tL = vec2(300,400), vec2(500,400), vec2(500,600), vec2(300,600) --positions of corners | |
--now we create two sets of three vertices to make two triangles | |
--it is best to list vertices anticlockwise | |
m.vertices={bL,bR,tR, tR,tL,bL} --can you see how each set of three forms a triangle? | |
--we'll colour each triangle a different colour | |
c1, c2 = color(255,0,0), color(255,255,0) | |
--assign the colours to the six vertices in order, three red then three yellow | |
m.colors={c1,c1,c1, c2,c2,c2} | |
end | |
function draw() | |
background(180) | |
m:draw() | |
end | |
function PrintExplanation() | |
output.clear() | |
print("Now we create a square made up of two triangles next to each other.") | |
print("The two triangles are given different colours so you can see them clearly") | |
end | |
--# AddRect | |
--Using addRect for rectangles | |
--[[ | |
To make it easier to add rectangles, which are used for many shapes, Codea has some special functions | |
addRect adds a rectangle to a mesh, and there are other functions to make it easy to change the vertex | |
positions, and even rotate them | |
This demo uses addRect to make a shape from several rectangles to show how easy it is. | |
--]] | |
function setup() | |
m=mesh() | |
--addRect adds a rectangle | |
--first two parameters are the centre point, next two are width, height | |
--we'll build a stick person | |
m:addRect(400,350,100,200) --body | |
m:addRect(365,200,30,150)--leg | |
m:addRect(435,200,30,150) --leg | |
m:addRect(400,435,350,30) --arms | |
m:addRect(400,480,50,60) --head | |
--our mesh now has 5 rectangles, each with 2 triangles of 3 vertices, so it has 5x2x3=30 vertices in total | |
--Codea creates all these vertices for us | |
print("Number of vertices = "..m.size) --we'll check this | |
--we'll set all the vertex colours to yellow, we can do this with one command | |
m:setColors(color(255,255,0)) | |
end | |
function draw() | |
background(180) | |
m:draw() | |
end | |
function PrintExplanation() | |
output.clear() | |
print("It's messy working with vertices, so addRect makes it easy to create rectangles") | |
print("If you made this shape using triangles, you would need to define 10 triangles and 30 vertices, instead of just 5 lines of code!") | |
end | |
--# Texture | |
--Adding an image, known as a TEXTURE | |
--[[ | |
We can add a picture to our mesh, rather than a colour. | |
You need to tell Codea which part of the texture image is at each vertex in the mesh, as a fraction 0-1 | |
An image texture is a rectangle, and the positions of its corners are | |
bottom left = (0,0) | |
bottom right = (1,0) ie all the way to the right, on the bottom | |
top left = (0,1) ie on the left, all the way to the top | |
top right = (1,1) ie all the way to the right and all the way up | |
So if a picture is 100x200 pixels, and a vertex is at (50,150) on the picture, then the texture position | |
is (0.5,0.75) ie (50/100,150/200) | |
You must set these positions for each vertex, but if you create your rectangles with addRect, and if your rectangle | |
uses the whole picture, Codea will do all the work for you. | |
--]] | |
function setup() | |
m=mesh() | |
--choose a picture to draw (change it if you like) | |
img=readImage("Planet Cute:Character Princess Girl") | |
m:addRect(400,400,img.width,img.height) --same size as image | |
--let's add a second one, twice the size | |
--Codea will scale the image to the size of the rectangle | |
m:addRect(250,250,img.width*2,img.height*2) | |
m.texture=img --it's this easy to use an image | |
--it will be used for all the rectangles on this mesh | |
--there's no need to set the texture positions if we use addRect, because Codea will do it for us | |
--the only time you need to do it yourself is if you don't want to use the whole image | |
--we'll look at that option later | |
end | |
function draw() | |
background(180) | |
m:draw() | |
end | |
function PrintExplanation() | |
output.clear() | |
print("We can use a texture (ie picture) instead of colours on our rectangles") | |
end | |
--# Tiling | |
--Using the same image repeatedly to "tile" an area | |
--[[ | |
If you add rectangles with addRect and a texture image, you can create a tiled effect, repeating the image | |
across an area. That's because Codea will use the texture image for EACH rectangle in the mesh. | |
The demo below creates a castle like this. | |
But there is one problem. We want to create a floor, a castle, and soldiers, each with different texture images. | |
However, a mesh can only have one texture image attached. | |
One solution is to create a separate mesh for each image, and that's what we'll do here. | |
In the next demo, we'll show a different solution. | |
--]] | |
function setup() | |
x,y=100,100 --start drawing here | |
size=70 --size of tiles | |
SetupMeshes() | |
end | |
function SetupMeshes() | |
--create one mesh for the bottom layer, a grassy surface | |
local imgFloor=readImage("Platformer Art:Block Grass") | |
floor=mesh() | |
for i=1,8 do --calculate positions and add rectangles | |
local xx=x+(i-0.5)*size --mid point of rectangle | |
floor:addRect(xx,y+size/2,imgFloor.width,size) | |
end | |
floor.texture=imgFloor | |
--another mesh for the brick castle | |
local imgBlock=readImage("Platformer Art:Block Brick") | |
--problem - image has round edges that leave gaps when we stack them, so trim the edges off | |
imgBlock=imgBlock:copy(3,3,imgBlock.width-6,imgBlock.height-6) | |
castle=mesh() | |
castle.texture=imgBlock | |
--we'll build a castle, 6 blocks wide by 7 high, with some gaps for windows and the castle top | |
--here is a map of the castle in a table | |
map={} | |
map[1]="bs b" --mark each block position with a "b", and each soldier with "s", gaps with " " | |
map[2]="bbbbbb" --you can change these if you like | |
map[3]="bbbbsb" | |
map[4]="bbbbbb" | |
map[5]="bsbbbb" | |
map[6]="bbbbbb" | |
map[7]="bbssbb" | |
--create a separate mesh for soldiers | |
imgSoldier=readImage("Planet Cute:Character Boy") | |
soldiers=mesh() | |
soldiers.texture=imgSoldier | |
--read the map and add soldiers and blocks to their meshes | |
for i=1,#map do | |
local yy = y+size*(#map-i+3/2) --y position of this block | |
for j=1,map[i]:len() do | |
local xx = x+(j+0.5)*size --x position of this block | |
local a=map[i]:sub(j,j) --get map character (b, s or blank) | |
if a~=" " then | |
if a=="b" then castle:addRect(xx,yy,size,size) | |
elseif a=="s" then soldiers:addRect(xx,yy,imgSoldier.width,imgSoldier.height) | |
end | |
end | |
end | |
end | |
end | |
function draw() | |
background(170, 194, 211, 255) | |
floor:draw() | |
soldiers:draw() | |
castle:draw() | |
end | |
function PrintExplanation() | |
output.clear() | |
print("We can 'tile' images using a mesh") | |
end | |
--# Tilemap | |
--Using several images on one texture | |
--[[ | |
A problem with meshes is that each can only have ONE texture image attached | |
In the previous demo, we made a separate mesh for each texture image. | |
But there is another way that is used by most game developers. | |
We put all the pictures into a single image, put all our rectangles into one mesh using that image, | |
and then tell Codea which part of the image to use for each rectangle. | |
A combined image of this kind is often called a spritesheet | |
Normally, you'll create the spritesheet beforehand, but we'll do it as part of this demo | |
Then we'll add some rectangles, and tell Codea which part of the image to use for each of them | |
if we used addRect, Codea provides a function setRectTex to add texture positions for each rectangle | |
We give it the x,y value of the bottom left corner, and the width and height | |
All these values need to be a fraction of width and height, ie between 0 and 1 | |
Note - is it better to use a spritesheet or separate meshes? A single mesh draws faster than many separate meshes, | |
although the difference is so small that you probably won't notice until you have hundreds of rectangles. | |
Most of the time, it doesn't matter, and you can choose whichever suits you best. | |
--]] | |
function setup() | |
--combine three pictures into one image | |
img,imgPos=MakeSpriteSheet() --returns the image, and the positions of the three pictures on that image | |
--now our mesh | |
m=mesh() | |
--add three rectangles | |
m:addRect(200,350,101,171) | |
m:addRect(300,450,101,171) | |
m:addRect(400,550,101,171) | |
m.texture=img --set the texture image | |
--now we need to use setRectTex to tell Codea which part of the image to use for each rectangle | |
--the values have to be fractions of width and height, so let's get the width and height of the total image | |
local w,h=img.width,img.height | |
--loop through all the rectangles and add texture positions to them | |
for i=1,3 do | |
--get the texture positions for this rectangle (give it a short name to make the code below easier to read) | |
local p=imgPos[i] | |
--because there are three rectangles created with addRect, we need to tell Codea which one we want | |
--Codea numbers them 1,2,3... in the order they are created | |
--we'll use the pictures in the same order as the rectangles, ie the left hand picture will be used | |
--for the first rectangle, so we can simply use our looping counter i as the rectangle number | |
--that's why the first item in brackets below is i, it tells Codea which rectangle we want | |
--the other items are the x,y position of the bottom left corner, and width and height | |
--all of these must be fractions 0-1, which is why I divide by w and h | |
m:setRectTex(i, p.pos.x/w, p.pos.y/h, p.w/w, p.h/h) | |
end | |
end | |
function draw() | |
background(180) | |
fill(0) | |
text("These three rectangles\nare on a single mesh",200,500) | |
m:draw() | |
--draw the spritesheet as well | |
text("..using this texture image which has three pictures on it",250,200) | |
sprite(img,50,50) | |
end | |
--the MakeSpriteSheet function creates the image and gives us a table of positions (imgPos) for each picture | |
--There are three items in imgPos, which we need for setting texture positions in the mesh | |
--pos (x,y position of bottom left corner), | |
--w (width) in pixels, and | |
--h (height) in pixels | |
function MakeSpriteSheet() | |
--make a list of the pics we want | |
pics={"Planet Cute:Character Boy","Planet Cute:Character Pink Girl","Planet Cute:Character Princess Girl"} | |
--they are all 101 x 171 pixels, and we'll draw them in a row from left to right | |
--we'll leave a few pixels in between, drawing them 105 pixels apart, so we need an image 315 x171 pixels | |
local img=image(315,171) | |
setContext(img) --tell Codea to draw on this image instead of the screen | |
local imgPos={} --make a table to tell us how to find these images later | |
--we'll store the bottom left x and y, width, height | |
--naming the table items makes the code easier to use later | |
imgPos[1]={pos=vec2(0,0), w=101,h=171} | |
imgPos[2]={pos=vec2(105,0),w=101,h=171} | |
imgPos[3]={pos=vec2(210,0),w=101,h=171} | |
--sprite command usually needs the mid point position of each image, but we only have the bottom left corner | |
--so we can tell sprite to use that instead | |
spriteMode(CORNER) | |
for i=1,3 do | |
sprite(pics[i],imgPos[i].pos.x,imgPos[i].pos.y) | |
end | |
setContext() --stop drawing on the image | |
return img,imgPos --return the image and the positions of the pictures | |
end | |
function PrintExplanation() | |
output.clear() | |
print("We can use several different pictures in a mesh, by first combining them into one image") | |
end | |
--# Moving_1 | |
--Moving our rectangles | |
--[[ | |
We have several rectangles in a mesh | |
Now how do we move them and rotate them, especially if they are all moving differently? | |
There is a special setRect command for this, if we've added the rectangles with addRect | |
We'll use the previous example of three images and a spritesheet, in this demo, and move and rotate them | |
--]] | |
function setup() | |
img,imgPos=MakeSpriteSheet() ---same as previous demo | |
SetupMesh() --put all the mesh code in its own function to keep it tidy | |
end | |
function SetupMesh() | |
--you can do this first part any way you like | |
rects={} --a table to hold position and movement details for all our rectangles | |
--note the items are named, to make the code easier to follow when we draw | |
--pos=current position, | |
--vel=velocity (is added to pos each time we draw) | |
--angle=rotation angle, | |
--rot=change in rotation, ie we add rot to angle when we draw | |
rects[1] = {pos=vec2(200,350), vel=vec2(0.1,0.2), angle=0, rot=0.1} | |
rects[2] = {pos=vec2(300,450), vel=vec2(0.1,-0.1), angle=0, rot=-0.3} | |
rects[3] = {pos=vec2(400,550), vel=vec2(-0.1,-0.2), angle=0, rot=0.2} | |
--now the mesh | |
m=mesh() | |
--add our three rectangles | |
--we can position them all at 0,0 because we will be changing their positions every frame | |
--When we change the positions, we will need to tell Codea which rectangle to change | |
--It is a good idea to store the rectangle number while we are creating it, because in more complex | |
--projects, we may be working with hundreds of rectangles | |
--Codea helps us by returning the rectangle number when you use addRect, so we'll store that to use later | |
for i=1,3 do | |
rects[i].id = m:addRect(0,0,101,171) | |
end | |
m.texture = img --and the texture image | |
--this next part is the same as the last demo, we set the texture positions for each rectangle | |
local w,h = img.width,img.height | |
for i=1,3 do | |
local p = imgPos[i] | |
m:setRectTex(rects[i].id, p.pos.x/w, p.pos.y/h, p.w/w, p.h/h) | |
end | |
end | |
function draw() | |
background(180) | |
--reposition and rotate all our rectangles using setRect | |
for i=1,#rects do | |
local r=rects[i] --put the position details for this rect into r to make the code below easier to read | |
--setRect parameters are rectangle number, x,y position, width, height, rotation angle in radians | |
m:setRect(i, r.pos.x, r.pos.y, 101, 171, math.rad(r.angle)) --pretty easy, huh? | |
--update position and rotation for this rectangle | |
r.pos = r.pos+r.vel | |
r.angle = r.angle+r.rot | |
end | |
m:draw() | |
end | |
function MakeSpriteSheet() --same as the last demo | |
--make a list of the pics we want | |
pics={"Planet Cute:Character Boy","Planet Cute:Character Pink Girl","Planet Cute:Character Princess Girl"} | |
--they are all 101 x 171 pixels, and we'll draw them in a row from left to right | |
--we'll leave a few pixels in between, drawing them 105 pixels apart, so we need an image 315 x171 pixels | |
local img=image(315,171) | |
setContext(img) --tell Codea to draw on this image instead of the screen | |
local imgPos={} --make a table to tell us how to find these images later | |
--we'll store the start x, start y, width, height | |
--naming the table items makes the code easier to use later | |
imgPos[1]={pos=vec2(0,0), w=101,h=171} | |
imgPos[2]={pos=vec2(105,0),w=101,h=171} | |
imgPos[3]={pos=vec2(210,0),w=101,h=171} | |
--sprite command usually needs the mid point position of each image, but we only have the bottom left corner | |
--so we can tell sprite to use that instead | |
spriteMode(CORNER) | |
for i=1,3 do | |
sprite(pics[i],imgPos[i].pos.x,imgPos[i].pos.y) | |
end | |
setContext() --stop drawing on the image | |
return img,imgPos --return the image and the positions of the pictures | |
end | |
function PrintExplanation() | |
output.clear() | |
print("We can easily move and rotate our rectangle images") | |
end | |
--# Moving_2 | |
--Moving and rotating a whole mesh | |
--[[ | |
If you want to move and rotate a whole mesh, maybe with several objects, this is the way to do it | |
1. When you create your mesh, centre it on (0,0). Your mesh will rotate around a point, usually the centre of the | |
mesh - make this (0,0). You don't need to make a vertex for it, but all your other points must be positioned | |
relative to it. | |
For example, if you have a 100 x 50 rectangle, then if its centre is at (0,0), the four corners will be at | |
(-50,-25), (50,-25), (50,25), (-50,25) | |
2. Before drawing, "translate" to the position you want. This redefines the point (0,0) as that position, and if | |
you now draw your mesh [which is centred on (0,0) ] it will actually draw at the translated position. If it | |
sounds confusing, imagine you are drawing on a sheet of paper, and the position (0,0) is under your hand, | |
where it is easiest to draw. You want to draw something in the top left corner, which means stretching and | |
not drawing as well. So instead, you pull the paper toward you, so the top left corner is under your hand. You | |
have just "translated" [your drawing position] to the top left corner. | |
If we couldn't translate like this, we would have to adjust the position of EVERY vertex before drawing - and | |
when you have meshes with thousands of vertices, that is a lot of work! And if the mesh is rotating...!! | |
3. After translating, rotate, and then draw. Imagine our piece of paper again. We've pulled it toward us so the | |
place we want to draw is under our hand. But we want to draw something at an angle of 30 degrees. So we turn | |
the paper around that point by 30 degrees, so now we can draw the image the right way up. | |
4. When we're done, reverse the rotation and translation. Codea does this using two oddly named functions | |
pushMatrix() --stores the current screen settings | |
popMatrix --puts back the screen settings you stored with pushMatrix | |
The names push and pop are chosen because the settings are stored in a "stack", and the usual names for | |
adding to a stack and getting items from it, are "push" and "pop" | |
This demo shows how to do this using the stick figure from an earlier demo | |
--]] | |
function setup() | |
--create the stick figure from the addRect demo, centred on (0,0) | |
--the previous stick figure is not centred on (0,0), so how did I know where the middle was? | |
--I cheated by getting the previous demo to add up all the vertices, and took the average, which was (400,333) | |
--I subtracted this from all the vertex positions, to centre the figure on (0,0) | |
m=mesh() | |
m:addRect(0,17,100,200) --body | |
m:addRect(-35,-133,30,150)--leg | |
m:addRect(35,-133,30,150) --leg | |
m:addRect(0,102,350,30) --arms | |
m:addRect(0,147,50,60) --head | |
m:setColors(color(255,255,0)) | |
--we'll make it move slowly across the screen, and rotate | |
pos = vec2(150,150) --starting position | |
posChange = vec2(0.3,0.2) --how far it moves each time we draw | |
angle = 0 --rotation angle | |
angleChange=0.1 --change in angle each time we draw | |
end | |
function draw() | |
background(200) | |
pushMatrix() --store screen settings | |
translate(pos.x,pos.y) | |
rotate(angle) | |
m:draw() | |
popMatrix() --restore screen settings | |
--update position and angle | |
pos=pos+posChange | |
angle=angle+angleChange | |
end | |
function PrintExplanation() | |
output.clear() | |
print("Moving and rotating a whole mesh is a little different") | |
end | |
--# Curves | |
--Curves (when addRect is not enough - creating your own mesh, vertex by vertex) | |
--[[ | |
Because meshes use triangles with straight edges, rectangular objects are the easiest to make in 3D (which is why | |
Minecraft looks the way it does), and addRect is very useful. But what if you need to draw other shapes, like | |
curves? | |
VERTICES | |
You will have to set all the vertices yourself, grouped into triangles, and if you want a smooth curve, you may | |
need a lot of them. | |
There is a special triangulate command in Codea that may help. If you give it a table of points which make a shape (the points must be in clockwise or anticlockwise order), it will return a set of triangles that can be used in a mesh. | |
TEXTURE IMAGE | |
Then, if you want to attach an image to the mesh, you have to define all the texture positions for each vertex. | |
Generally, in 2D, it's easiest to use rectangles with curved texture images, to create smooth curves (eg to create a circle, make a picture of a circle and add it as a texture on a mesh rectangle). | |
THIS DEMO | |
We'll create a circular set of points - you choose how many points using the parameter slider - and use the | |
triangulate command to make mesh triangles from these points. Each triangle will be a different colour so you can see how they were created. | |
You can turn on the Texture option to see an image put onto this circular mesh, instead of colours. This requires | |
us to set texture positions for each point in our mesh. | |
--]] | |
function setup() | |
parameter.integer("Points",5,100,5,MakePizza) | |
parameter.boolean("ShowTriangle",false,MakePizza) | |
parameter.boolean("UseTexture",false,MakePizza) | |
end | |
--makes a circular mesh | |
function MakePizza() | |
--r is radius, n is number of points | |
r,n=300,Points | |
pizza=mesh() | |
v={} | |
for i=1,n do | |
--calculate x,y position of point | |
local a=2*math.pi*i/n --angle in radians | |
--yes, time for high school math again! | |
v[i]=vec2(r*math.sin(a), r*math.cos(a)) | |
end | |
pizza.vertices=triangulate(v) | |
--if UseTexture is set, define texture positions for each point in the mesh | |
if UseTexture then | |
local img=readImage("Cargo Bot:Starry Background") --pick a square image to put on the circle | |
--imagine laying the image on top of the circle and resizing it, so the circle just fits inside it | |
--the middle of the circle - which is the point (0,0) - will be at the middle of the image | |
--the width of the image will equal the radius of the circle | |
--the texture positions are fractions (0-1) of the width of the image | |
--to turn our screen positions into texture positions, this is the adjustment | |
--texture position of point(x,y) = (0.5,0.5) + (x,y) * 0.5/r | |
--we start at (0.5,0.5) because this is the texture equivalent of the circle centre of (0,0) | |
--then we divide by r, and divide by 2 because our radius r is half the width (or height) | |
--perhaps you can start to see how meshes can get tricky! | |
t={} | |
for i=1,pizza.size do --m.size tells us how many vertices there are (same as #pizza.vertices) | |
--when you store vertices in a mesh, it is done as a vec3, we need a vec2, ie just the x,y part | |
local p=vec2(pizza.vertices[i].x,pizza.vertices[i].y) --get the vertex position as a vec2 | |
t[i]=vec2(0.5,0.5) + p*0.5/r | |
end | |
pizza.texCoords=t | |
pizza.texture=img | |
pizza:setColors(color(255)) --remove individual triangle colours | |
elseif ShowTriangle then --colour each slice(ie each triangle of three vertices) a different colour | |
colors={} | |
for i=1,pizza.size,3 do --m.size tells us how many vertices there are (same as #pizza.vertices) | |
local c=color(math.random(0,255),math.random(0,255),math.random(0,255)) | |
colors[i],colors[i+1],colors[i+2]=c,c,c | |
end | |
pizza.colors=colors | |
pizza.texCoords,pizza.texture=nil,nil --remove texture if we were using one | |
else --just use once colour for the whole shape | |
pizza:setColors(color(186, 88, 181, 255)) | |
end | |
end | |
function draw() | |
background(200) | |
translate(WIDTH/2,HEIGHT/2) | |
pizza:draw() | |
end | |
function PrintExplanation() | |
output.clear() | |
print("This demo draws a circle - you can adjust the number of points") | |
print("The triangulate function is used to make triangles from a set of points") | |
print("The ShowTriangle parameter gives each triangle a different colour") | |
print("The UseTexture parameter attaches an image texture") | |
end | |
--# 3D | |
--[[ | |
Some 3D objects have thousands of vertices, which is why most people create them using a | |
program like Blender, which does the hard work for you. | |
one of the hardest in 3D is a sphere, | |
especially if you want to wrap an image around it. | |
The very basic 3D demo below draws a 3D block. Even with a simple block, you can see how much work it is! | |
To learn more, look at the 3D demo app. | |
--]] | |
function setup() | |
img=readImage("Platformer Art:Block Brick") | |
--make it square by trimming off the bottom | |
img=img:copy(3,3,img.width-6,img.height-6) | |
b=MakeBlock(30,20,10,img) | |
r,dr=vec3(0,0,0),vec3(0.2,-0.33,0.27) | |
end | |
function draw() | |
background(150) | |
perspective() --turn on 3D | |
camera(-10,10,100,0,0,0) | |
rotate(r.x,1,0,0) | |
rotate(r.y,0,1,0) | |
rotate(r.z,0,0,1) | |
b:draw() | |
r=r+dr | |
end | |
function MakeBlock(w,h,d) --width,height,depth | |
local m=mesh() | |
--define the 8 corners of the block ,centred on (0,0,0) | |
local fbl=vec3(-w/2,-h/2,d/2) --front bottom left | |
local fbr=vec3(w/2,-h/2,d/2) --front bottom right | |
local ftr=vec3(w/2,h/2,d/2) --front top right | |
local ftl=vec3(-w/2,h/2,d/2) --front top left | |
local bbl=vec3(-w/2,-h/2,-d/2) --back bottom left (as viewed from the front) | |
local bbr=vec3(w/2,-h/2,-d/2) --back bottom right | |
local btr=vec3(w/2,h/2,-d/2) --back top right | |
local btl=vec3(-w/2,h/2,-d/2) --back top left | |
--now create the 6 faces of the block, each is two triangles with 3 vertices (arranged anticlockwise) | |
--so that is 36 vertices | |
--for each face, I'm going to start at bottom left, then bottom right, then top right, and for the second | |
--triangle, top right, top left, then bottom left | |
m.vertices={ | |
fbl,fbr,ftr, ftr,ftl,fbl, --front face | |
bbl,fbl,ftl, ftl,btl,bbl, --left face | |
fbr,bbr,btr, btr,ftr,fbr, --right face | |
ftl,ftr,btr, btr,btl,ftl, --top face | |
bbl,bbr,fbr, fbr,fbl,bbl, --bottom face | |
bbr,bbl,btl, btl,btr,bbr --back face | |
} | |
--add texture positions, we will use the same image for each face so we only need 4bcorner positions | |
local bl,br,tr,tl=vec2(0,0),vec2(1,0),vec2(1,1),vec2(0,1) | |
local t={} | |
for i=1,6 do --use a loop to add texture positions for each face, as they are the same for each face | |
t[#t+1]=bl | |
t[#t+1]=br | |
t[#t+1]=tr | |
t[#t+1]=tr | |
t[#t+1]=tl | |
t[#t+1]=bl | |
end | |
m.texCoords=t | |
m.texture=img | |
m:setColors(color(200)) | |
return m | |
end | |
function PrintExplanation() | |
output.clear() | |
print("A simple 3D block mesh") | |
end | |
--# Main | |
-- MultiStep | |
function setup() | |
steps = listProjectTabs() | |
if steps[1]=="Notes" then table.remove(steps,1) end --remove first tab if named Notes | |
table.remove(steps) --remove the last tab | |
startStep() | |
global = "select a step" | |
end | |
function showList() | |
output.clear() | |
for i=1,#steps do print(i,steps[i]) end | |
end | |
function startStep() | |
if cleanup then cleanup() end | |
lastStep=Step or readProjectData("lastStep") or 1 | |
lastStep=math.min(lastStep,#steps) | |
saveProjectData("lastStep",lastStep) | |
parameter.clear() | |
parameter.integer("Step", 1, #steps, lastStep,showList) | |
parameter.action("Run", startStep) | |
loadstring(readProjectTab(steps[Step]))() | |
if PrintExplanation then PrintExplanation() end | |
setup() | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment