[SOLVED] For the love of god, SURFACES. Help.

Discussion in 'Programming' started by Sake_v2, Mar 8, 2017.

Tags:
  1. Sake_v2

    Sake_v2 Member

    Joined:
    Sep 20, 2016
    Posts:
    74
    I used to have a working colored lightning system in Game Maker 8.0 (I think it was that one) some time ago. Then, on the Studio version, the exact same code simply wouldn't work, and after a lot of trying around, I was able to get SOMETHING, but not as before. I was going to worry about this after the game was finished, but whatever, here is a image.

    [​IMG]

    The image on the RIGHT is how it was before, there was no noticeable harsh border on the light, I was able to create a smooth blue lightning out of that with no border. Also the green light. The image on the left, is how it is now. It is KINDA blue and green, but I can't get the smooth lightning effect working again, always with that border. (Yes, I tried using bm_subtract and drawing a circle_colour from green to black and blue to black, that is the effect its creating).

    The code before on the obj_light was this:
    Create event
    Code:
    globalvar light;
    light = surface_create(view_wview,view_hview);
    Step event

    Code:
    surface_set_target(light);
    draw_set_color(make_color_rgb(100,100,100));
    draw_rectangle(view_xview,view_yview,view_wview,view_hview,false);
    surface_reset_target();
    Draw event

    Code:
    draw_set_blend_mode(bm_subtract);
    draw_surface(light,view_xview,view_yview);
    draw_set_blend_mode(bm_normal);
    Then on the blue, green light etc:
    End step event:
    Code:
    size = 300;
    
    draw_set_blend_mode(bm_subtract);
    surface_set_target(light);
    draw_ellipse_color(x-size/2-view_xview,y-size/2-view_yview,x+size/2-view_xview,y+size/2-view_yview,c_blue,c_black,false);
    surface_reset_target();
    draw_set_blend_mode(bm_normal);
    Unfortunately on Studio this stopped working, even using now the draw_circle_coloUr and everything. I'm pretty sure because the draw_set_color(make_color_rgb(100,100,100)); to decide how dark it is doesn't work anymore, instead I have to draw the rectangle with draw_set_color(c_black) and then draw_set_alpha(0.8) or something to determine how dark. Any help on creating the effect on the RIGHT again, would be appreciated.
     
  2. dphsw

    dphsw Member

    Joined:
    Oct 19, 2016
    Posts:
    82
    If I understand correctly, you're saying that some of your drawing code (drawing to surfaces) is in Step events. I don't know how things were different in previous versions (I've only used GMS) but as far as I know you can't do any drawing at all in step events, only in draw events. If you need to make sure some stuff is drawn before the draw event, there's also the 'Draw Begin' event for that purpose.
     
  3. Sake_v2

    Sake_v2 Member

    Joined:
    Sep 20, 2016
    Posts:
    74
    Yes. Thanks for replying. But I fixed that and the actual code are using draw events only, still not creating the effect I'm trying to, though.
     
  4. frumple

    frumple Member

    Joined:
    Feb 4, 2017
    Posts:
    55
    You can draw to surfaces in other events and use some draw functions outside Draw. Without surface juggling draw functions will not have visible results. Another issue is the use of globalvar which may be deprecated in Studio. global.light should be used to declare light as global and to access/modify it.

    But this is all a bit pointless since this is the old code, and not the actual code that isn't working. Seeing that could help identify issues. Maybe.

    http://docs.yoyogames.com/source/da...uage overview/variables/global variables.html
     
  5. Sake_v2

    Sake_v2 Member

    Joined:
    Sep 20, 2016
    Posts:
    74
    Pretty sure its not a global variable problem, though. The global var light is working just fine, it probably wouldn't even run the game or draw at all if it wasn't. I posted the old code so that maybe someone would be able to see which modifications would have to be made to work on Studio. This is how I'm drawing it now:
    obj_light draw event:

    Code:
    if surface_exists(light)
    {
        surface_set_target(light);
        draw_set_color(c_black);
        draw_set_alpha(0.2);
        draw_rectangle(-12,-12,view_wview[0]+12,view_hview[0]+12,false);
        draw_set_blend_mode(bm_subtract);
        with(obj_greenlight1)
         {
              draw_circle_colour(x-view_xview[0]+12,y-view_yview[0]+12,143,c_lime,c_black,false);
          }
        surface_reset_target();
        draw_set_alpha(1);
        draw_surface(light,view_xview[0]-12,view_yview[0]-12);
        draw_set_blend_mode(bm_normal);
    }
    Tried different variations with draw end events, still can't create the smooth effect :(
     
  6. sp202

    sp202 Member

    Joined:
    Sep 26, 2016
    Posts:
    968
    Swap out lime for white and see how that looks.
     
  7. dphsw

    dphsw Member

    Joined:
    Oct 19, 2016
    Posts:
    82
    You seem to start drawing your light surface now with the code
    Code:
       surface_set_target(light);
       draw_set_color(c_black);
       draw_set_alpha(0.2);
       draw_rectangle(-12,-12,view_wview[0]+12,view_hview[0]+12,false);
    
    where previously you just had:
    Code:
    surface_set_target(light);
    draw_set_color(make_color_rgb(100,100,100));
    draw_rectangle(view_xview,view_yview,view_wview,view_hview,false);
    
    Right now it looks like you're not clearing the light target to a constant colour anywhere - and drawing a rectangle that's black with alpha 0.2 each frame will make the surface darker and darker each frame, until it's nearly black (I think once it's RGB(2,2,2), drawing black on it with an alpha of 0.2 will just make it RGB(1.6,1.6,1.6) which will round back up to 2, so it will stop getting any darker.) You should probably clear the surface to something like rgb(100,100,100) as before.
    BTW, if you're clearing the whole surface, you don't need to figure out the coordinates for it - there's a draw_clear function for that.

    And I'm not sure if it makes a difference (it might get reset automatically when you change surfaces, I'm not certain), but you might want to set the drawing colour back to white after drawing your lights, in case having it set to drawing darkly affects the drawing of other things. (Or have it set to rgb(100,100,100), if that was actually happening before.)
     
  8. Nocturne

    Nocturne Friendly Tyrant Forum Staff Admin

    Joined:
    Apr 13, 2016
    Posts:
    6,890
    Don't do that. Use simply:
    Code:
    draw_clear_alpha(c_black, 0.2);
    
    the other way, what you are doing is drawing a transparent black rectangle over the previous contents of the surface, when what you want to do is clear the surface. I would say as well that normally you'd draw all the lights to an opaque black surface and then draw the surface itself at the alpha value you require (and with the blending you require).
     
  9. Joe Ellis

    Joe Ellis Member

    Joined:
    Aug 30, 2016
    Posts:
    936
    I would use additive rather than subtractive, simply do draw_clear(c_black) on the lighting surface just before you draw the lights, then set blendmode to bm_add, draw the lights(circles with white or light color in the middle which fade out to black)<-- black is important here, it has to be black, as this means NOTHING is getting ADDED, any other color will result in the hard borders your seeing

    I would use a shader for this though as its alot more versatile and you can easily invert values and also use multiply blendmode like on photoshop, which is what you want for something like this, and gamemaker doesnt have a built in multiply blendmode, in a shader you simply do -

    Pixelcolor = Normalsurfacecolor * (LightsurfaceColor + Ambient)

    also aswell, I dont know if you already know any of this but I just thought I'd write abit of help about surfaces

    Its fine to draw to a surface in any event, however only the draw events will make the things visible, as this is where the screen buffer is submitted,
    So if your drawing the lighting in the step event thats fine, the color data gets written to the lighting surface, but the part where the lighting surface gets mixed with the normal surface needs to be in the draw event, well you could theoretically mix them together in the step event, then draw the combined result as a surface in the draw event, but that would be wasting memory
    Another thing to bear in mind is that if your using views, or projections, you need to set the projection to fit on the surface just after its been set as target, cus if you think, say the view/camera is in the middle a 5000x5000 room, and the surface you wanna draw to is only 1600x900, all the draw functions you do on the surface will "miss" the surface as theyre getting offset by the view/camera position, so to fix this you need to temporarily set the camera projection to over the surface while your drawing to it, I usually use d3d_set_projection_ortho, x&y at 0,0, as this is where the surface begins, and the width/height to the width/height of the surface, so anything you draw then will be drawn on the surface, providing the coordinates you specify are in the surface dimensions, this could cause a problem if lights are in a room bigger than the surface but its easy to fix by calculating offset values eg. lightXonsurface= LightX-CameraX
    lightYonsurface= LightY-CameraY
     
    Last edited: Mar 9, 2017
  10. Sake_v2

    Sake_v2 Member

    Joined:
    Sep 20, 2016
    Posts:
    74
    I changed the make_color_rgb code because it stopped working on Studio. I learned back on the day from a tutorial, and that was the way instead of c_black to determine how dark the light was. On studio, its completely dark, that's why I changed it.

    I used that, still no change or am I doing something wrong?

    No change.

    Tried the same code but with bm_add. With bm_add, the green color works fine, and the smooth effect kinda works too, but the dark color with draw_clear(c_black) does not.


    What I tried to do now was this:

    Code:
    if surface_exists(light)
    {
        surface_set_target(light);
        draw_clear_alpha(c_black,0.5);
        draw_set_blend_mode(bm_subtract);
        with(obj_lamp)
        {
            draw_circle_colour(x-view_xview[0]+12, y-view_yview[0]+12,30,c_green,c_black,false);
        }
        surface_reset_target();
        draw_surface(light,view_xview[0]-12,view_yview[0]-12);
        draw_set_blend_mode(bm_normal);
    }
    Now not only it isn't smooth, it also isn't green.
    [​IMG]
    With bm_add, it creates this.
    [​IMG]
    Green, kind of smooth, but no dark color around.

    This is too painful. Is there a tutorial for this on Studio somewhere (with working colored lightning)? I can't find it. Thanks for the replies though.
     
    Last edited: Mar 9, 2017
  11. Joe Ellis

    Joe Ellis Member

    Joined:
    Aug 30, 2016
    Posts:
    936
    the thing is if your using bm_add still when you overlay the lighting onto the normal layer, it cant darken it, only lighten it, so I would learn how shaders work and then you can easily multiply the 2 surfaces together, eg. the blackness will be (0.0,0.0,0.0), so multiply any rgb value by 0 and it becomes 0 and the darkening will work, if its half darkness(half way through the light patch) it will multiply the level's colors by 0.5, the only problem with this is that multiplying can only darken stuff if its values are always between 0 and 1, so thats why I suggested adding an ambient shade to it, this will make the lighter patches actually light up the stuff its over and the darkness will not be 100% black either, alternatively you can multiply the lighting layer by a certain amount thats above 1 to increase the ceiling/max brightness, and the blackness will remain black, but you will lose a tiny bit of color depth, most of the time its not noticable tho
    The shader code would look like this:
    Code:
    varying vec2 v_vTexcoord;
    
    uniform float Brightness;
    
    uniform sampler2D Lighting;
    
    void main()
    {
        gl_FragColor = texture2D( gm_BaseTexture, v_vTexcoord ) * (texture2D( Lighting, v_vTexcoord ) * Brightness);
    }
    I can send you an example if your interested
     
  12. Sake_v2

    Sake_v2 Member

    Joined:
    Sep 20, 2016
    Posts:
    74
    The reason why I prefer surfaces over shaders is simply because I have pratically ZERO knowledge with shaders. And if you analyze it, the code I'm using is quite short and simple, I'm sure just a couple of lines would fix the problem. I just don't know what it is, so still needing help. But an example would be nice (for someone who doesn't know shaders).
     
  13. Joe Ellis

    Joe Ellis Member

    Joined:
    Aug 30, 2016
    Posts:
    936
    Ok I'll try and do one for you, and if you send me what you've done so far, I can try and fix the surface code, send it to my email if you want
    joe.ellis@live.co.uk
     
  14. Sake_v2

    Sake_v2 Member

    Joined:
    Sep 20, 2016
    Posts:
    74
    Thank you for the help. Not emailing because I don't use email that often and the lightning object is quite simple, really.
    Current code.

    obj_light

    Create event
    Code:
    globalvar light;
    light = surface_create(view_wview[0]+24,view_hview[0]+24);
    Step event
    Code:
    if !surface_exists(light)
    {
        light = surface_create(view_wview[0]+24,view_hview[0]+24);
    }
    Room end event

    Code:
    if (surface_exists(light))
    {
        surface_free(light);
    }
    Draw event
    Code:
    if surface_exists(light)
    {
        surface_set_target(light);
        draw_clear_alpha(c_black,0.5);
        draw_set_blend_mode(bm_subtract);
        with(obj_lamp)
        {
            draw_circle_colour(x-view_xview[0]+12, y-view_yview[0]+12,30,c_green,c_black,false);
        }
        surface_reset_target();
        draw_surface(light,view_xview[0]-12,view_yview[0]-12);
        draw_set_blend_mode(bm_normal);
    }
    Above code not working because its creating the effect I posted on the other post.
    The reason why I used those view_wview[0]+24 "offsets" is simply because I use smooth camera movement. If the surface is exactly the size of the view, sometimes the surface wouldn't cover one line of pixels.
    And the obj_lamp code doesn't have any code.
     
  15. Joe Ellis

    Joe Ellis Member

    Joined:
    Aug 30, 2016
    Posts:
    936
    To be honest it doesnt seem like its possible to do it using subtract in that way,
    first you need to draw_clear(c_white) not black, if your using subtract, black is white & white is black, as your taking whatever color away from whats already there, same with the green light, it will be removing the green thats already there so everything will end up magenta, if you want the light green you need to set it as magenta, but this is not only annoying but also quite inadequate, as it can only darken stuff and take magenta out of stuff causing it to be left with green which will look like your in a green version of a darkroom, you need to set every different color to its inverse in order to get the correct color,
    you could add an extra step, after the light surface has been drawn, invert it, but again thats more complicated than it needs to be

    I just made the example of how to do it with shaders, it does everything you want and it only took me about an hour,

    https://www.dropbox.com/s/knj9zcl5mymf9gf/Lighting Surfaces.gmx.zip?dl=0

    Even though you'll have to learn how to use shaders, this is probably the easiest & most professional way to do an effect like this

    Do you want me to make a commented version of it?
     
    Last edited: Mar 10, 2017
  16. Sake_v2

    Sake_v2 Member

    Joined:
    Sep 20, 2016
    Posts:
    74
    Hello 321looloo, thank you for taking your time to make an example like this. No need for a commented version, I plan on learning shaders eventually, and your example for sure is gonna help. For now, I found out what the problem was. It wasn't with the code and it wasn't because of the Studio version modifications or anything like that. The problem was with the method I use for setting the game resolution/view_size by drawing the application surface manually. I drew the application surface on a Post Draw event to make sure everything was done drawing, and the lights were also being drawn on a End Step event. Now that I figured out the problem, I can find a way to fix it. I'm going to use this surface method until I learn more about shaders. Problem solved, thanks guys.
     
    Joe Ellis likes this.

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice