Sign in to follow this  
Matruz

Particle system in DX10

Recommended Posts

Matruz    122
Hello, I have been learning a bit about DX10, so I decided to tackle the example on the particle system in the DX10 tutorial that comes in the SDK, I read it and then started to code a version of if that does not use DXUT (as the example in the tutorial does), however all I am getting a black screen instead of the "fireworks" display I get when I run the code of the tutorial. I have checked my code but something still eludes me. Could someone please help me? Here's my CPP code:
#include <windows.h>
#include <tchar.h>
#include <d3d10.h>
#include <d3dx10.h>

#define MAX_PARTICLES 30000
#define SAFE_DELETE_ARRAY(p) { if (p) { delete[] (p);   (p)=NULL; } }

HINSTANCE g_hInst;	//global handle for the app
HWND g_WndHandle;		//global variable for window handle

int g_Width = 640;
int g_Height = 480;

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
bool InitWindow(HINSTANCE, int, int);

ID3D10Device *g_pD3DDevice = NULL;
IDXGISwapChain *g_pSwapChain = NULL;
ID3D10RenderTargetView *g_pRenderTargetView = NULL;
ID3D10Texture2D	*g_pDepthStencil = NULL;
ID3D10DepthStencilView *g_pDepthStencilView = NULL;
ID3D10Effect *g_pEffect10 = NULL;
ID3D10InputLayout *g_pParticleVertexLayout = NULL;
ID3D10Buffer *g_pParticleStart;
ID3D10Buffer *g_pParticleStreamTo;
ID3D10Buffer *g_pParticleDrawFrom;
ID3D10ShaderResourceView *g_pParticleTexRV;
ID3D10Texture1D *g_pRandomTexture;
ID3D10ShaderResourceView *g_pRandomTexRV;

ID3D10EffectTechnique *g_pRenderParticles;
ID3D10EffectTechnique *g_pAdvanceParticles;
ID3D10EffectMatrixVariable *g_pmWorldViewProj;
ID3D10EffectMatrixVariable *g_pmInvView;
ID3D10EffectScalarVariable *g_pfGlobalTime;
ID3D10EffectScalarVariable *g_pfElapsedTime;
ID3D10EffectScalarVariable *g_pSecondsPerFirework;
ID3D10EffectScalarVariable *g_pNumEmber1s;
ID3D10EffectScalarVariable *g_pMaxEmber2s;
ID3D10EffectVectorVariable *g_pvFrameGravity;
ID3D10EffectShaderResourceVariable *g_pDiffuseTex;
ID3D10EffectShaderResourceVariable *g_pRandomTex;

D3DXMATRIX ViewMatrix;
D3DXMATRIX ProjMatrix;
bool g_bFirst = true;

struct PARTICLE_VERTEX
{
	D3DXVECTOR3 Pos;
	D3DXVECTOR3 vel;
	float Timer;
	UINT Type;
};

bool InitDirect3D();
bool InitParticleSystem();
void ShutDownDirect3D();
void Render();
void PreFrame();
void DoFrame(float, float);
void PostFrame();
HRESULT CreateParticleBuffer(ID3D10Device*);
HRESULT CreateRandomTexture(ID3D10Device*);
bool AdvanceParticles(ID3D10Device*, float, float, D3DXVECTOR4);
bool RenderParticles(ID3D10Device*, D3DXMATRIX&, D3DXMATRIX&);

int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
	//initialize the window
	if(!InitWindow(hInstance, g_Width, g_Height))
	{
		return false;
	}

	if(!InitDirect3D())
	{
		ShutDownDirect3D();
		return false;
	}

	//main message loop
	MSG msg = {0};
	while(WM_QUIT != msg.message)
	{
		while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) == TRUE)
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		//additional game logic...
		Render();
	}

	ShutDownDirect3D();

	return (int)msg.wParam;
}

