• 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!

Legacy GM Need help adding a sky backdrop (which fills the screen) to the back of a 3D game?

S

SilverTom93

Guest
(I'm working on a 2D platformer which has a 3D look to it)
In my object which draws 3D projection stuff in its Draw event, I added a bit of code and the first line of it tells it to "draw_background_stretched" behind all of the other objects. Like so:
Code:
draw_background_stretched(bg_sky,x,y,room_width,room_height)
So what I'm gathering from this is that the background image I chose in that function fills the back of the room view completely, like a sky or like a view of space. When I come to play the game, the background just sits there in the middle of the screen's view and hasn't been stretched to all four corners at all. It's too small for some reason. :mad:

But yeah, the question is: How do I make the background stretched completely to all four corners of my game screen? (Or do I need to put anything in the "x, y, w, h" parts to make it fully stretched? Is there a way I can enlarge it to the same size as the game's view size?)

I have no clue why this isn't working or if I'm missing an obvious bit of code here o_O I've attached a screenshot of how the "apparently stretched" background looks in game - again, I don't know why it isn't filling the entire screen... If anyone can help figure out what I'm doing wrong here, then I'd be very thankful :D
whyisthisnotstretched.png
(On another note, if there's a bit of code which makes the background resistant to changes in ambient lighting, then let me know)
 

Roderick

Member
You could draw a d3d wall behind everything else, and big enough to fill the view. Put the image on it as a texture with 1 for both the h and v repeat. Then draw the wall relative to the camera each step, so that it's always in the same spot, if you need it stationary.
 
S

SilverTom93

Guest
You could draw a d3d wall behind everything else, and big enough to fill the view. Put the image on it as a texture with 1 for both the h and v repeat. Then draw the wall relative to the camera each step, so that it's always in the same spot, if you need it stationary.
Ah ok, good idea :D What line of code should I use for that? I've got the "d3d_draw_wall" part but I'm not sure what to put for everything else inside of it.

This is the Draw event code I've got:
Code:
d3d_draw_wall(20,20,20,1280,720,40, bg_sky,0,0)

draw_set_colour(c_white)
d3d_set_projection(obj_player.x,obj_player.y - 6,1300,obj_player.x,obj_player.y - 7,180,0,0,1)
draw_set_alpha(1)
Also I'm not too sure where I need to position that line within my code and if that'll affect the results :confused:
 

Roderick

Member
I'm still learning d3d myself, so I'm afraid I can't say for sure. Hopefully you can figure it out yourself, or if not, someone else can help.
 
S

SilverTom93

Guest
I'm still learning d3d myself, so I'm afraid I can't say for sure. Hopefully you can figure it out yourself, or if not, someone else can help.
After a lot of experimentation, I managed to draw a floor which fills the back of the view, fills the screen, and stays stationary! Only problem is, it's not adding the texture onto it now, and it just makes the entire wall a solid grey colour? :/ wall background.png
 
A

Azure Spectre

Guest
The easiest way I have found to do this is switching to 2D projection, drawing the background, then drawing everything else. It's a pretty nice trick for HUDs as well. I find that walls/floors/spheres always have lighting/texture problems and weird distortions.

Any 3D HUD tutorial will likely show you how to do this sort of thing. If you have trouble I could post some code, but I don't have much time at the moment. :p

Code:
d3d_draw_wall(20,20,20,1280,720,40, background_get_texture(bg_sky),0,0);
Try this will fix texture problem
Also this will create a new texture every step, which is not ideal. Assigning your textures once in the create event is much better practice.
 
S

SilverTom93

Guest
I tried ShubhamBansod's method of putting "background_Get_Texture" in the line of code I had in the Draw event, and it worked! (The texture was a bit zoomed in, maybe because I over-sized the wall a bit, but I'll fix it ;))

The easiest way I have found to do this is switching to 2D projection, drawing the background, then drawing everything else. It's a pretty nice trick for HUDs as well. I find that walls/floors/spheres always have lighting/texture problems and weird distortions.

Any 3D HUD tutorial will likely show you how to do this sort of thing. If you have trouble I could post some code, but I don't have much time at the moment. :p


Also this will create a new texture every step, which is not ideal. Assigning your textures once in the create event is much better practice.
I don't really understand that "switch to 2D, draw the background, then draw everything else" part (I'm still learning bits of GML language, I'm one of the old drag-n-drop users XD) but if it can be used for HUDs then it sounds pretty cool! (I might need some code ideas for this though because most of the time I have no idea what GML terms to use when coding :confused:)
 
The easiest way I have found to do this is switching to 2D projection, drawing the background, then drawing everything else. It's a pretty nice trick for HUDs as well. I find that walls/floors/spheres always have lighting/texture problems and weird distortions.

Any 3D HUD tutorial will likely show you how to do this sort of thing. If you have trouble I could post some code, but I don't have much time at the moment. :p


Also this will create a new texture every step, which is not ideal. Assigning your textures once in the create event is much better practice.
In create event
Code:
texSky = background_get_texture(bg_sky);
In Draw event
Code:
d3d_draw_wall(20,20,20,1280,720,40, texSky,0,0);
 
What is understand BY reading ur post is u want a sky bneth all other 3d objects?
If it is that try
Code:
d3d_draw_floor(0,0,0,room_width,room_height,0, texSky,1,1);
Read the manual in this and use horizontal and vertical repeat texture so your textures dont stretch and looks good!
 
A

Azure Spectre

Guest
I tried ShubhamBansod's method of putting "background_Get_Texture" in the line of code I had in the Draw event, and it worked! (The texture was a bit zoomed in, maybe because I over-sized the wall a bit, but I'll fix it ;))



I don't really understand that "switch to 2D, draw the background, then draw everything else" part (I'm still learning bits of GML language, I'm one of the old drag-n-drop users XD) but if it can be used for HUDs then it sounds pretty cool! (I might need some code ideas for this though because most of the time I have no idea what GML terms to use when coding :confused:)
So the way I do it uses the event_perform() function to choose the order of drawing.
Something along these lines:
Code:
//Draw event of the main camera object

//Start with background
//2d projection
d3d_set_projection_ortho(0,0,room_width,room_height,0)
d3d_set_lighting(0)
draw_set_color(c_white)//draw color to white
//draw background 2d stuff
with(all)
{
    event_perform(ev_alarm,0);
}
//Now all 3d game world objects
//3d Projection
d3d_set_projection_perspective(0,0,room_width,room_height,0)
d3d_set_perspective(1)
d3d_set_projection_ext(x,y,z,targetx,targety,targetz,0,0,1,45,room_width/room_height,30,6000);//this is copy pasted from my game, replace as needed
draw_set_color(c_white)//draw color to white
d3d_set_lighting(1);
//draw all 3d stuff
with(all)
{
        event_perform(ev_alarm,1);
}
//End with foreground (HUD)
//2d projection
d3d_set_projection_ortho(0,0,room_width,room_height,0)
d3d_set_lighting(0)
draw_set_color(c_white)//draw color to white
//draw background 2d stuff
with(all)
{
    event_perform(ev_alarm,2);
}
Then you put all your draw actions for the background in the alarm0 event, 3d in alarm1, foreground in alarm2. Then make sure any objects with a sprite set visible=0; so they don't draw their default sprites somewhere weird.
This may not be the best way, but it works very well for me, as I don't use alarms for anything.
 
You can Also set the order of drawing the objects BY setting negative and positive depth value accordingly
No need to use other event and codes
 
A

Azure Spectre

Guest
You can Also set the order of drawing the objects BY setting negative and positive depth value accordingly
No need to use other event and codes
I recall having problems with this, doesn't 3D mode change the depth based on position relative to the camera or something? If what you say is true, that certainly does make things much simpler. :confused:
 
S

SilverTom93

Guest
What is understand BY reading ur post is u want a sky bneth all other 3d objects?
If it is that try
Code:
d3d_draw_floor(0,0,0,room_width,room_height,0, texSky,1,1);
Read the manual in this and use horizontal and vertical repeat texture so your textures dont stretch and looks good!
I tried doing that but it then made the sky appear in front of some background scenery I had :/ (So it works, and does draw quite far back, but not fully behind everything.) It also made some 2D sprites in the level disappear :oops:

I've gone back to my old method for now in case there isn't a fix for this (my old method is creating a massive, manually-sized stationary wall with a depth of 900, so it's definitely behind all of the background scenery while still filling the whole screen). Also, if I put numbers such as 20,20,20 in the first 3 command option thingies, it instead draws a glitchy diagonal line across my game view. Pretty confusing stuff o_O
 
S

SilverTom93

Guest
So the way I do it uses the event_perform() function to choose the order of drawing.
Something along these lines:
Code:
//Draw event of the main camera object

//Start with background
//2d projection
d3d_set_projection_ortho(0,0,room_width,room_height,0)
d3d_set_lighting(0)
draw_set_color(c_white)//draw color to white
//draw background 2d stuff
with(all)
{
    event_perform(ev_alarm,0);
}
//Now all 3d game world objects
//3d Projection
d3d_set_projection_perspective(0,0,room_width,room_height,0)
d3d_set_perspective(1)
d3d_set_projection_ext(x,y,z,targetx,targety,targetz,0,0,1,45,room_width/room_height,30,6000);//this is copy pasted from my game, replace as needed
draw_set_color(c_white)//draw color to white
d3d_set_lighting(1);
//draw all 3d stuff
with(all)
{
        event_perform(ev_alarm,1);
}
//End with foreground (HUD)
//2d projection
d3d_set_projection_ortho(0,0,room_width,room_height,0)
d3d_set_lighting(0)
draw_set_color(c_white)//draw color to white
//draw background 2d stuff
with(all)
{
    event_perform(ev_alarm,2);
}
Then you put all your draw actions for the background in the alarm0 event, 3d in alarm1, foreground in alarm2. Then make sure any objects with a sprite set visible=0; so they don't draw their default sprites somewhere weird.
This may not be the best way, but it works very well for me, as I don't use alarms for anything.
I'm currently in the process of copying this code, adding in the background + hud stuff, and I'm soon going to test if it works :D Quick question though: where you've put "targetx,targety,targetz - replace as needed", would I replace them with obj_player.x, obj_player.y, etc. or something else? (Also when I type all of this, the "z" doesn't turn red in the code... is this a problem?)

EDIT: wait, nevermind, I already had a d3d_set_projection line from the code I had before (without the "ext" at the end of it.) I'm guessing I need to just replace your game's projection code with this one I had? The line of code I had before is:
Code:
d3d_set_projection(obj_player.x,obj_player.y - 6,1300,obj_player.x,obj_player.y - 7,180,0,0,1)
 
Last edited by a moderator:
S

SilverTom93

Guest
So I've put Azure Spectre's Draw event code into my object called "p3d" which sets up the 3D stuff. I put all the code in its Draw event; the only thing I replaced was:
Code:
d3d_set_projection_ext(x,y,z,targetx,targety,targetz,0,0,1,45,room_width/room_height,30,6000);
Which I replaced with:
Code:
d3d_set_projection(obj_player.x,obj_player.y - 6,1300,obj_player.x,obj_player.y - 7,180,0,0,1)
When I tested this, the game displayed itself in 2D, not following the player, and the game's speed+framerate was insanely low :eek: I'm guessing this is because it's coping with way too much stuff in the draw event? I have no clue o_O (I'm using a fairly powerful gaming PC, so seeing a basic 3D game have major slow-down is quite weird.)

My old method was just putting this in the draw event:
Code:
draw_set_colour(c_white)

d3d_draw_floor(-600, -600, 900, 1900, 1000, 900, background_get_texture(bg_sky), 1, 1)

d3d_set_projection(obj_player.x,obj_player.y - 6,1300,obj_player.x,obj_player.y - 7,180,0,0,1)

draw_set_alpha(1)
Here's how the game looks normally. Also: I've found out that using the "Draw GUI" event makes some text+stuff overlay over everything, so could I perhaps use that function instead to make a HUD?screenshot1.png
 
Last edited by a moderator:
A

Azure Spectre

Guest
So I've put Azure Spectre's Draw event code into my object called "p3d" which sets up the 3D stuff. I put all the code in its Draw event; the only thing I replaced was:
Code:
d3d_set_projection_ext(x,y,z,targetx,targety,targetz,0,0,1,45,room_width/room_height,30,6000);
Which I replaced with:
Code:
d3d_set_projection(obj_player.x,obj_player.y - 6,1300,obj_player.x,obj_player.y - 7,180,0,0,1)
When I tested this, the game displayed itself in 2D, not following the player, and the game's speed+framerate was insanely low :eek: I'm guessing this is because it's coping with way too much stuff in the draw event? I have no clue o_O (I'm using a fairly powerful gaming PC, so seeing a basic 3D game have major slow-down is quite weird.)

My old method was just putting this in the draw event:
Code:
draw_set_colour(c_white)

d3d_draw_floor(-600, -600, 900, 1900, 1000, 900, background_get_texture(bg_sky), 1, 1)

d3d_set_projection(obj_player.x,obj_player.y - 6,1300,obj_player.x,obj_player.y - 7,180,0,0,1)

draw_set_alpha(1)
Here's how the game looks normally. Also: I've found out that using the "Draw GUI" event makes some text+stuff overlay over everything, so could I perhaps use that function instead to make a HUD?View attachment 3574
If you are using my code, make sure you set the visibiliy of all your objects to false, because they will try to automatically draw their sprite in 2D. Also change all 3D draw events to alarm1 Events.

If you are only drawing simple things in 2D, you can just delete the lines about calling every object to draw, and have the camera object draw the background/HUD.
Draw GUI will probably work for HUD, it looks to me like it's just a second draw event. (I'm used to GM8 so I was not familiar to that event)

All of this considered, I've revised my code to hopefully be more useful.

Option 1: Use the alarm event on just the 3D objects, simplify the 2D drawing so it doesn't call all objects 3 times...
Code:
//Draw event of the main camera object

//Start with background
//2d projection
d3d_set_projection_ortho(0,0,room_width,room_height,0)
d3d_set_lighting(0)
draw_set_color(c_white)//draw color to white
//draw background 2d stuff
draw_background(bg_sky,0,0)

//Now all 3d game world objects
//3d Projection
d3d_set_projection_perspective(0,0,room_width,room_height,0)
d3d_set_perspective(1)
d3d_set_projection(obj_player.x,obj_player.y - 6,1300,obj_player.x,obj_player.y - 7,180,0,0,1)
draw_set_color(c_white)//draw color to white
d3d_set_lighting(1);
//draw all 3d stuff
with(all)
{
        event_perform(ev_alarm,1);
}

//End with foreground (HUD)
//2d projection
d3d_set_projection_ortho(0,0,room_width,room_height,0)
d3d_set_lighting(0)
draw_set_color(c_white)//draw color to white
//draw foreground 2d stuff
//Put your HUD code here
Option 2: Don't use the alarm events at all, use draw GUI for the HUD, set the camera's depth to a large negative number, and let instances handle their own drawing. (Probably the better option?)
Code:
//Draw event of the main camera object

//Start with background
//2d projection
d3d_set_projection_ortho(0,0,room_width,room_height,0)
d3d_set_lighting(0)
draw_set_color(c_white)//draw color to white
//draw background 2d stuff
draw_background(bg_sky,0,0)

//Now all 3d game world objects
//3d Projection
d3d_set_projection_perspective(0,0,room_width,room_height,0)
d3d_set_perspective(1)
d3d_set_projection(obj_player.x,obj_player.y - 6,1300,obj_player.x,obj_player.y - 7,180,0,0,1)
draw_set_color(c_white)//draw color to white
d3d_set_lighting(1);
//End it here, let the instances handle their own drawing

//Draw GUI Event
//2d projection
d3d_set_projection_ortho(0,0,room_width,room_height,0)
d3d_set_lighting(0)
draw_set_color(c_white)//draw color to white
//draw foreground 2d stuff
//Put your HUD code here
 
Top