Bobby Anguelov's Blog

A day in the life of a wannabe game developer

3D DirectX10 Free Look Camera (Timer based)

Introduction: Camera Basics

Okay so I promised I’d write a tutorial on writing a simple freelook camera, this tutorial doesnt only apply to DirectX10 but to any graphics API. Okay so the simplest possible camera we cam implement short of a first person style camera is a free look camera, without roll, so basically only two degrees of freedom: left/right and up/down, we are also going to implement some basic movement controls forwards/backwards and Strafe Left/Right.

First things first, as usual I’m not going to go into major detail about viewing and projections, if you want more info check out: http://en.wikipedia.org/wiki/Graphical_projection and http://en.wikipedia.org/wiki/3D_projection . Okay now to view any 3D scene we need a virtual camera with a field of view (FOV- theta) and near (a) and far (b) view planes, these together form a view frustum as show in figure 1. This frustum defines what is visible in the scene, all geometry clipping and hidden surface removal is based on this frustum.

Figure 1 - view Frustum (courtesy DX10 docs)

Now the shape of this frustum is controlled by the projection that we we to employ, there are several types of projective but chances are you will end up using a perspective projection. Now the projection is attached to our virtual camera (think of the projection as a camera lens), to orient ourselves in a scene we need to know the position that we are viewing the scene from, the direction in which we’re looking and which way is up (shown in figure 2), now this up direction is very important for movement calculations and obviously to display the scene the right way up ;)   These three parameters are called the eye position, the view vector and the up vector.

Figure 2 - Virtual Camera

For a free look camera, we need the up vector to be in the direction of the camera top, if we were doing a first person camera where the viewer is stuck on the ground then the up direction will always be towards the sky. So in conclusion to view a scene, you need a virtual camera positioned somewhere in a scene (pos/up/view) with some sort of lens (projection).

Now I need to quickly explain what happens to an object’s vertices when it travels through the rendering pipeline. When a object’s vertex gets sent down the rendering pipeline it has a position in its own model space, this position is now moved to wherever the object is required to be in the world by multiplying the vertex by the world matrix for the object. Now if you run through the world you would think of it as the world standing still and the camera moving, but for now it is beneficial to think of it in the opposite way, that the camera is stationary and its the world that’s moving. Cause mathematically that is exactly whats happening.

The camera never moves, the worlds position is just adjusted to give that impression. So we’ve positioned our object in the world, the next step it move it according to our view point, if we want to looking to the left of the object, we need to move the entire world to the right, so we multiply the vertex position with the view matrix to move it as necessary. Remember each object will have its own world matrix but used the exact same view matrix, the last step is to convert from 3D to the 2D image that is displayed on the screen, the camera lens does that just like it does in a real camera, the vertices are flatten to the near viewing plane by multiplying the vertex by the projection matrix. The entire process is show below in figure 3.

Figure 3 - Vertex Transformations

The Camera Body: The Container Class

Figure 4 - Camera Class

Figure 4 shows the class structure for our camera, source code is below, we have the two matrices: view and projection, we have function to position the camera, change the view and so on…
#define TWO_PI 6.283185307179586476925286766559
#define DEG_TO_RAD 0.01745329251994329576923690768489

class camera
{
	/*******************************************************************
	* Members
	********************************************************************/
private:

	//view parameters
	float heading, pitch;					//in radians

	//matrices
	D3DXMATRIX viewMatrix;
	D3DXMATRIX projectionMatrix;
	D3DXMATRIX rotationMatrix;

	//view vectors
	const D3DXVECTOR3 dV, dU;				//default view and up vectors
	D3DXVECTOR3 eye, view, up;

	//movement vectors and movement toggles
	D3DXVECTOR3 forward, strafeRight;
	int movementToggles[4];					//fwrd, bck, strfLft, strfRght

	//camera timer for movement
	HRTIMER::timer camTimer;

	/*******************************************************************
	* Methods
	********************************************************************/
public:

	//constructor and destructor
	camera();
	virtual ~camera();

	//set projection methods
	void setPerspectiveProjection( float FOV, float aspectRatio, float zNear, float zFar );

	//camera positioning methods
	void setPositionAndView( float x, float y, float z, float hDeg, float pDeg );
	void adjustHeadingPitch( float hRad, float pRad );
	void setMovementToggle( int i, int v );

	//update camera view/position
	void update();

	//get methods
	D3DXMATRIX& getViewMatrix() { return viewMatrix; }
	D3DXMATRIX& getProjectionMatrix() { return projectionMatrix; }

private:

	//create view, forward, strafe vectors from heading/pitch
	void updateView();
};

The Camera Lens: Creating the Projection Matrix

Lets do the easiest thing first, creating the camera lens or projection matrix. Almost all graphical APIs have a helper functions to create this matrix for you. To create a left handed perspective projection  in D3D10, the function you need is: D3DXMatrixPerspectiveFovLH( outputMatrix, FOV, aspectRatio, nearPlane, farPlane)… The code to create this matrix is:

void camera::setPerspectiveProjection(float FOV, float aspectRatio, float zNear, float zFar)
{
	//convert FOV from degrees to radians
	FOV = FOV * (float) DEG_TO_RAD;

	D3DXMatrixPerspectiveFovLH( &projectionMatrix, FOV, aspectRatio, zNear, zFar );
}

I’m setting the projection matrix’s FOV using a degree parameter, since I only do it once and its easier to visualize a degree based FOV its fine, the helper function requires radians, so I simply convert to radians using the constant defined in the class header file. The aspect ratio is the ratio of width:height for your display window. If your window is 640×480 then the aspect ratio is 640:480 -> 4:3 or numerically 1.3333333333…

The Camera: Creating the View Matrix

Since we are using a camera with only 2 degree of freedom (axes of movement) ->heading (left/right) and pitch (up/down),  we store the direction in which we’re facing as a angle on each axis. These angles are stored as radians. The final view vector is calculated from these two variables and original position of the view and the up vector is adjusted accordingly. This mean that to get an accurate up vector we need to initialize the camera with correct values when we create it, so that the up vector is valid once the view changes. so the constructor for the camera class is:

camera::camera():	dV( D3DXVECTOR3(0,0,1) ),
					dU( D3DXVECTOR3(0,1,0) ),
					eye( D3DXVECTOR3(0,0,0) ),
					view( D3DXVECTOR3(0,0,1) ),
					up( D3DXVECTOR3(0,1,0) ),
					forward( D3DXVECTOR3(0,0,1) ),
					strafeRight( D3DXVECTOR3(1,0,0) ),
					heading(0),
					pitch(0)
{
	//set matrices to identity
	D3DXMatrixIdentity( &viewMatrix );
	D3DXMatrixIdentity( &projectionMatrix );

	//initialize movement toggles
	movementToggles[0] = 0;
	movementToggles[1] = 0;
	movementToggles[2] = 0;
	movementToggles[3] = 0;
}

This always initializes our camera at the position (0,0,0), facing the positive z axis. *NOTE: we will discuss the movement toggles later on. We also set our default view and up vectors to (0,0,1) and (0,1,0) respectively. We will use these default vectors to calculate the new view vector from the heading and pitch parameters when the view changes. So how do we adjust the view? Well we simple modify the heading  and pitch parameters and run the updateView() function which we’ll define later. Just to be safe we add hard limits to the values of the heading and pitch (0~2pi) just so over the course of the program we don’t overflow the variables.

void camera::adjustHeadingPitch( float hRad, float pRad )
{
	heading += hRad;
	pitch += pRad;

	//value clamping - keep heading and pitch between 0 and 2 pi
	if ( heading > TWO_PI ) heading -= (float) TWO_PI;
	else if ( heading < 0 ) heading = (float) TWO_PI + heading;

	if ( pitch > TWO_PI ) pitch -= (float) TWO_PI;
	else if ( pitch < 0 ) pitch = (float) TWO_PI + pitch;
}

