A few weeks ago, quite by accident I stumbled upon SoftTH. I always wanted to "triplehead" my system but I didn't want to spend a lot of money on an extra videocard to run them in SLI. Around the same time, a friend also gave me two old 19" Samsung monitors so this was the perfect time to try out triplehead through software. I bought a cheap used Geforce 7900 GS and got going with SoftTH.
SoftTH automagically creates a config file for you to use. It simply adds up the resolutions of your monitors and uses that as the total resolution for your game. And although this works and looks good, with just a little extra effort you can actually make it look a lot better!
Problem with the default approach
The problem with the standard approach is that it does not take into account the physical size of your monitors, nor does it take into account that your monitors have bezels. Let me try to explain that with a few images.
First, let's assume you have three monitors. Your primary monitor (the one in the middle) is 1920 pixels wide while the monitors on the left and right are both 1024 pixels wide (I've chosen such a big difference between the size of the monitors on purpose because it perfectly illustrates the problems you will encounter). What most people do (and what SoftTH does by default), is simply add up these three values. So the total width of your game's viewport would become 1920 + 1024 + 1024 = 3968 pixels.
This view is then split up and sent to your monitors as follows:
This works but there are a few problems with this approach. Suppose your three monitors look like this:
Even though your primary monitor has almost twice as much pixels horizontally than the monitors on the left and right (1920px vs 1024px), those monitors are almost the same width physically as your primary monitor. So how does it look when we superimpose the three parts of the main view on top of these monitors?
So even though the monitors on the left and right monitor are almost as wide as your primary monitor, they spread out 1024 pixels of the original image over this width while the center monitor spreads out 1920 pixels. This means that the image left and right will be stretched horizontally (quite a bit actually). Also, since the outer monitors are less high, the image is squashed vertically.
This is caused because the monitors have a different dot pitch (the primary monitor packs a lot more pixels per inch than the outer two monitors).
Another problem is that we don't take the bezels of each monitor into account. Let's use a simple image to illustrate this problem:
And for argument's sake, this time let's use three equally sized monitors and spread the image over these three monitors:
Looks weird, doesn't it? The red lines no longer look attached, and the green shapes look awefully distorted. That's what happens if you simply split the original image in three and render them as if the three screens had no bezels.
How we really want the image rendered, is like this:
Yes, parts of the image are now obscured by the bezels but that's exactly how it would be in real life, if we were looking through three windows.
So how do we do that? Well, that's not as hard as it looks.
The solution
So we actually have two problems. The first is that we might be using monitors that don't have the same dot pitch (dpi), And we want to take the monitors' bezels into account. If we get rid of these two problems, we end up with a perfect render.
Let's assume again we have three monitors. The primary (center) monitor has a resolution of 1920x1200 while the resolution of the outer monitors is 1024x768.
First of all, we need to consider all three screens as a single screen with the same dot pitch. Because we want the primary (center) monitor to have a pixel perfect image, we want to use the primary monitor's dot pitch for all three monitors. We can usually find the dot pitch of a monitor in its manual, but unfortunately this is usually rounded to the nearest (standard) dpi value and thus not very accurate. We actually will have to measure it ourselves.
In below example I measure in inches. But you can measure in centimeters instead if you like, it doesn't matter for the calculations.
So step 1 would be to measure the width of the primary monitor. Mind you, we need the width of the screen - not the monitor:
Let's say we measure 20 inch (or 51cm) while the screen has a horizontal resolution of 1920px. This means that the screen's dpi is 1920/20 = 96dpi.
In step 2, we need to measure the entire width of the viewport - so all three monitors including the bezels. Mind you, we musn't include the outer bezels:
Say we measured 54.5 inch. That means that if this was one big 54.5 inch wide monitor with 96 dpi, it would have 54.5 x 96 = 5232 pixels horizontally.
In step 3, we need to know the physical width (and height) of the outer monitors. Again, we need the actual screen width, not the entire monitor's width:
Suppose we measure 16 inch. This means that if this was a 96 dpi monitor, it would have a horizontal resolution of 16 x 96 = 1536 pixels. This is the monitor's virtual width.
We do the same thing for the height. Say we measure 12 inch. That means if this was a 96 dpi monitor, it would have a vertical resolution of 12 x 96 = 1152 pixels. This is the monitor's virtual height.
Since in this example both outer monitors are the same, we don't need to measure the second outer monitor (if you use different outer monitors, you will need to measure that monitor as well).
In step 4, we need to figure out the (virtual) width of the two bezels in pixels:
We can either measure them and multiply the measured width by the dpi (96), or if we are using identical outer monitors, we can calculate the width. Either way, we have to make sure that the total (virtual) width in pixels of all three monitors plus the width of the bezels (in pixels) equals the total width found in step 1.
So in this case, 1920 px + 1536 px + 1536 px + virtual width left bezel + virtual width right bezel must equal 5232 px. If you measured the bezels, this probably means you will have to add/substract a few pixels to the measured width to make sure it adds up to the right value.
Since we use identical outer monitors in this example, we can simply calculate the width of a bezel:
Bezel width = ( 5232 - (1920 + 1536 + 1536) ) / 2 = 120 px
Now we have everything we need to manually create a SoftTH config file (config.SoftTHconfig), and we put it all together in step 5:
A) Horizontal resolution primary monitor: 1920 px
B) Vertical resolution primary monitor: 1200 px
C) Width viewport: 5232 px (step 2)
D) Height viewport: 1200 px (vertical resolution primary monitor)
E) Virtual width left outer monitor: 1536 px (step 3)
F) Virtual height left outer monitor: 1152 px (step 3)
G) Virtual width right outer monitor: 1536 px (step 3)
H) Virtual height right outer monitor: 1152 px (step 3)
I) Virtual width bezel #1: 120 px (step 4)
J) Virtual width bezel #2 120 px (step 4)
So this is how we use these values in config.SoftTHconfig:
In section main:
[main] ; Use value C and D: renderResolution=5232x1200
In section head_1 (assuming that head_1 is your left monitor):
[head_1] devID=1 ; use values 0 (zero), 0 (zero), E and F: sourceRect=0,0,1536,1152 transportResolution=1536x1152
in section head_primary:
[head_primary] ; The primary (center) monitor doesn't start at 1536 (virtual width of left monitor), but 1536 + 120 (width of bezel #1) = 1656 ; Use values E + I, 0 (zero), A and B: sourceRect=1656,0,1920,1200 ; Use values A and B: screenMode=1920x1200
In section head_2 (assuming that head_2 is your right monitor):
[head_2] devID=2 ; The right monitor starts at 1536 (width left monitor) + 120 (width bezel #1) + 1920 (width center monitor) + 120 (width bezel #2) = 3696 ; use values E + I + A + J, 0 (zero), E and F: sourceRect=3696,0,1536,1152 transportResolution=1536x1152
And there you have it. A perfect render over three monitors.
Now I have made a few assumptions here. First of all, I made the assumption all three monitors are lined up at the top. If they are not, then you will need to measure the distance between the top of the primary monitor, and the top of the outer monitors and offset the vertical values in the config file by the calculated virtual pixel distance.
The other assumption I have made, is that your center monitor is the largest of the three.
But no matter what your setup is, you should be able to use above theory to create the perfect setup. And don't think for one second it isn't worth it. You will not be disappointed. The result is absolutely amazing and feels/looks much more natural and realistic.
Enjoy!