#### Howdy, Stranger!

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

# How to make fps higher at a 3d game.

edited September 2016 Posts: 31

I made a 3d game and it is very simple now. It is like Minecraft. I use Mesh to print the graphics, but the fps only have 7-10! Does anyone know how to make the fps more higher at 3d games? Thank you.

Tagged:

• Mod
edited September 2016 Posts: 9,480

Since you don't include any code to look at or any details on what you're doing other than `Mesh to print graphics`, all I can say is `start removing things until it goes faster`. How many meshes do you have, vertices, etc. What version iPad are you using. Give us as much info as you can.

• edited September 2016 Posts: 31

@dave1707 sorry, I forgot to put code...
There is all the code from my project.

``````--# Control
Control = class()

function Control:init(x)

end

function Control:draw()
for k , touch in pairs (touches) do
if touch.state == BEGAN then
touchX,touchY = touch.x,touch.y
elseif touch.state == MOVING then
AngleY = AngleY - (touch.y - touchY) / 4
AngleX = AngleX - (touch.x - touchX) / 4
touchX,touchY = touch.x,touch.y
end
end
end

function Control:touched(touch)

end
--# DrawBlock
DrawBlock = class()

function DrawBlock:init(x)

end

function DrawBlock:draw()
perspective ()
for py = 1 , 256 do
for px = 1 , 16 do
for pz = 1 , 16 do
if Blocks [py] [px] [pz] ~= 0 then
for i = 1 , 12 do
DrawBlocksList = {0}
if math.ceil (i / 2) == 1 then
if Blocks [py + 1] [px] [pz] == 0 then
DrawBlocksList [1] = 1
end
elseif math.ceil (i / 2) == 2 then
if Blocks [py] [px] [pz - 1] == 0 then
DrawBlocksList [1] = 2
end
elseif math.ceil (i / 2) == 3 then
if Blocks [py] [px] [pz + 1] == 0 then
DrawBlocksList [1] = 3
end
elseif math.ceil (i / 2) == 4 then
if Blocks [py - 1] [px] [pz] == 0 then
DrawBlocksList [1] = 4
end
elseif math.ceil (i / 2) == 5 then
if Blocks [py] [px - 1] [pz] == 0 then
DrawBlocksList [1] = 5
end
elseif math.ceil (i / 2) == 6 then
if Blocks [py] [px + 1] [pz] == 0 then
DrawBlocksList [1] = 6
end
end
if DrawBlocksList [1] ~= 0 then
for o = 0 , 1 do
BlockMesh.vertices = {vec3 (px * BlockWidth,py * BlockWidth,pz * BlockWidth) + Vertices [i] [1],vec3 (px * BlockWidth,py * BlockWidth,pz * BlockWidth) + Vertices [i] [2],vec3 (px * BlockWidth,py * BlockWidth,pz * BlockWidth) + Vertices [i] [3]}
BlockMesh.texCoords = TexCoords [i % 2 + 1]
if Blocks [py] [px] [pz] == 1 then
if math.ceil (i / 2) == 1 then
if BlockMesh.texture ~= "Cargo Bot:Crate Green 1" then
BlockMesh.texture = "Cargo Bot:Crate Green 1"
end
elseif  math.ceil (i / 2) == 4 then
if BlockMesh.texture ~= "Cargo Bot:Crate Green 1" then
BlockMesh.texture = "Cargo Bot:Crate Green 1"
end
else
if BlockMesh.texture ~= "Cargo Bot:Crate Green 1" then
BlockMesh.texture = "Cargo Bot:Crate Green 1"
end
end
elseif Blocks [py] [px] [pz] == 2 then
if BlockMesh.texture ~= "Project:FlatPlanet Dirt" then
BlockMesh.texture = "Project:FlatPlanet Dirt"
end
elseif Blocks [py] [px] [pz] == 3 then
if BlockMesh.texture ~= "Project:FlatPlanet Stone" then
BlockMesh.texture = "Project:FlatPlanet Stone"
end
end
BlockMesh:draw ()
end
end
end
end
end
end
end
end

function DrawBlock:touched(touch)