bool InitWindow(HINSTANCE hInstance, int width, int height)
{
	WNDCLASSEX wcex;

	//Fill in the WNDCLASSEX structure, This describes how the window will look to the system
	wcex.cbSize = sizeof(WNDCLASSEX);	//size of the structure
	wcex.style = CS_HREDRAW | CS_VREDRAW;	//the class style
	wcex.lpfnWndProc = (WNDPROC)WndProc;	//the window procedure callback
	wcex.cbClsExtra = 0;					//extra bytes to allocate for this class
	wcex.cbWndExtra = 0;					//extra bytes to alloate for this instance
	wcex.hInstance = hInstance;				//handle to the application instance
	wcex.hIcon = 0;							//icon to associate with the application
	wcex.hCursor = LoadCursor(NULL, IDC_ARROW);	//the default cursor to use
	wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);	//the background color
	wcex.lpszMenuName = NULL;	//the resource name for the menu
	wcex.lpszClassName = TEXT("DirectXExample");	//class name being created
	wcex.hIconSm = 0;	//handle to small icon
	RegisterClassEx(&wcex);

	//resize the window
	RECT rect = {0, 0, width, height};
	AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);

	//create the window from the class above
	g_WndHandle = CreateWindow(TEXT("DirectXExample"),
		TEXT("DirectXExample"),
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		rect.right - rect.left,
		rect.bottom - rect.top,
		NULL,
		NULL,
		hInstance,
		NULL);

	if(!g_WndHandle)
	{
		return false;
	}

	//display the window on the screen
	ShowWindow(g_WndHandle, SW_SHOW);
	UpdateWindow(g_WndHandle);

	return true;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	//check any available messages from the queue
	switch(message)
	{
		//allow the user to press the Escape key to end the application
		case WM_KEYDOWN:	
			switch(wParam)
			{
				//check if the use hit the escape key
				case VK_ESCAPE:
					PostQuitMessage(0);
					break;
			}
			break;
		case WM_DESTROY:
			PostQuitMessage(0);
			break;
	}

	//always return the message to the default widow procedure for further processing
	return DefWindowProc(hWnd, message, wParam, lParam);
}

bool InitDirect3D()
{
	DXGI_SWAP_CHAIN_DESC swapChainDesc;
	ZeroMemory(&swapChainDesc, sizeof(swapChainDesc));

	//fill the values
	swapChainDesc.BufferCount = 1;
	swapChainDesc.BufferDesc.Width = g_Width;
	swapChainDesc.BufferDesc.Height = g_Height;
	swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
	swapChainDesc.BufferDesc.RefreshRate.Numerator = 60;
	swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
	swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	swapChainDesc.OutputWindow = g_WndHandle;
	swapChainDesc.SampleDesc.Count = 1;
	swapChainDesc.SampleDesc.Quality = 0;
	swapChainDesc.Windowed = TRUE;

	//create the D3D device and swap chain
	HRESULT hr = D3D10CreateDevice(NULL,
		D3D10_DRIVER_TYPE_HARDWARE,
		NULL,
		0,
		D3D10_SDK_VERSION,
		&g_pD3DDevice);

	if(FAILED(hr))
		return false;

	IDXGIDevice *pDXGIDevice;
	hr = g_pD3DDevice->QueryInterface(__uuidof(IDXGIDevice), (void **)&pDXGIDevice);
	
	if(FAILED(hr))
		return false;

	IDXGIAdapter *pDXGIAdapter;
	hr = pDXGIDevice->GetParent(__uuidof(IDXGIAdapter), (void**)&pDXGIAdapter);
	
	if(FAILED(hr))
		return false;

	IDXGIFactory *pIDXGIFactory;
	hr = pDXGIAdapter->GetParent(__uuidof(IDXGIFactory), (void **)&pIDXGIFactory);

	if(FAILED(hr))
		return false;

	hr = pIDXGIFactory->CreateSwapChain(g_pD3DDevice, &swapChainDesc, &g_pSwapChain);

	if(FAILED(hr))
		return false;

	//get the backbuffer from the swap chain
	ID3D10Texture2D *pBackBuffer;
	hr = g_pSwapChain->GetBuffer(0, __uuidof(ID3D10Texture2D), (LPVOID*)&pBackBuffer);
	
	if(FAILED(hr))
		return false;

	//create the render target view
	hr = g_pD3DDevice->CreateRenderTargetView(pBackBuffer, NULL, &g_pRenderTargetView);

	if(FAILED(hr))
		return false;

	//release the backbuffer
	pBackBuffer->Release();

	//make sure render target was created
	if(FAILED(hr))
		return false;

	// Create depth stencil texture
    D3D10_TEXTURE2D_DESC descDepth;
    descDepth.Width = g_Width;
    descDepth.Height = g_Height;
    descDepth.MipLevels = 1;
    descDepth.ArraySize = 1;
    descDepth.Format = DXGI_FORMAT_D32_FLOAT;
    descDepth.SampleDesc.Count = 1;
    descDepth.SampleDesc.Quality = 0;
    descDepth.Usage = D3D10_USAGE_DEFAULT;
    descDepth.BindFlags = D3D10_BIND_DEPTH_STENCIL;
    descDepth.CPUAccessFlags = 0;
    descDepth.MiscFlags = 0;
    hr = g_pD3DDevice->CreateTexture2D(&descDepth, NULL, &g_pDepthStencil);
    if(FAILED(hr))
        return false;

    // Create the depth stencil view
    D3D10_DEPTH_STENCIL_VIEW_DESC descDSV;
    descDSV.Format = descDepth.Format;
    descDSV.ViewDimension = D3D10_DSV_DIMENSION_TEXTURE2D;
    descDSV.Texture2D.MipSlice = 0;
    hr = g_pD3DDevice->CreateDepthStencilView(g_pDepthStencil, &descDSV, &g_pDepthStencilView);
    if(FAILED(hr))
        return false;

	g_pD3DDevice->OMSetRenderTargets(1, &g_pRenderTargetView, g_pDepthStencilView);
	//g_pD3DDevice->OMSetRenderTargets(1, &g_pRenderTargetView, NULL);

	//create and set the viewport
	D3D10_VIEWPORT viewPort;
	viewPort.Width = g_Width;
	viewPort.Height = g_Height;
	viewPort.MinDepth = 0.0f;
	viewPort.MaxDepth = 1.0f;
	viewPort.TopLeftX = 0;
	viewPort.TopLeftY = 0;
	g_pD3DDevice->RSSetViewports(1, &viewPort);

	D3DXVECTOR3 Eye(0.0f, 0.0f, -170.0f);
    D3DXVECTOR3 At(0.0f, 70.0f, 0.0f);
    D3DXVECTOR3 Up(0.0f, 1.0f, 0.0f);
    D3DXMatrixLookAtLH(&ViewMatrix, &Eye, &At, &Up);

	D3DXMatrixPerspectiveFovLH(&ProjMatrix, (float)D3DX_PI * 0.25f, g_Width / (float)g_Height, 0.1f, 100.0f);

	if(!InitParticleSystem())
		return false;
	
	return true;
}

