How can I use a render script to make one Tilemap layer get its alpha from another layer?

Hi there! :blush:

Is it possible to set up a Tilemap layer so that it uses the alpha (transparency) from another layer—either above or below it—at the same tile position, by editing the render_script? If so, how would I go about doing that?

Here’s what I’m working with:
I’ve combined three textures—two RGB and one greyscale—into a single rgba image for the tilesource. I have three Tilemap layers: Top, Middle, and Bottom. The Middle layer contains greyscale tiles that I want to use as alpha masks. My goal is for the Top layer to get its alpha values from the Middle layer at the same tile positions.

I’d really appreciate any help or guidance you can give. Thanks a lot!

The tilemap layers are drawn one by one z-sorted with other components such as sprites. The tilemaps are drawn using the tilemap.material.

I think your best bet is to split your tilemap layers into multiple tilemaps (top.tilemap, middle.tilemap and bottom.tilemap), and draw the middle.tilemap (the mask) to a render target. Next you use this render target as an input when you draw top.tilemap. You need a custom render script and custom versions of your tilemap materials.

3 Likes

Thanks for your reply! I tried doing this, but for some reason, mask_sampler is showing the same texture as texture_sampler. Also, the top Tilemap seems to be blending with the bottom one when I build the project. I’d really appreciate it if you could help me figure out what I’m doing wrong.

my code that i added in render_script:

function init(self)
    -- Create an RGBA render target 
    local w            = render.get_window_width()
    local h            = render.get_window_height()
    local color_params = {
        format     = graphics.TEXTURE_FORMAT_LUMINANCE,
        width      = w,
        height     = h,
        min_filter = graphics.TEXTURE_FILTER_LINEAR,
        mag_filter = graphics.TEXTURE_FILTER_LINEAR,
        u_wrap     = graphics.TEXTURE_WRAP_CLAMP_TO_EDGE,
        v_wrap     = graphics.TEXTURE_WRAP_CLAMP_TO_EDGE
    }
    -- supply a name, then the table of buffers
    self.mask_target   = render.render_target("mask_target", {
        [graphics.BUFFER_TYPE_COLOR0_BIT] = color_params
    })

    -- Define render predicates for each tilemap layer (tags set on materials)
    self.bottom_pred   = render.predicate({ tag = "bottom" })
    self.mask_pred     = render.predicate({ tag = "mask" })
    self.top_pred      = render.predicate({ tag = "top" })
end

function update(self)
    -- render the other components: sprites, tilemaps, particles etc
    --
    render.enable_state(graphics.STATE_BLEND)
    render.draw(predicates.tile, draw_options_world)
    render.draw(predicates.particle, draw_options_world)
    render.disable_state(graphics.STATE_DEPTH_TEST)

    -- Added Code after the above renders of sprites, tilemaps, particles
    -- 1) Render middle (mask) tilemap into render target
    render.set_render_target(self.mask_target)
    render.clear({ [graphics.BUFFER_TYPE_COLOR0_BIT] = vmath.vector4(0, 0, 0, 0) })
    render.draw(self.mask_pred) -- draw all objects tagged “mask”
    -- Restore default target (screen)
    render.set_render_target(render.RENDER_TARGET_DEFAULT)

    -- 2) Draw bottom tilemap normally
    render.draw(self.bottom_pred) -- draw all objects tagged “bottom”

    -- 3) Bind mask texture and draw top tilemap
    -- Bind the render target’s color buffer to texture unit 1
    render.enable_texture(1, self.mask_target, graphics.BUFFER_TYPE_COLOR0_BIT)
    render.draw(self.top_pred) -- draw all objects tagged “top” using mask
    render.disable_texture(1)

my top.material:

name: "tile_map"
tags: "top"
vertex_program: "/builtins/materials/tile_map.vp"
fragment_program: "/test_material/materials/top_tilemap.fp"
vertex_constants {
  name: "view_proj"
  type: CONSTANT_TYPE_VIEWPROJ
}
fragment_constants {
  name: "tint"
  type: CONSTANT_TYPE_USER
  value {
    x: 1.0
    y: 1.0
    z: 1.0
    w: 1.0
  }
}
samplers {
  name: "mask_sampler"
  wrap_u: WRAP_MODE_CLAMP_TO_EDGE
  wrap_v: WRAP_MODE_CLAMP_TO_EDGE
  filter_min: FILTER_MODE_MIN_LINEAR
  filter_mag: FILTER_MODE_MAG_LINEAR
}

my top.fp:

#version 140
varying  mediump vec2 var_texcoord0;
uniform sampler2D texture_sampler; // slot 0: atlas
uniform sampler2D mask_sampler;    // slot 1: our RT
out vec4 out_fragColor;
uniform fs_uniforms { mediump vec4 tint; };

void main() {
    vec4 c = texture(texture_sampler, var_texcoord0);
    float m = texture(mask_sampler, var_texcoord0).r;
    out_fragColor = vec4(c.rgb * tint.xyz, c.a * m * tint.w);
}