We also said we would be adding movement controls: forwards, backwards  and strafing. To move we will need to know which direction is forward ( hint: the view vector ;) ) and which way is directly right, backwards and left are obviously in the direct opposite direction. We now have the two unit vectors forward and strafeRight which also need to be updated as soon as the view changes. As we said forward is easy as it is the view vector and backward is the negative forward vector. How do we calculate the right vector? Well we have the forward direction and the up direction so right should be ortogonal (90 degrees) to both of them (ie the x axis, if forward is the z axis and u is the y axes), hm, we have two vectors and need to get another vector orthogonal to them, if we think back to basic calculas and we suddenly remember that the cross product of two vectors gives us an orthogonal vector, wiki the cross product for more details. We also need to unsure that the movement vectors are unit vectors to ensure consistant movement.

To create the new view and up vectors, we first create a rotation matrix which will rotate any point/vector by the degrees on each axis that we specify, we then rotate the default view and up vectors (du & dv) to get the new view and up vectors. Easy Peasy…

We now have all the info necessary to create our updateView() function.

void camera::updateView()
{
	//create rotation matrix
	D3DXMatrixRotationYawPitchRoll( &rotationMatrix, heading, pitch, 0 );

	//create new view and up vectors
	D3DXVec3TransformCoord( &view, &dV, &rotationMatrix );
	D3DXVec3TransformCoord( &up, &dU, &rotationMatrix );

	//create new forward and strafe vectors
	D3DXVec3Normalize( &forward, &view );
	D3DXVec3Cross( &strafeRight, &up, &view );
	D3DXVec3Normalize( &strafeRight, &strafeRight );

	//take into account eye position
	view = eye + view;

	//update view matrix
	D3DXMatrixLookAtLH( &viewMatrix, &eye, &view, &up );
}

Statically Positioning our Camera

void camera::setPositionAndView(float x, float y, float z, float hDeg, float pDeg)
{
	//set eye coordinates
	eye.x = x;
	eye.y = y;
	eye.z = z;

	//set heading and pitch
	heading = hDeg * (float) DEG_TO_RAD;
	pitch = pDeg * (float) DEG_TO_RAD;

	//update view
	updateView();
}

This simply positions the camera on a location and set the view according to the heading/pitch params specified.

Moving our Camera

There are two ways to move the camera, incrementally step by by, i.e. on each update (frame) we move the camera by a fixed amount  but there is a massive problem with this, variable framerates! Imagine if we moved the camera by 1 unit every frame, on a midrange PC getting around 45 frames per second  we will be moving at 45units a second, but now comes a guy with a monster machine and runs the game at 75 frames per second and our movement speed has increased as well, this is unacceptable and would ruin any game. I dont know if any of you remember how quake3’s physics was reliant on the FPS, and so guys getting higher FPS rates could run faster and jump further than guys with lower FPS rates. So how do we correct this? We need to ensure a fixed movement rate based on time and not frames, so we do just that, we make movement timer based! We firstly add movement toggles, which get activated when a player pushes a movement key, and deactivated when he releases it, this is necessary to ensure that if a player pushes both forward and back the camera doesnt move and then when he releases a single key it immediately starts moving in the still active direction.

The to work out the distance moved between updates, we create a simple timer and check the elapsed time in seconds, we then multiply this time by the movement rate per second. Both of these functions are shown below:

/*******************************************************************
* set camera movement toggles
********************************************************************/
void camera::setMovementToggle( int i, int v )
{
	movementToggles[i] = v;
}

/*******************************************************************
* update camera view and position - timer based for fluid movement
********************************************************************/
void camera::update()
{
	//get current elapsed time
	float t = (float) camTimer.getElapsedTimeSeconds();

	//update position - 1.5 unit per second
	eye +=	 t * ( movementToggles[0] + movementToggles[1] ) * 1.5f * forward +
			 t * ( movementToggles[2] + movementToggles[3] ) * 1.5f * strafeRight;

	//update view
	updateView();

	//reset timer
	camTimer.reset();
}

This update function is what gets called from the main game loop, also the reason why updateView() is declared private. On each frame update, you will process input, set the movement toggles appropriately, run the adjustHeadingPitch() function and then run the update() function to create the new view matrix.

NOTE: The timer used is based on my silly encapsulation of the tick timers in the windows API, look at my High Resolution Timers entry.

Conclusion

So there we have it, a super simple super basic free look camera implementation in less than a 100 lines of code. In the next blog entry I will be covering how to give the camera mouse control using Windows Raw Input. With those two tutorials you will have all the tools to create a basic input system for your game!!!

Hoep you enjoyed it!

6 December 2009 Posted by Bobby | DirectX 10, DirectX 10 Tutorials, Game Development, Graphics Programming, Programming | , , , , , , , , | 1 Comment

The “Perfect” Post Apocalyptic RPG

 Before I continue I just need to state for the record that I am a fallout (originals) fanboi. In my opinion Fallout 1/2 are the pinnacle of post apocalyptic cRPGs, actually probably the pinnacle of cRPGs in general, I can’t think of a single cRPG I’ve played through more times that the fallout games. Baldur’s Gate 1 and 2, are probably second on my list. In the last decade there hasn’t been a single game that has even come close to removing them from the top spots on the list of my all time favorite games.

So I’ve been thinking a bit about some of the recent games I’ve played and all the things that I liked and I found lacking in them. So I’m gonna outline what I feel the games did right and what they did wrong. Then I’m gonna give a basic description of what I feel would make my perfect post apocalyptic (gonna refer to it as PA from now on) RPG.

Let’s start with the classics:

Fallout 1/2

What They Did Right

Um, pretty much everything… haha, okay typical fanboi comment aside, what made those games that great? One thing stands out above everything else, the writing! Yes the setting design and the art style was amazing as well but it got outshined by the quality of the writing. The depth of characters, the locations, the back stories, the quests, the little jokes thrown in randomly, all these things fleshed out the game. Ironically the weakest story in both games was the main plot. I played those games just for the dialogues and the characters. The only other game that came close to the depth of the world and the dialogue was Baldur’s Gate 2.

Let me just go on a little bit of a rant now, to a large extent during the time period that the games were made, gaming was still a small exclusive past time. Most gamers of that period were male, and older, and usually a little geeky. There was no massive casual gaming culture as we knew , the console age was just starting and PC games were still in large, the smart gamers choice. I kinda feel that this contributed greatly to the depth of writing present in the original fallout games, when there was more focus on that sort of thing, and much less focus on large explosions, instant action and shiny graphics in games. Storylines were appreciated and dialogue sequences weren’t skipped just to get to the next level of killing hordes of nazi/aliens/etc. I miss those days, but maybe that’s just me.

Let’s move onto the combat and character systems in Fallout, the combat was a slow strategic affair, more a kin to a game of chess rather than a quake deathmatch. That again was indicative of the times, turn based combat was pretty common in games at the time and so no one complained. I personally loved the slower more thoughtful approach to combat. It made battles all the more epic since at the end you felt like you had not only outgunned your opponents but out thought them as well.

The character system was the now familiar SPECIAL system, which was based if I recall correctly on the GURPS system. I’m not gonna go into detail about the system, but it was basically a standard DnD style character attributes system. In addition to the character stats you had a list of skills, ranging from combat skills to dialogue skills, and perks. Anyone that’s played fallout3 will be familiar with both these. I really preferred the more open approach to character development found here in comparison to the rigid DnD character systems that pigeonholed your character from the start.

