Jump to content

  • Log In with Google      Sign In   
  • Create Account


High-poly model XNA 10 FPS !


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
20 replies to this topic

#1 FantasyVII   Members   -  Reputation: 299

Like
0Likes
Like

Posted 16 October 2012 - 07:39 PM

Hello everyone,

So I have a 3D model that has around 150K polygons. So I tried to render it in XNA and my FPS dropped from 2500 FPS to 30 FPS. I tried to render two models and my FPS drop from 30 FPS to 7 FPS.


I have a 3930K with 6 cores and 12 threads and 1 of my threads is at 100%. So I guess I'm hitting CPU limit before GPU limit. My GPU usage is only 40%. So I guess I need to do Multithreading to use all 6 cores.

I just want to know am I crazy for rendering 300K polygons at once (150K * 2)? is 300K polygons is too high? how do other games render? How many polygons does a modern game has?

how many polygons can I render at once? do I have to use something like LOD to limit how many polygons I can render at once?

sorry for all of these question but i'm new to 3D development.

Sponsor:

#2 apatriarca   Crossbones+   -  Reputation: 1649

Like
1Likes
Like

Posted 16 October 2012 - 08:19 PM

You can draw much more than 300k polygons at once. How are your meshes loaded and drawn?

#3 phil_t   Crossbones+   -  Reputation: 3258

Like
1Likes
Like

Posted 16 October 2012 - 09:00 PM

Yeah, 300k shouldn't be having as much impact as you're seeing.

Also, it's normal for one thread to be at 100% CPU in an XNA game loop. It does not indicate a problem.

#4 Hodgman   Moderators   -  Reputation: 29469

Like
4Likes
Like

Posted 16 October 2012 - 09:37 PM

According to your numbers, the first model increased your frame times by 33ms, and the second model increased your frame times by another 110ms. Is there any reason why the second model would be 3 times more expensive than the first?

You mention your CPU specifications, but why not GPU specifications? How are you measuring GPU usage? Have you tried using a CPU profiler to confirm it's the bottleneck?

Edited by Hodgman, 16 October 2012 - 10:28 PM.


#5 MrDaaark   Members   -  Reputation: 3551

Like
1Likes
Like

Posted 16 October 2012 - 10:03 PM

Number of polygons isn't a good metric. How are you drawing the model? What shaders are you using, and is there more than one material on the model?

A model in XNA is an array of meshes that are split up by materials. Then the default model drawing example code loops through the array and draws a model one material/batch at a time.

That's fine for simple example programs or basic demos but you don't want all those redundant state changes in complex scenes.

#6 FantasyVII   Members   -  Reputation: 299

Like
0Likes
Like

Posted 17 October 2012 - 02:36 AM

You can draw much more than 300k polygons at once. How are your meshes loaded and drawn?


Here is my drawing class

Sorry I'm not using Code tage. but when I do use code tage all the code is displayed on one line!!

namespace _3D_Collection_test
{
class BasicModel
{
Model model;

public Vector3 Position, Rotation;
Matrix ViewMatrix, ProjectionMatrix;

public BasicModel(Vector3 Position, Vector3 Rotation)
{
this.Position = Position;
this.Rotation = Rotation;
}

public void Initialize(Matrix ViewMatrix, Matrix ProjectionMatrix)
{
this.ViewMatrix = ViewMatrix;
this.ProjectionMatrix = ProjectionMatrix;
}


public void LoadContent(ContentManager Content, string ModelPath)
{
model = Content.Load<Model>(ModelPath);
}

public void SetPosition(Vector3 Position)
{
this.Position = Position;
}

public void Update(Matrix ViewMatrix, Matrix ProjectionMatrix)
{
KeyboardState keyState = Keyboard.GetState();
if (keyState.IsKeyDown(Keys.Right))
{
Position.X += 5;
}
if (keyState.IsKeyDown(Keys.Left))
{
Position.X -= 5;
}
if (keyState.IsKeyDown(Keys.Up))
{
Position.Z -= 5;
}
if (keyState.IsKeyDown(Keys.Down))
{
Position.Z += 5;
}
this.ViewMatrix = ViewMatrix;
this.ProjectionMatrix = ProjectionMatrix;
}

public void Draw()
{
foreach (ModelMesh modelMesh in model.Meshes)
{
foreach (BasicEffect Effect in modelMesh.Effects)
{
Effect.EnableDefaultLighting();
Effect.PreferPerPixelLighting = true;
Effect.DirectionalLight0.Enabled = true;
Effect.DirectionalLight0.Direction = new Vector3(-1, -1, -1);
Effect.DirectionalLight0.DiffuseColor = Color.White.ToVector3();

Effect.World = Matrix.CreateScale(1.0f) *
Matrix.CreateRotationX(MathHelper.ToRadians(Rotation.X)) *
Matrix.CreateRotationY(MathHelper.ToRadians(Rotation.Y)) *
Matrix.CreateRotationZ(MathHelper.ToRadians(Rotation.Z)) *
Matrix.CreateTranslation(Position);

Effect.Projection = ProjectionMatrix;
Effect.View = ViewMatrix;
}
modelMesh.Draw();
}
}
}
}


