Code Samples

Curved Motion Streak

The following function is a vertex shader in hlsl for motion blur. In addition to manipulating vertices to create a motion streak, I was challenged to create a streak that curved according to to object's motion. This function uses the mathematics of circles to create a curved motion streak that would in post-processing be blurred on top of the scene.


// HLSL vertex shader to create a curved motion streak using
// the previous transformation and previous previous 
// transformation
Vs_Output VS_MotionBlur(VS_Input IN)
{
	Vs_Output vs_out;
	float eps = 0.0001; //A really small value
	float3 changepos = float3(0,0,0); // represents the vertex's change in position

	//Put normal in view space
	vs_out.normal = normalize(mul(worldView, IN.normal));

	float4 currPos = mul(world, float4(IN.vertexPos, 1)); // Current transformation
	float4 prevPos = mul(prevWorld, float4(IN.vertexPos, 1)); //Previous transformation
	float3 motion1 = currPos.xyz - prevPos.xyz; // Difference vector, representing the motion
	float len1 = length(motion1); // Length of motion

	if (abs(len1) > eps){
		float cDot = dot(motion1, vs_out.normal) / len1 ;

		// Only manipulate vertices that are "in the back" of the object's motion.  You only want
		// a streak behind the object
		if ( cDot < 0){
			cDot = abs(cDot);
			float lenarc;

			//Previous previous transformation
			float4 prevprevPos = mul(prevprevWorld, float4(IN.vertexPos, 1));
			float3 motion2 = prevPos.xyz - prevprevPos.xyz; //Previous motion vector

			float len2 = length(motion2);

			float3 v = cross(motion2, motion1); // vector to represent the circle's normal
			
			if (length(v) > eps){
				v = normalize(v);

				// A midpoint of the motion, used like a chord of the circle
				float3 p1 = currPos - (motion1 / 2); 

				// Vector that intersects circle's center
				float3 n1 = cross(motion1, v); 
				n1 = normalize(n1);

				// A midpoint of the motion, used like a chord of the circle
				float3 p2 = prevPos - (motion2 / 2);

				// Vector that intersects circle's center
				float3 n2 = cross(motion2, v);
				n2 = normalize(n2);

				float n1n2len = max(length(cross(n1, n2)), eps);

				float t1 = length(cross((p2 - p1), n2)) / n1n2len; // Intersection of two rays

				float3 center = p1 - t1 * n1; // Center point for the circle
				float3 radius =  currPos - center; // Calculate circle's radius
				float r = t1;
				changepos = cross(v, radius); // represents the vertex's change in position
				
				len1 = (len2 > eps) ? len1 * len2 : len1; // Only use len1 if len2 is too small
				
				// Calculate angle to rotate along the circle (determines length of streak)
				float angle = k * len1 * cDot * radians(180) * perDeltaT; 
				lenarc = r * 2 * sin(angle); // length of the arc, determined by angle

				//axis angle rotation
				changepos = changepos * cos(angle) + v * dot(v, changepos) * (1 - cos(angle)) 
					+ cross(changepos, v) * sin(angle);
				changepos = normalize(changepos);
			}
			else{
				lenarc = cDot * 2 * k * perDeltaT; // Just use straight line as backup
			}
			
			// change the vertice's position based on values calculated
			currPos = currPos - (float4(changepos, 0) * lenarc); 
		}
	}

	
	vs_out.vertexPos = mul(viewProj, currPos);
	vs_out.color = float4( 0.8f, 0.9f, 1.0f, 1);
	vs_out.tex = IN.tex;

	return vs_out;
}

		


Post-process Draw

The following function is the Draw function used for a post-process technique class. It was designed to be generic for many kinds of post-processes, so there are variables that describe which render targets to use as input, which textures to output to (including back buffer), and which technique to use. Types of post-processes include things like "Gaussian blur", "Depth of Field", and "Motion Blur".


// Draw function for a post-process technique
//
// input: data stores the render targets and other information
// pScreenVB is the vertex buffer of the screen quad
// ClearColor is the clean color of the surface buffer
//
// output: output textures are changed by shader technique

void PostProcess::Draw(ShaderData* data, IDirect3DVertexBuffer9 *pScreenVB, DWORD ClearColor){

	// If outputting to back buffer, set render target to the back buffer.
	// Otherwise, set to the post-process surface
	if (output_method_ & TOBACKBUFFER)
		(*d3ddev_)->SetRenderTarget(0,*(data->b_buffer_));
	else
		(*d3ddev_)->SetRenderTarget(0, surface_);

	// Initiate directX device, sprite device, FVF, vertex buffer of screen,
	// and the technique of the post-process
	(*d3ddev_)->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, ClearColor, 1.0f, 0);
	(*d3ddev_)->BeginScene();
	(*d3dspt_)->Begin(D3DXSPRITE_ALPHABLEND);

	(*d3ddev_)->SetFVF(CUSTOMFVF);
	(*d3ddev_)->SetStreamSource(0,pScreenVB,0,sizeof(SVertex));
		
	(*d3deffect_)->SetTechnique(technique_.c_str());


	// Set all the input textures
	// strShaderTex is an array of strings storing the name of texures in the shader
	for (int sTex = 0; sTex < NUM_SHADERTEX; ++sTex){

		// Use main rendering texture (Usually updated at the end of groups of post-processes
		if (input_method_[sTex] & WITHTEXMAIN)
			(*d3deffect_)->SetTexture(strShaderTex[sTex].c_str(), *(data->texMain_));

		//Use secondary rendering texture
		else if (input_method_[sTex] & WITHTEXRENDER)
			(*d3deffect_)->SetTexture(strShaderTex[sTex].c_str(), *(data->texRender_));

		//Use one of the other rendering targets
		else{
			bool isApplied = false;
			for (int i = 0; i < data->numtexs_ && !isApplied; ++i){
				int select = 1 << (NUMWITHTEXS + i);
				if (input_method_[sTex] & select){	// Use appropriate texture
					(*d3deffect_)->SetTexture(strShaderTex[sTex].c_str(), *(data->tex_[i]));
					isApplied = true;
				}
			}
		}
	}

	// Draw onto a textured quad representing the screen
	unsigned int numPasses;
	(*d3deffect_)->Begin(&numPasses, NULL);    // begin using the effect
		for (unsigned int uPass = 0; uPass < numPasses; ++uPass){
			(*d3deffect_)->BeginPass(uPass);    // begin the pass
				(*d3ddev_)->DrawPrimitive(D3DPT_TRIANGLEFAN,0,2);
			(*d3deffect_)->EndPass();    // end the pass
		}
	(*d3deffect_)->End();

	// Output to back buffer
	if (!(output_method_ & TOBACKBUFFER)){
		(*d3ddev_)->EndScene();
		(*d3dspt_)->End();
	}

	//Output to another specified texture
	if (output_method_ & TOTEXMAIN)
		data->texMain_ = &texture_;
	if (output_method_ & TOTEXRENDER)
		data->texRender_ = &texture_;
	for (int i = 0; i < data->numtexs_; ++i){
		int select = 1 << (i + NUMTOTEXS);
		if (output_method_ & select)
			data->tex_[i] = &texture_;
	}
}
		



Copyright © 2009 Kelly Jacobs. All rights reserved.