Sign in to follow this  

DirectX Point Sprites Not Visible

This topic is 2850 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello, I'm trying to add point sprites to my DirectX9 code, for faster particle effects. My code compiles, but the point sprites themselves do not appear. I know that something is happening, because the frame rate drops when I try rendering a large number of them, but they are not visible on the screen. I also know that all the data in my game (point sprite positions, size, color, etc.) are all correct, and the texture is valid, because I can draw all my particles one at a time, using the ID3DXSprite interface, my data, and my texture, and everything appears where it's supposed to be. It's when using the Point Sprite interface that things don't show up. Finally, I've checked the capabilities of my hardware and everything should be workable on my graphics card. My game (and engine) are 2D, so I've had a rough time finding code to compare with on the internet (since most point sprite code is made for 3D). If someone could tell me what I'm doing wrong, I'd greatly appreciate it. Here are the relevant sections of code. I've stripped out a bunch of stuff that I think is irrelevant and has nothing to do with point sprite rendering. The point sprites are particles in a set of rocket smoke trails. Here's the vertex definition:
#define D3DFVF_POINTSPRITEVERTEX (D3DFVF_XYZ | D3DFVF_PSIZE | D3DFVF_DIFFUSE)

struct POINTSPRITEVERTEX
{
	float m_x, m_y, m_z;
	float m_size;
	DWORD m_color;
};

Here's a listing of the variables used by my GraphicsSystem class:
		LPDIRECT3D9 pD3D9;
		LPDIRECT3DDEVICE9 pD3DDevice9;
		LPDIRECT3DSURFACE9 pD3DSurface9;
		LPD3DXSPRITE pD3DXSprite;
		
		LPDIRECT3DVERTEXBUFFER9 pPSVB;	// Buffer to hold point sprite vertices
		int m_Num_Point_Sprites_Buffer;
		int m_Max_Num_Point_Sprites_Buffer;
		POINTSPRITEVERTEX* m_Point_Sprite_Vertex_Buffer;

		D3DLOCKED_RECT* pRect;

		int m_Pitch;
		DWORD* pBack_Buffer;
		RECT Font_Rect;

		int m_Screen_Height;
		int m_Screen_Width;

		bool m_Fullscreen;
		bool m_Maintain_Double_Precision;

		HWND m_HWND;

		bool m_Rendering;
		bool m_Sprite_Drawing;
		bool m_Point_Sprite_Drawing;


Here is the code for setting up DirectX and my vertex buffers.
// Initialization
CGraphicsSystem::Init()
{
	pD3D9 = Direct3DCreate9(D3D_SDK_VERSION);
	
	if (pD3D9 == NULL)
	{
		throw Exception("Could not create Direct3D9 Object.", __FILE__, __LINE__);
	}

	// get the display mode
	D3DDISPLAYMODE d3ddm;
	pD3D9->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm);

	// set the presentation parameters
	D3DPRESENT_PARAMETERS d3dpp;
	ZeroMemory(&d3dpp, sizeof(d3dpp));
	d3dpp.BackBufferWidth = m_Screen_Width;
	d3dpp.BackBufferHeight = m_Screen_Height;
	d3dpp.BackBufferCount = 1;
	d3dpp.BackBufferFormat = d3ddm.Format;
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	d3dpp.Windowed = !m_Fullscreen;
	d3dpp.EnableAutoDepthStencil = true;
	d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
	d3dpp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
	d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
	d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;	// for frame rate detection

	DWORD behavior_flags;

	if (m_Maintain_Double_Precision)
	{
		behavior_flags = D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE;
	}
	else
	{
		behavior_flags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
	}

	if (FAILED(pD3D9->CreateDevice(D3DADAPTER_DEFAULT, 
                                 D3DDEVTYPE_HAL, m_HWND,
                                 behavior_flags,
                                 &d3dpp, &pD3DDevice9)))
	{
		throw Exception("Could not create a Direct3D9 device.", __FILE__, __LINE__);
	}

	// For checking capabilities
	D3DCAPS9 caps;
	pD3DDevice9->GetDeviceCaps(&caps);

	if(FAILED(D3DXCreateSprite(pD3DDevice9, &pD3DXSprite)))
	{
		throw Exception("Could not create a Direct3D9 Sprite Object.", __FILE__, __LINE__);
	}

	if(pD3DXSprite == NULL)
	{
		throw Exception("A valid Direct3D9 Sprite Object was not created.", __FILE__, __LINE__);
	}

	// Get the back buffer for pixel plotting
	if(FAILED(pD3DDevice9->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pD3DSurface9)))
	{
		throw Exception("Could not get the back buffer of the Direct3D9 device.", __FILE__,
						__LINE__);
	}

	
	m_Max_Num_Point_Sprites_Buffer = DEFAULT_MAX_NUM_POINT_SPRITES;  // 4096 to start

	if(FAILED(pD3DDevice9->CreateVertexBuffer(m_Max_Num_Point_Sprites_Buffer * sizeof(POINTSPRITEVERTEX), 0,
												D3DFVF_POINTSPRITEVERTEX, D3DPOOL_DEFAULT, &pPSVB, NULL)))
	{
		throw Exception("Could not create a Point Sprite Vertex Buffer.", __FILE__, __LINE__);
	}

	m_Point_Sprite_Vertex_Buffer = new POINTSPRITEVERTEX[m_Max_Num_Point_Sprites_Buffer];

	for (int i = 0; i < m_Max_Num_Point_Sprites_Buffer; i += 1)
	{
		m_Point_Sprite_Vertex_Buffer[i].m_z = 0;
	}

	m_Num_Point_Sprites_Buffer = 0;

		pRect = new D3DLOCKED_RECT;
}

