Cull Mode does not seem to have effect on FPS count

Started by
8 comments, last by BeanDog 17 years, 4 months ago
I am trying to figure out why "device.RenderState.CullMode" does not seem to have effect on the FPS counter. I do a very simple test - put a lot of objects (teapots) so that the FPS drops sufficiently. Then I do two things 1. device.RenderState.CullMode = Cull.CounterClockwise; This does not affect the FPS OR... 2. I turn the camera so that all objects are outside of the view frustrum. This does not affect the FPS either. So I'm thinking - what the heck - according to the description of Culling - When it is on it stops the processing of textures that are invisible (back of textures or outside of the view frustrum). But with or without Culling the camera feels really sluggish. Any ideas what else is I missing ... [Edited by - Moni on December 15, 2006 8:42:58 AM]
Advertisement
Assuming that you're only sending one teapot per rendering call, I think you'll find that your framerate is limited by the number of rendering calls you make rather than the number of total triangles on the screen. Increase the number of triangles in each teapot to, say, 10K, and you'd see more of a difference with the cull mode.

As far as the frustum is concerned, your graphics card is still doing all the transformation calculations up until the actual rendering--and I doubt that you're fillrate limited at this point (no fancy pixel shaders, no hundreds of levels of overdraw). If you want real frustum culling, it should be done by you in software at the mesh level (Is the sphere bounding this teapot within the view frustum planes? No? Then don't send it to the card at all!)
Two things I can think of.

1. CullMode is usually set to begin with I believe, so try turning it to None then setting it and see if you see a difference.

2. Try setting your presentation parameters interval property to immediate when you are setting your device.
All makes total sense.

I am actually creating separate teapots - not one drawn in many places.

I found I can max out the memory of the card by pre-loading them in a list. I am guessing that this is the case because I get an out of memory message but the system memory did not make an blip.

BeanDog
When you say I am limited by the number of rendering calls - I understand this as follows:
With regards to FPS there is no much difference if I render a single teapot 1000 times vs 1000 teapots once each - the pure processing-related demand on the card is the same. In this case the only difference is that the memory of the card will persist only one teapot the first time and 1000 teapots the second - right?

Btw - you are right - no fancy pixel shaders in this case etc. just the defaults.

I do not have a bounding sphere for the teapot. Can you please set me in the right direction with regard to "Frustrum Culling in the software at the mesh level". Some big picture explanation will be enough so that I can pick the key-words and probably a reading advice to continue on my own.

ImperfectFreak
Thanks dude - I will follow your advice - About the setting of the presentation paramenters to immediate - Can you please help me with the actual name of parameter or a syntax of a line or two so that I can search the net for more info using these as key-words.

Thanks so much ...
Quote:Original post by Moni
When you say I am limited by the number of rendering calls - I understand this as follows:
With regards to FPS there is no much difference if I render a single teapot 1000 times vs 1000 teapots once each - the pure processing-related demand on the card is the same. In this case the only difference is that the memory of the card will persist only one teapot the first time and 1000 teapots the second - right?

This is a misconception of modern graphics cards that's gotten me many times. My early attempts at tiled 2D engines using 3D API calls were making one DrawPrimitive call per tile--thus about 500 DrawPrimitive calls of 2 triangles each per frame. By reorganizing my code to call DrawPrimitive once per tile type (about 25 DrawPrimitive Calls of 40 triangles each), my framerate went through the roof. Just for fun, I put all 1000 triangles into one DrawPrimitive call, and that 1000-triangle call finished in the same amount of time as one of my 2-triangle calls.

At least in the generation of cards I was working with at the time (GeForce3 and competitors), the overhead of each DrawPrimitive call was large enough that 2 triangles had basically no time difference from 1000 triangles--and removing a 2-triangle call improved my speed as much as removing a 1000-triangle call. On my particular card, I had to get up around 5000 single-textured triangles before there was any loss of speed compared to 1 single-textured triangle.

