• RuntimesGodot
  • [Godot] Spine Backface Culling Feature

@Mario I want to inquire about what technical difficulties you had with backface culling if you tried to implement it into Godot runtime. I know Godot v3.5 only really support backface cull in 3D spatial nodes. Your response is much appreciated since the workaround would affect Spine weighted meshes and animation keying.

Related Discussions
...

I haven't tried implementing it because, as you also stated, it's really only supported in SpatialNodeinstances, which we currently do not support.

One possible approach for CanvasItem/Node2D would be to do the culling on the CPU: before submitting the mesh, iterate through all triangles, calculate their winding order, and replace culled triangles with degenerate triangles, e.g. by setting all indices of the triangle to the same index.

The issue with that is that it can become a bit complex if you also take into account negative scale.

Maybe ShaderMaterial could be coerced to do backface culling somehow, but I haven't looked into that too deeply. A quick look tells me it's not really possible.

    Mario
    Thank you for your insight. I don't think shaders could work either. Godot divides ShaderMaterial Shader into either 2D canvas_item or 3D spatial shader type. The FRONT_FACING ( gl_FrontFacing ) is only recognized in 3D spatial type.

    https://docs.godotengine.org/en/3.5/tutorials/shaders/converting_glsl_to_godot_shaders.html

    • Mario がこの投稿に返信しました。

      SilverStraw then I suppose all we can do is manual culling on the CPU, or implement a SpineSprite3D (for which there is an issue)

      2ヶ月 後

      I enabled 2D backface culling glEnable(GL_CULL_FACE) on the GLES3 reset_canvas method line in Godot 3.5 C++ source (https://github.com/godotengine/godot/blob/3.5/drivers/gles3/rasterizer_canvas_base_gles3.cpp#LL939C26-L939C26). GLES2 has an equivalent method also. The drawback is that it affects the editor GUI as well. I tried adding a working blackface culling option to the CanvasItem but I wasn't successful.

      The editor popup windows' background texture disappear when you enable backface culling on canvas reset 😅. This gdscript plugin patches the missing background textures by adding something in (hopefully).

      tool
      extends EditorPlugin
      
      var background_texture = preload("res://solid_color.png")
      
      func _enter_tree() -> void:
      	var base :Control = get_editor_interface().get_base_control()
      	var class_names_filter :Array =  [
      		"EditorAbout",
      		"EditorExport",
      		"EditorFileDialog",
      		"EditorSettings",
      		"ExportTemplateManager",
      		"PluginConfigDialog",
      		"ProjectSettingsEditor",
      		"ProjectExportDialog",
      		"ScriptCreateDialog"
      	]
      	var result :Array = []
      	self.findByClass( base, class_names_filter, result )
      	for control in result:
      		self.add_TextureRect( control )
      	result = []
      	#For what ever reason, assigning show_behind_parent for Popup controls in the same loop
      	#as the rest of the other control classes make the other TextureRect nodes disappear.
      	self.findByClass( base, ["Popup"], result )
      	for control in result:
      		var t :TextureRect = self.add_TextureRect( control )
      		t.show_behind_parent = true
      		#t.self_modulate.a = .5
      
      func findByClass(node :Node, class_names :Array, result :Array ) -> void:
      	for class_Name in class_names:
      		if node.is_class( class_Name ) :
      			result.push_back(node)
      	for child in node.get_children():
      		self.findByClass( child, class_names, result )
      
      func add_TextureRect( control_node :Control ) -> TextureRect:
      	var base: Control = get_editor_interface().get_base_control()
      	var texture_rect := TextureRect.new()
      	texture_rect.texture = background_texture
      	texture_rect.expand = true
      	texture_rect.stretch_mode = TextureRect.STRETCH_TILE
      	texture_rect.modulate = Color.gray
      	connect("tree_exiting", texture_rect, "queue_free")
      	control_node.add_child( texture_rect )
      	self.match_rect(texture_rect, control_node)
      	control_node.move_child( texture_rect, 0 )
      	return texture_rect
      
      func match_rect( of :Control, to :Control ) -> void:
      	of.rect_min_size = to.rect_min_size
      	of.rect_size = to.rect_size
      	of.rect_global_position = to.rect_global_position
      
      
      • Nate が「いいね」しました。
      7日 後

      Hax!

      I got too excited at first 😞. There is an issue when the SpineSprite is on the edge of the view port that it breaks face culling and appear 🥲.

      8日 後

      Update:

      After more testing, inserting glEnable(GL_CULL_FACE) into RasterizerCanvasGLES3::render_joined_item seem to be a better location than RasterizerCanvasBaseGLES3 _draw_polygon ( https://github.com/godotengine/godot/blob/3.5/drivers/gles3/rasterizer_canvas_gles3.cpp#L1240 ). The editor user interface is not affected. Zooming in or sprites getting close to the view port edge does not break the face culling.

      Nice!

      4ヶ月 後
      NateGodot タグ を追加しました。
      2ヶ月 後

      This is still using Godot 3.5 C++ source for GLES3 rendering. I finally got Godot shader language for 2d to control face culling.

      Source changes:



      Neat! Do you think the core devs would accept a PR from you? Seems like a feature not only valuable for spine-godot.

      I can try to do a pull request.

      1年 後

      Update on Godot 4.3 using Compatibility renderer using GLES3.



      • Luke が「いいね」しました。

      I forgot to add the line

      CullMode cull_mode;

      after the

      enum CullMode{
          CULL_DISABLED,
          CULL_FRONT,
          CULL_BACK
      }

      It would be totally worth it to submit that as a proposal to Godot. Exposing culling in 2D is a good thing for tons of use cases, not only Spine.