void Render()
{
	if(g_pD3DDevice != NULL)
	{
		PreFrame();

		static DWORD timeLastFrameStarted = 0;
		static float t = 0.0f;
		static DWORD dwTimeStart = 0;
        
		DWORD dwTimeCur = GetTickCount();
        
		if(dwTimeStart == 0)
		{
			dwTimeStart = dwTimeCur;
			timeLastFrameStarted = dwTimeStart;
		}
			
        float timeElapsed = (dwTimeCur - timeLastFrameStarted) / 1000.0f;
		t = (dwTimeCur - dwTimeStart) / 1000.0f;
		timeLastFrameStarted = dwTimeCur;
		
		DoFrame(t, timeElapsed);
		
		PostFrame();
	}
}

void PreFrame()
{
	g_pD3DDevice->ClearRenderTargetView(g_pRenderTargetView, D3DXCOLOR(0.0f, 0.0f, 0.0f, 0.0f));
	
	g_pD3DDevice->ClearDepthStencilView(g_pDepthStencilView, D3D10_CLEAR_DEPTH, 1.0f, 0);
}

void DoFrame(float fGlobalTime, float fElapsedTime)
{
	g_pD3DDevice->IASetInputLayout(g_pParticleVertexLayout);
	
	D3DXVECTOR4 vGravity = D3DXVECTOR4(0.0f, -9.8f, 0.0f, 0.0f);

	AdvanceParticles(g_pD3DDevice, fGlobalTime, fElapsedTime, vGravity);

	RenderParticles(g_pD3DDevice, ViewMatrix, ProjMatrix);
}

void PostFrame()
{
	g_pSwapChain->Present(0, 0);
}

