I’m trying to make a health bar using a textureprogressbar. I have a shader that fades out the right side of the material so it transitions smoothly. My issue is I don’t know how to only apply it to the Progress texture of the textureprogressbar instead of the material for the whole object.
You can create a unique material for it inside the inspector when clicking right next to the Material on the drop-down button. If you have several Materials like this you can also set the Material to „Local to Scene“ in the inspector.
In the node itsself? When I do that the shader affects the entire element, progress,overlay,and under texture. How do I make it just affect the progress texture?
It would be easier to create a custom Control that has the same functionality as a ProgressBar and do everything yourself.
If you want to go low level you could also use a ProgressBar and create a custom StyleBox class that uses the RenderingServer directly to draw a new canvas item with the Material you want.
Like:
@tool
class_name StyleBoxShader extends StyleBox
@export var material:Material
@export var texture:Texture2D
# the canvas item we are going to use
var canvas_item_rid:RID
func _init() -> void:
# create the canvas item
canvas_item_rid = RenderingServer.canvas_item_create()
func _notification(what: int) -> void:
if what == NOTIFICATION_PREDELETE:
# don't forget to free it
RenderingServer.free_rid(canvas_item_rid)
func _draw(to_canvas_item: RID, rect: Rect2) -> void:
# clear the canvas item
RenderingServer.canvas_item_clear(canvas_item_rid)
# set its parent to the canvas item from the object we want to draw
# this will inherit transform, modulation and visibility from it
RenderingServer.canvas_item_set_parent(canvas_item_rid, to_canvas_item)
# set our material to the canvas item
RenderingServer.canvas_item_set_material(canvas_item_rid, material.get_rid())
if is_instance_valid(texture):
# if texture is valid, use it
RenderingServer.canvas_item_add_texture_rect(canvas_item_rid, rect, texture.get_rid())
else:
# if texture is not valid, draw a white rectangle
RenderingServer.canvas_item_add_rect(canvas_item_rid, rect, Color.WHITE)
func _get_draw_rect(rect: Rect2) -> Rect2:
return rect
func _get_minimum_size() -> Vector2:
return Vector2.ZERO
This “trick” could also work with a custom Texture2D but the TextureProgressBar class uses the RenderingServer directly when drawing the textures using nine patch so the Texture2D._draw*() callbacks are never called.
Hey there! I know it’s a little late but I may have found a workaround (assuming this isn’t bad practice)
For my game, I simply just create two texture progress bars:
The first texture progress bar is a dummy one with only the under texture set since it remains static the values do not need to be adjusted, and then create a second
The second texture progress bar has only the progress texture set and sits over the top of the dummy one – and this is the texture that you apply a shader to. Granted, I have only tested this with particles as I did not need a shader specially; however, I am certain that it would function just the same.