Dark Bit Factory & Gravity
PROGRAMMING => General coding questions => Topic started by: Phoenix on September 03, 2007
-
Hey all DBF members!
I know there has to be some OpenGL users out there, Rbraz at least! I haven't visited you for a long time, which is a shame. Especially because of the atmosphere of this community, which is awesome :cheers:
Anyways, onto the question. I have drawn a nice little image in paint to illustrate the problem.
(http://randomuploads.sitesled.com/texture.png)
I have a quad, and also a texture. I can easily draw a texture onto the quad, making it cover the whole rectangle, but I want to draw multiple instances of my texture onto the quad, as seen at the rightmost part of the image. Can't really figure out how to do it though :-\ At the moment, I have one quad for each texture I want to draw, but that's not really performance efficient when having 500 textures on screen. (500*4=2000 vertices. If I had one rectangle it would be 1*4=4, quite a difference!)
Any help is greatly appreciated!
Martin
-
No doubt that the Opengl experts here will tell you a better solution than this, but it sounds to me like you need two textures, one to have the image you want to copy and one target texture.
you could try using glCopyTexImage2D to draw multiple instances of the source texture to the target texture?
-
Yep, that's pretty much it except you can only draw to the framebuffer so you:
set the viewport to match the size of your target texture
draw your texture to it
copy from the framebuffer with glcopyteximage2d to your target texture
reset viewport to original size.
I think that's how it's done anyway.
-
Hi Phoenix, you can't get the image on the right with a single quad and just that texturemap. Either you need to use more quads, one for each squished circle, or you need to use a texture with that image on it. Don't worry too much about having lots of geometry, that can be fixed up later if it's too slow.
Jim
-
Phoenix,
Jims right, dont worry about speed yet. 2000 texture mapped quads is nothing. In fact, depending on cards, you may find its faster than making a new texture and drawing one quad. Even worse, if you make one new texture that is not square (the obvious thing to do from your diagram) and you are not very careful with opengl state, your program will drop to 1-2 frames a second.
Personally until I know its too slow, I'd simply draw all the quads.
Chris
-
I think this would be a good test - try it both ways and compare framerates. It would probably only be about your card's performance but now I'm curious as to which is actually faster.
But I'd take the easy way out and make lots of quads if you really want my opinion.
-
I had a test program with 50 spinning balls, 50 quads. It ran at ~100 fps on my computer. But at my big computer, it ran at 1000 fps. So performance shouldn't be much of a problem if you have a decent computer. My laptop isn't decent, and it had 100 fps.
But let's say we have a 800x600 screen, filled with tiles. The tiles are 32x32, making the screen 25x19 tiles. 25*19=475 quads, which is way too slow on my laptop (~7 fps). Jim, you say that speed can be fixed, could you explain how? If there is no way to optimize it, is there another method that can handle many images on screen at the same time? Blitz could handle lots of images on screen at the same time, and it's generally considered to be slow, so surely there must be an effective approach.
-
drawing tons of quads should not be a problem.... geometry in OpenGL is very very fast (and even if explicit calls show some slowdown, there are then other ways to optimize)..
one thing to avoid, especially in this case (as far as I understood) is that if you use the same texture, then avoid making calls to glBindTexture() before drawing each quad. Or if you can have a loop that looks like this:
glBindTexture()
glBegin(GL_QUADS)
for (c=0; c < NUM_QUADS; c++)
{
glTexCoordXXX()
glVertexXXX()
}
glEnd()
it should be pretty fast...
You cannot have a quad filled in with several textures (unless you use multi-texture extensions, which are not great at all and if this is the case, the you should switch to shaders)
-
After stripping the code down a lot, there aren't many lines left. This is called 500 times:
Gl.glBegin( Gl.GL_QUADS );
Gl.glVertex3f( X, Y, 0.0f );
Gl.glVertex3f( (Width + X), Y, 0.0f );
Gl.glVertex3f( (Width + X), (Height + Y), 0.0f );
Gl.glVertex3f( X, (Height + Y), 0.0f );
Gl.glEnd();Without any textures, colors or anything, and I get 15-20 fps. Is that normal? Should I stop using glBegin/glEnd?
-
Tell us processor and graphics card, but I'd say thats definitely not normal. 500 quads at less than 20fps? I'd call that a WTF the mid 90s called and asked for their performance back?
It almost sounds like you are dropping back to software. That might be happening if you are asking for a pixel format that is unsupported. What pixel format are you using?
Thats only a wild guess but really this is very unusual.
Chris
-
1.5 GHz Intel processor, 64mb graphics card. Runs at more than 1000 fps with 2.54 GHz Intel/256mb video memory.
-
No way its that slow so either the pixel format is screwed or somehow its finding a SW implementation fo OGL not hardware. Please post your windowing code...
-
I'm using a SimpleOpenGLControl (found in the Tao framework), with C#, and it's attached to a Windows Form. Pixel format seems to be normal:
Gdi.PIXELFORMATDESCRIPTOR pfd = new Gdi.PIXELFORMATDESCRIPTOR();// The pixel format descriptor
pfd.nSize = (short) Marshal.SizeOf(pfd); // Size of the pixel format descriptor
pfd.nVersion = 1; // Version number (always 1)
pfd.dwFlags = Gdi.PFD_DRAW_TO_WINDOW | // Format must support windowed mode
Gdi.PFD_SUPPORT_OPENGL | // Format must support OpenGL
Gdi.PFD_DOUBLEBUFFER; // Must support double buffering
pfd.iPixelType = (byte) Gdi.PFD_TYPE_RGBA; // Request an RGBA format
pfd.cColorBits = (byte) colorBits; // Select our color depth
pfd.cRedBits = 0; // Individual color bits ignored
pfd.cRedShift = 0;
pfd.cGreenBits = 0;
pfd.cGreenShift = 0;
pfd.cBlueBits = 0;
pfd.cBlueShift = 0;
pfd.cAlphaBits = 0; // No alpha buffer
pfd.cAlphaShift = 0; // Alpha shift bit ignored
pfd.cAccumBits = accumBits; // Accumulation buffer
pfd.cAccumRedBits = 0; // Individual accumulation bits ignored
pfd.cAccumGreenBits = 0;
pfd.cAccumBlueBits = 0;
pfd.cAccumAlphaBits = 0;
pfd.cDepthBits = depthBits; // Z-buffer (depth buffer)
pfd.cStencilBits = stencilBits; // No stencil buffer
pfd.cAuxBuffers = 0; // No auxiliary buffer
pfd.iLayerType = (byte) Gdi.PFD_MAIN_PLANE; // Main drawing layer
pfd.bReserved = 0; // Reserved
pfd.dwLayerMask = 0; // Layer masks ignored
pfd.dwVisibleMask = 0;
pfd.dwDamageMask = 0;
Complete window code, if needed.
windowForm = new Form();
windowForm.ClientSize = new Size( ScreenWidth, ScreenHeight );
windowWidth = windowForm.Width;
windowHeight = windowForm.Height;
windowForm.Icon = null;
windowForm.Text = windowTitle;
windowForm.FormClosing += new FormClosingEventHandler( windowForm_FormClosing );
windowForm.Resize += new EventHandler( windowForm_Resize );
// Window mode specific settings
// Changes borders/control boxes/etc
switch( mode )
{
case WindowMode.Windowed:
windowForm.FormBorderStyle = FormBorderStyle.FixedSingle;
windowForm.MaximizeBox = false;
windowForm.MinimizeBox = false;
break;
case WindowMode.Fullscreen:
Resolution.CResolution changeRes = new Resolution.CResolution( screenWidth, screenHeight );
windowForm.FormBorderStyle = FormBorderStyle.None;
windowForm.WindowState = FormWindowState.Maximized;
windowForm.TopMost = true;
break;
case WindowMode.WindowScalable:
windowForm.FormBorderStyle = FormBorderStyle.Sizable;
break;
case WindowMode.BorderlessWindow:
windowForm.FormBorderStyle = FormBorderStyle.None;
break;
}
// Initialize the OpenGL graphics device
glDevice = new SimpleOpenGlControl();
glDevice.Location = new Point( 0, 0 );
glDevice.Size = new Size( screenWidth, screenHeight );
glDevice.InitializeContexts();
windowForm.Controls.Add( glDevice );
// Set up OpenGL
Gl.glMatrixMode( Gl.GL_PROJECTION );
Gl.glOrtho( 0, screenWidth, screenHeight, 0, -1, 1 );
Gl.glMatrixMode( Gl.GL_MODELVIEW );
Gl.glClearColor( 1, 1, 1, 1 );
// Enable transparency
Gl.glBlendFunc( Gl.GL_SRC_ALPHA, Gl.GL_ONE_MINUS_SRC_ALPHA );
Gl.glEnable( Gl.GL_BLEND );
// We're done setting up, so the program is running
running = true;
// Show the created window
windowForm.Show();
-
OK so check that accumBits is 0, depth bits is 32, colorBits is 32 and stencilBits is 0. I dont know what SimpleOpenGlControl() is ...
-
No luck, I changed them but the FPS still sits at 15-20.
-
do not remove glBegin()/glEnd() calls. They control the geometry definition => removing them will ruin the GL geometry pipeline
-
1.5 GHz Intel processor, 64mb graphics card. Runs at more than 1000 fps with 2.54 GHz Intel/256mb video memory.
Seems to me that you have a problem with your gfx driver, have you tried to update it ?
-
Perhaps it's PB itself that's slowing it down?
I was going to suggest using glDrawBuffers and friends, but only if your poly count was in the order of 10,000 or so. 500 is nothing.
Jim