void ShutDownDirect3D()
{
	//release render target
	if(g_pRenderTargetView)
	{
		g_pRenderTargetView->Release();
	}

	//release the effect
	if(g_pEffect10)
	{
		g_pEffect10->Release();
	}

	if(g_pParticleVertexLayout)
	{
		g_pParticleVertexLayout->Release();
	}

	if(g_pParticleStart)
	{
		g_pParticleStart->Release();
	}

	if(g_pParticleStreamTo)
	{
		g_pParticleStreamTo->Release();
	}

	if(g_pParticleDrawFrom)
	{
		g_pParticleDrawFrom->Release();	
	}

	if(g_pRandomTexture)
	{
		g_pRandomTexture->Release();
	}

	if(g_pRandomTexRV)
	{
		g_pRandomTexRV->Release();
	}
	
	if(g_pParticleTexRV)
	{
		g_pParticleTexRV->Release();
	}

	//release the swapchain
	if(g_pSwapChain)
	{
		g_pSwapChain->Release();
	}

	//release the D3D Device
	if(g_pD3DDevice)
	{
		g_pD3DDevice->Release();
	}
}

bool InitParticleSystem()
{
	HRESULT hr = D3DX10CreateEffectFromFile(L"ParticleSys.fx",
		NULL,
		NULL,
		"fx_4_0",
		D3D10_SHADER_ENABLE_STRICTNESS,
		0,
		g_pD3DDevice,
		NULL,
		NULL,
		&g_pEffect10,
		NULL,
		NULL);

	if(FAILED(hr))
	{
		MessageBox(NULL, L"The FX file cannot be located.  Please run this executable from the directory that contains the FX file.", L"Error", MB_OK);
		return false;
	}
		
	g_pRenderParticles = g_pEffect10->GetTechniqueByName("RenderParticles");
	g_pAdvanceParticles = g_pEffect10->GetTechniqueByName("AdvanceParticles");

	g_pmWorldViewProj = g_pEffect10->GetVariableByName("g_mWorldViewProj")->AsMatrix();
	g_pmInvView = g_pEffect10->GetVariableByName("g_mInvView")->AsMatrix();
	g_pfGlobalTime = g_pEffect10->GetVariableByName("g_fGlobalTime")->AsScalar();
	g_pfElapsedTime = g_pEffect10->GetVariableByName("g_fElapsedTime")->AsScalar();
	g_pSecondsPerFirework = g_pEffect10->GetVariableByName("g_fSecondsPerFirework")->AsScalar();
	g_pNumEmber1s = g_pEffect10->GetVariableByName("g_iNumEmber1s")->AsScalar();
	g_pMaxEmber2s = g_pEffect10->GetVariableByName("g_fMaxEmber2s")->AsScalar();
	g_pvFrameGravity = g_pEffect10->GetVariableByName("g_vFrameGravity")->AsVector();
	g_pDiffuseTex = g_pEffect10->GetVariableByName("g_txDiffuse")->AsShaderResource();
	g_pRandomTex = g_pEffect10->GetVariableByName("g_txRandom")->AsShaderResource();

	D3D10_INPUT_ELEMENT_DESC layout[] =
	{
		{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },  
        { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0 },
		{ "TIMER", 0, DXGI_FORMAT_R32_FLOAT, 0, 24, D3D10_INPUT_PER_VERTEX_DATA, 0 },
		{ "TYPE", 0, DXGI_FORMAT_R32_UINT, 0, 28, D3D10_INPUT_PER_VERTEX_DATA, 0 },
	};

	UINT numElements = sizeof(layout) / sizeof(layout[0]);

	D3D10_PASS_DESC passDesc;
    g_pAdvanceParticles->GetPassByIndex(0)->GetDesc(&passDesc);
    hr = g_pD3DDevice->CreateInputLayout(layout, numElements, passDesc.pIAInputSignature,
		passDesc.IAInputSignatureSize, &g_pParticleVertexLayout);
    
	if(FAILED(hr))
        return false;

	D3DXCOLOR colorMtrlDiffuse(1.0f, 1.0f, 1.0f, 1.0f);
	D3DXCOLOR colorMtrlAmbient(0.35f, 0.35f, 0.35f, 0.35f);

	hr = CreateParticleBuffer(g_pD3DDevice);

	if(FAILED(hr))
        return false;

	hr = D3DX10CreateShaderResourceViewFromFile(g_pD3DDevice,
		L"particle.dds",
		NULL,
		NULL,
		&g_pParticleTexRV,
		NULL);

	if(FAILED(hr))
        return false;

	hr = CreateRandomTexture(g_pD3DDevice);

	if(FAILED(hr))
        return false;

	return true;
}

