Sunday, April 27, 2008

I set dependencies on visual studio projects frequently. Here is some macro code that simplifies that process.

At the last 2 studios I joined one of the first things I did was to make an "All" solution. A single visual studio solution containing all projects required to build the game (or in Gamebryo's case, engine, samples, & tools).

A nice big solution like that needs to have dependencies set right. Visual Studio's interface for doing this is inefficient for anything but toy "solutions". But, they gave us macros, and it's easy to set dependencies with those.

Example solution file, with projects broken into logical groups

With these macros, you first select a group you would like to change the dependency information for. Run macro Step1. Then, select the group of projects that all the previous projects depend on. You'll then see this window:

Macro Dialog confirming dependencies about to be set.

Setting dozens or hundreds of project dependencies is a breeze with these macros.

Sub Step2_SelectDependeeProjects_AssignDependencies() 'DESCRIPTION: Step 2 of 2 for setting dependencies on projects If SelectedProjects Is Nothing Then MsgBox("You must first select projects to have dependencies set on, with SelectDependentProjects macro") Return End If

' Storage for list of projects: Public SelectedProjects As List(Of EnvDTE.Project)

' Helper functions: Function GetSelectedProjects() As List(Of EnvDTE.Project) Dim projs As List(Of EnvDTE.Project) = New List(Of EnvDTE.Project) For Each selectedItem As EnvDTE.SelectedItem In DTE.SelectedItems Try ' to get projects If Not selectedItem.Project Is Nothing Then If Not projs.Contains(selectedItem.Project) Then projs.Add(selectedItem.Project) End If End If Catch End Try Next Return projs End Function

Function GetStringOfEachProject(ByVal ProjectsList As List(Of EnvDTE.Project)) As String Dim OutputString As String = "" For Each proj As EnvDTE.Project In ProjectsList If OutputString.Length > 0 Then ' add new line OutputString += vbLf End If OutputString += " " + proj.Name Next Return OutputString End Function

Monday, April 21, 2008

Game Architect doesn't update often, but when Kyle posts it's worth the read.

Definitely read his GDC 2008 wrap up, and if you're into engines, read his thoughts on Day 1 Studio's Despair Engine.

I especially enjoyed the engine section on orthogonal hierarchies, a topic I've discussed with many before regarding scene graphs. He mentions that they've split what many have overloaded into a single scene graph into at least 5 hierarchies.

Saturday, April 12, 2008

Here's an article with a neat inline ASCII bar chart technique for spreadsheets.

So, you're a programmer, game designer, artist, producer, or... just about anyone. Chances are you've used Excel. You may even use it to look at data!

Look, here's some generic data (Fig. 1):Wouldn't it be much easier to look at with a chart? Why not build a chart right into the spreadsheet, along side the data (Fig. 2):

Note the bar graphs adjacent to the data columns from above

Real data may have 100s or 1,000s of rows, with several columns. Being able to skim through the spreadsheet and have the data graphically represented inline is often a big win for readability and locality.

The technique is simple. Excel has a formula to repeat a string several times. For the "Range" graph, the formula is just =REPT("#", D). This works out nicely because the values are integer and small.

The "Value" data takes just a bit more work, but is still trivial to write. Here I've used =REPT("|", F6*20), (Fig. 3)With just a bit more work, we can setup a nice general formula that can be tweaked for each data range, and is more robust. Also, setting the font of the graph to "Small Fonts" with a point size of 4 give us single pixel accuracy in our bar chart, see (Fig. 4).

Note the broken bar indicating overflow for the first 2 lines,the easily configurable min max range,and the single pixel accuracy of the bars.

Each row of the bar chart uses the formula:=LEFT(CONCATENATE(REPT("|",E$57-1),">"),MAX(0,(D34-E$53)/(E$55-E$53)*E$57))

Let me break it down:

I'm going to substitute names instead of cell references, so it's easier to follow along:(If you don't know about them, try selecting a cell and using Insert/Name/Define and Insert/Name/Apply some time. But, it's out of the scope of this article)

Ok, the formula is then:=LEFT(CONCATENATE(REPT("|",Chars-1),">"),MAX(0,(DataValue-Min)/(Max-Min)*Chars))

First, we want to map the data values between Min and Max to appear on the bar chart, so we normalize to 0-1 range:=LEFT(CONCATENATE(REPT("|",Chars-1),">"),MAX(0,(DataValue-Min)/(Max-Min)*Chars))

Then, multiply by the max number of characters we want a bar chart line to have:=LEFT(CONCATENATE(REPT("|",Chars-1),">"),MAX(0,(DataValue-Min)/(Max-Min)*Chars))

Then, we want to clamp to positive numbers only, so that data values less than our minimum value don't break our graph:=LEFT(CONCATENATE(REPT("|",Chars-1),">"),MAX(0,(DataValue-Min)/(Max-Min)*Chars))

That gives us the number of characters to display. But, we would like to visually show when the data values are larger than the bar chart can show. So, instead of taking the number so far and giving it to REPT, we give it to LEFT. Left will take N characters from a string, and we'll terminate that string with a > symbol to show that the graph is maxing out. The equation could be as such:=LEFT("|||||||||||||||||||||||||||||>",MAX(0,(DataValue-Min)/(Max-Min)*Chars))

But, hard-coding the number of characters on the graph is a draw back. We want to be able to copy and paste this solution around, and scale the graph up as needed. So, we use REPT to generate the |||||||| characters, and concatenate with the final >=LEFT(CONCATENATE(REPT("|",Chars-1),">"),MAX(0,(DataValue-Min)/(Max-Min)*Chars))

The controls for the graph can be put in the column of the graph above or below the data. We can easily have several columns of bar charts, each with tunable parameters.

I use this technique frequently, I hope you keep it in mind (at least the simple version) the next time you're trolling over data in Excel.

Sunday, April 6, 2008

Cinematic shots in movies and television shows use depth of field frequently. Decorative point lights in the background pushed out of focus are a familiar image. You can try it when your out at lunch by ordering a cola, and blurring your vision as you stare at the ice cubes. The bright highlights will blossom out.

The Playstation 2 had excellent fill rate, enabling the over use of blur in many games. Combined with masking or thresholding, this was were we saw the mass emergence of (cheap) high dynamic range effects in games. Though, the "high" in this case wasn't very high, and most of the effect was just the blur.

Those blurs were typically a separable Gaussian blur, for performance reasons. The separable blur is just a horizontal then vertical blur, O(n) instead of O(n^2) for a general case 2D blur.

A Gaussian blur, however, is not the effect created when a point light is out of focus in a camera. The proper convolution varies a bit from camera to camera, but here is an example taken with my SLR:

This shape is primarily a constant intensity circle, with diffusion ringing near the edges. High quality cinematic cameras will also often show the aperture edges, however in my camera there was too much flaring to see these. Pay attention in a movie, however, and you're likely to see octagons instead of circles.

To illustrate a cross section of the intensity (hey, why not) I've done the following in Photoshop:

Unwrapped the image with polar coordinates:

Smoothed the image with a strong horizontal blur:

Added a gradient:

Applied a threshold:

The result is a graph where the center of the disk is at the top, and the outer edge at the bottom. The distance along the X axis indicates the intensity.

The diffraction ringing near the edge is clearly visible, with the center of the disk being approximately a constant intensity.

There is still some noise towards the top of the profile, which is from the center of the image. That is due to the noise that appeared there, and was not blurred by the horizontal blur. (It was stretched out when unwrapping the polar coordinates).

To render this effect on ~2008 era GPUs is a heavy weight operation. However, some games have done so, e.g. Lost Planet's port to DirectX. (Beyond 3D article) They had extra processing power to spend when porting from the Xbox 360 to DirectX 10 cards such as the GeForce 8800.

Instead of horizontally & vertically blurring the image, for each point a triangle is rendered to a small area with its intensity modulating a texture. For a single bright pixel, the result is a copy of the convolution texture around that point. (Read their article for details on scene segmentation and geometry shader usage.)

Here I've highlighted the effect in two Lost Planet images from www.4gamer.net (1 and 2). The top images show the standard Guassian blur, the bottom images show the texture effect.

Click image for larger view.Compare the blurry sparks on top
to the hexagon out of focus sparks on bottom.

Note they were able to increase the size of the blur with the texture effect, because it remained cinematic. That size of a Gaussian blur would just look muddy.

Try it at home: In Photoshop try opening up a image you have with small point lights, or just make one with a black background and a few small white dots. Give it a go with
Filter / Blur / Gaussian Blur and
Filter / Blur / Lens Blur.