Here are the functions in the render loop:
void CInGameGameState::Render_Active()
{
	Graphics_System->Clear_Screen(0, 0, 0);

	Graphics_System->Begin_Rendering();

	Graphics_System->Begin_Point_Sprite_Drawing();

	for (int i = 0; i < m_Num_Visible_Rocket_Smoke_Trails; i += 1)
	{
		m_Visible_Rocket_Smoke_Trails[i]->Render();
	}

	Graphics_System->Prepare_Point_Sprites();
	Graphics_System->Draw_All_Point_Sprites();

	Graphics_System->End_Point_Sprite_Drawing();

	Graphics_System->End_Rendering();

	Graphics_System->Render_Screen();
}

Here are the functions called in the above code:

void CSmokeTrail::Render()
{
	// Render entries has all the data for the point sprites - for the purposes of this forum post, assume the data is all valid
	// and makes sense

	for (int i = 0; i < m_Num_Render_Entries; i += 1)
	{
		D3DXVECTOR2 pos = m_Render_Entries[i].m_vPosition;
		float alpha = m_Render_Entries[i].m_Alpha;

		for (int j = 0; j < m_Render_Entries[i].m_Steps; j += 1)
		{
			Graphics_System->Add_Point_Sprite(pos.x, pos.y, m_Render_Size * 1000.f, 255, 255, 255, 255 * alpha);

			pos += m_Render_Entries[i].m_dPosition;
			alpha += m_Render_Entries[i].m_dAlpha;
		}
	}
}

///////////////////////////////////////////////////////////

void CGraphicsSystem::Clear_Screen(BYTE i_red, BYTE i_green, BYTE i_blue)
{
	if(FAILED(pD3DDevice9->Clear(0, NULL, D3DCLEAR_TARGET,
		                 D3DCOLOR_XRGB(i_red, i_green, i_blue), 1.0f, 0)))
	{
		char buffer[256];
		sprintf(buffer, "Could not clear the screen of the Direct3D9 device.  Color was R = %d, G = %d, B = %d.",
				i_red, i_green, i_blue);
		throw Exception(buffer, __FILE__, __LINE__);
	}
}

///////////////////////////////////////////////////////////

void CGraphicsSystem::Begin_Rendering()
{
	if(FAILED(pD3DDevice9->BeginScene()))
	{
		throw Exception("Could not begin scene with the Direct3D9 device.", __FILE__,
						__LINE__);
	}

	m_Rendering = true;
}

///////////////////////////////////////////////////////////

void CGraphicsSystem::End_Rendering()
{
	if(FAILED(pD3DDevice9->EndScene()))
	{
		throw Exception("Could not end scene with the Direct3D9 device.", __FILE__,
						__LINE__);
	}

	m_Rendering = false;
}

