Rendering sprites off screen

Started by
8 comments, last by lar0922 15 years, 11 months ago
Hi guys! Is it possible to draw ID3DXSprite sprites to something other than a D3D device, for example to a texture or something like that? Right now I'm writing an application which uses quite a lot of sprites, and rendering them all individually each frame eats up quite a lot of CPU power. What I would like to do is only render them all individually when a change in position/scale/etc has been made, and render one big texture (with all the smaller sprites on it) the rest of the time, so that no unnecessary calculations/transformations has to be made when not needed. Any advice would be much appreciated! Edit: Forgot to mention, this question is C++ related.
Advertisement
I don't believe that ID3DXSprite touches the render-target of the device at all, so I *think* it will render to whatever you have set as the current render-target. You could check for sure by running your program through PIX, and seeing whether IDirect3DDevice9::SetRenderTarget gets called by ID3DXSprite::Begin or ID3DXSprite::End. If it does mess with the render-target, you could always tell ID3DXSprite that you want to manage render-states yourself by specifying D3DXSPRITE_DONOTMODIFY_RENDERSTATE when you call ID3DXSprite::Begin. Of course if you do that you'll need to set all of the rener-states yourself, for things like alpha-blending, texture stage states, and texture filtering.
How many sprites are you drawing per frame?

Are you avoiding drawing sprites that are off the edges of the screen?

How many calls to ID3DXSprite::Begin() per frame? You should only need one.
Thanks a lot for your reply, MJP! I will look into that.

Adam_42: Thanks for the reply! As of right now I'm drawing 114 sprites per frame.
None of the sprites are off the edges of the screen.
Also, I'm only calling Begin() and End() once each frame, with multiple Draw() calls in between.
I'm having very little CPU usage when running the application on the computer I'm on right now, but while testing it on other systems with lower hardware specs I found that CPU usage was around 30% which is way too high as this is an application that is meant to be running in the background so keeping CPU usage down is a priority. I think it would help performance a lot to draw all the sprites as one, especially as there are no animations and the sprites are stationary in position most (almost all) of the time.
Yep, it's super easy.

I'm working on a project now that uses ID3DXSprite to render to a ID3DXRenderToSurface. You dont need to SetRenderTarget, you just go
// You cannot call BeginScene here if you are already in// a IDirect3DDevice9::BeginScene() / EndScene() blockID3DXRenderToSurface::BeginScene()ID3DXSprite::Begin()// draw your spritesID3DXSprite::End()ID3DXRenderToSurface::EndScene()
Just to clarify...all ID3DXRenderToSurface does is call IDirect3DDevice9::SetRenderTarget as well as keep the render-target texture and surface contained in one interface.
Thanks for the replies!

I tried your method, Cantos, but I'm having problems trying to figure out how to draw the surface to the screen.
I worked this method out from the offscreen rendering sample here.

render_target.h
#pragma once#include <d3d9.h>#include <d3dx9.h>#include "slr_types.h"namespace slr{	class render_target	{		friend class Sunshine;		friend class render_target_pool;	public:		render_target();		~render_target();	protected:		render_target(IDirect3DDevice9* D3DDevice, sint Width, sint Height);		inline IDirect3DTexture9* get_texture() const { return dynamic_texture; }		inline ID3DXRenderToSurface* get_render_surface() const { return render_surface; }		inline IDirect3DSurface9* get_texture_surface() const { return texture_surface; }	private:		IDirect3DTexture9* dynamic_texture;		IDirect3DSurface9* texture_surface;		ID3DXRenderToSurface* render_surface;	};}


render_target.cpp
#include "render_target.h"slr::render_target::render_target(IDirect3DDevice9* device,                                   sint width, sint height)  : dynamic_texture(NULL),   texture_surface(NULL),   render_surface(NULL){	HRESULT hr = D3DXCreateTexture( device,		                        width,					height,					1,					D3DUSAGE_RENDERTARGET,					D3DFMT_A8R8G8B8,					D3DPOOL_DEFAULT,					&dynamic_texture );	if (FAILED(hr))	{		// error	}	D3DSURFACE_DESC desc;	hr = dynamic_texture->GetSurfaceLevel( 0, &texture_surface );	if (FAILED(hr)) // error	hr = texture_surface->GetDesc( &desc );	if (FAILED(hr)) // error	hr = D3DXCreateRenderToSurface( device, 		                        desc.Width, 		                        desc.Height, 		                        desc.Format, 		                        FALSE, 		                        D3DFMT_D16, 		                        &render_surface );	if (FAILED(hr))	{		// error	}	// clear the surface	render_surface->BeginScene(texture_surface,NULL);	device->Clear(0,NULL,D3DCLEAR_TARGET,0x0,1.0f,0);	render_surface->EndScene(0);}


From there, you call get_texture() and use it in a normal call to ID3DXSprite::Draw(), or get_texture_surface() and use the surface in a IDirect3DDevice9::StretchRect onto the backbuffer.

Quote:Just to clarify...all ID3DXRenderToSurface does is call IDirect3DDevice9::SetRenderTarget as well as keep the render-target texture and surface contained in one interface.
I did not know that. You seem to be indicating that you can pull a texture from the ID3DXRenderToSurface interface, is some of my above code redundant?
Quote:Original post by Cantos
I did not know that. You seem to be indicating that you can pull a texture from the ID3DXRenderToSurface interface, is some of my above code redundant?


No you can't pull a texture from it, I must have been thinking of something else. But it does call SetRenderTarget for you, either with the surface you've provided or with a surface created internally (if the surface you provide isn't a valid render-target). So it look like what you're doing is perfectly fine.
Thanks a lot, Cantos! Works like a charm. :)
I also would like to thank MJP for his input. I really appreciate it.

This topic is closed to new replies.

Advertisement