Another excellent design feature in the fallout games was the option to not fight! You could make it through a massive part of the game without firing a shot. This allowed me to replay the game several times with entirely different experiences. I played as a standard gunfighter character that just slaughtered everyone, then I played as a smooth talker, and realized how much additional depth the game had, and how much content I had missed out on by just gunning my way through everything. The level design was also excellent, there was no repetition between areas, you never got bored exploring. Items were also pretty scarce and so you had a sense of achievement when scavenging. There were tons of different weapons, different ammo types, different armors, etc.

The enemies were varied and tough, at no point did I feel like a god prancing through the world invulnerable, there was always some brotherhood of steel paladin or some super mutant to cut me back down to size.

What They Did Wrong

I honestly can’t really think of anything to complain about here. There were several glitches with quests not working properly and other miscellaneous bugs but those are not design problems. Design wise I can’t think of anything that could have been better. So

I’ve fanboi’d myself out so let’s move onto the best modern PA games: Fallout 3 and STALKER, seeing as we’re in a fallout mood we’ll start with fallout 3.

Fallout 3

What They Did Right

Their world design on the surface is excellent, wandering out in the DC wasteland from a first person viewpoint was excellent. I found the experience quite immersive. The various locations were quite well designed as well but there was some pretty major problems in regards to the world when you look at it in a little more depth, but I’ll get to that. The first person view and the graphics were again quite good and really help immerse the player in the environment, I found the combat system fun (it had some problems) for the most part, and really didn’t mind the VATS add on, it was fun blowing off parts in slow motion.

What They Did Wrong

(WARNING: bethesda fans should stop reading now)

When will bethesda realize that p&p RPG systems DONOT work well in first person? The obviously didn’t learn the lesson from morrowind or oblivion. Why bother giving the player the illusion of aim, when it had no effect on damage. How many times was the player stormed in oblivion by an enemy with 6 arrows sticking out his face? Seriously, it just shatters any immersion the player has with the game. The same happens in FO3, it didn’t matter if you shot someone in the face or in the foot, emptying a clip into an enemies face at close range only to have them still come at you is just stupid! Having a PnP character system in a realtime FPS game is stupid, what is it used for? just calculating whether you hit and how much damage you did? Uh, that’s what aim and distance is for, seeing as its already an FPS and chances are they already do an intersection test to see whether they should run a weapon hit check. Shooting a monster at point blank range and not hitting is ridiculous, and just ruins that sense of immersion once again.

The locations in the game while well designed from the outside lacked any sort of depth, a settlement with 6 people in it? seriously? Even megaton with its masses of people (read 20) only had 3 or 4 worth talking to. Just like every other recent bethesda game, there was a massive lack of depth. The levels were repetitive, if I had to see another sewer / subway I was going to scream. They just made a shallow simple hack and slash game and called it fallout. Yeh, it was fun for a while, until I ran through my bazilionth tunnel.

Also there were some consistency issues I had with the game, they’d be destroyed building and cars everywhere, the aftermath of a nuclear attack, and yet all the cars energy packs seem to have made it out okay, even though the cars themselves were destroyed. Also the addition of the nuke launcher?! Seriously?! I cna only think both those items were added in for the console “instant gratification” players take like “lotsa splosions!”. Weapons were not varied enough, and also items were everywhere, I don’t think I ever ran out of stimpacks or ammo. Obviously in a desolate wasteland, every single fridge or box will have tons of ammo and stuff in it, since no-one would bother looting (sarcasm!). Power armor was strewn everywhere, you never struggled for weapons or armor. Then they threw in a half baked recipe system that never really worked, the items you made were mediocre at best and you never really needed them anyways, again another stupid left over from oblivion.

The enemies were ridiculously easy to kill, supermutants going down with something ridiculous like three shots from a hunting rifle. I think by around level 14, nothing in the game could touch me, I’d maxed out my gun skills, my speech skills, my repair skills, and was busy maxing out my energy weapons skills. The quests were simple and linear, no back stories, no depth: “fetch me 30 nuka cola bottles”, why? because the NPC collects them of course. Why would I even give a damn? The moral choices were clear as night and day with the exceptions of the ghouls and tenpenny tower (kudos on that one guys). The characters were shallow and uninteresting. Trying to talk your way through things was pointless, it always boiled down to a fight. I honestly got bored 3/4 of the way through and didn’t bother finishing it.

The game can be simply described as a PA hack and slash, they might as well have foregone the quests entirely and just gone the diablo route. All in all it was a fun, simple, flashy, repetitive game without any sort of depth.

STALKER: SOC and CS

What they did right

 (I do realize stalker is not an RPG but it had a lot of RPGesque elements)

No stupid character system to calculate hits and so on, these guys were smart enough to realize that FPS and hit checks don’t work so well. You shoot a guy in the head he goes down, shoot him in the body, you’ll need to shoot him again.

Amazing environment, beautifully done, I don’t think any game has managed to capture that sense of desolation and abandonment as well as STALKER did.

 Excellent weapon range and customization options, excellent item range and artifact options. Pretty much every aspect in regards to weapons and items in the game was excellent. Items were scarce, health packs were pretty rare, various ammo types were extremely rare, artifacts were obviously rare, basically everything you carried, you had worked hard to acquire.

 The enemies were tough from the start till the end, you never once felt overpowering and untouchable.

What They Did Wrong

Infinite enemies, that was the one thing that pissed me off about both games, you’d killed everything in an area leave, come back literally 3 minutes later and the area would be repopulated with enemies. It just made the game annoying especially when travelling across multiple areas, you’d have geared up at a vendor, then by the time you got to your objective you’d be at half health with no health packs and no ammo.

CS introduce a broken faction system, which was interesting if it had worked! I should put this in the things they did right but since it never really worked I have no idea what it was supposed to do.

Terrible incomprehensible storyline and endings, I finished both games and really have no idea what the hell was going on. I had to go read the damn wikipedia page to get an idea of the storyline I had just played. I’ll put it down to a poor translation from russian to english. The game had so much potential for storytelling, tons of stalkers huddled around camp fires that could tell you rumors or interesting stories. They made use of it once or twice but not enough. The quests were all just fetch quests. Simple task / reward affairs, again so much potential especially in regards to the faction system. I really felt that having quests to go weaken enemy factions strongholds would have been excellent, so much potential for inter faction politics. Instead they made a open world FPS till you reached a certain point, where you couldn’t go back and followed a per defined route to an end mission that left you entirely unsatisfied. It’s like being led to a candy store through a rough ghetto, only to go inside and be given a stick of celery.

So now we come to my perfect PA RPG

My personal perfect PA RPG

Okay, so after lots of thinking, I actually think STALKER is an excellent base for a great PA RPG, but with some heavy modifications. Let’s just take stalker as a based and fallout’ify it a bit :) This is not going to be a full design doc, that I’m working on in my spare time but rather an idea of the things that I think would make a great game.

The World

The world present in stalker was excellent, it was well designed but severely underused. There were so many areas that could have been excellent little sub plot triggers or quest locations. Like the pump house in Clear Sky, great location, well modeled and designed and absolutely no reason to be there.

The world should be just like the stalker world, open and varying, there was next to no repetition across areas in stalker, unlike in the “seen one subway tunnel seen em all” fallout 3.

The Gameplay

Fallout 3 made me see that FPS is an excellent format for a PA game, you want to be able to feel that sense of destruction, emptiness, hopelessness that would be present in such a world, where fallout 1/2 portrayed that feeling through the rich writing, fallout 3 out did them in that regard with the magnificent vistas of destruction (pity that was all there practically was, an outside image).

In regards to the character system, I don’t think that a strict pen and paper style character system has any place in a first person game, it’s too restrictive and like I mentioned tends to destroy some of that sense of immersion. I’d suggest a system of skills, where you can increase the skills with each level. I’d also suggest reducing the number of skills to the bare minimum:  light weapons, heavy weapons, first aid, repair, speech, electronics.

I’d suggest health to remain the same as when the player starts out, so that the game is equipment based more so that stat based. I’d like to struggle to acquire my equipment and know that without it I’m pretty much as vulnerable as at the start of the game.

The combat system should also be a bit modified, I think that in additions to the skills there should be a proficiency list of all the weapons in the game. When you first find a weapon you should not have any skill in using it, an M4 is nothing like an AK so the assumption made in most games so far is that it is. I’d suggest introducing a system similar to that in dungeon siege 2, where the more you use a weapon type like an M4 the more proficient you get in using it. Start off with a massive crosshair and insane recoil and slowly reduce both these with use.

The weapons skills should affect the learning rate of each weapon. This game mechanic will further tie you to certain weapons and make the game inventory centric.

Characters shouldn’t be able to master all the weapons in the game, and so it should give them incentive to replay with different load outs. I’d also suggest various levels of specialization (beginner, intermediate, expert, marksman, etc) with each weapon, so once you cross over into a new level you unlock a special function like automatic fire, or three round burst, or allows you to use different ammo type…

The Weapons, Armor and Items

The range available in stalker was excellent, and the upgrade/customization system present in Clear Sky was the best I’ve seen in any game to date. I’d say keep a similar range of weapons. Perhaps add in some more ammo types and armors. Add in helmets and add helmet customizations. Perhaps even add extras like pants, boots etc, which affect things like stealth, stamina, etc… This adds the option for random generation of items (diablo style).

Players like customization, and the game should provide them to create entirely custom characters and loadouts. Have character skills affect the efficacy of items, good first aid gives you more health from health packs, better repair better repairs items, pretty much the way the fallout games handled the link between skills and items.

The Enemies

Enemies should be like the player, and their difficulty should depend on their equipment and skill sets as well, ie. a tough enemy must have high end armor and be at the max weapon level with a good quality customized weapon while an easy enemy must be wearing light armor and still be figuring out which end of the gun the bullets come out of.

At no point should the player feel invincible or fragile, obviously with better equipment, the weaker enemies will pose no challenge. The player must also be rewarded for good aim, and as such feel that he can take down tougher enemies if gets the right shots in. Getting a lucky shot in always feels so rewarding. Perhaps add the VATS system in as well just for some spice, calculate the chance to hit based on distance and weapon skill.  

The Storyline / Quests

Now the most important part of any RPG is the story, the characters and the quest. I’d suggest making it a very open “main” plot, something like the player’s brother needs money for an operation and the player entered the zone to raise the cash. Something that is a goal to work towards but that doesn’t restrict the player from the start. The game should be all about exploring the game world, learning about all the characters, the back stories, the politics. The player should be able to leave a lasting effect on the world. Having an ending like fallout’s with a slideshow of all the areas you visiting and how your actions affected them would be amazing.

The game should be like a long TV action series,  lots of character, lots of dialogue, lots of action.

Try to avoid stupid things like simple fetch quests, make them a little bit more elaborate, it will take a bit of thought, but that’s what you’re paying your game designers/writers for.  Make it interesting, make the choices have consequences, ie, “if you do a job for boss a, against boss b, boss b’s thugs might rob you of your belongings” etc… I think that multi part elaborate quests are what should be done rather than simple boring task. I recently finished GTA4 and towards the end of the game, I didn’t even bother watching the cut scenes, cause they boiled down to 4-5minute speeches to tell you to go to “point x” and kill “person y”.  Keep things interesting.

The game shouldn’t be about instant gratification, it should be a game where the player sits down and can’t stop playing for hours. I hate it when I sit down with a game and after an hour I’m about to throw my keyboard out the window when I’ve been given my 45th go to the other side of the map and kill/fetch something quest (ie STALKER, far cry 2, GTA 4).

Conclusion

This rant got to be super long and I apologize, It isn’t as detailed as I’d like it to be but if it was it would take another 15 or more pages and I doubt you’d want to read that much. I hope that people would agree with some of the things I’ve said or might even have better ideas. The comment box is just below, please use it :)

18 May 2009 Posted by Bobby | Game Design, Game Development, Game Reviews, Gaming, General, Role Playing Games (RPG) | , , , | 4 Comments

DirectX 10 Tutorial 3 – Textures

So it’s been sometime since the last tutorial and I apologize for that, I’ve been busy wrapping up my exams for my second degree and finishing off a mini thesis for one of my subjects. So now that it’s all over with I‘ve sat down and done a small tutorial on dx10 texturing.

A lot of other tutorials leave texturing for later on in the tutorial but I’m going to do it now because it’s so simple and further illustrates the point of shader programs and what role they play.

Texturing?

So what is texturing? You can think of it like applying wallpaper to a blank wall, you take an image and attach it to an object in your scene. Well that’s not entirely true, what texturing actually does is use an image as a reference for what color an object is. Where before we set the color for each vertex and then let the API automatically interpolate the colors between vertices now we’re giving it an image to sample for those colors.

I’m not going to go into great detail regarding mipmaps and so on since it isn’t really necessary at this point, hopefully I’ll have the time to come back to it at a later stage and even if I don’t google is your friend :P

Texturing occurs in the pixel shader stage of the pipeline, just before fragments are rasterized and so the bulk of the texturing code (all 1 line of it) needs to be done in HLSL.

There is one last thing I need to cover before I can get into the code, as I said earlier we give a object an image to use as a reference for the colors on the surface defined in the object but how does the API know which pixel in the image to use for a set of world co-ordinates on the surface? Well this is actually quite simple.

image1

If we look at the above picture, for a 128×128 pixel texture which we want to use for the quad on the right. The first we need to do is set up some sort of coordinate system for the texture. We use the letters u and v for the two axes, please notice that v increases in a downwards direction, u and v are known as texture coordinates. This is because in an image, the first pixel is the top left image and the last pixel is the bottom right. Another restriction on this coordinate system is that u and v are real numbers ranging from 0 to 1 where 1 is 100% of the texture dimension. So the texture coordinates u=0.5, v=0.5 will return the center pixel in a texture.

Okay to attaching this texture to an object defined by a set of vertices in world space, we need to add a piece of information to each vertex: the texture coordinate of that vertex in respect to the texture. So for any two vertices, the API will sample the color values of the texture between the texture coordinates specified for each vertex.  At any point in the object it will have a texture coordinate, to calculate what pixel to use in the image as the color reference is simple. The pixel coordinates x,y are simply calculated as such: x= round(u*(textureWidth-1)), y= round(v*(textureHeight-1)).  Simple huh?

In the above image we want to use the entire texture for the quad and so specify the u,v coordinates accordingly. We also show the corresponding pixel coordinates for a point on the object with u,v coordinates: (0.2,0.3). Okay so that an idiots guide to texturing theory. Let’s dig into the code.

The first thing we need to do is take tutorial 2 and modify it for texturing. We remove the rotation for the triangle and add an extra vertex to generate a quad as in the below image:

image2

The code for the quad is:

v[0] = vertex( D3DXVECTOR3(-1,-1,0), D3DXVECTOR4(1,0,0,1));
v[1] = vertex( D3DXVECTOR3(-1,1,0), D3DXVECTOR4(0,1,0,1));
v[2] = vertex( D3DXVECTOR3(1,-1,0), D3DXVECTOR4(0,0,1,1));
v[3] = vertex( D3DXVECTOR3(1,1,0), D3DXVECTOR4(1,1,0,1));

Loading the Textures

So let’s load our textures, our first step is setting up storage for our textures and a way to pass it through to the shader program:

std::vector<ID3D10ShaderResourceView*> textureSRV;
ID3D10EffectShaderResourceVariable* pTextureSR;

