Brian Bennett
Game Programmer
July 29th
This week, I was able to add a smoke trail to my fire ball. The smoke uses alpha blending just like the outer part of the fire. This completes the fire effect. It is made up of three emitters in total. One is the inner flame, one is the outer flame and now the smoke as well.
I have also implemented a particle counter so I can keep track of all the particles in the scene. I simply have to subscribe a particle system to the counter. The counter outputs the sum of all of its subscribers particle counts as the total particles at any time. This is then displayed right below the FPS counter. As you can see in the video, I am at about 2000 particles between the 3 point emitters on the fire and smoke effect as well as the rain effect. I can adjust the values of the particle systems to allow for more and will be doing some stress testing. I also want to add a few more fire and smoke emitters to the scene. It is also worth noting that the counter keeps track of all the particles in the scene not just the ones being displayed.
I am also very close to finishing the config files. This way I simply will just need to feed the particle system a string that says where to find the effects file and what it is called and when the particle system is initialized then it will read in those values. Currently, I am setting those values in the code myself which is quite annoying. This will make it much easier to add emitters that use the same properties as other emitters in the scene. I am using XML as the language of the effects files and TinyXML to read the files and grab the values. Below is an example of my smoke effect file. All the effects will look similar to this just with different attribute values. I have a bug with some of the values right now which should only take a max of 2 hours to figure out and I want to figure out a way to bring in my color values as well as a few others that are not simply numbers or strings.
Lastly, I made another pass to my particle system. Before, I was using a pool of verts and a vector of particles. The pool of verts was always set to the maximum number of allowed particles and never changed so no new or deletes. The pool of verts is what is sent to the GPU. Each vert is just a Position, Color, and Size. The vector of particles changed its size based since it only contained alive particles. Each particle contains much more information like velocity, time, lifespan, etc. What I did was I would add to the vector when spawning new particles and removing them when they died. i also did not use new or delete. I would make a new particle on the stack and then make a copy on the vector using the copy constructor. the only times I had to malloc was when the vector had to grow in size, but since the vector never shrunk in capacity this did not happen often. Lastly, I would copy the values of the vector particles into the verts and would draw only those verts that I just updated. With 2000 particles on the screen I was still able to hit 60 fps with this implementation.
In my second pass of this, I decided to make a pool of particles whose size never changed just like the vert pool. So I added a alive bool to the particles and would loop through the entire particle pool when creating new particles and updating them. Still not calling new or delete expect for the initial allocations and still copying over the values from the particle list to the vert list and drawing only the current particle count verts. In this implementation, I was only at 50 fps and since I spawn particles per frame the particle count was not as high. The perfromance hit was in the loops. My max particle count was set to 5000 at the time, which none of my emitters were getting close to, but it caused the update loops to take longer than adding and removing particles from the vector of the previous implementation. I lowered the max particle count to 500 and the problem went away, but it was interesting to see this development take place.
I will finish the config files this weekend as there are just a few bugs and I am going to stress the system and add more emitters to see just how many particles my system can handle.
June 2016 - July 2016
This week, I was able to complete a fire effect in my particle system. It uses two point emitters. One uses additive blending and represents the center of the flame where it is most intense. The other uses alpha blending and represents the parts of the flame that are not so intense which tend to be on the outer most parts of the flame. I plan on adding a very slight white smoke that would emit just above the center.
I also updated the project so that I can manipulate the particle system at runtime. Right now, I can just move the fire emitter on key presses and I can adjust the intensity of the rain as well.
Lastly, I set up a general particle system class. Before, I was making a new class for every effect which obviously is not ideal. Now with the general particle system class, I can set up the various variables, give a customized depth sentcil setting and set up a blend option as well. I can also give each particle system its own shaders as well. There are a few variables I added later that I would like to add as well; mainly the deviation to velocity and start position variables. I have also been working on reading these values in from a config file, but was unable to finish that this week.
This week, I found a solve for my color blending problem. I implemented both additive blending and I fixed my bug with alpha blending.
The Image above shows a smoke effect with alpha blending on the left and additive blending on the right.
This Image shows the problem I had before. After looking thrrough the debugger, I saw that some of the particles were failing the depth test and getting culled out. This meant that in additive blending they would not get added to the pixels color and similarly in alpha blending even though the areas of the quad that we were rendering were transparent.
I ended up changing the depth stencil to always compare every pixel whether or not it fails the Z test or not. This means every color will be considered when drawing the particle system. This is more computationally expensive though. I noticed that getting too close to the system results in frame drops especially if there is a lot of particles in one spot. With this implementation, it means that high density particles would need to be off in the distance as the further away they were the better the performance was. It is also worth noting that I am not ordering the particles in either alpha or additive blending.
I have also started a rain particle effect. You can kinda see it in the pictures above, but it still needs iterations. I used a point sprite shader to draw lines going up and down instead of triangles. I have them spawning along a plane and I give them a velcoity going straight down. This adds a basic rain effect. I want to be able to change the thickness of the lines and provide variations to the direction it moves down. I also want to implemend one that uses a texutre and a quad as that will look better.
July 21st
July 14th
July 7th
I am still having trouble with blending in my point sprite shader. I am unclear on what the problem is. As you can see in the picture, some particles are being ocluded from the picture from other particles even though the parts of those particles are transparent. I may need to change the order in which I am rendering the particles to go more back to front, but this can be expensive. I will be trying additive blending this next week.
June 30th
As part of my time at FIEA, the programmers are tasked with a personal programming project. I chose to create a particle system using directx. I also want to create a C# tool that can edit the particle system in real time by creating a C++/CLI bridge. The bridge will allow the tool to run the C++ code of the particle system.
I was able to create the particle system using a vertex and pixel shadder. The code is below:
cbuffer MatrixBuffer
{
matrix worldMatrix;
matrix viewMatrix;
matrix projectionMatrix;
};
struct VertexInputType
{
float4 position : POSITION;
float2 tex : TEXCOORD0;
float4 color : COLOR;
};
struct PixelInputType
{
float4 position : SV_POSITION;
float2 tex : TEXCOORD0;
float4 color : COLOR;
};
// Vertex Shader
PixelInputType ParticleVertexShader(VertexInputType input)
{
PixelInputType output;
// Change the position vector to be 4 units for proper matrix calculations.
input.position.w = 1.0f;
// Calculate the position of the vertex against the world, view, and projection matrices.
output.position = mul(input.position, worldMatrix);
output.position = mul(output.position, viewMatrix);
output.position = mul(output.position, projectionMatrix);
// Store the texture coordinates for the pixel shader.
output.tex = input.tex;
// Store the particle color for the pixel shader.
output.color = input.color;
return output;
}
// Pixel Shader
float4 ParticlePixelShader(PixelInputType input) : SV_TARGET
{
float4 textureColor;
float4 finalColor;
// Sample the pixel color from the texture using the sampler at this texture coordinate location.
textureColor = shaderTexture.Sample(SampleType, input.tex);
// Combine the texture color and the particle color to get the final color result.
finalColor = textureColor * input.color;
return finalColor;
}
Here is my particle shadder class:
class ParticleShader
{
private:
struct MatrixBufferType
{
D3DXMATRIX world;
D3DXMATRIX view;
D3DXMATRIX projection;
};
public:
ParticleShader();
ParticleShader(const ParticleShader&);
~ParticleShader();
bool Initialize(ID3D11Device*, HWND);
void Shutdown();
bool Render(ID3D11DeviceContext*, int, D3DXMATRIX, D3DXMATRIX, D3DXMATRIX, ID3D11ShaderResourceView*);
private:
bool InitializeShader(ID3D11Device*, HWND, LPCSTR, LPCSTR);
void ShutdownShader();
void OutputShaderErrorMessage(ID3D10Blob*, HWND, LPCSTR);
bool SetShaderParameters(ID3D11DeviceContext*, D3DXMATRIX, D3DXMATRIX, D3DXMATRIX, ID3D11ShaderResourceView*);
void RenderShader(ID3D11DeviceContext*, int);
private:
ID3D11VertexShader* m_vertexShader;
ID3D11PixelShader* m_pixelShader;
ID3D11InputLayout* m_layout;
ID3D11Buffer* m_matrixBuffer;
ID3D11SamplerState* m_sampleState;
};
class ParticleSystem
{
private:
struct ParticleType
{
float positionX, positionY, positionZ;
float red, green, blue;
float velocity;
bool active;
};
struct VertexType
{
D3DXVECTOR3 position;
D3DXVECTOR2 texture;
D3DXVECTOR4 color;
};
public:
ParticleSystem();
ParticleSystem(const ParticleSystem&);
~ParticleSystem();
bool Initialize(ID3D11Device*, LPCSTR);
void Shutdown();
bool Frame(float, ID3D11DeviceContext*);
void Render(ID3D11DeviceContext*);
ID3D11ShaderResourceView* GetTexture();
int GetIndexCount();
private:
bool LoadTexture(ID3D11Device*, LPCSTR);
void ReleaseTexture();
bool InitializeParticleSystem();
void ShutdownParticleSystem();
bool InitializeBuffers(ID3D11Device*);
void ShutdownBuffers();
void EmitParticles(float);
void UpdateParticles(float);
void KillParticles();
bool UpdateBuffers(ID3D11DeviceContext*);
void RenderBuffers(ID3D11DeviceContext*);
private:
float m_particleDeviationX, m_particleDeviationY, m_particleDeviationZ;
float m_particleVelocity, m_particleVelocityVariation;
float m_particleSize, m_particlesPerSecond;
int m_maxParticles;
int m_currentParticleCount;
float m_accumulatedTime;
Texture* m_Texture;
ParticleType* m_particleList;
int m_vertexCount, m_indexCount;
VertexType* m_vertices;
ID3D11Buffer *m_vertexBuffer, *m_indexBuffer;
};
I am currently using directx 9 by the use of d3d so I am working on moving this to directx11.