HRESULT CreateParticleBuffer(ID3D10Device *pD3Ddevice)
{
	HRESULT hr = S_OK;

	D3D10_BUFFER_DESC vbdesc;
	vbdesc.ByteWidth = (UINT)sizeof(PARTICLE_VERTEX);
	vbdesc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
	vbdesc.CPUAccessFlags = 0;
	vbdesc.MiscFlags = 0;
	vbdesc.Usage = D3D10_USAGE_DEFAULT;

	D3D10_SUBRESOURCE_DATA vbInitdata;
	ZeroMemory(&vbInitdata, sizeof(D3D10_SUBRESOURCE_DATA));

	PARTICLE_VERTEX vertStart;
	vertStart.Pos = D3DXVECTOR3(0.0f , 0.0f, 0.0f);
	vertStart.vel = D3DXVECTOR3(0.0f, 40.0f, 0.0f);
	vertStart.Timer = 0.0f;
	vertStart.Type = 0;

	vbInitdata.pSysMem = &vertStart;
	vbInitdata.SysMemPitch = (UINT)sizeof(PARTICLE_VERTEX);

	hr = pD3Ddevice->CreateBuffer(&vbdesc, &vbInitdata, &g_pParticleStart);

	vbdesc.ByteWidth = (UINT)(sizeof(PARTICLE_VERTEX) * MAX_PARTICLES);
	vbdesc.BindFlags |= D3D10_BIND_STREAM_OUTPUT;

	hr = pD3Ddevice->CreateBuffer(&vbdesc, NULL, &g_pParticleDrawFrom);
	hr = pD3Ddevice->CreateBuffer(&vbdesc, NULL, &g_pParticleStreamTo);

	return hr;
}

HRESULT CreateRandomTexture(ID3D10Device *pD3DDevice)
{
	HRESULT hr = S_OK;

	int iNumRandValues = 1024;
    srand(timeGetTime());
	
    D3D10_SUBRESOURCE_DATA InitData;
    InitData.pSysMem = new float[iNumRandValues * 4];
    if(!InitData.pSysMem)
        return E_OUTOFMEMORY;
    InitData.SysMemPitch = iNumRandValues * 4 * sizeof(float);
    InitData.SysMemSlicePitch = iNumRandValues * 4 * sizeof(float);
    for(int i = 0; i < iNumRandValues * 4; i++)
    {
        ((float*)InitData.pSysMem)[i] = float((rand() % 10000) - 5000);
    }

    
	D3D10_TEXTURE1D_DESC dstex;
    dstex.Width = iNumRandValues;
    dstex.MipLevels = 1;
    dstex.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
    dstex.Usage = D3D10_USAGE_DEFAULT;
    dstex.BindFlags = D3D10_BIND_SHADER_RESOURCE;
    dstex.CPUAccessFlags = 0;
    dstex.MiscFlags = 0;
    dstex.ArraySize = 1;
    
	hr = pD3DDevice->CreateTexture1D(&dstex, &InitData, &g_pRandomTexture);
    
	SAFE_DELETE_ARRAY(InitData.pSysMem);

    // Create the resource view
    D3D10_SHADER_RESOURCE_VIEW_DESC SRVDesc;
    ZeroMemory(&SRVDesc, sizeof(SRVDesc));
    SRVDesc.Format = dstex.Format;
    SRVDesc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE1D;
    SRVDesc.Texture2D.MipLevels = dstex.MipLevels;
    hr = pD3DDevice->CreateShaderResourceView(g_pRandomTexture, &SRVDesc, &g_pRandomTexRV);

    return hr;
}