According to your numbers, the first model increased your frame times by 33ms, and the second model increased your frame times by another 110ms. Is there any reason why the second model would be 3 times more expensive than the first?

You mention your CPU specifications, but why not GPU specifications? How are you measuring GPU usage? Have you tried using a CPU profiler to confirm it's the bottleneck?

I really don't know.

I measure my GPU usage using Afterburner and I look at task manger to see my CPU usage.

When I don't draw any models on the screen my GPU usage is 100% and my CPU usage is 0%. When I draw one or two models my GPU usage is 0% and one of my CPU threads is at 100%.

No model drawn:-
Posted Image


One model drawn:-
Posted Image


Two models drawn:-
Posted Image


Number of polygons isn't a good metric. How are you drawing the model? What shaders are you using, and is there more than one material on the model?

A model in XNA is an array of meshes that are split up by materials. Then the default model drawing example code loops through the array and draws a model one material/batch at a time.

That's fine for simple example programs or basic demos but you don't want all those redundant state changes in complex scenes.


I'm using BasicEffect.

Edited by FantasyVII, 17 October 2012 - 02:42 AM.


#7 Tasaq   Members   -  Reputation: 1215

Like
5Likes
Like

Posted 17 October 2012 - 03:06 AM

How your model is built? If each leaf on your tree is separate ModelMesh, for 150k model it will create tons of batches. (you can simply check it by counting iterations of first foreach, the one with ModelMesh).
You can have 25k batches per second at 1ghz cpu, that leaves ~400 batches per frame to maintain 60 fps. It's wise to use less but large batches rather than small but many batches (it's because for each leaf you need to give gpu it's world matrix, texture etc).

Edited by Tasaq, 17 October 2012 - 03:07 AM.


#8 FantasyVII   Members   -  Reputation: 299

Like
0Likes
Like

Posted 17 October 2012 - 03:23 AM

How your model is built? If each leaf on your tree is separate ModelMesh, for 150k model it will create tons of batches. (you can simply check it by counting iterations of first foreach, the one with ModelMesh).
You can have 25k batches per second at 1ghz cpu, that leaves ~400 batches per frame to maintain 60 fps. It's wise to use less but large batches rather than small but many batches (it's because for each leaf you need to give gpu it's world matrix, texture etc).


well this is what I did in the draw method.