Quote:Original post by Moni
I do not have a bounding sphere for the teapot. Can you please set me in the right direction with regard to "Frustrum Culling in the software at the mesh level". Some big picture explanation will be enough so that I can pick the key-words and probably a reading advice to continue on my own.

First, you'll find better results on Google if you spell the word correctly: "Frustum". To get started, here's a good, easy-read article on Flipcode, GameDev's biggest defunct competitor. The basic idea is to find the planes defining the edges of the visible area in your 3D scene. Then find a sphere that completely contains each of your objects (for simplicity in later math). Compare each sphere to the planes around the visible area, and if they're outside the viewing area, don't render them at all.

There are, of course, many ways to go about doing this, and spheres aren't the only way to do it, but they are the easiest way, IMHO.
I think you idea of culling is incorrect.

What you are seing is triangle cullling , a quick way to see if each triangle needs to be drawn or not. Normally ist Frontface , back face or no culling of the triangle. This can only be done once the verticies are know , that means its has to calculate all the points for drawing.

What I think you need is a layer above this where you actually decide what needs to be drawn , is this object in the view fustrum , yes - then draw it , else dont send it to the grafix card.

The grafix card will try to draw what you tell it to draw.

Wow - thanks guys!!!

I can "see" much better now.

Huh ... I thought that if I called teapot.DrawSubset(0) and the teapot is outside of the frustum the graphic card is not going to bother with it.

Now I uderstand that I should call DrawSubset only if it makes sense to do it - namely the object is visible.

I will study the tips for DrawPrimitives

Thanks for the links - reading the stuff right now :)

I am guessing though that this tip will not affect the call to DrawSubset which renders the teapot - right? Cause with the teapot I do not handle the triangles explicitly but as part of the mesh.

Therefore whatever the card is doing it is already optimized to a max. for DrawSubset on a Mesh ...

So ... If I do have teapots "to the horizon" and they are visible this will still sink me down ... because DrawSubset will have to be called for each of them separately one way or the other ... I am guessing because as opposed to DrawPrimitives there is no way to lump them in a single type call - or I just don't know how :)

Like let's say there are only two teapots - at two different locations.
I have to call DrawSubset for the first. Translate to the second location and DrawSubset for the second again - right ... no way to lump them together in a single call ... I hope I make sense.

Btw ... I am really sorry for offering silly things like "teapots to the horizon" - naturally this is not meaningful but it helps me understand the code by using a simple Mesh to teach me how to render properly cause in a game I will sure not have a single object running around .... and if my fundamentals are wrong it will be tough to sort it all out if the complexity is high ... :)
Quote:Original post by Moni
I am guessing though that this tip will not affect the call to DrawSubset which renders the teapot - right? Cause with the teapot I do not handle the triangles explicitly but as part of the mesh.

Therefore whatever the card is doing it is already optimized to a max. for DrawSubset on a Mesh ...

DrawSubset calls DrawPrimitives itself, but also does a lot of other work for you as well. Calling DrawSubset on a 50-triangle mesh and a 1000-triangle mesh is likely to take about the same time, regardless of culling or anything else, because the overhead of the call is so high compared to the time it takes to process and render such a small number of triangles. If you'd like to see a speed difference by turning culling on and off, you'll have to greatly increase the number of triangles per call, so that the actual rendering itself is the bottleneck of the process.

This is why it's very important to batch rendering calls whenever possible--the fewer calls to DrawSubset or DrawPrimitive, the better. D3DXSprite will do batch rendering of 2D sprites for you automatically (store up the whole frame's worth of sprites that have the same texture, then draw them in one call).
Got it now.

It sounds to me so "obvious" now and it was "darkness" 24h ago ... huh.

Sometimes there is that "wall" you hit when you cover new material and without a little push you are stuck.

Thanks guys.
I hear you. Some other kind souls on GameDev got me through many a similar wall years ago.

This topic is closed to new replies.

Advertisement