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 in Questions 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. :)

Comments

  • dave1707dave1707 Mod
    edited September 2016 Posts: 7,810

    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
  • dave1707dave1707 Mod
    edited September 2016 Posts: 7,810

    @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).

  • @Kolosso Thank you for the help, very helpful. :)

  • @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.

  • @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.

  • @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.

  • @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?)

  • IgnatzIgnatz Mod
    Posts: 5,396

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

  • @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).

  • @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.

  • @Kolosso But how can one mesh draw different xyz?

  • dave1707dave1707 Mod
    Posts: 7,810

    @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?

  • @Kolosso How can the mesh know where to draw?

  • @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?

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

  • @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! :)

  • @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.

  • dave1707dave1707 Mod
    Posts: 7,810

    @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.

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

  • @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.

  • dave1707dave1707 Mod
    Posts: 7,810

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

  • @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?

  • @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.

  • dave1707dave1707 Mod
    Posts: 7,810

    @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
    
  • @dave1707 thank you very much for the code :) , I will study on it, thank you very much. :D

  • @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?

  • dave1707dave1707 Mod
    edited September 2016 Posts: 7,810

    @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.

  • IgnatzIgnatz 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.

  • dave1707dave1707 Mod
    edited September 2016 Posts: 7,810

    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
                m:addRect(x*42+21,y*42+21,42,42)
            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
                m:addRect(x*42+21,y*42+21,42,42)
            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
    
Sign In or Register to comment.