bool AdvanceParticles(ID3D10Device *pD3DDevice, float fGlobalTime, float fElapsedTime, D3DXVECTOR4 vGravity)
{
	ID3D10Buffer *pBuffers[1];

	if(g_bFirst)
		pBuffers[0] = g_pParticleStart;
	else
		pBuffers[0] = g_pParticleDrawFrom;

	UINT stride[1] = { sizeof( PARTICLE_VERTEX) };
    UINT offset[1] = {0};

	pD3DDevice->IASetVertexBuffers(0, 1, pBuffers, stride, offset);
	pD3DDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_POINTLIST);

	pBuffers[0] = g_pParticleStreamTo;
	pD3DDevice->SOSetTargets(1, pBuffers, offset);

	g_pfGlobalTime->SetFloat(fGlobalTime);
	g_pfElapsedTime->SetFloat(fElapsedTime);
	vGravity *= fElapsedTime;
	g_pvFrameGravity->SetFloatVector((float*)&vGravity);
	g_pRandomTex->SetResource(g_pRandomTexRV);
	g_pSecondsPerFirework->SetFloat(0.4f);
	g_pNumEmber1s->SetInt(100);
	g_pMaxEmber2s->SetFloat(15.0f);

	D3D10_TECHNIQUE_DESC techDesc;
	g_pAdvanceParticles->GetDesc(&techDesc);

	for(UINT p = 0; p < techDesc.Passes; ++p)
	{
		g_pAdvanceParticles->GetPassByIndex(p)->Apply(0);
		if(g_bFirst)
			pD3DDevice->Draw(1, 0);
		else
			pD3DDevice->DrawAuto();
	}

	pBuffers[0] = NULL;
	pD3DDevice->SOSetTargets(1, pBuffers, offset);

	ID3D10Buffer *pTemp = g_pParticleDrawFrom;
    g_pParticleDrawFrom = g_pParticleStreamTo;
    g_pParticleStreamTo = pTemp;
	
	g_bFirst = false;
	
	return true;
}

bool RenderParticles(ID3D10Device *pD3DDevice, D3DXMATRIX &mView, D3DXMATRIX &mProj)
{
	D3DXMATRIX mWorldView;
    D3DXMATRIX mWorldViewProj;

	ID3D10Buffer *pBuffers[1] = { g_pParticleDrawFrom };
	UINT stride[1] = { sizeof(PARTICLE_VERTEX) };
    UINT offset[1] = {0};
	pD3DDevice->IASetVertexBuffers(0, 1, pBuffers, stride, offset);
	pD3DDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_POINTLIST);
	
	D3DXMatrixMultiply(&mWorldViewProj, &mView, &mProj);
	g_pmWorldViewProj->SetMatrix((float*)mWorldViewProj);
	g_pDiffuseTex->SetResource(g_pParticleTexRV);
	D3DXMATRIX mInvView;
    D3DXMatrixInverse(&mInvView, NULL, &mView);
	g_pmInvView->SetMatrix((float*)mInvView);

	D3D10_TECHNIQUE_DESC techDesc;
    g_pRenderParticles->GetDesc(&techDesc);

	for(UINT p = 0; p < techDesc.Passes; ++p)
	{
		g_pRenderParticles->GetPassByIndex(p)->Apply(0);
		pD3DDevice->DrawAuto();
	}

	return true;
}
And the shader:
//
// Explanation of different particle types
//
#define PT_LAUNCHER 0 //Firework Launcher - launches a PT_SHELL every so many seconds
#define PT_SHELL    1 //Unexploded shell - flies from the origin and explodes into many PT_EMBERXs
#define PT_EMBER1   2 //basic particle - after it's emitted from the shell, it dies
#define PT_EMBER2   3 //after it's emitted, it explodes again into many PT_EMBER1s
#define PT_EMBER3   4 //just a differently colored ember1
#define P_SHELLLIFE 3.0
#define P_EMBER1LIFE 2.5
#define P_EMBER2LIFE 1.5
#define P_EMBER3LIFE 2.0

struct VSParticleIn
{
	float3 pos : POSITION;
	float3 vel : NORMAL;
	float Timer : TIMER;
	uint Type : TYPE;
};

struct VSParticleDrawOut
{
	float3 pos : POSITION;
	float4 color : COLOR0;
	float radius : RADIUS;
};

struct PSSceneIn
{
	float4 pos : SV_POSITION;
	float2 tex : TEXTURE0;
	float4 color : COLOR0;
};

cbuffer cb0
{
	matrix g_mWorldViewProj;
	matrix g_mInvView;
	float g_fGlobalTime;
	float g_fElapsedTime;
	float g_fSecondsPerFirework = 1.0f;
	int g_iNumEmber1s = 30;
	float g_fMaxEmber2s = 15.0f;
	float4 g_vFrameGravity; 
};