Textures are loaded as ID3D10 resources, to which you need to create a view; a view tells DX how to access a particular resource. Since a texture is a shader resource that’s the type of view we need. The second variable is how we pass the texture id to the HLSL shaders.

So how do we load a texture from an image file? Well if you thought it would be a complicated and involved process you’re wrong, it’s a single function call (D3DX10CreateShaderResourceViewFromFile), and the code to load multiple textures into our texture storage is below.

vector<string> filenames;
filenames.push_back("textures/t1.bmp");
filenames.push_back("textures/t2.bmp");
filenames.push_back("textures/t3.bmp");

//load textures
for ( int i=0; i < (int) filenames.size(); i++ )
{
	textureSRV.push_back(NULL);

	if ( FAILED( D3DX10CreateShaderResourceViewFromFile( pD3DDevice, filenames[i].c_str(), NULL, NULL, &textureSRV[i], NULL ) ) )
	{
		  char err[255];
		  sprintf_s(err, "Could not load texture: %s!", filenames[i].c_str());
		  return fatalError( err );
	}
}

That function merges two steps, the creation of the texture and the resulting view to it, in one. Okay so now we’ve loaded the texture now what? Well we need to modify our vertex struct to support texture coordinates, texture coordinates have two dimensions, u and v, horizontal and vertical respectively. To attach a texture to a polygon you need to specify what part of the texture you want to put over the polygon.

struct vertex
{
	D3DXVECTOR3 pos;
	D3DXVECTOR4 color;
	D3DXVECTOR2 texCoord;
}

We use a 2d vector to specify the u,v coordinates for each vertex. So this also means the code for the qaud has changed to:

v[0] = vertex( D3DXVECTOR3(-1,-1,0),D3DXVECTOR4(1,0,0,1),D3DXVECTOR2(0.0f, 1.0f) );
v[1] = vertex( D3DXVECTOR3(-1,1,0),D3DXVECTOR4(0,1,0,1),D3DXVECTOR2(0.0f, 0.0f) );
v[2] = vertex( D3DXVECTOR3(1,-1,0),D3DXVECTOR4(0,0,1,1),D3DXVECTOR2(1.0f, 1.0f) );
v[3] = vertex( D3DXVECTOR3(1,1,0),D3DXVECTOR4(1,1,0,1),D3DXVECTOR2(1.0f, 0.0f) );

Since we changed the vertex struct we also need to modify the inputlayout accordingly, remember that the input layout tells DX what each vertex looks like. All we need to change is the input_element_desc for the input layout:

D3D10_INPUT_ELEMENT_DESC layout[] =
{
	{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
	{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0 },
	{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 28, D3D10_INPUT_PER_VERTEX_DATA, 0 }
};

Last step is to tell the API which texture to which just before we draw an object. Since in most basic cases we will only be using a single texture (multi-texturing comes later)  we only need a single texture shader resource variable which we just update to the texture we want.

//set texture
pTextureSR->SetResource( textureSRV[textureIndex] );

Okay so now if we run the program we get… The exact same thing as before. Why?! Well this is obvious since we havent touched the pixel shader program at all.

Texturing using the Pixel Shader

So lets just tweak the shader program (basicEffect.fx), first thing we need to do is specify a texture variable for the shader as such:

Texture2D tex2D;

Then we create a samplerState, remember when I said earlier that we sample the texture to get a color at a specific set of u,v coordinates, a texture resource resource in HLSL has a sample method that samples that texture and returns the value at a specific point, now the way in which it sample that texture is done via the sampleState object. This object sets all the parameters for the default sampler. A very basic samplerState is show below:

SamplerState linearSampler
{
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = Wrap;
    AddressV = Wrap;
};

It has three elements: a filter which specifies how the sampling is to be done over the texture, in our case we’re just doing a basic linear sampling (all the sampling states and their descriptions are available in the SDK docs, the addressU and addressV specify how to handle u and v values that lie outside the 0 to 1 range.

Remember how I said that u and v are in the range 0 to 1, well that’s not exactly true, sometimes to want to texture an object using 4 smaller versions of a texture rather than stretching the texture to fit the the object. The below image shows what happens for a few common addressU , addressV values:

image31

There are other state variables for the samplerState object, once again all the info necessary is in the sdk docs.

Now we need to modify the vs_input and ps_input structs to handle the extra 2d texcoord variable:

struct VS_INPUT
{
	float4 Pos : POSITION;
	float4 Color : COLOR;
	float2 Tex : TEXCOORD;
};

struct PS_INPUT
{
	float4 Pos : SV_POSITION;
	float4 Color : COLOR;
	float2 Tex : TEXCOORD;
};

And the vector and pixel shaders accordingly. The only difference in the pixel shader is that for texturing we need to return the sampled color and not the vertex color. We use the sample method on the texture object , the sampler state we defined earlier and the texture coordinates we specified earlier.

PS_INPUT VS( VS_INPUT input )
{
	PS_INPUT output;
	output.Pos = mul( input.Pos, World );
	output.Pos = mul( output.Pos, View );
	output.Pos = mul( output.Pos, Projection );
	output.Color = input.Color;
	output.Tex = input.Tex;

	return output;
}

float4 textured( PS_INPUT input ) : SV_Target
{
	return tex2D.Sample( linearSampler, input.Tex );
}

float4 noTexture( PS_INPUT input ) : SV_Target
{
	return input.Color;
}

We also create two new techniques “full” and “texturing disabled”:

technique10 full
{
    pass P0
    {
        SetVertexShader( CompileShader( vs_4_0, VS() ) );
        SetGeometryShader( NULL );
        SetPixelShader( CompileShader( ps_4_0, textured() ) );
    }
}

technique10 texturingDisabled
{
    pass P0
    {
        SetVertexShader( CompileShader( vs_4_0, VS() ) );
        SetGeometryShader( NULL );
        SetPixelShader( CompileShader( ps_4_0, noTexture() ) );
    }
}

Then we load these two techniques exactly as we did in the previous tutorial. If we compile and run the program we’re presented with a now textured quad.

image4

If we change the texture co-ordinates to :

v[0] = vertex( D3DXVECTOR3(-1,-1,0), D3DXVECTOR4(1,0,0,1), D3DXVECTOR2(0.0f, 2.0f) );
v[1] = vertex( D3DXVECTOR3(-1,1,0), D3DXVECTOR4(0,1,0,1), D3DXVECTOR2(0.0f, 0.0f) );
v[2] = vertex( D3DXVECTOR3(1,-1,0), D3DXVECTOR4(0,0,1,1), D3DXVECTOR2(2.0f, 2.0f) );
v[3] = vertex( D3DXVECTOR3(1,1,0), D3DXVECTOR4(1,1,0,1), D3DXVECTOR2(2.0f, 0.0f) );

The result is this:

image5

You can download the source code for this tutorial below. In the code you’ll notice that I add a method to swap the texture on the quad by modifying the textureIndex when I set the texture and to disable texturing by using the “texturingDisabled” technique instead of “Full”. Take a look at the wndProc method to see the controls and how they work.

I hope you’ve enjoyed this tutorial, I’ve already started working on the 4th one which will be about meshes and index buffers. I’m going to slowly write the turorials and build upon each one towards the final goal of rendering a field of thousands of blades of waving grass. I feel its pretty pointless to show you all the section seperately without explaining how they all link up together.

Source Code

Download the visual studio 2008 project: dxTutorial3.zip

29 November 2008 Posted by Bobby | DirectX 10, DirectX 10 Tutorials, Game Development, General, Graphics Programming, HLSL, Programming | , , , , , , , , | 6 Comments

DirectX 10 Tutorial 2: Basic Primitive Rendering

Okay I managed to find sometime and wrote a very basic second tutorial that introduces the main concepts behind primitive rendering in DX10. This tutorial builds upon the base code of tutorial 1 so check that out if you haven’t already.

Also I need to mention that I’m not writing these tutorials for complete beginners, I expect you to at least have a very basic understanding of graphics programming and the terminology involved. I’m not going to go into a lot of detail regarding terms like culling, rasterizing, fragments etc.

One last aside before the tutorial, what makes DX10 different to DX and openGL 2.0 is the removal of the fixed function pipeline. Now what the hell does that all mean? Well in directx9 and openGL, they had default ways of handling vertices, colors, texture co-ordinates etc. You’d pass through a vertex and a color and it would know what to do. It also handled lighting and other effects. In DX10 these defaults were removed and the core API has been simplified and reduced, this allows you to have full control over each pipeline stage and removes any past limitation on number of light sources and so on, but it has a major downside, the complexity and difficulty has now increased.

If we take lighting for example, before a hobbyist could enable lighting with a few function calls and would get a satisfactory result now for the same effect, the hobbyist would have to write pixel and vertex shaders using the phong (or other) equations to manually calculate the effect of lighting.

Basic Rendering and first steps into HLSL

Okay enough of that, let’s dig in. To render something there are several steps we need to take:

  1. Generate the vertices
  2. Send the vertices to the pipeline
  3. Apply any transformations need to the vertices (vertex shader)
  4. Set the vertex color (pixel shader)

Seems pretty simple? If only. The first addition to the code is the loading of an HLSL (high level shader language) effect file; this file will define the vertex and pixel shaders we will be using. The contents of the effect file are:

matrix World;
matrix View;
matrix Projection;

struct PS_INPUT
{
	float4 Pos : SV_POSITION;
	float4 Color : COLOR0;
};

PS_INPUT VS( float4 Pos : POSITION, float4 Color : COLOR )
{
	PS_INPUT psInput;

	Pos = mul( Pos, World );
	Pos = mul( Pos, View );

	psInput.Pos = mul( Pos, Projection );
	psInput.Color = Color;

    return psInput;
}

float4 PS( PS_INPUT psInput ) : SV_Target
{
    return psInput.Color;
}

technique10 Render
{
    pass P0
    {
        SetVertexShader( CompileShader( vs_4_0, VS() ) );
        SetGeometryShader( NULL );
        SetPixelShader( CompileShader( ps_4_0, PS() ) );
    }
}

Its pretty simple, the vertex shader applies the matrix transformation by multiplying the vertex by the world, view and projection matrices we’ve declared in the file, and then it sends the tansformed vertex to the pixel shader which simply returns the color to the rasterizer, which draws it out on our frame.

We also define a Render technique which specifies which pixel/vertex shader programs we need to run for it. The effect file can contain multiple pixel/vertex shaders functions and techniques. Each technique can also feature multiple passes.

Loading the HLSL Effect File

Now to load the effect file we do the following:

if ( FAILED( D3DX10CreateEffectFromFile(  	"basicEffect.fx",
											NULL,
											NULL,
											"fx_4_0",
											D3D10_SHADER_ENABLE_STRICTNESS,
											0,
											pD3DDevice
											NULL, NULL,
											&pBasicEffect,
											NULL, NULL  ) ) ) return fatalError("Could not load effect file!");

pBasicTechnique = pBasicEffect->GetTechniqueByName("Render");

//create matrix effect pointers
pViewMatrixEffectVariable = pBasicEffect->GetVariableByName( "View" )->AsMatrix();
pProjectionMatrixEffectVariable = pBasicEffect->GetVariableByName( "Projection" )->AsMatrix();
pWorldMatrixEffectVariable = pBasicEffect->GetVariableByName( "World" )->AsMatrix();

What the above code does is load the effect file and creates an effect from it, it compiles the effect file on load, so any syntax errors in the file will cause this step to fail, so catching the error here is extremely important!

Then we create a pointer to the “Render()” technique defined in the file. This technique is what we will use for rendering, it defines what the pixel and vertex shader will do for any vertices pumped into the pipeline.

The last steps are to set up pointers to the effect matrix variables we declared in the effect file so we can update them during runtime. HLSL variables aren’t limited to just matrices, and there are lots of things you can achieve using HLSL but I’ll leave that research up to you!

So now we’ve loaded the effect file which defines the vertex and pixel shader parts of the pipeline, so now let’s deal with the input assembly stage. We define a basic vertex struct as follows:

struct vertex
{
      D3DXVECTOR3 pos;
      D3DXVECTOR4 color;

      vertex( D3DXVECTOR3 p, D3DXVECTOR4 c ) : pos(p), color(c) {}
};

Now we need to tell DX10 and more specifically the technique how to handle this vertex type, this is done via an InputLayout. First thing we do is fill out an input element desc structure. This defines the format of the vertex. The parameters are present in the SDK docs, but the important one is the byte offset parameter, as you will notice for the second structure the offset is 12 since the first element consists of 3 4byte variables.

D3D10_INPUT_ELEMENT_DESC layout[] =
{
	{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT,0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
	{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT,0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0 }
};

The next step is getting the description of the pass and creating the input layout. Since each pass in a technique will take in the same input format, we just get the first pass in the technique and use that to create the input layout. Once the layout is created we set it as the active input layout. This is important since you may need to process multiple types of vertices and may need to swap input layouts as needed.

UINT numElements = 2;
D3D10_PASS_DESC PassDesc;
pBasicTechnique->GetPassByIndex( 0 )->GetDesc( &PassDesc );

if ( FAILED( pD3DDevice->CreateInputLayout( layout,
											numElements,
											PassDesc.pIAInputSignature,
											PassDesc.IAInputSignatureSize,
											&pVertexLayout ) ) ) return fatalError("Could not create Input Layout!");

// Set the input layout
pD3DDevice->IASetInputLayout( pVertexLayout );

Vertex Buffers

Phew, nearly done with the initialization, the last major thing we need to do is create the vertex buffer. The vertex buffer is a buffer that stores vertices before pumping them through to the video card, think of it as a waiting line for a carnival ride, people queue up until the ride is ready and then they get on, while the ride is busy, more people will queue up and so on.

There are several ways to efficiently use the vertex buffers, one of which is using the map function with the D3D10_MAP_WRITE_DISCARD flag but that’s something I’ll get to later.

So let’s create the vertex buffer. As expected the first step is filling out a DESC structure, the important parameters are the usage parameter which specifics what type of buffer to create, we want to be able to update it during runtime so we make it a dynamic buffer, and the CPUaccessFlag which specifies the type of access the CPU is granted to the buffer, again since we wish to update it during runtime, we allow writing by the CPU.

Then we create the vertex buffer and set the Input Assembler to use it. The parameters and their descriptions are once again found in the SDK documentation.

//create vertex buffer (space for 100 vertices)
//---------------------------------------------

UINT numVertices = 100;

D3D10_BUFFER_DESC bd;
bd.Usage = D3D10_USAGE_DYNAMIC;
bd.ByteWidth = sizeof( vertex ) * numVertices;
bd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
bd.MiscFlags = 0;

if ( FAILED( pD3DDevice->CreateBuffer( &bd, NULL, &pVertexBuffer ) ) ) return fatalError("Could not create vertex buffer!");;

// Set vertex buffer
UINT stride = sizeof( vertex );
UINT offset = 0;
pD3DDevice->IASetVertexBuffers( 0, 1, &pVertexBuffer, &stride, &offset );

Setting up the Rasterizer

In my example I render a spinning triangle, but by default DX10 enables backface culling, this results in my triangle being visible only half the time so I want to disable that, since culling occurs during the rasterizer stage I need to create a custom rasterizer state and set the pipeline to use that:

D3D10_RASTERIZER_DESC rasterizerState;
rasterizerState.CullMode = D3D10_CULL_NONE;
rasterizerState.FillMode = D3D10_FILL_SOLID;
rasterizerState.FrontCounterClockwise = true;
rasterizerState.DepthBias = false;
rasterizerState.DepthBiasClamp = 0;
rasterizerState.SlopeScaledDepthBias = 0;
rasterizerState.DepthClipEnable = true;
rasterizerState.ScissorEnable = false;
rasterizerState.MultisampleEnable = false;
rasterizerState.AntialiasedLineEnable = true;

ID3D10RasterizerState* pRS;
pD3DDevice->CreateRasterizerState( &rasterizerState, &pRS);
pD3DDevice->RSSetState(pRS);

NOTE: you may have noticed that all the d3d device function are preceded by a label for which stage of the pipeline they affect, pretty nice of the developers to do that :P

Okay wow, we’ve gone through a lot just to set up the pipeline to render, and we havent even rendered anything yet. Jeez! I’m sure you openGL kids are screaming murder at this point, and I agree it is a bit more effort but to be honest after working in DX10 for the last couple of weeks I cant even imagine going back to openGL, while openGL might require less code, its so much messier.

Meet the Matrices

Damn I got side tracked, onto the rendering, first step lets create a world matrix, this defines the position and orientation of the object in the world, at a later stage every object in our scene will have its own world matrix.

//create world matrix
static float r;
D3DXMATRIX w;
D3DXMatrixIdentity(&w);
D3DXMatrixRotationY(&w, r);
r += 0.001f;

then we update the effect variables, using the pointers we created earlier

//set effect matrices
pWorldMatrixEffectVariable->SetMatrix(w);
pViewMatrixEffectVariable->SetMatrix(viewMatrix);
pProjectionMatrixEffectVariable->SetMatrix(projectionMatrix);

Filling the Vertex Buffer

Now the meat and potatoes of the whole tutorial, updating the vertex buffer. The first we do is lock the buffer, this allows us to safely write to the buffer without worrying about having any vertices being sent down the pipeline while we’re busy updating.

This function returns a pointer to the block of memory storing the vertex data. I’ve used a “discard” flag, which simply means that any previous data in the buffer must get discarded, if the buffer was busy being used to feed vertices into the pipeline, the map call will return a pointer to a new empty block of memory and discard the previous block once its finished being used. There are various other flags that I’ll probably cover in later tutorials but for now lets leave it at that.

Using our return pointer we set three vertices. We then unlock the buffer.

//fill vertex buffer with vertices
UINT numVertices = 3;
vertex* v = NULL;

//lock vertex buffer for CPU use
pVertexBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**) &v );

v[0] = vertex( D3DXVECTOR3(-1,-1,0), D3DXVECTOR4(1,0,0,1) );
v[1] = vertex( D3DXVECTOR3(0,1,0), D3DXVECTOR4(0,1,0,1) );
v[2] = vertex( D3DXVECTOR3(1,-1,0), D3DXVECTOR4(0,0,1,1) );

pVertexBuffer->Unmap();

Input Assembly

The next step is telling the Input Assembly what type of primitive we’re drawing using the set topology function.

// Set primitive topology
pD3DDevice->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP );

Finally using our technique pointer we get a Description of it and then process all the passes present in the technique. For each pass, we send through the vertices present in the vertex buffer using the draw command specify the number of vertices to draw and the start index in the vertex buffer.

Drawing the scene (finally) ;)

DX10 can only have one active vertex buffer at a time so if you have multiple buffers remember to load the correct one before you do any draw calls. The fact that there is an offset hints that you can store multiple objects in a single buffer and then draw them all using mutiple consecutive draw calls.

//get technique desc
D3D10_TECHNIQUE_DESC techDesc;
pBasicTechnique->GetDesc( &techDesc );

for( UINT p = 0; p < techDesc.Passes; ++p )
{
      //apply technique
      pBasicTechnique->GetPassByIndex( p )->Apply( 0 );

      //draw
      pD3DDevice->Draw( numVertices, 0 );
}

So that’s it, we’ve reached the end of the second tutorial, we’ve covered a lot of ground and I apologize that I haven’t gone too in depth regarding the functions and their parameters but I don’t have the time right now for in depth tutorials and I feel that a little bit of research and self study would be more beneficial than me spoon feeding you in these tutorials.

Tutorial 2

I’m actually hoping that these tutorials may serve as just a reference for your own code or just give you ideas and insight for your own projects.

Source Code

The source code and VS2k8 project for the tutorial can be found here: tutorial2.zip

2 September 2008 Posted by Bobby | DirectX 10, DirectX 10 Tutorials, Game Development, Graphics Programming, HLSL, Programming | , , , , , , | 5 Comments

DirectX 10 Tutorial 1: Setting up the D3D10 device

Introduction

So if you read my review of Wendy Jones’ book, you know my feelings on the state of DX10 tutorials and books, I want to try and maybe help some people out with tutorials in getting started with DX10, I am by no means an expert and the tutorials will basically cover everything that I’ve learnt so far. They will not be rehashes of the SDK tutorials nor Wendy Jones’ book. I’m hoping to slowly build up a dxManager wrapper class that can be easily used for some basic D3D apps. So let’s get started with the most basic topic: setting up the D3D device for drawing.

Note: The DX10 SDK tutorials are excellent, they are a must read and my early tutorials will be a concatenation of the information found in them!

Win32

The entry point of most 3D tutorials is win32 and so I’m not going to rewrite all those tutorials. If you want an excellent win32 tutorial Google forger’s win32 tutorials, they are the best I’ve found. Basically a simple win32 window consists of two things: the window and the window processing function (acts as an event handler). Inside of the tutorial project I’ve attached you’ll see three functions that create a window: the winMain function, the initialize window function and the wndProc, the functions are very basic and so I’m not going to go into any more detail. There are plenty of tutorials available online if you want more detail on win32.

dxManager

Before I start with the directX initialization stuff, I just want to cover something: the dxManager class. Most tutorials you’ll find will have the directX variables as global with a few global functions in a single file to render a simple triangle. Even Wendy Jones does so in her book, but I’m not, simply because it’s a terrible practice, its messy, inextensible and just plain silly. I’m going to instead create a dxManager class to wrap all my directX functions and just neaten things up.

In later tutorials you’ll see the justification for this more clearly. Enough of me prattling on, let’s dig in.

3D basics

Okay let just cover some very basic concepts about 3D graphics, the graphics API (directX/openGL) is what you’ll use to draw your objects out to the screen. The API is basically a layer that sits between your graphics card and you, you tell the layer what to do and the layer then tells the card.

The card makes use of a pipeline structure to display objects, I’m not going to go into the justifications about this since Google is your friend. Basically there a few key stages (their names differ across APIs), below is a diagram of the stages in DX10 followed by a brief description (taken from the SDK docs):

  • Input-Assembler Stage - The input-assembler stage is responsible for supplying data (triangles, lines and points) to the pipeline.
  • Vertex-Shader Stage – The vertex-shader stage processes vertices, typically performing operations such as transformations, skinning, and lighting. A vertex shader always takes a single input vertex and produces a single output vertex.
  • Geometry-Shader Stage - The geometry-shader stage processes entire primitives. Its input is a full primitive (which is three vertices for a triangle, two vertices for a line, or a single vertex for a point). In addition, each primitive can also include the vertex data for any edge-adjacent primitives. This could include at most an additional three vertices for a triangle or an additional two vertices for a line. The Geometry Shader also supports limited geometry amplification and de-amplification. Given an input primitive, the Geometry Shader can discard the primitive, or emit one or more new primitives.
  • Stream-Output Stage – The stream-output stage is designed for streaming primitive data from the pipeline to memory on its way to the rasterizer. Data can be streamed out and/or passed into the rasterizer. Data streamed out to memory can be recirculated back into the pipeline as input data or read-back from the CPU.
  • Rasterizer Stage - The rasterizer is responsible for clipping primitives, preparing primitives for the pixel shader and determining how to invoke pixel shaders.
  • Pixel-Shader Stage – The pixel-shader stage receives interpolated data for a primitive and generates per-pixel data such as color.
  • Output-Merger Stage - The output-merger stage is responsible for combining various types of output data (pixel shader values, depth and stencil information) with the contents of the render target and depth/stencil buffers to generate the final pipeline result.