///////////////////////////////////////////////////////////

void CGraphicsSystem::Render_Screen()
{
	if (m_Point_Sprite_Drawing == true)
	{
		End_Point_Sprite_Drawing();
	}

	if(FAILED(pD3DDevice9->Present(NULL, NULL, NULL, NULL)))
	{
		m_Failed_To_Present += 1;

		if (m_Failed_To_Present > PRESENT_FAILURE_TOLERANCE)
		{
			throw Exception("Could not present the scene with the Direct3D9 device.",
							__FILE__, __LINE__);
		}
	}
	else
	{
		m_Failed_To_Present = 0;
	}
}

///////////////////////////////////////////////////////////

void CGraphicsSystem::Begin_Point_Sprite_Drawing()
{
	if (m_Rendering == false)
	{
		Begin_Rendering();
	}

	if (Texture_Manager->m_Sparticle_Texture.m_pTexture == NULL)
	{
		throw Exception("Attempting to start point sprite drawing without a valid sparticle texture in the texture manager.", __FILE__, __LINE__);
	}

	// Texture_Manager->m_Sparticle_Texture.m_pTexture is a valid and loaded LPDIRECT3DTEXTURE9
	pD3DDevice9->SetTexture(0, Texture_Manager->m_Sparticle_Texture.m_pTexture);


	pD3DDevice9->SetRenderState(D3DRS_POINTSPRITEENABLE, true);
	pD3DDevice9->SetRenderState(D3DRS_POINTSCALEENABLE, false);


	pD3DDevice9->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
	pD3DDevice9->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
	pD3DDevice9->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);


	m_Point_Sprite_Drawing = true;
}

///////////////////////////////////////////////////////////

void CGraphicsSystem::End_Point_Sprite_Drawing()
{
	pD3DDevice9->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
	pD3DDevice9->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

	pD3DDevice9->SetRenderState(D3DRS_ALPHABLENDENABLE, false);

	pD3DDevice9->SetRenderState(D3DRS_POINTSPRITEENABLE, false);

	m_Point_Sprite_Drawing = false;
}

///////////////////////////////////////////////////////////

void CGraphicsSystem::Add_Point_Sprite(float i_x1, float i_y1, float i_size, 
									   BYTE i_red, BYTE i_green, BYTE i_blue, BYTE i_alpha)
{
	if (m_Num_Point_Sprites_Buffer >= m_Max_Num_Point_Sprites_Buffer)
	{
		CTxtFile text_file("point_sprite_report.txt", WRITE);
		char buffer[128];
		sprintf(buffer, "Resizing point sprite buffer from %d maximum points to %d maximum points", m_Max_Num_Point_Sprites_Buffer, 2 * m_Max_Num_Point_Sprites_Buffer);
		text_file.Write_Next_String(buffer);
		text_file.Close_File();

		POINTSPRITEVERTEX* new_buffer = new POINTSPRITEVERTEX[2 * m_Max_Num_Point_Sprites_Buffer];

		for (int i = 0; i < m_Max_Num_Point_Sprites_Buffer; i += 1)
		{
			new_buffer[i] = m_Point_Sprite_Vertex_Buffer[i];
		}

		for (int i = m_Max_Num_Point_Sprites_Buffer; i < 2 * m_Max_Num_Point_Sprites_Buffer; i += 1)
		{
			new_buffer[i].m_z = 0;
		}

		if (m_Point_Sprite_Vertex_Buffer != NULL)
		{
			delete [] m_Point_Sprite_Vertex_Buffer;
			m_Point_Sprite_Vertex_Buffer = NULL;
		}

		if (pPSVB)
		{
			pPSVB->Release();
			pPSVB = NULL;
		}

		m_Point_Sprite_Vertex_Buffer = new_buffer;

		m_Max_Num_Point_Sprites_Buffer *= 2;

		if(FAILED(pD3DDevice9->CreateVertexBuffer(m_Max_Num_Point_Sprites_Buffer * sizeof(POINTSPRITEVERTEX), 0,
													D3DFVF_POINTSPRITEVERTEX, D3DPOOL_DEFAULT, &pPSVB, NULL)))
		{
			throw Exception("Could not create a Point Sprite Vertex Buffer during resizing.", __FILE__, __LINE__);
		}
	}

	m_Point_Sprite_Vertex_Buffer[m_Num_Point_Sprites_Buffer].m_x = i_x1;
	m_Point_Sprite_Vertex_Buffer[m_Num_Point_Sprites_Buffer].m_y = i_y1;
	m_Point_Sprite_Vertex_Buffer[m_Num_Point_Sprites_Buffer].m_size = i_size;

	DWORD t_color = D3DCOLOR_ARGB(i_alpha, i_red, i_green, i_blue);

	m_Point_Sprite_Vertex_Buffer[m_Num_Point_Sprites_Buffer].m_color = t_color;
	m_Num_Point_Sprites_Buffer += 1;
}

