• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

GameMaker Starfield Help

Ladi_Pix3l

Member
I wanna create a star field like this but I have no idea where to start.



probably not as obnoxious but basically white stars (or pixels) doing this.
Sleeping on this for a week and its driving me nuts. Like WTF.

One way I thought about was just having sprites/instances scale over time but that looked hideous. So my next approach was to scale but also have them move but HOLY BACON CHIPS that was dumb too. . .

So before I completely give up and assume this can't be done, what's another way to achieve this?
 
Last edited:

Ladi_Pix3l

Member
Well it's just for a background place holder for my space-ish game. It won't be asfast as this gif is suggesting
 
D

Danei

Guest
you could put a particle emitter at the center of the room and send out particles with like... random velocity and acceleration within a range. It's hard to imagine how things are going to look before trying them, but that's the first thing I would try. Rather than scaling the size over time as they move, what I would do is give the particle's sprite a couple of frames, where the first ones are dimmer/bluer and the later ones are brighter and more white, if that makes sense.
 
I've done starfields in a lot of different ways, but today I'm interested in a simple implementation using line primitives.

So the idea I'm presenting here is pretty simple. The stars are basically a bunch of line segments, put into a vertex buffer so they can be drawn super fast. A shader moves the stars, wraps them back in front of the camera once they pass behind it, and applies a pseudo perspective projection so that you don't have to set one up yourself. Oh, and to prevent the stars from popping into existence, they have to fade away the farther they are from the camera.

See spoiler for more details:
setup:

Notes about _min_apparent_brightness, _max_dist, and _brightness:
In the shader, the stars fade with distance, the apparent brightness of a star will be its brightness divided by distance squared. apparent_brightness = brightness / distance^2
Brightness is the true brightness of a star. Apparent brightness is how bright it appears on screen.
If stars are really far away, then their brigthness will be reduced by so much that they will be invisible. Therefore dimmer stars can be wrapped around our space at shorter distances.
At what range should a star be wrapped? distance = sqrt( brightness/min_apparent_brightness). This is just taking the previous equation, and rearranging it to solve for distance.
Ok, and lets say that we don't want any stars to be further away than some max distance. This puts a constraint on the maximum possible brightness allowed. brightness = min_apparent_brightness * max_distance^2. Same equation as before, except solving for brightness (max_brightness).
Code:
//=============================================================
    var _max_dist = 1000;
    var _min_apparent_brighness = 1/255;
    var _num_stars = 5000;
    vertex_format_begin();
    vertex_format_add_custom( vertex_type_float4, vertex_usage_position); //(x,y,z) = position, (w)[1=leading point,0=trailing point]
    vertex_format_add_custom( vertex_type_float4, vertex_usage_colour ); //(r,g,b) = colour, (a) = "_range"
    vertex_format_add_custom( vertex_type_float1, vertex_usage_normal );  // = _brightness
    vf_stars = vertex_format_end();
    vb_stars = vertex_create_buffer();
    vertex_begin(vb_stars,vf_stars);
    var _max_brightness = _min_apparent_brighness * power(_max_dist,2); //0.01 is min apparent brightness
    var _angle, _dist, _x, _y, _z, _colour, _r, _b, _g, _brightness, _range;
    repeat(_num_stars) {
        _colour = choose($FFFFFF, $FF8080, $8080FF);  //random colour
        _brightness = _max_brightness * random_range(0.1,1.0);  //random brightness
        _range = power( _brightness / _min_apparent_brighness, 1/2 );  //range at which star fades to minimum brightness
        _angle = random(360);
        _dist = random_range(0.01,0.2)*choose(-_range,_range);
        _x = dcos(_angle)*_dist;
        _y = dsin(_angle)*_dist;
        _z = random(_range);
        _r = colour_get_red( _colour )/255;
        _g = colour_get_green( _colour )/255;
        _b = colour_get_blue( _colour )/255;
        vertex_float4( vb_stars, _x, _y, _z, 0);  //trailing point position
        vertex_float4( vb_stars,  0,  0, _b, _range );  //trailing point colour (image you posted had stars fading to blue, so these do too)
        vertex_float1( vb_stars, _brightness );
        vertex_float4( vb_stars, _x, _y, _z, 1);  //leading point position
        vertex_float4( vb_stars, _r, _g, _b, _range );  //leading point colour
        vertex_float1( vb_stars, _brightness );
    }
    vertex_end(vb_stars);
    vertex_freeze(vb_stars);
//=============================================================
draw:
Code:
shader_set( sh_stars);
shader_set_uniform_f(shader_get_uniform(sh_stars,"time"),current_time);
vertex_submit(vb_stars,pr_linelist,-1);
shader_reset();
sh_stars vertex shader:

z position of star is modified according to -time*speed.
then the star's z position is wrapped using a mod function (in_Colour.a is the distance at which the star is wrapped, and is based on its brightness [brighter stars wrapped further away]).
the front end of the star is moved closer to the camera with -stretch*in_Position.a (in_Position.a is 0 for trailing point of star, 1 for leading point).
the colour of the star is reduced according the depth of the star squared, hence /(gl_Position.w*gl_Position.w).

Code:
    attribute vec4 in_Position;
    attribute vec4 in_Colour;
    attribute float in_Normal;
    varying vec4 v_vColour;
    const float speed = 0.02;   //speed of star
    const float stretch = 4.0;  //length of star
    uniform float time;
    void main() {
        gl_Position = vec4( in_Position.xy, 0.0, mod( in_Position.z - time * speed, in_Colour.a) - stretch * in_Position.a );
        float brightness = min(2.0,in_Normal / (gl_Position.w*gl_Position.w));  //fade brightness with distance (cap max brightness as well)
        v_vColour = vec4( in_Colour.rgb * brightness, 1.0);
    }
sh_stars fragment shader:
Code:
    varying vec4 v_vColour;
    void main() {
        gl_FragColor = v_vColour;
    }

EDIT: Made a small change. Capped maximum apparent brigthness in shader. This required the addition of a new vertex attribute, because apparent brightness is now multiplied with the star colour after the apparent brightness is capped.
 
Last edited:

Ladi_Pix3l

Member
im gonna re read this a few hundred plus times because a lot of the equations seem more counter intuitive from it's initial goal is. But even with the understanding this made my head hurt.


I mean I get the what the shader is doing but. . .idk. . . I need to look this over a few times
 
I mean I get the what the shader is doing but. . .idk. . . I need to look this over a few times
Let's see if I can clear things up a bit.

a = apparent brightness, b = brightness, d = distance
a = b / d^2
By the way, it isn't really necessary for stars to reduce in apparent brightness with distance squared, but I've tried several different things, and that seems to produce the nicest results.
let’s say we want a minimum apparent brightness of 1/255
and maximum distance is 1000
so replacing those variables with constant values:
1/255 = b / 1000^2
solve for (maxiumum) brightness:
b = 1/255 * 1000^2
Our stars have a random brightness up to the maximum.
So we want to know how far away they can get before they reach minimum apparent brightness:
d = sqrt( b / 1/255 )
note: I've called "d", "_range" in the setup script. and "b" here is a random brightness up to max brightness. and "1/255" is the minimum apparent brightness
upload_2018-12-19_17-37-44.png
 
Last edited:

Ladi_Pix3l

Member
So. . . . okay. . .-_-

Apparent brightness is the brightness that appears on the screen. Understood.
With creating a limit to the brightness we are essentially creating a distance in measurement. Understood.
Having the equation to d = sqrt will determine the amount of apparent brightness making equivalent to it's current distance? I think I get this. . maybe.

So in a nut shell we're (well you) are creating a replication of a stars zooming trough space.
 

Haow

Member
Why, in the world, are their larger and more stars more often on the left side then the right side!?!? Just look up a picture of hyperspace and you will see that the left is more dressed than the right, every, single, time... It must be the way the math works.
 
Using the code I posted above you will get results that look like this. Except picture it in motion. Note: the size and aspect ratio of the view port shouldn't make any important difference. It also doesn't matter what camera or view or projection you set, because they aren't even used.
upload_2018-12-20_15-18-1.png
There are all kinds of ways you could distribute the stars or cause them to fade with distance. I tried to pick something that looked fairly natural, but perhaps you can think of some way better.

The reason I'm promoting the idea of putting the stars into a vertex buffer and drawing them with a shader is that they will draw super fast. You could perhaps get more flexible results drawing them as sprites individually, but it will be a much less efficient process. But if that doesn't really matter, we can talk about that alternative some more.
 
Last edited:

Ladi_Pix3l

Member
Using the code I posted above you will get results that look like this. Except picture it in motion. Note: the size and aspect ratio of the view port shouldn't make any important difference. It also doesn't matter what camera or view or projection you set, because they aren't even used.
View attachment 22352
There are all kinds of ways you could distribute the stars or cause them to fade with distance. I tried to pick something that looked fairly natural, but perhaps you can think of some way better.

The reason I'm promoting the idea of putting the stars into a vertex buffer and drawing them with a shader is that they will draw super fast. You could perhaps get more flexible results drawing them as sprites individually, but it will be a much less efficient process. But if that doesn't really matter, we can talk about that alternative some more.
Very nice and thank you. =) if I wanted to adjust the speed of the stars, do I mess with the speed in the shader of adjust the equation a bit?
 

Joe Ellis

Member
I dont really understand why you need to do all the perspective calcs when you can make a matrix that does it for you, its like manually calculating a world matrix to rotate and position an object, there's a few functions that does it for you, alot quicker cus its built into gm,
I'd just make a vertex buffer with 1000 stars, set a float attribute for the offset of the merge from start to finish, then you have a merge uniform that moves them
 
Top