cbuffer cbImmutable
{
	float3 g_positions[4] =
	{
		float3(-1.0f, 1.0f, 0.0f),
		float3(1.0f, 1.0f, 0.0f),
		float3(-1.0f, -1.0f, 0.0f),
		float3(1.0f, -1.0f, 0.0f),
	};
	float2 g_texcoords[4] =
	{
		float2(0.0f, 1.0f),
		float2(1.0f, 1.0f),
		float2(0.0f, 0.0f),
		float2(1.0f, 0.0f),
	};
};

Texture2D g_txDiffuse;
SamplerState g_samLinear
{
	Filter = MIN_MAG_MIP_LINEAR;
	AddressU = Clamp;
	AddressV = Clamp;
};

Texture1D g_txRandom;
SamplerState g_samPoint
{
	Filter = MIN_MAG_MIP_POINT;
	AddressU = Wrap;
};

BlendState AdditiveBlending
{
	AlphaToCoverageEnable = FALSE;
	BlendEnable[0] = TRUE;
	SrcBlend = SRC_ALPHA;
	DestBlend = ONE;
	BlendOp = ADD;
	SrcBlendAlpha = ZERO;
	DestBlendAlpha = ZERO;
	BlendOpAlpha = ADD;
	RenderTargetWriteMask[0] = 0x0F;
};

BlendState NoBlending
{
	AlphaToCoverageEnable = FALSE;
	BlendEnable[0] = FALSE;
};

DepthStencilState DisableDepth
{
	DepthEnable = FALSE;
	DepthWriteMask = ZERO;
};

VSParticleDrawOut VSSceneMain(VSParticleIn input)
{
	VSParticleDrawOut output = (VSParticleDrawOut)0;
	
	output.pos = input.pos;
	output.radius = 1.5f;
	
	if(input.Type == PT_LAUNCHER)
	{
		output.color = float4(1.0f, 0.1f, 0.1f, 1.0f);
		output.radius = 1.0f;
	}
	else if(input.Type == PT_SHELL)
	{
		output.color = float4(0.1f, 1.0f, 1.0f, 1.0f);
		output.radius = 1.0f;
	}
	else if(input.Type == PT_EMBER1)
	{
		output.color = float4(1.0f, 1.0f, 0.1f, 1.0f);
		output.color *= (input.Timer / P_EMBER1LIFE);
	}
	else if(input.Type == PT_EMBER2)
	{
		output.color = float4(1.0f, 0.1f, 1.0f, 1.0f);
	}
	else if(input.Type == PT_EMBER3)
	{
		output.color = float4(1.0f, 0.1f, 0.1f, 1.0f);
		output.color *= (input.Timer / P_EMBER3LIFE);
	}
	
	return output;
}

VSParticleIn VSPassThroughMain(VSParticleIn input)
{
	return input;
}

float3 RandomDir(float fOffset)
{
	float tCoord = (g_fGlobalTime + fOffset) / 300.0f;
	return g_txRandom.SampleLevel(g_samPoint, tCoord, 0.0f);
}

void GSGenericHandler(VSParticleIn input, inout PointStream<VSParticleIn> ParticleOutputStream)
{
	input.pos += input.vel * g_fElapsedTime;
	input.vel += g_vFrameGravity;
	input.Timer -= g_fElapsedTime;
	ParticleOutputStream.Append(input);
}

void GSLauncherHandler(VSParticleIn input, inout PointStream<VSParticleIn> ParticleOutputStream)
{
	if(input.Timer <= 0)
	{
		float3 vRandom = normalize(RandomDir(input.Type));
	
		VSParticleIn output;
		output.pos = input.pos + input.vel * g_fElapsedTime;
		output.vel = input.vel + vRandom * 8.0f;
		output.Timer = P_SHELLLIFE + vRandom.y * 0.5f;
		output.Type = PT_SHELL;
		ParticleOutputStream.Append(output);
		
		input.Timer = g_fSecondsPerFirework + vRandom.x * 0.4f;
	}
	else
	{
		input.Timer -= g_fElapsedTime;
	}
	
	ParticleOutputStream.Append(input);
}

void GSShellHandler(VSParticleIn input, inout PointStream<VSParticleIn> ParticleOutputStream)
{
	if(input.Timer <= 0)
	{
		VSParticleIn output;
		
		float3 vRandom = float3(0.0f, 0.0f, 0.0f);
		
		for(int i = 0; i < g_iNumEmber1s; i++)
		{
			vRandom = normalize(RandomDir(input.Type + i));
			output.pos = input.pos + input.vel * g_fElapsedTime;
			output.vel = input.vel + vRandom * 15.0f;
			output.Timer = P_EMBER1LIFE;
			output.Type = PT_EMBER1;
			ParticleOutputStream.Append(output);
		}
		
		for(int i = 0; i < abs(vRandom.x) * g_fMaxEmber2s; i++)
		{
			vRandom = normalize(RandomDir(input.Type + i));
			output.pos = input.pos + input.vel * g_fElapsedTime;
			output.vel = input.vel + vRandom * 10.0f;
			output.Timer = P_EMBER2LIFE * 0.4f * vRandom.x;
			output.Type = PT_EMBER2;
			ParticleOutputStream.Append(output);
		}
	}
	else
	{
		GSGenericHandler(input, ParticleOutputStream);
	}
}

void GSEmber1Handler(VSParticleIn input, inout PointStream<VSParticleIn> ParticleOutputStream)
{
	if(input.Timer > 0)
	{
		GSGenericHandler(input, ParticleOutputStream);
	}
}

void GSEmber2Handler(VSParticleIn input, inout PointStream<VSParticleIn> ParticleOutputStream)
{
	if(input.Timer <= 0)
	{
		VSParticleIn output;
		
		for(int i = 0; i < 10; i++)
		{
			output.pos = input.pos + input.vel * g_fElapsedTime;
			output.vel = input.vel + normalize(RandomDir(input.Type + i)) * 10.0f;
			output.Timer = P_EMBER3LIFE;
			output.Type = PT_EMBER3;
			ParticleOutputStream.Append(output);
		}
	}
	else
	{
		GSGenericHandler(input, ParticleOutputStream);
	}
}

[maxvertexcount(128)]
void GSAdvanceParticlesMain(point VSParticleIn input[1], inout PointStream<VSParticleIn> ParticleOutputStream)
{
	if(input[0].Type == PT_LAUNCHER)
	{
		GSLauncherHandler(input[0], ParticleOutputStream);
	}
	else if(input[0].Type == PT_SHELL)
	{
		GSShellHandler(input[0], ParticleOutputStream);
	}
	else if(input[0].Type == PT_EMBER1 || input[0].Type == PT_EMBER3)
	{
		GSEmber1Handler(input[0], ParticleOutputStream);
	}
	else if(input[0].Type == PT_EMBER2)
	{
		GSEmber2Handler(input[0], ParticleOutputStream);
	}
}

[maxvertexcount(4)]
void GSSceneMain(point VSParticleDrawOut input[1], inout TriangleStream<PSSceneIn> SpriteStream)
{
	PSSceneIn output;
	
	for(int i = 0; i < 4; i++)
	{
		float3 position = g_positions[i] * input[0].radius;
		position = mul(position, (float3x3)g_mInvView) + input[0].pos;
		output.pos = mul(float4(position, 1.0f), g_mWorldViewProj);
		
		output.color = input[0].color;
		output.tex = g_texcoords[i];
		SpriteStream.Append(output);
	}
	SpriteStream.RestartStrip();
}

float4 PSSceneMain(PSSceneIn input) : SV_Target
{
	return g_txDiffuse.Sample(g_samLinear, input.tex) * input.color;
}

technique10 RenderParticles
{
	pass p0
	{
		SetVertexShader(CompileShader(vs_4_0, VSSceneMain()));
		SetGeometryShader(CompileShader(gs_4_0, GSSceneMain()));
		SetPixelShader(CompileShader(ps_4_0, PSSceneMain()));
		
		SetBlendState(AdditiveBlending, float4(0.0f, 0.0f, 0.0f, 0.0f), 0xFFFFFFFF);
		SetDepthStencilState(DisableDepth, 0);
	}
}

GeometryShader gsStreamOut = ConstructGSWithSO(CompileShader(gs_4_0, GSAdvanceParticlesMain()), "POSITION.xyz; NORMAL.xyz; TIMER.x; TYPE.x");
technique10 AdvanceParticles
{
	pass p0
	{
		SetVertexShader(CompileShader(vs_4_0, VSPassThroughMain()));
		SetGeometryShader(gsStreamOut);
		SetPixelShader(NULL);
		
		SetDepthStencilState(DisableDepth, 0);
	}
}

Share this post


Link to post
Share on other sites

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