Particle SystemsAnother application of vertex shaders is the computation of a particle system's behavior on the GPU. This is somewhat more complex because the parameter passing can be unintuitive. Imagine an explosion, for example: Particles fly off in all directions following straight lines from a central position. This effect can easily be built into a vertex shader because we can compute each particle's position from its initial values—pass position, velocity, and time elapsed to the shader—and it will take care of the rest. The equation would be Pos=pos0 + vel0*t We can use this same philosophy to compute any effect that depends on initial values only: pass these values and use the shader as an equation solver. Now, imagine that we have a somewhat more complex particle system, where each frame has a degree of uncertainty, so each iteration is computed from the preceding one. For example, imagine a column of smoke, which is affected per frame with Perlin Noise, like this: pos.x=prevpos.x+noise(x,y,z)*0.01; pos.y=prevpos.y+0.1; pos.z=prevpos.z+noise(x,z,y)*0.01; This is harder to lay down to code. Each shader iteration recomputes the position, which we would need to recover after the processing, so we can feed it to the next iteration, and so on. For the time being, this is not possible, so we will have to restrict ourselves to shaders based on initial conditions only. Here is, for example, the source code for a shader that computes the position and orientation of a particle emanating from an initial position, with a certain velocity: void particle(float4 position: POSITION, float4 color: COLOR, float2 texcoord: TEXCOORD0, float4 velocity: TEXCOORD1, float4 initialpos: TEXCOORD2, out float4 oPosition: POSITION, out float2 oTexCoord: TEXCOORD0, out float3 oColor: COLOR, uniform float timevalue, uniform float4x4 modelviewProj) { float4 newpos=initialpos+position+velocity*timevalue; oPosition=mul(modelviewProj, newpos); oTexCoord=texCoord; oColor=color; } The code is straightforward. All we have to do is feed the shader with particle coordinates in the form displayed in the figure, and the shader will translate them to the initial position and animate them with time. We did not deal with alignment this time because it was explained in the previous shader example. By merging both, you will achieve a pretty interesting combined result (see Figure 21.6). Figure 21.6. Particle system using shaders for simulation and DirectX PointSprites as the rendering primitive. Particles are blended additively. |