添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement . We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account SubViewport & TileMap doesn't respect Visibility Layer / Canvas Cull Mask when Y Sort is enabled. #75206 SubViewport & TileMap doesn't respect Visibility Layer / Canvas Cull Mask when Y Sort is enabled. #75206 bryanwood opened this issue Mar 22, 2023 · 3 comments

Windows 11

Issue description

Enabling Y-Sort for a TileMap node causes it to show up in a SubViewport even when the visibility_layer and canvas_cull_mask don't match.

Should look like this:

Get this with Y Sort toggled on:

I've had a look at tile_map.cpp and it doesn't look like the visibility_layer is passed to the canvas_items it creates. tile_map overrides set_light_mask and passes this along, seems it would be appropriate to pass along the visibility_layer as well?

I've patched this locally and seems to work but it involved making set_visibility_layer and set_visibility_layer_bit methods overridable in canvas_item.h.

The tile_map.cpp changes:

void TileMap::_update_visibility_layer_for_canvas_items() {
	for (unsigned int layer = 0; layer < layers.size(); layer++) {
		for (KeyValue<Vector2i, TileMapQuadrant> &E : layers[layer].quadrant_map) {
			TileMapQuadrant &q = E.value;
			for (const RID &ci : q.canvas_items) {
				RS::get_singleton()->canvas_item_set_visibility_layer(ci, get_visibility_layer());
		_rendering_update_layer(layer);
void TileMap::set_visibility_layer(uint32_t p_visibility_layer) {
	// Set material for the whole tilemap.
	CanvasItem::set_visibility_layer(p_visibility_layer);
	TileMap::_update_visibility_layer_for_canvas_items();
void TileMap::set_visibility_layer_bit(uint32_t p_visibility_layer, bool p_enable) {
	CanvasItem::set_visibility_layer_bit(p_visibility_layer, p_enable);
	TileMap::_update_visibility_layer_for_canvas_items();

Not really confident with engine or c++ dev and contributing but happy to make a PR.

Steps to reproduce

Given this scene tree:

and these settings:

Viewport (SubViewportCullMaskSetTo2):

TileMap (TileMapSetToVisibleOnLayer1):

Parent Nodes (Node2D_VisibleSetToLayer1And2 and VisibleSetToLayer1And2):

The tilemap will still be present in the viewport texture of ViewportTextureShowsTileMapAndSprite

Minimal reproduction project

Tile Map Visibility Layer For Canvas Items.zip

I've had a look at tile_map.cpp and it doesn't look like the visibility_layer is passed to the canvas_items it creates. tile_map overrides set_light_mask and passes this along, seems it would be appropriate to pass along the visibility_layer as well?

I've patched this locally and seems to work but it involved making set_visibility_layer and set_visibility_layer_bit methods overridable in canvas_item.h.

The tile_map.cpp changes:

void TileMap::_update_visibility_layer_for_canvas_items() {
	for (unsigned int layer = 0; layer < layers.size(); layer++) {
		for (KeyValue<Vector2i, TileMapQuadrant> &E : layers[layer].quadrant_map) {
			TileMapQuadrant &q = E.value;
			for (const RID &ci : q.canvas_items) {
				RS::get_singleton()->canvas_item_set_visibility_layer(ci, get_visibility_layer());
		_rendering_update_layer(layer);
void TileMap::set_visibility_layer(uint32_t p_visibility_layer) {
	// Set material for the whole tilemap.
	CanvasItem::set_visibility_layer(p_visibility_layer);
	TileMap::_update_visibility_layer_for_canvas_items();
void TileMap::set_visibility_layer_bit(uint32_t p_visibility_layer, bool p_enable) {
	CanvasItem::set_visibility_layer_bit(p_visibility_layer, p_enable);
	TileMap::_update_visibility_layer_for_canvas_items();

The thing is the TileMap's canvas item is parent to the layers' canvas items which are parent to quadrants' canvas items (within the rendering server) so the TileMap's visibility layer should automatically be taken into account, there should be no need to manually propagate the visibility layers to each quadrant. So the issue seems to be not related to the TileMap specifically, I'd guess it's rather something about how y-sorted canvas items are handled within the rendering server.

Meaning the suggested code changes would maybe fix the symptom, but likely not the actual issue.

For confirmation: tile_map_is_not_the_problem.zip

Disabling Y-sorting for either Node2D or PseudoTileMap makes the PseudoQuadrant be properly not rendered.

Thank you for the explanation and example, think I understand how that's working a little better now. I looked into the rendering server and how canvas items are culled when y sorted.

There's _cull_canvas_item and it checks if the item is visible and then if the visibility_layer / canvas_cull_mask match. Y sorted nodes are dealt with in _collect_ysort_children which makes a visible check before adding them to the flattened array, I think this should also check for visibility_layer / canvas_cull_mask?

I tried adding that check (and calling _mark_ysort_dirty() when calling canvas_item_set_visibility_layer ) and it works for the example scene in tile_map_is_not_the_problem.zip but not for the one I originally posted. Think this is because the ysort_children_count that's reset to -1 by _mark_ysort_dirty() is reused for each viewport even though they'd be different lengths for different viewports if visibility_layer is taken into account when culling Y sorted items.