You are currently browsing the CodeBot @ Work weblog archives for December, 2009.
- 3D Stuff (12)
- AI (1)
- BumpTop (5)
- C/C++ (22)
- Open Source (8)
- Radiant (11)
- Seneca (6)
- Stuff (17)
- The Mortal Realm (2)
- Uncategorized (14)
- win32 (12)
- July 9, 2010: On Visual Studio 2010...
- December 22, 2009: Efficient Rendering, A La Mark.
- December 3, 2009: A Simple Opponent
- December 3, 2009: Blog++
- September 7, 2009: Food Budgeting
- July 3, 2009: Too Busy...
- March 26, 2009: How Do Patents Apply To Me?
- February 27, 2009: U.S. And Human Rights
- February 7, 2009: I've Been Busy...
- November 10, 2008: Radiant Update
Archive for December 2009
Efficient Rendering, A La Mark.
December 22, 2009 by Mark.
Rendering efficiently is one of those topics that is widely spoken about in the world of 3D graphics. Asking a question like ‘What is the best way to render a bunch of Objects’ is as open ended as asking ‘What is the best way to cook chicken soup.’ It is all based on application and preference and in all likelihood, there is no universal answer to this question. However, there are a series of specific solutions to this problem that can help in creating a mechanism that is best for the particular situation.
My problem is rather generic and will require a generic solution. I have a bunch of objects that need to be sorted by certain criteria in order to minimize state changes. It has to also support Shaders (Cg in my case) and it should minimize Shader state change between object rendering. Furthermore, an object must be generic enough to support complex models with bones and animations. On top of that, it should be easy to use. To start, we might need to break this down into smaller parts.
Objects:
For the time being, lets refer to an Object as a list of vertices inside a vertex buffer. It may or may not be accompanied by an index buffer, but in most cases it will. This Object will be shuffled to the graphics card to be rendered for each Object that exists in our world. This is inevitable until we support something complex like hardware based instancing.
State Changes:
Unless you want all objects to be rendered in the same way, in the same spot, and with the same vertices, you probably want some sort of state change. A state change is a change in any part of the system, whether it is the position of the camera, a new Object to be drawn, or a new effect. To quantify a state change, it is best to organize it into the types of state changes: swapping Render Targets, Shaders, Technique, Shader parameters, and using a different vertex or index buffer to draw an object. The order of the state changes, as listed above, matters because the changes at the beginning of the list are the most expensive and the changes at the end of the list are least expensive.
The RenderGraphNode:
This is a generic interface to which many types of nodes will be derived from. Each derivation of the node will be the embodiment of the changes listed above. In addition to the state change, the node will also be a container for child nodes. Usually the node will be generic enough to contain any type of node. However, in our case, we want to preserve an order to our nodes so that we optimize the state changes. The root of our tree will be a change in Render Targets. For the most part, there will only be one Render Target, the backbuffer (our screen). When a child node is added, it will automatically be sorted into the correct place in order to minimize the state change. This is especially important for Shader parameter changes because there can be multiple parameters in one Shader.
The RenderGraph:
In order to encapsulate all this, I need a class that will be the owner of Render Targets. It will be the only thing passed into the Renderer for drawing. At that point it will traverse the tree and render.
Sounds simple right? Yeah, but something doesn’t feel good about this design.
If we leave the design at this point, we are left with a bunch of nodes in which the user has to put together. This design is acceptable by some. In fact, OpenSceneGraph uses such a design for its SceneGraph. It is a bunch of classes that fit together in a tree fashion. Throw in a Visitor pattern into the mix for easy iteration and you have an engine. I’m not quite as happy with that design as my OpenSceneGraph counterparts are. The problem is, in my eyes, that it’s very verbose. Putting together a simple scene with an airplane in it was quite lengthy. You have to add a GeometryNode to a TechniqueNode to a ShaderNode to a RenderingTarget, and so on.
So back to my original question, what is the best way to implement something like this? When I figure it out, I’ll write about it.
Posted in Radiant, 3D Stuff, C/C++, Stuff | No Comments »
A Simple Opponent
December 3, 2009 by Alex.
The current game project, “The Mortal Realm”, involves a battle system which is turn based and played on a hex grid. Thus, it requires an AI opponent. Currently, the outline of the AI mind is fairly simple.
Firstly, there is the long-term plan. This is achieved via a genetic algorithm. A computer player would have a number of units, up to ten, that can be fielded into a battle at any given time. The genetic algorithm determines the long-term goal of each unit. Note that, this does not determine the turn to turn actions of a unit. The general setup of this one goes like this:
a) The Solution Representation is, like most other genetic algorithms, an array, where each slot represents the long term goal of a unit. The long-term goals are typically actions such as “Take and Hold x Position” or “Set up Ambush at x Position” or “Charge recklessly at the enemy army”.
b) Mutations simply change a value of a long-term goal in a random slot inside a solution. For instance, slot 6 might be “Take and Hold x Position”. It could change to “Take and Hold y Position” or “Set up Ambush at x position”.
c) Crossover is a simple single point crossover. Choose a random slot, between 1-10, as the crossover point. The first child takes all the genes of the first parent before the crossover point and all the genes of the second parent after the crossover point.
As a simple explantion, the genetic algorithm works something like this. First, you have a population of solutions. In my case, that means I have a collection of arrays, each array representing a long-term battle plan. Each slot in an array is considered a gene, the long term plan for a single unit. The initial population is created at random, that is, the solutions I come up with are completely arbitrary. Then, I have a method, called the objective function, which calculates the value of a solution. This objective function takes into account the terrain, the position of enemy troops and also the particular arrangement of friendly troops. Noting that I have to take into account the arrangement of friendly troops, you cannot calculate the value of a gene independently because it changes based on what the other genes are. So now I have a population of randomly created “individuals” (solutions) and I have a way to calculate their fitness with my objective function (que Nazi references).
Next, you create the next generation of individuals. This is a stochastic process based on fitness. The more fit an individual is, the more likely it gets to reproduce. In order to create offspring, two individuals are selected at random, with a higher preference given to people who have higher fitness. They then create offspring via the crossover method. Two parents produce two children via crossover (ie. each child will somehow share the genes of its parents). After enough offspring is created for the next generation we then check if any will undergo a mutation. Unlike real-life, genetic algorithms do not allow mutations to produce non-viable offspring. A mutant is always viable. However, the rate of mutation is very low.
Now you have the next generation of offspring, some of which may have mutated. Then you decide which of the parents and offspring survive to make the next generation. Like before, it is a stochastic process where individuals are randomly chosen, with a preference toward higher fitness levels. Then once this is complete, you repeat the process.
Once you are done (it may take hundreds of generations to produce a good solution) you’ve proven evolution. Also, we have a long-term battle plan for the computer opponent. This battle plan shapes the turn to turn actions it takes with its units, as it tries to stick to the plan and also react to transient issues. Next post, I’ll talk about how the computer opponents determines its turn to turn actions for each unit.
-Alex
Posted in AI, The Mortal Realm, C/C++ | No Comments »
Blog++
December 3, 2009 by Mark.
I’m converting my blog to something a bit more useful. My long rants about my game engine were all leading towards a game of some sort. In the process I have recruited a friend to help me realize that dream. So, give a kind welcome to Alex.
Our first title will be a strategy turned-based war game by the name of ‘The Mortal Realm.’ It will feature my 3D engine and a robust battle system. As far as complexity goes, this game is one of the simplest we have come up with. It’s a simple point and click style of game with very minimal artwork. I’m hoping it will be a great test bed for my engine as well as Alex’s AI.
Posted in The Mortal Realm, Radiant, 3D Stuff, C/C++, Stuff | No Comments »