///////////////////////////////////////////////////////////

void CGraphicsSystem::Prepare_Point_Sprites()
{
	VOID* pVertices;
    if(FAILED(pPSVB->Lock(0, m_Num_Point_Sprites_Buffer * sizeof(POINTSPRITEVERTEX), (void**)&pVertices, 0)))
	{
		throw Exception("Could not lock point sprite vertex buffer.", __FILE__, __LINE__);
	}

	memcpy(pVertices, m_Point_Sprite_Vertex_Buffer, m_Num_Point_Sprites_Buffer * sizeof(POINTSPRITEVERTEX));

	pPSVB->Unlock();
}

///////////////////////////////////////////////////////////

void CGraphicsSystem::Draw_All_Point_Sprites()
{
	pD3DDevice9->SetStreamSource(0, pPSVB, 0, sizeof(POINTSPRITEVERTEX));
	pD3DDevice9->SetFVF(D3DFVF_POINTSPRITEVERTEX);
	pD3DDevice9->DrawPrimitive(D3DPT_POINTLIST, 0, m_Num_Point_Sprites_Buffer);
	m_Num_Point_Sprites_Buffer = 0;
}

///////////////////////////////////////////////////////////


Does anyone know why the point sprites aren't showing up? Thanks.

Share this post


Link to post
Share on other sites
Well, I seem to have it working, but I don't understand why and am hoping someone can explain why.

I needed to add RHW to my vertex format (this was difficult to discover as almost all sources online only talk about point sprites in a 3D context):


#define D3DFVF_POINTSPRITEVERTEX (D3DFVF_XYZRHW | D3DFVF_PSIZE | D3DFVF_DIFFUSE)

struct POINTSPRITEVERTEX
{
float m_x, m_y, m_z, m_rhw;
float m_size;
DWORD m_color;
};



Every vertex had to have its RHW member set to 1.0.

My question is: Why do I have to use RHW and set it to 1.0? What does it mean and, more importantly, why can't it suffice that I use a simple XYZ coordinate, given that everything is being done in 2D?

---

I also have another question, regarding alpha blending:

I want to alpha blend my point sprites (they are a particle system!), yet I have to change more than the alpha value. The vertex has a color, but setting it equal to D3DCOLOR_RGBA(255, 255, 255, 255) draws it in full strength, as does setting it equal to D3DCOLOR_RGBA(255, 255, 255, 0), despite the fact that alpha is 0 there. To draw it at half-strength, I need to use a color of D3DCOLOR_RGBA(128, 128, 128, 255), instead of D3DCOLOR_RGBA(255, 255, 255, 128).

However, when using ID3DXSPRITE to draw sprites, I can simply alter the alpha value of a given sprite's color to draw it at a faded value. That is, setting the color of a sprite to D3DCOLOR_RGBA(255, 255, 255, 128) draws it half-faded in ID3DXSPRITE::Draw().

Why is this? Why is the alpha value of color the sole determinant of alpha for ID3DXSPRITE but completely irrelevant for point sprites?

I really would like to understand, as it may become important when trying to draw colored point sprites!

For example, take a white texture. A dark red version of that sprite is D3DCOLOR_RGBA(128, 0, 0, 255) in ID3DXSPRITE at full brightness, but half-faded it is D3DCOLOR_RGBA(128, 0, 0, 128). Given that alphas seem to be treated differently, how do I draw a dark red point sprite at full brightness? Or a dark red point sprite at half-brightness?

Share this post


Link to post
Share on other sites

This topic is 2850 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this