#Rendering an overlay — performance concerns

7 messages · Page 1 of 1 (latest)

teal crescent
#

Hey all, I'm doing something which I figure should be very simple and have basically 0 cost, though I don't really have good heuristics for what is and what is not expensive when it comes to rendering so I figured I'd run it by here and see if I'm doing something completely ass-backwards.

Basically, I'm doing a roguelike thingy and have implemented FOV. I want to render this FOV as an overlay on top of my existing sprites. It is no issue creating this image, but when rendering it it feels like it heats up my computer more than neccesary. I make a very small image and then scale it up to my grid size (which is 24 pixels) so the image doesn't end up being very big at all. This is the code I have right now:

fn player_sight_render_visibility(
    mut commands: Commands,
    window: Single<&Window>,
    player: Single<(Entity, &Sight, Ref<Position>), With<Player>>,
    tiles: Res<BlockedTiles>,
    settings: Res<GameSettings>,
    camera: Single<(&OrthographicProjection, &GlobalTransform, Ref<Transform>), (With<Camera2d>)>,
    overlay: Single<Entity, With<Overlay>>,
    mut images: ResMut<Assets<Image>>,
) {
    let (player_ent, sight_data, ref player_pos) = *player;
    let (projection, camera_transform, ref transform) = *camera;
    if !transform.is_changed() && !player_pos.is_changed() {
        return;
    }
    eprintln!("creating new shadow image");
    let camera_pos = camera_transform.translation().xy();
    let (cam_x, cam_y) = translate_camera_position(&*settings, camera_pos.x, camera_pos.y);
    let (window_w, window_h) = window.size().into();

    let (window_w,window_h) = translate_camera_position(&*settings, window_w, window_h);
    let buffer = ImageBuffer::from_fn(window_w as u32, window_h as u32, |x,y| {
        let pos = Position::new(cam_x - window_w / 2  + x as i32, cam_y + window_h / 2 - y as i32);
        if sight_data.visible_tiles.contains(&pos) {
            LumaA([0f32, 0.])
        } else {
            LumaA([0f32, 0.5])
        }
    });


    let mut image = Image::from_dynamic(DynamicImage::from(buffer), false, RenderAssetUsages::RENDER_WORLD);
    image.sampler = ImageSampler::nearest();
    let img_handle = images.add(image);
    let mut overlay_sprite = Sprite::from_image(img_handle);
    overlay_sprite.anchor = Anchor::TopLeft;

    let k = settings.grid_size as f32;
    commands.entity(*overlay).insert((
        overlay_sprite,
        Transform::from_scale(Vec3::new(k, k, 1.0))
            .with_translation(Vec3::new(camera_pos.x - window.size().x / 2., camera_pos.y + window.size().y / 2., 0.0))
    ));
}

is this just inherently a very inefficient way of doing things? is there any other method I should use? It's not like my computer is burning up by any means but the GPU still gets pretty active whereas rendering just my other small sprites seems to be pretty much "free".

#

okay actually I think I was just a bit too paranoid about the performance here. it doesn't seem to have a big impact now when I tried with it off and on.

Still, I would appreciate some pointers about my code on this! I'm very much a noob when it comes to game programming, so my question is mostly is this like a reasonable approach to this problem?

tame patrol
teal crescent
#

yep!

tame patrol
# teal crescent yep!

depending on your usecase, what you've done is just fine. The only other big option is to use a custom shader, but thats quite advanced.

#

some ideas:

  • you could make the overlay entity a child of your camera, so that it inherits the cameras Transform

  • you could make the overlay an Ui image, which can be set to cover the entire screen once and you never have to move it

  • you could cover each tile individually, so that you don't have to re-compute the image if visibility changes - just have to make some entities visible/invisible. this will mean you're technically rendering these many entities more, but if they're just black squares for example they'll be instanced so you can probably render thousands of them without noticing

  • you could make your tiles invisible, revealing a dark background

tame patrol