end
--# SetUp
SetUp = class()

function SetUp:init(x)
Vertices = {
{vec3 (-1 * BlockWidth,0 * BlockWidth,-1 * BlockWidth),vec3 (0 * BlockWidth,0 * BlockWidth,-1 * BlockWidth),vec3 (-1 * BlockWidth,0 * BlockWidth,0 * BlockWidth)},
{vec3 (0 * BlockWidth,0 * BlockWidth,-1 * BlockWidth),vec3 (0 * BlockWidth,0 * BlockWidth,0 * BlockWidth),vec3 (-1 * BlockWidth,0 * BlockWidth,0 * BlockWidth)},
-- Top
{vec3 (-1 * BlockWidth,-1 * BlockWidth,-1 * BlockWidth),vec3 (0 * BlockWidth,-1 * BlockWidth,-1 * BlockWidth),vec3 (-1 * BlockWidth,0 * BlockWidth,-1 * BlockWidth)},
{vec3 (0 * BlockWidth,-1 * BlockWidth,-1 * BlockWidth),vec3 (0 * BlockWidth,0 * BlockWidth,-1 * BlockWidth),vec3 (-1 * BlockWidth,0 * BlockWidth,-1 * BlockWidth)},
-- Front
{vec3 (-1 * BlockWidth,-1 * BlockWidth,0 * BlockWidth),vec3 (0 * BlockWidth,-1 * BlockWidth,0 * BlockWidth),vec3 (-1 * BlockWidth,0 * BlockWidth,0 * BlockWidth)},
{vec3 (0 * BlockWidth,-1 * BlockWidth,0 * BlockWidth),vec3 (0 * BlockWidth,0 * BlockWidth,0 * BlockWidth),vec3 (-1 * BlockWidth,0 * BlockWidth,0 * BlockWidth)},
-- back
{vec3 (-1 * BlockWidth,-1 * BlockWidth,-1 * BlockWidth),vec3 (0 * BlockWidth,-1 * BlockWidth,-1 * BlockWidth),vec3 (-1 * BlockWidth,-1 * BlockWidth,0 * BlockWidth)},
{vec3 (0 * BlockWidth,-1 * BlockWidth,-1 * BlockWidth),vec3 (0 * BlockWidth,-1 * BlockWidth,0 * BlockWidth),vec3 (-1 * BlockWidth,-1 * BlockWidth,0 * BlockWidth)},
-- Bottom
{vec3 (-1 * BlockWidth,-1 * BlockWidth,-1 * BlockWidth),vec3 (-1 * BlockWidth,-1 * BlockWidth,0 * BlockWidth),vec3 (-1 * BlockWidth,0 * BlockWidth,-1 * BlockWidth)},
{vec3 (-1 * BlockWidth,-1 * BlockWidth,0 * BlockWidth),vec3 (-1 * BlockWidth,0 * BlockWidth,0 * BlockWidth),vec3 (-1 * BlockWidth,0 * BlockWidth,-1 * BlockWidth)},
-- Right
{vec3 (0 * BlockWidth,-1 * BlockWidth,-1 * BlockWidth),vec3 (0 * BlockWidth,-1 * BlockWidth,0 * BlockWidth),vec3 (0 * BlockWidth,0 * BlockWidth,-1 * BlockWidth)},
{vec3 (0 * BlockWidth,-1 * BlockWidth,0 * BlockWidth),vec3 (0 * BlockWidth,0 * BlockWidth,0 * BlockWidth),vec3 (0 * BlockWidth,0 * BlockWidth,-1 * BlockWidth)}
-- Left
}
TexCoords = {
{vec2 (1,0),vec2 (1,1),vec2 (0,1)},
{vec2 (0,0),vec2 (1,0),vec2 (0,1)}
}
end

function SetUp:draw()

end

function SetUp:touched(touch)

end

--# GeneratedTerrain
GeneratedTerrain = class()