The aim of this tutorial is to set up the D3D device to be ready for later tutorials. We will set up the swap chain, the D3D device, the render target, the viewport and finally just set up a view and projection matrix for the future.

The SwapChain and the D3D device

This is what is written in the SDK regarding the swapchain: “An IDXGISwapChain interface implements one or more surfaces for storing rendered data before presenting it to an output.” What this basically means is that you will set up a few “frames” or “buffers” to which you will draw and then swap out when you’re finished drawing. This is how you enable double or triple buffering in DX10.

Once we’ve set up our swapchain we create a D3D device with that swapchain, pretty simple.

To achieve this we need to fill out a DXGI_SWAP_CHAIN_DESC structure and then call D3D10CreateDeviceAndSwapChain to create our swap chain and our D3D device. The function parameters are in the SDK docs and I’m not going to describe what each one does since I’m pretty sure you can read it yourself. You will need pointers to both a swap chain interface and a D3D device interface. Here’s the code to set up and create the swap chain and D3D device.


//Set up DX swap chain
//--------------------------------------------------------------

DXGI_SWAP_CHAIN_DESC swapChainDesc;
ZeroMemory(&swapChainDesc, sizeof(swapChainDesc));

//set buffer dimensions and format
swapChainDesc.BufferCount = 2;
swapChainDesc.BufferDesc.Width = width;
swapChainDesc.BufferDesc.Height = height;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;;

//set refresh rate
swapChainDesc.BufferDesc.RefreshRate.Numerator = 60;
swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;

//sampling settings
swapChainDesc.SampleDesc.Quality = 0;
swapChainDesc.SampleDesc.Count = 1;

//output window handle
swapChainDesc.OutputWindow = *hWnd;
swapChainDesc.Windowed = true;

//Create the D3D device
//--------------------------------------------------------------

if ( FAILED( D3D10CreateDeviceAndSwapChain(	NULL,
											D3D10_DRIVER_TYPE_HARDWARE,
											NULL,
											0,
											D3D10_SDK_VERSION,
											&swapChainDesc,
											&pSwapChain,
											&pD3DDevice ) ) ) return fatalError("D3D device creation failed");

The RenderTarget

The render target describes what the format of output of the output merger stage will be. This output format is the same the format of the swapchain buffers. So what we need to do is get all the details from the swapchain about its buffer format and use that to create a render target.

//Create render target view
//--------------------------------------------------------------

//try to get the back buffer
ID3D10Texture2D* pBackBuffer;

if ( FAILED( pSwapChain->GetBuffer(0, __uuidof(ID3D10Texture2D), (LPVOID*)&pBackBuffer) ) ) return fatalError("Could not get back buffer");

//try to create render target view
if ( FAILED( pD3DDevice->CreateRenderTargetView(pBackBuffer, NULL, &pRenderTargetView) ) ) return fatalError("Could not create render target view");

//release the back buffer
pBackBuffer->Release();

//set the render target
pD3DDevice->OMSetRenderTargets(1, &pRenderTargetView, NULL);

Note: Something that should be mentioned here is the “Release” call, basically all resources are semi-managed, basically resources are only freed once nothing is using them, whenever a resource is used an internal counter is incremented (semaphore) , once something doesn’t need the resource any more the counter is decremented. Once this counter reaches 0, the resource is freed. Here we don’t need the pBackBuffer resource any longer so we release it, if nothing else is using it then the resource is freed.

The Viewport

The viewport converts vertex positions to render target positions; this is the key step in the rasterizer stage. Creating this structure is really simple, it basically takes the height and width of your window and the starting positions of the window (usually 0 and 0). The depth variables should be set to 0 and 1 for min and max respectively. Once you have multiple viewports this will change but don’t worry about that for now.

//create viewport structure
viewPort.Width = width;
viewPort.Height = height;
viewPort.MinDepth = 0.0f;
viewPort.MaxDepth = 1.0f;
viewPort.TopLeftX = 0;
viewPort.TopLeftY = 0;

//set the viewport
pD3DDevice->RSSetViewports(1, &viewPort);

The View and Projection Matrices

Okay now we’re nearly done, the last thing we need to set up is the view and projection matrices. The view matrix basically positions and orients the camera in the scene. The matrix usage and transformations will be covered in the next tutorial.

The projection matrix basically defines the range of the view from the camera. This is explained extremely well in the 4th tutorial in the SDK docs! I really suggest reading it. It can also apply perspective to the scene; this basically allows near objects to be large and far objects to be small. In our case we’re going to set up a basic perspective projection with a view angle of 45 degrees and a max depth of 100 units. The near depth must not be set to 0, I will explain why in a later tutorial regarding picking and unprojecting co-ordinates.

// Set up the view matrix
//--------------------------------------------------------------

D3DXVECTOR3 eye(0.0f, 0.0f, -5.0f);
D3DXVECTOR3 view(0.0f, 0.0f, 1.0f);
D3DXVECTOR3 up(0.0f, 1.0f, 0.0f));

D3DXMatrixLookAtLH( &viewMatrix, eye, view, up );

//Set up projection matrix
//--------------------------------------------------------------
D3DXMatrixPerspectiveFovLH(&projectionMatrix, (float)D3DX_PI * 0.5f, (float)width/height, 0.1f, 100.0f);

Rendering of the Scene

Okay so we’ve set up our D3D device, let just output something. Unfortuneatly in DX10 doing that isnt all that simple and there are several more stage we need to do before we can proceed. So for now lets just clear the screen and flip the buffers.


//clear scene
pD3DDevice->ClearRenderTargetView( pRenderTargetView, D3DXCOLOR(0,0,0,0) );

//SCENE RENDERING GOES HERE!!!

//flip buffers
pSwapChain->Present(0,0);

Conclusion

So that’s it for my first tutorial! I didn’t cover a lot of material but I’ve set up the base for the rest of the tutorials, and time-permitting I’ll put up several more in the coming weeks.

Source Code

Tutorial 1 VS2k8 project and Source Code: tutorial1.zip

31 August 2008 Posted by Bobby | DirectX 10, DirectX 10 Tutorials, Game Development, General, Graphics Programming, Programming | , , , | 19 Comments

DPT and Mod Progress…

Okay, its been a really busy week, i’ve been working on the DPT stuff during the day and my evenings have been working on the design doc for our game mod. I’ve completed a rough version of the dpt program but there are still some issues with it, i think the problem is with the algorithm and not the implementation. I need to have it completed before friday so i’ll stressing a little bit… I’m gonna meet with my dad tomorrow and discuss it and hopefully we can figure out whats going on…

As for my game mod, i’ve finally started on the design document for it, it a very rough badly written version but its enough to give to the writer and have her strat on an actual little episode storyline, once that is done we can actually start implementing it. I’ve got a rough idea for the game rule system but the control scheme we had envisioned would probably prove troublesome, so i’ll need to work out some of the kinks. Hopefully i can provide something a bit more solid soon.

 I’m going put the link to the design document here so you see what i’ve done so far…

here it is: Game Design Document Initial pre-alpha Version (please be gently with it, haha)

 anyways i’ve been working for over 8 hours straight now and i’m starting to lose it so i’m off home to pass out…

12 December 2007 Posted by Bobby | Game Design, Game Development, Gaming, General, Hardware | | No Comments Yet