Game Development Community

How can I create a parallax starfield in Torque3D?

by RealDecoy Inc · in Torque 3D Professional · 02/21/2010 (3:47 pm) · 22 replies

Hey, having a bit of a wierd problem, didn't expect this to be as difficult as it turned out to be (And I'm sure I'm just missing something)

I just finished porting my code so far into 1.1 Beta.

What I'm doing is building a top down space game (basically functions on a 2d plane but with 3d graphics).

I want a parallax starfield in the background.

I decided first that using a groundplane, texturing it with an alpha transparent png with stars on it, then layering several groundplanes deep would work perfectly... Works fine, except I can't seem to find how to adjust the depth of a ground plane (they all render in the exact same spot, but the alpha transparency on the png works great, just not that useful without depth lol)

Anyway, so next I tried piece of geometry. Which works great, can stack depth and get the exact effect I want, except, it's not infinite. And there are certain situations I would want basically infinite travel in all directions (which a groundplane gives me).

Next I thought perhaps I could do it with particles, just have it fill the screen with some stars, at random positions, and move them relative to camera movement or something. Just couldn't get my head around how to do that with the particle engine.

Lastly I thought, perhaps I could render a flat texture straight to the camera (like a GUI object) but set it's Z depth to be always behind all rendered geometry, then I could have a few layers, and just scroll the texture on it relative to camera movement to create the effect...

Couldn't figure that one out either...

In addition to wanting this to exist in all missions being played, I also want the effect to render behind the "main menu" but I'm not quite sure how to do that either...

Anyway, if anyone can point me at a resource or tutorial that pre-exists, or give me some pointers or tips on how I could go about achieving what I am trying to do, I would really appreciate it.

This is meant to be a very simple casual style game, and we were hoping to do it without any real engine modification (entirely in torquescript) then we will be expanding a more robust release if this one is successful, and carry our torquescript code over, and then allow for some engine modification for the more advanced project.

But that said, if we need to modify the engine to achieve what we are trying to do, that's not a big problem. We are just trying to keep the complexity to an absolute minimum.

Thanks!
Page «Previous 1 2
#1
02/21/2010 (9:53 pm)
Pretty cool ideas to achieve (almost) the same results. I think you could still use groundplanes with a small modification. This would probably take the least effort.

Check out groundPlane.cpp. At a glance, try poking at planeBox, onAdd() and generateGrid. I'm sure you could squeeze a z in there somewhere.

#2
02/22/2010 (12:40 am)
Ok, I'll have to modify groundplane. That is likely the easiest to achieve this with, and will be easiest to maintain with my overall game model going forward I think...

That should be a fairly simple mod.

Now I just have to figure out how to have a mission loaded and sitting in the background of the main menu on game start :) lol.

Thanks!
#3
02/22/2010 (12:44 am)
you could also use multiple terrains, just load a blank height map to make it flat and instance it.
#4
02/22/2010 (3:57 am)
Moving a GroundPlane in Z is safe. However, when using multiple GroundPlanes for this, make sure set their geometry settings thus that the resulting geometry is really light. GroundPlanes are in fact rather expensive since they buy their infinite nature by dynamically generating geometry on the fly according to the render frustum used (which, since the lighting pipeline may also render with custom frustums a couple of times, can actually lead to multiple generations of the same GroundPlane per frame). These dynamic vertex buffers and primitive buffers are really bad for GPUs and will eat viciously into frame time.

In terms of rendering speed, placing bitmap GUIs behind the scene render GUI is probably the cheapest solution. Remember that GroundPlanes are a full part of the rendering pipeline (including lighting) which incurs a certain cost and gives you something you actually don't want here. Since you only want some background texture, a GUI would be perfect.

@Ken
Think the texturing would be a bit of a problem and it would be quite an expensive solution.
#5
02/22/2010 (11:02 am)
@Ken: Unfortunately with terrains I would loose the infinite nature...

@Rene: Good point about the GroundPlane, I hadn't thought about the impact on the render pipeline. And the fact that it would be lit. Although my scenes will likely be fairly sparse on polys, because it's a space theme, with simplistic ships, and the odd sphere for a planet or moon, maybe an asteroid here or there, but in the end my scenes will be quite low-poly. But the lighting is a concern, the stars will look wonky if lit by point lights. (which I had hoped to use for some weapon effects to add some nice dynamic lighting)

I'm still a bit new in dealing with torque, so what would be the proper way to layer a bitmap in a way that it's statically rendered behind the scene? And is there an offset parameter on a bitmap gui? (so that I can cause it to pan as the camera moves?)

Thanks!
#6
02/22/2010 (11:14 am)
I think a shader would be a better way to render a star field, no? Maybe a post effect that renders before the scene, so it's behind everything?
#7
02/22/2010 (11:26 am)
Unfortunately my lack of experience writing shaders (as in never even tried, and have no idea where to start) would hamper me there...

Can anyone point me at a good shader tutorial that might help me figure this out? because that sounds like a viable option.

Thanks!
#8
02/22/2010 (11:44 am)
Also, would a shader work? In that how would a shader know about camera movement? in order to create the parallax effect on the starfield?

I'm thinking the gui element in the background is the best way to approach this (And easy to achieve in a menu as well) but need to figure out how to have a bitmap gui element live behind the scene...
#9
02/22/2010 (11:57 am)
A post effect shader, as Manoel suggested would be a very nice solution.

To add to the ideas: You could create your own class which would always be at the cam's position - much like a skybox. Then you could control lighting along with the render order. You could even use material stages and different texture animation settings per stage. You can find example objects from which you can get started in the T3D/examples folder.
#10
02/22/2010 (12:16 pm)
I agree a shader sounds like a very elegant solution, but then I go back to my 2 questions:
- Can a shader track camera position to be able to create parallax?
- Where do I start to learn/figure out how to create a custom effect like this?

Also for this custom class idea your talking about, that's not a bad idea either. But I suspect it would require editing the engine source (not really a bad thing, but if it can be avoided I would prefer to avoid it, since it will make keeping up with new engine releases during development much easier, and since I'm building on a beta, I will definitely need to roll up to a release version before releasing the finished product)
#11
02/22/2010 (12:40 pm)
A shader can receive all kinds of information, but you have to tell it what you need. Some features like view matrices, elapsed time, etc.. are there for you to get. Some others that are specific to a task you might need to add.

But I just got another idea that takes the fun of both worlds. You could also use a modified version of the BasicClouds class.

It wouldn't really mean editing the engine source - more like adding to it. Engine updates would be pretty easy to do since you could keep your new class separated from the engine source.
#12
02/22/2010 (1:03 pm)
I'll try to come up with a simple example of a post effect that does 2D parallax scrolling later at night.
#13
02/22/2010 (1:30 pm)
Wow, thanks Manoel, that would really help get me started with the shader side of things.

Also That's not a bad idea Konrad... If the shader won't work I'll take a look at that approach as well...

Some great ideas coming from this thread!

Thanks again for all your help so far everyone!
#14
02/23/2010 (12:36 am)
Here it goes:

1) Create a file called "starFieldP.hlsl" In shaders\common\postFx\. This will be the shader file that renders the parallax scrolling layers. We only need a pixel shader file, since in 99% of the cases the default PostFX vertex shader does the job. Place this code inside "starFieldP.hlsl":

#include "./postFx.hlsl" //Every post effect shader needs this

uniform sampler2D inputTex : register(S0); //This is our (single) texture sampler

//The two uniforms below are avaiable to every post effect
//for a full list, look in PostEffect::_setupConstants() in the source
uniform float accumTime;  //This is a timer value we can use for animating stuff
uniform float3 eyePosWorld; //The eye position - this will be used to scroll

float4 main( PFXVertToPix IN ) : COLOR
{   
   //We'll calculate a scroll offset based on the camera's XZ position
   //I scale it down so it doesn't moves too fast and flip the Y axis   
   float2 scrollBase = eyePosWorld.xz * 0.02 * float2(1, -1);
   
   //Now we'll add an auto-scroll in the X axis
   scrollBase.x += accumTime * 0.01;
   
   //We'll read the first layer. Scaling the UV by 3x will make the texture
   //tile 3X, and we'll have this layer scroll at 2X speed
   float4 color = tex2D( inputTex, IN.uv0*3 + scrollBase * 2.0 );
   
   //Now read the texture again using more tiling and a smaller scrolling 
   //value than the first layer. We'll add this color to the first layer
   color += tex2D( inputTex, IN.uv0*4 + scrollBase * 1.5 );
   
   //Layer #3 will be even slower. Add to layer #1 and #2.
   color += tex2D( inputTex, IN.uv0*5 + scrollBase );
   
   //Now return the final color
   return color;   
}

2) Create a script in core\scripts\client\postFx called starfield.cs. Paste this code in it:
singleton ShaderData( StarFieldShader )
{
   DXVertexShaderFile 	= "shaders/common/postFx/postFxV.hlsl";
   DXPixelShaderFile 	= "shaders/common/postFx/starFieldP.hlsl";

   pixVersion = 2.0;   
};

//The render states used when rendering the post effect
singleton GFXStateBlockData( StarFieldBlock : PFX_DefaultStateBlock )
{
   samplersDefined = true; // We need this to use textures at all
   samplerStates[0] = SamplerWrapLinear; //Each texture slot need one of those
};

singleton PostEffect( StarFieldFX )
{
   isEnabled = true;
   allowReflectPass = false;
        
   renderTime = "PFXAfterBin";
   renderBin = "SkyBin";
   renderPriority = 0.1;
      
   shader = StarFieldShader;
   stateBlock = StarFieldBlock;
   texture[0] = "starfield.jpg";
};

3) In core\scripts\client\renderManager.cs, find this line:
DiffuseRenderPassManager.addManager( new RenderObjectMgr() { bintype = "Sky"; renderOrder = 0.1; processAddOrder = 0.1; } );
And replace it by this:
DiffuseRenderPassManager.addManager( new RenderObjectMgr(SkyBin) { bintype = "Sky"; renderOrder = 0.1; processAddOrder = 0.1; } );
We need this so we can make our post effect render after the sky (we need names to refer to bins in post effects).

4) Place the starfield.jpg texture in core\scripts\client\postFx. This is important because it seems post effects cannot load textures from outside their base folder. There's a sample texture here: i48.tinypic.com/b6q72s.jpg
5) If nothing is missing, it should work automatically. Here's a screenshot:i48.tinypic.com/2dw7zwg.png
#15
02/23/2010 (10:53 am)
Wow! That's AWESOME! lol... that did almost all the work for me! Now I can fine tune that to my hearts desire!

You should post this as a resource!

As a side note, will this auto-render behind all geometry period? including GUI objects? (so if I have no background behind my gui it will auto-render behind the gui? or will I need to have a mission rendering in the background to get the starfield shader to run?

Thanks!
#16
02/23/2010 (11:59 am)
You're not using a mission? Then you'll need a GameTSCtrl to display the post effect. They don't interact with the GUIs and are rendered inside the game view.
#17
02/24/2010 (3:50 am)
Real, maybe I'm wrong but I think I would solve the problem of groundplanes at the same deepth texturing 2 (or more) groundplanes with different starfields textures, with different sizes for stars.. if you use an animated material for the one with bigger stars it seems to move faster and gives you the impression of different distance of the 2 ground planes starsfields... obviously in that case it function only if you navigate with your starship always in the same direction since the animated material slide always in the same direction...
#18
02/24/2010 (8:04 am)
Manoel: I am using a mission, for the gameplay itself. I was also hoping to have the starfield render behind the main menu simply as a background effect.

Your solution with the shader will work perfectly for the gameplay aspect and you have saved me a ton of time. But for the menu background I was hoping to use the same solution. If GameTSCtrl allows me to do that, great. If not then I can always come up with another option for the menu (or not use the starfield at all. :)

Thanks!
#19
02/28/2010 (7:54 am)
As a follow up to this, I have implimented Manoel's starfield, and the effect is great. Unfortunately the scroll rate is fixed, and the stars aren't reactive to the camera movement.

Konrad had suggested that I might be able to pass the camera information into the effect (location/rotation or something) so that I could calculate the movement based on that?

Any thoughts on that?

If I can't get it to react naturally to camera movement it looks... very strange.

Thanks! :)
#20
02/28/2010 (8:01 am)
Nevermind, I just re-read the source of the shader itself, and it appears Manoel already thought of that for me! :) (he even heavily commented the code to explain).

That's what I get for blindly implimenting first rather than reading the code as I go.

Thanks!
Page «Previous 1 2