function GeneratedTerrain:init()
Blocks = {}
for py = 0 , 257 do
Blocks [py] = {}
for px = 0 , 17 do
Blocks [py] [px] = {}
for pz = 0 , 17 do
Blocks [py] [px] [pz] = 0
end
end
end
for px = 1 , 16 do
for pz = 1 , 16 do
Blocks [128] [px] [pz] = 1
Blocks [127] [px] [pz] = 1
for py = 1 , 3 do
-- Blocks [128 - py] [px] [pz] = 2
end
for py = 1 , 124 do
-- Blocks [125 - py] [px] [pz] = 3
end
end
end
Blocks [128] [1] [1] = 1
Blocks [128] [2] [1] = 1
Blocks [128] [1] [2] = 1
end

function GeneratedTerrain:draw()

end

function GeneratedTerrain:touched(touch)

end

--# Main
supportedOrientations (LANDSCAPE_ANY)
function setup()
Variable:init ()
BlockMesh = mesh ()
-- BlockMesh:setColors (255,255,255,255)
end
sprite ()
function draw()
background(176,233,252,255)
lookX,lookY,lookZ = camX + math.sin (math.rad (AngleX)) * 10,camY + math.sin (math.rad (AngleY)) * 10,camZ + math.cos (math.rad (AngleX)) * 10
camera (camX,camY,camZ,lookX,lookY,lookZ)
DrawBlock:draw ()
Control:draw ()
print ("FPS : "..math.floor (1 / DeltaTime))
end

function touched (touch)
if touch.state == ENDED then
touches [touch.id] = nil
else
touches [touch.id] = touch
end
end

--# Variable
Variable = class()

function Variable:init(x)
BlockWidth = WIDTH / 8
DrawBlocksList = {}
-- block
AngleX,AngleY = 180,180
camX,camY,camZ = -300,130 * BlockWidth,BlockWidth
lookX,lookY,lookZ = camX + math.sin (math.rad (AngleX)) * 10,camY + math.sin (math.rad (AngleY)) * 10,camZ + math.cos (math.rad (AngleX)) * 10
-- camera
touches = {}
touchX,touchY = 0,0
-- touch
SetUp:init ()
GeneratedTerrain:init ()
-- init ()
parameter.number ("camX",-1000,1000,-300)
parameter.number ("camY",11000,20000,130 * BlockWidth)
parameter.number ("camZ",-1000,1000,BlockWidth / 2)
parameter.number ("AngleX",-1000,1000,-620)
parameter.number ("AngleY",-1000,1000,-45)
end

function Variable:draw()

end

function Variable:touched(touch)

end
``````
• Mod
edited September 2016 Posts: 9,480

@Gai_Gai Unfortunatly it runs at 0 FPS on my iPad Air. All I see is something blue and that's it. Any textures or whatever that you use, if they're not the built in Codea assets, they can't be seen by anyone else. They're local to you but blank for us. Maybe you can tell us what we're supposed to be seeing. I'm not going to spend any time trying to figure this out. Maybe someone else with a faster iPad will look into it, but it's too slow for me to do anything.

EDIT: Anytime you post code, put 3~'s on a line before and after the code so it formats correctly. I added them to your code above.

• edited September 2016 Posts: 160

Well, I don't mean to be rude but I find your code a bit messy and hard to read, so I'll just give you tips (but I'm not an expert):
1. I recommend splitting your voxel world (aka blocky world) into chunks (like Minecraft) and each chunk will have a mesh. This way, you can draw only the chunks that are near the camera to reduce the amount of vertices being drawn.
2. I recommend culling (I think that's the right term!) the meshes. That means you need to get your code to figure out which sides of the blocks are covered. Only if a side is not covered by a block, should your code add vertices to the chunk's mesh for that side of the block.
3. Also, I see in your draw function, `BlockMesh:setColors (255,255,255)`. It just needs to be called once (just after `BlockMesh` is declared).

• Posts: 31

@Kolosso Thank you for the help, very helpful.

• Posts: 31

@dave1707 I changed the texture, I think now you can see the texture.And thank for teach me how to use the "~~~". I think the problem that solw down the fps is the mesh, can you teach me how to use the mesh that it does not solw down the fps? Thank you.

• edited September 2016 Posts: 31

@Kolosso , I already "culling" the mesh that between two blocks, It is better than the original one, but it only take fps higher a little (like 1-2). I try to put the DrawBlock:Draw as a comment but the fps is still low, and is a stop all the DrawBlocks class, the for is about 60. Does change the DrawBlock.vortex need a lot of time?

• Posts: 160

Is it culling every frame? If it is then I believe that's the problem. The vertices for the mesh only need to be set once unless the blocks will be changing. If that's the case, it should re-mesh only when there's a block change.

• Posts: 31

@Kolosso You mean one block use one mesh? I can try that. Because I use only one Mesh to draw all of the blocks and I change the vertices every block.

• Posts: 31

@Kolosso Thank you for the idea.

• Posts: 160

That's not really what I meant. If there is not that many blocks, you should use 1 mesh for all of them. If there are lots of blocks, you should split the blocks into chunks where each chunk has it's own mesh. You should make the vertices for your meshes once, at the setup function. Then draw the meshes in the draw function. Then change the vertices for the meshes when a block changes.

• Posts: 31

@Kolosso But the blocks I draw is 16*16 (a chunk), and the xyz of a block in a chunk is not the same, I need to change the xyz(vertices) every block, how can I make this faster?(easier?)

• Mod
Posts: 5,396

why are you changing vertices? Why not just translate the blocks?

• Posts: 31

@Ignatz so you mean mesh can translate? That is good idea, thank you for help me I will try it now.

• Posts: 160

@Ignatz Is my way inefficient? I was telling @Gai_Gai that they should split the world into chunks, and make each chunk own a mesh that draws only the sides of the blocks that are visible. Then replace those meshes whenever a block changes (example: a block placed).

• Posts: 31

@Kolosso so you mean that I only need to draw a block once if there is never will be a change?

• edited September 2016 Posts: 160

@Gai_Gai That is close to what I mean. You only need to make the vertices for your blocks once. Then you draw the meshes in the draw function. If there is a change, you remake the vertices of the meshes.

• Posts: 31

@Kolosso But how can one mesh draw different xyz?

• Mod
Posts: 9,480

@Gai_Gai One thing that's slowing things down is the print statement in draw(). Comment that out. You never or almost never want to put a print statement in draw().

• Posts: 160

@Gai_Gai What do you mean?

• Posts: 31

@Kolosso How can the mesh know where to draw?

• Posts: 31

@Kolosso Because there is a lot of block at there and each block have a different location, how mesh know where to draw ?

• edited September 2016 Posts: 160

@Gai_Gai Meshes can be translated with the `translate(x,y,z)` command. Is that what you were asking about?

• Posts: 31

@dave1707 I delete the print, the fps is still low, I don't think this is the problem.

• Posts: 31

@Kolosso Yea! Thank you! I try this at begin of the draw blocks and all of the blocks all moved! That is work! Thank you very much to help me.

• Posts: 160

@Gai_Gai I'm happy to help!

• Posts: 31

@Kolosso By the way, do I need 12 mesh for one type of block? Because if I don't use it, the mesh need to change the vertices again.

• Mod
Posts: 9,480

@Gai_Gai Deleting the print statement won't solve the whole problem, but it will help some. If you leave the print statement in there, it will eventually cause the program to slow down to a crawl and then crash.

• Posts: 31

@dave1707 What if I change the print to text? I what to see the fps.

• Posts: 31

@Kolosso By the way, do I need 12 mesh for one type of block? Because if I don't use it, the mesh need to change the vertices again.

• Mod
Posts: 9,480

You can do a parameter.watch("FPS") and put FPS=1/DeltaTime//1 in the draw() function.

• Posts: 31

@dave1707 That is a great idea, thanks for the help.

• Posts: 160

By the way, do I need 12 mesh for one type of block? Because if I don't use it, the mesh need to change the vertices again.

@Gai_Gai What do you mean?

• Posts: 31

@Kolosso I think I need 12 mesh for a type of block, because one mesh need to draw one triangle and the triangle has the same location and one block have 12 triangle so I think I need 12 mesh for a type of block.

• Posts: 160

@Gai_Gai meshes can hold unlimited amount of triangles.

• Mod
Posts: 9,480

@Gai_Gai If I look at your running code, there's a cube made up of 16x16x2 rectangles with the crate texture. On my iPad Air it runs at approx 7 FPS. Here's an example I put together with a cube made up of 17x17x2 rectangles with the crate texture. I changed the size of the texture to make it look solid. This runs at approx 50 FPS on my iPad. I'm not sure about everything you're doing in your code, but I just wanted to show you that the FPS can be increased. To see a 360 degree view of the inside of the cube, push cenX all the way to the right, then cenZ. Then push cenX all the way to the left, then cenZ. Repeat. Change eyeX,Y,Z for other views.

``````function setup()
parameter.watch("fps")
parameter.integer("eyeX",-4000,4000,0)
parameter.integer("eyeY",-200,200,40)
parameter.integer("eyeZ",-4000,4000,140)
parameter.integer("cenX",-1000,1000,-1000)
parameter.integer("cenZ",-1000,1000,-1000)
sides={}
for x=-8,8 do
for z=-8,8 do
table.insert(sides,side(x*20,40,z*20,"top"))
table.insert(sides,side(x*20,20,z*20,"bottom"))
end
end
for x=-8,8 do
for y=1,2 do
table.insert(sides,side(x*20,y*20,160,"front"))
table.insert(sides,side(x*20,y*20,-160,"back"))
table.insert(sides,side(180,y*20,x*20,"left"))
table.insert(sides,side(-180,y*20,x*20,"right"))
end
end
end

function draw()
background(40, 40, 50)
perspective(100)
camera(eyeX,eyeY,eyeZ, cenX,0,cenZ, 0,1,0)
for a,b in pairs(sides) do
b:draw()
end
fps=1/DeltaTime//1
end

side=class()

function side:init(x,y,z,pos)
v={ vec3(-10+x, -10+y,  10+z),      -- Left  bottom front
vec3( 10+x, -10+y,  10+z),      -- Right bottom front
vec3( 10+x,  10+y,  10+z),      -- Right top    front
vec3(-10+x,  10+y,  10+z),      -- Left  top    front
vec3(-10+x, -10+y, -10+z),      -- Left  bottom back
vec3( 10+x, -10+y, -10+z),      -- Right bottom back
vec3( 10+x,  10+y, -10+z),      -- Right top    back
vec3(-10+x,  10+y, -10+z) }     -- Left  top    back
self.ms=mesh()
self.ms.texture="Cargo Bot:Crate Green 1"
tex={ vec2(.1,.1),vec2(.9,.1),vec2(.1,.9),vec2(.9,.9) }
self.ms.texCoords={ tex[1],tex[2],tex[4],tex[1],tex[4],tex[3] }
if pos=="back" then
self.ms.vertices={ v[6],v[5],v[8],v[6],v[8],v[7] }
elseif pos=="front" then
self.ms.vertices={ v[1],v[2],v[3],v[1],v[3],v[4] }
elseif pos=="top" then
self.ms.vertices={ v[4],v[3],v[7],v[4],v[7],v[8] }
elseif pos=="bottom" then
self.ms.vertices={ v[5],v[6],v[2],v[5],v[2],v[1] }
elseif pos=="right" then
self.ms.vertices={ v[2],v[6],v[7],v[2],v[7],v[3] }
elseif pos=="left" then
self.ms.vertices={ v[5],v[1],v[4],v[5],v[4],v[8] }
end
self.ms:setColors(0,255,0,255)
end

function side:draw()
self.ms:draw()
end
``````
• Posts: 31

@dave1707 thank you very much for the code , I will study on it, thank you very much.

• Posts: 31

@dave1707 can you teach me how does the code work? I'm not understand how the code work. How can the location of the mesh change without change the vertices?

• Mod
edited September 2016 Posts: 9,480

@Gai_Gai The vertices values are different for each mesh. In the setup() function, I create an entry in the table sides for each mesh by calling side with different x,y,z values `table insert(sides,side(x*20,40,z*20,"top"))`. The first for loop creates all the meshes for the top and bottom of the cube. The second for loop creates the sides. If you look at those, you'll see that there will be different values. I'm not sure if this is usable for what you might want to do, but then I don't know what you want to do. This was written just to show that the FPS can be increased. There are 714 meshes, each with different vertices. I believe that the number of meshes can be reduced to 6 by creating a mesh for each side with all the vertices for those sides.

• Mod
Posts: 5,396

If you are creating a set of blocks in a kind of wall that won't move, ie the wall won't break up into pieces, it's way more efficient to create the wall as a single 3D block, and tile the texture image on it to create the illusion of separate blocks.

• Mod
edited September 2016 Posts: 9,480

As I said in my post above, the 714 meshes could be reduced to 6. Here's similar code to what I have above and it uses 6 meshes, one for each side, and runs at approx 60 FPS.

EDIT: Changed code.

``````function setup()
m=mesh()
for x=0,15 do
for y=0,15 do
end
end
m.texture="Cargo Bot:Crate Blue 1"
img=image(42*16,42*16)
setContext(img)
m:draw()
setContext()

m=mesh()
for x=0,15 do
for y=0,1 do
end
end
m.texture="Cargo Bot:Crate Green 2"
img1=image(42*16,42*2)
setContext(img1)
m:draw()
setContext()

parameter.watch("fps")
parameter.integer("eyeX",-4000,4000,0)
parameter.integer("eyeY",-200,200,0)
parameter.integer("eyeZ",-4000,4000,0)
parameter.integer("cenX",-1000,1000,-1000)
parameter.integer("cenZ",-1000,1000,-1000)
sides={}
table.insert(sides,side(100,21,100,"top"))
table.insert(sides,side(100,21,100,"bottom"))
table.insert(sides,side(100,21,100,"front"))
table.insert(sides,side(100,21,100,"back"))
table.insert(sides,side(100,21,100,"left"))
table.insert(sides,side(100,21,100,"right"))
end

function draw()
background(0)
perspective(100)
camera(eyeX,eyeY,eyeZ, cenX,0,cenZ, 0,1,0)
for a,b in pairs(sides) do
b:draw()
end
fps=1/DeltaTime//1
end

side=class()

function side:init(x,y,z,pos)
v={ vec3(-x, -y,  z),      -- Left  bottom front
vec3( x, -y,  z),      -- Right bottom front
vec3( x,  y,  z),      -- Right top    front
vec3(-x,  y,  z),      -- Left  top    front
vec3(-x, -y, -z),      -- Left  bottom back
vec3( x, -y, -z),      -- Right bottom back
vec3( x,  y, -z),      -- Right top    back
vec3(-x,  y, -z) }     -- Left  top    back
self.ms=mesh()
tex={ vec2(0,0),vec2(1,0),vec2(0,1),vec2(1,1) }
self.ms.texCoords={ tex[1],tex[2],tex[4],tex[1],tex[4],tex[3] }
if pos=="back" then
self.ms.texture=img1
self.ms.vertices={ v[6],v[5],v[8],v[6],v[8],v[7] }
elseif pos=="front" then
self.ms.texture=img1
self.ms.vertices={ v[1],v[2],v[3],v[1],v[3],v[4] }
elseif pos=="top" then
self.ms.texture=img
self.ms.vertices={ v[4],v[3],v[7],v[4],v[7],v[8] }
elseif pos=="bottom" then
self.ms.texture=img
self.ms.vertices={ v[5],v[6],v[2],v[5],v[2],v[1] }
elseif pos=="right" then
self.ms.texture=img1
self.ms.vertices={ v[2],v[6],v[7],v[2],v[7],v[3] }
elseif pos=="left" then
self.ms.texture=img1
self.ms.vertices={ v[5],v[1],v[4],v[5],v[4],v[8] }
end
self.ms:setColors(255,255,255,255)
end

function side:draw()
self.ms:draw()
end
``````
• Posts: 3

You could make an if statement when the FPS is less than 40 then smooth graphics is disabled else smooth graphics is enabled.

``````if FPS <= 40 then
noSmooth()
else
smooth()
end
``````