public void Draw(SpriteBatch spriteBatch)
{
foreach (ModelMesh modelMesh in model.Meshes)
{
spriteBatch.Begin();
spriteBatch.DrawString(spriteFont, "" + model.Meshes.Count, new Vector2(200, 200), Color.Red);
spriteBatch.End();
foreach (BasicEffect Effect in modelMesh.Effects)
{
//Code.....................
}
}


and I got 5901.

and this what SketchUp show
Posted Image
Uploaded with ImageShack.us

Edited by FantasyVII, 17 October 2012 - 03:26 AM.


#9 FantasyVII   Members   -  Reputation: 299

Like
0Likes
Like

Posted 17 October 2012 - 03:44 AM

I just don't understand why is my CPU doing all the work and my GPU is doing nothing? and Why when I don't draw anything my GPU usage is 100% and my CPU usage 0%?

#10 Ripiz   Members   -  Reputation: 529

Like
1Likes
Like

Posted 17 October 2012 - 04:59 AM

When you draw something CPU validates whether you have set correct Vertex Buffer, Index Buffer, Shaders, and all other states.

When you don't draw anything you're basically spamming GPU with command "Show this on the monitor". It probably hits memory bandwidth limit because it attempts to copy your frame everytime.

#11 FantasyVII   Members   -  Reputation: 299

Like
0Likes
Like

Posted 17 October 2012 - 05:05 AM

When you draw something CPU validates whether you have set correct Vertex Buffer, Index Buffer, Shaders, and all other states.

When you don't draw anything you're basically spamming GPU with command "Show this on the monitor". It probably hits memory bandwidth limit because it attempts to copy your frame everytime.


so the only solution is to use less poly model and using multithreading to eliminate the CPU bottleneck?

#12 hupsilardee   Members   -  Reputation: 486

Like
3Likes
Like

Posted 17 October 2012 - 05:20 AM

Well the first thing to do is cap the number of frames you show per second, because nobody gets any extra benefit from 2500 fps as opposed to 100 fps, and if you give your (or your player's) graphics card some breathing space it will run cooler and probably live longer.

The next thing to do is reduce the polygon count. Ideally I wouldn't go for more than 1 million vertices per frame, even with the most efficient state changing systems. 150k poly for a tree (!) is completely ridiculous, and unless its a game about tree surgery, nobody's gonna notice the difference between 150k polys and 8k polys.

Finally. The sample XNA draw model code looked terrible when I last saw it a few years ago. Whenever you change the current pixel shader (by changing the effect), the gpu has to finish drawing all models with the current shader before it can change, which causes a delay. The better approach is to draw everything that uses the same shader in one go, then switch to the next shader and repeat, changing the constants/parameters as you go. If you can then reduce the number of changes of texture, it will run even faster.

Lastly, group as many things as possible into one draw call. Nvidia recommends about 300 draw calls per frame in total (this might be a bit out of date though).

#13 FantasyVII   Members   -  Reputation: 299

Like
0Likes
Like

Posted 17 October 2012 - 05:38 AM

Well the first thing to do is cap the number of frames you show per second, because nobody gets any extra benefit from 2500 fps as opposed to 100 fps, and if you give your (or your player's) graphics card some breathing space it will run cooler and probably live longer.


Yah I know, I'm just doing that to show how much the model decreases my FPS.

The next thing to do is reduce the polygon count. Ideally I wouldn't go for more than 1 million vertices per frame, even with the most efficient state changing systems. 150k poly for a tree (!) is completely ridiculous, and unless its a game about tree surgery, nobody's gonna notice the difference between 150k polys and 8k polys.


Ok I was wrong about one thing. The tree model has 80K polygons and 150K vertices Now your saying that I shouldn't go above one million vertices per frame. well I only have 150K vertices. so I must be doing something wrong?

Finally. The sample XNA draw model code looked terrible when I last saw it a few years ago. Whenever you change the current pixel shader (by changing the effect), the gpu has to finish drawing all models with the current shader before it can change, which causes a delay. The better approach is to draw everything that uses the same shader in one go, then switch to the next shader and repeat, changing the constants/parameters as you go. If you can then reduce the number of changes of texture, it will run even faster.

Lastly, group as many things as possible into one draw call. Nvidia recommends about 300 draw calls per frame in total (this might be a bit out of date though).


How can I do that? Can you direct me to some website that show a better / faster way to render the models?

I'm sorry I just got into 3D like a week ago Posted Image

Edited by FantasyVII, 17 October 2012 - 05:43 AM.


#14 jrh2365   Members   -  Reputation: 619

Like
1Likes
Like

Posted 17 October 2012 - 06:19 AM

and I got 5901.


If you mean that the number of meshes in your model is 5901, that would definitely be your problem. That would mean 5901 draw calls every time you draw the tree.

Lastly, group as many things as possible into one draw call. Nvidia recommends about 300 draw calls per frame in total (this might be a bit out of date though).



#15 FantasyVII   Members   -  Reputation: 299

Like
0Likes
Like

Posted 17 October 2012 - 06:23 AM


and I got 5901.


If you mean that the number of meshes in your model is 5901, that would definitely be your problem. That would mean 5901 draw calls every time you draw the tree.

Lastly, group as many things as possible into one draw call. Nvidia recommends about 300 draw calls per frame in total (this might be a bit out of date though).


Ok but how do i do that? how do I set only 300 caller per frame?

#16 yufei   Members   -  Reputation: 127

Like
0Likes
Like

Posted 17 October 2012 - 07:26 AM

Have you count the number of effects? Each ModelMesh in XNA is futher divided into ModelMeshPart, so it may take more then 5901 batches.

#17 jrh2365   Members   -  Reputation: 619

Like
1Likes
Like

Posted 17 October 2012 - 10:15 AM

Ok but how do i do that? how do I set only 300 caller per frame?


I'm not familiar with SketchUp, but it should have a way to combine the separate pieces.

#18 phil_t   Crossbones+   -  Reputation: 3258

Like
1Likes
Like

Posted 17 October 2012 - 12:35 PM

Ok I was wrong about one thing. The tree model has 80K polygons and 150K vertices Now your saying that I shouldn't go above one million vertices per frame. well I only have 150K vertices. so I must be doing something wrong?


Well, 80k polygons is 240k vertices that need processing. Many of these are vertices that are shared between triangles of course - if those triangles are processed close to each other (in time), then the GPU can re-use the results. So in reality, you'll be pushing somewhere between 150K and 240K. Hopefully closer to the former, if the code that generated the mesh ordered the triangles efficiently.

80k polygons is a huge amount for a tree. If you plan to be rendering more than a handful, you'll definitely want to make this a lot lower.

But anyway, like I think you've discovered, it's most likely the number of batches you're rendering that's the problem. 5901 batches! That's really only necessary if you're using 5901 different materials. Presumably your trees uses a maximum of two (one for the leaves, one for the trunk)... hopefully the program you used to generate it can combine the meshes to reflect that.

#19 FantasyVII   Members   -  Reputation: 299

Like
0Likes
Like

Posted 17 October 2012 - 02:14 PM


Ok I was wrong about one thing. The tree model has 80K polygons and 150K vertices Now your saying that I shouldn't go above one million vertices per frame. well I only have 150K vertices. so I must be doing something wrong?

Well, 80k polygons is 240k vertices that need processing. Many of these are vertices that are shared between triangles of course - if those triangles are processed close to each other (in time), then the GPU can re-use the results. So in reality, you'll be pushing somewhere between 150K and 240K. Hopefully closer to the former, if the code that generated the mesh ordered the triangles efficiently.
80k polygons is a huge amount for a tree. If you plan to be rendering more than a handful, you'll definitely want to make this a lot lower.
But anyway, like I think you've discovered, it's most likely the number of batches you're rendering that's the problem. 5901 batches! That's really only necessary if you're using 5901 different materials. Presumably your trees uses a maximum of two (one for the leaves, one for the trunk)... hopefully the program you used to generate it can combine the meshes to reflect that.


hmmm...

Ok then thank you guys so much. that really helped.

I'm now looking at Hardware instancing. because I'm trying to draw around 10,000 cubes (24 vertices each cube) at the same time. and Hardware instancing really really helps.

before using Hardware instancing my FPS was around 15 FPS and I was able to render 10,000 cubes. After using Hardware instancing I can now render 100, 000 at 45 FPS. The only problem is that Hardware instancing is a bit complicated for me.

anyways thank you all Posted Image

Edited by FantasyVII, 17 October 2012 - 02:15 PM.


#20 hupsilardee   Members   -  Reputation: 486

Like
1Likes
Like

Posted 18 October 2012 - 03:22 AM

Glad to see my advice was of use.

Now if you're making a game with a Minecraft style world, instead of drawing every single block as a cube you can split the world into chunks - Minecraft uses 16x128x16 blocks per chunk. Then draw the chunks near the player using the instancing method - this allows you to create and destroy blocks near the player cheaply - and combine all blocks in further away chunks into smaller meshes.

These articles are helpful reading

http://0fps.wordpress.com/2012/06/30/meshing-in-a-minecraft-game/
http://0fps.wordpress.com/2012/07/07/meshing-minecraft-part-2/




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS