GameMaker [Solved] Lighting Surfaces on non-integer view positions

Anixias

Member
Hi all, I'm making a 2D platformer sort of game. I am wondering how best to handle the lighting surface since the view is almost never at an integer position, and surfaces only deal with integers as far as I'm aware.

The view size is 480x270 and the game is rendered at 1920x1080 144FPS. For my lighting surface(s), I have to draw a mask onto it to prevent lighting from affecting the sky or background, but if I do that using the background positions, which are non-integer, they are simply rounded to integers and the lighting will always be off slightly in an extremely noticeable way, causing a sort of "sub-pixel glow" on edges of objects. I had this same issue on a different isometric game but just ignored it.

What is a good way to deal with this given that all positions will be non-integer? I could use a lighting surface at the same size as the screen rather than the view but this could potentially create other issues regarding the background mask and may still not be enough.
 
Can you post a picture of your problem so we can be sure we understand what you're talking about?

EDIT: The only way I've been able to produce a problem similar to what you describe is when using anti-aliasing.
 
Last edited:

Anixias

Member
Creating two surfaces (one being a lighting mask, the other being the lighting itself) equal to the view size and drawing them in Draw GUI at 0,0. Ignore the character being lit, the mask only works with tiles until I add matrix transformations to render everything else at -view_x, -view_y. It would work best if I could utilize the GUI width and height rather than the view size, but I'm not sure how that would exactly be doable. Maybe more matrix functions could do it?

It really glitches a lot when I walk around and the view moves, since the view is at non-integer coordinates but surfaces only deal with integers.

 
A

Annoyed Grunt

Guest
You should try floor()ing your draw coordinates rather than let the GPU round them.
 

Anixias

Member
I manged to solve it 99% of the way by making the two surfaces 1px wider and taller and flooring the offset to draw the mask at, then when I draw the surface, I draw it at (-frac(vx))*(apw/vw),(-frac(vy))*(aph/vh) where vx/vy are view positions, vw/vh are view sizes, and apw/aph are application surface sizes.

It, however, does occasionally render slightly off for like a single frame, and really looks terrible when that happens. Not sure what to do about it.
 

GMWolf

aka fel666
Sounds more like you are not timing your renders correctly.
It could be you are rendering something before an update, then something else after, which will cause the two rendered things to appear unsynchronized, especially if things are moving fast.
 

Anixias

Member
I think it's more of an artifact of floating point rounding errors or something as it's only noticable while the camera is moving and it doesn't happen super often (often enough that it's visible and a little annoying, but not broken or anything).

Also, I could not get matrix transformations to work. I'm trying to do something like with(all) event_perform(ev_draw,ev_draw); but I want every object to be offset by -view_x and -view_y. Instead, everything except the tile mask disappeared (on the mask, they still render correctly in their normal drawing. this is only regarding creating the lighting mask).

Edit: I'm rendering the tilemap in the lighting mask in the Draw GUI Begin event. Maybe there is a frame of delay somewhere? Not sure how to fix it. The screenshot above is no longer happening as I add the floating point values back in when I actually render the lighting, however there is still a glow similar to that effect occasionally for a single frame.
 

Anixias

Member
Using the approach I linked above, I managed to solve it. The simple steps are:
Draw Begin - Render backgrounds here. Copy application_surface to a blank (0 alpha) surface (surf_bg)
Draw - Draw non-backgrounds normally
Draw End - Render lighting here
Draw GUI Begin - Copy application_surface to a blank (0 alpha) surface (surf_app), then render surf_bg and surf_app.

In order to get it all to work, clouds had to have alpha premultiplied, and I used a few other shaders and surface tricks to prevent "alpha holes" in surfaces.

 
Top