Game Development Community

dev|Pro Game Development Curriculum

TGEA Seamless Cubemap Builder

by Lorne McIntosh · 04/24/2008 (8:55 am) · 6 comments

Download Code File

Set Up

To start off, create a new script file in your data/server/scripts folder. We've named ours "buildcubemap.cs". Copy/Paste the code at the bottom of this article into your new script file (or download it from the resource link above).

To make sure the code executes when running the game, also include the following line in your game.cs inside the function onServerCreated().

exec("./buildcubemap.cs");

How to Run the thing

Pick the point at which you want the cubemap to be generated from (most likely the center of your room or environment). An easy way I have found to do it is walk your player to that spot, hit F11 to go into the mission editor mode, hit Alt-C to go into free-cam mode, select your player by clicking on them, hit F3 to view the player properties and then scroll down to get the xyz coordinates of where your player is located. Another way is to create an object and just move it to where you want the camera to be, get the xyz location and then delete it.

Open up your console and type the following code but replacing the stuff in quotes with real data.

buildcubemap("x y z", "texture size");

"X Y Z" is the xyz coordinates that you want the cubemap to be generated from. "texture size" is the size of the texture you want to generate.

example: buildcubemap("0 0 0", "512");

That example code would take 6 pictures starting at the origin of the map, and output them as 512x512 .png files into your games root directory.

Important!: This tool literally takes screenshots of torque so make sure you close the mission editor and don't move the mouse while the application is running. Make sure any models that aren't supposed to be in the scene have been removed or they will appear in your cubemaps. If you are also inspecting the code, you will notice that the first image doesn't come out correct so I've added a little piece of code to take that into consideration.

Manual Work

We couldn't figure out how to get the camera to rotate and take the screenshots with the correct orientation so you will need to re-orient the images manually using Photoshop or a similar graphics tool:

ypos - needs to rotate 180
xneg - needs to rotate 90 clockwise
yneg - perfect
xpos - needs to rotate 90 counter-clockwise
zneg - needs to rotate 180
zpos - perfect

All Done

Hopefully from this you have 6 images that will generate a seamless cubemap.

//-----------------------------------------
//buildcubemap.cs
//-----------------------------------------

//build a cubemap of the given size rendered from the given position
function buildcubemap(%position, %size)
{
   %delay = 1000;
   %HalfPI = 3.14159265359 / 2.0;
   
	echo("Building cubemap...");
	
   //save the current settings
   %oldControl = LocalClientConnection.getControlObject();
   %oldMode = canvas.getVideoMode();
   
   //set camera as control object
   LocalClientConnection.setControlObject(LocalClientConnection.camera);
   
   //set resolution
   canvas.setVideoMode(%size, %size, Canvas.isFullScreen());
   
   //turn off console & HUD so it's not in the screenshot
   Canvas.popDialog(ConsoleDlg);
   Canvas.popDialog(MainChatHud);
   
   //the first setTransform doesn't work properly for some reason, let's get it over with now
   LocalClientConnection.camera.schedule(%delay*1, "setTransform", %position @ " 0 0 1 0");
   
   
   //take the 6 screenshots
   //    ideally cubemaps would come out perfect and ready to use, but torque doesn't support
   //    rolling the camera so you'll need to apply the specified rotations manually in photoshop
   LocalClientConnection.camera.schedule(%delay*2, "setTransform", %position @ " 0 0 1 0");              //rotate 180 in photoshop
	schedule(%delay*3, 0, "screenshot", "cubemap_ypos.png", "PNG");
	
   LocalClientConnection.camera.schedule(%delay*4, "setTransform", %position @ " 0 0 1 " @ %HalfPI);     //rotate 90 counter-clockwise in photoshop
	schedule(%delay*5, 0, "screenshot", "cubemap_xpos.png", "PNG");
	
   LocalClientConnection.camera.schedule(%delay*6, "setTransform", %position @ " 0 0 1 " @ %HalfPI*2);
	schedule(%delay*7, 0, "screenshot", "cubemap_yneg.png", "PNG");
	
   LocalClientConnection.camera.schedule(%delay*8, "setTransform", %position @ " 0 0 1 " @ %HalfPI*3);   //rotate 90 clockwise in photoshop
	schedule(%delay*9, 0, "screenshot", "cubemap_xneg.png", "PNG");
	
   LocalClientConnection.camera.schedule(%delay*10, "setTransform", %position @ " 1 0 0 " @ %HalfPI);    //rotate 180 in photoshop
	schedule(%delay*11, 0, "screenshot", "cubemap_zneg.png", "PNG");
	
   LocalClientConnection.camera.schedule(%delay*12, "setTransform", %position @ " -1 0 0 " @ %HalfPI);
	schedule(%delay*13, 0, "screenshot", "cubemap_zpos.png", "PNG");
	
   
   //set the video mode back   
   canvas.schedule(%delay*14, "setVideoMode", getWord(%oldMode, $WORD::RES_X), getWord(%oldMode, $WORD::RES_Y), Canvas.isFullScreen());	
	
	//set the control object back
	LocalClientConnection.schedule(%delay*14, "setControlObject", %oldControl);
	
	//turn console & HUD back on
	canvas.schedule(%delay*14, "pushDialog", ConsoleDlg, 99);
   canvas.schedule(%delay*14, "pushDialog", MainChatHud );
	
	//aaaand we're done!
	schedule(%delay*15, "echo", "Done!");
}

About the author

Ubiq Visuals is a software and creative content developer for the entertainment industry. Our vision is to provide inspiration and the tools for soon-to-be game designers and creative minds of all ages.


#1
04/24/2008 (4:50 pm)
Cool, this will come in handy.
#2
04/24/2008 (7:44 pm)
Is this similar in function, to say... The Source engine, where in the Hammer editor you plop down a env_cubemap entity and in game you type "build_cubemaps", and it generates a cubemap for each entity laid down in the level... and then anything that needs a cubemap references those images? Or does it just basically generate the images and you do the rest as needed?

[edit]
Nevermind, just browsed the script more thoroughly and I see now that it just generates the images... And then you have to edit them!

Still, good and useful script. Nice work.
[/edit]
#3
04/25/2008 (12:47 am)
I was just busy with Cubemaps. I do have a problem however (not with your script). How would you change the Cubemap from Level-to-Level? Not everyone only has one mission. I've been wondering about this the past day.
#4
04/26/2008 (12:15 am)
@James: What I've done for that is to export all relevant models so that they can accept setskins (make sure they are named base.mytexturename) and then place a setting in the missionfile to specify the missiontype setting. Then when these models load you can do a setskin with that specifier. Have the material for the new skin be the same as before, but with the relevant cubemap, or color settings for that map in the new materials.
#5
04/27/2008 (7:21 pm)
@Nathan
Yeah, the way Valve handles cubemaps in Source engine is nearly perfect. I love that system. One day I'd like to combine this resource with J.C. Smith's excellent suggestion above to create something similar. Objects would automatically switch their cubemap based on which "env_cubemap" entity they are currently closest to. It might not even be that hard... but probably won't happen for a long time.
#6
02/05/2012 (9:45 pm)
Yes! So glad I came across this, thank you!