Sprite Color Variation in Godot 4 with a simple shader

แชร์
ฝัง
  • เผยแพร่เมื่อ 28 พ.ย. 2024

ความคิดเห็น • 20

  • @piousthepious
    @piousthepious ปีที่แล้ว +5

    This was very cool!

    • @_yep_
      @_yep_  ปีที่แล้ว

      Thanks ! ;)

  • @DanielTheFox
    @DanielTheFox 11 หลายเดือนก่อน +1

    Nice tutorial, thanks a lot! :)
    It was actually a life saver for me while getting color comparison to work in order to replace certain parts of my pixel art sprites dynamically.
    I ended up using two dummy colors ("full green" and "full red") which I replace dynamically for each instance of an object in my game which I'll publish soonish.
    Background:
    Colors are vectors of floats in Godot and comparing floats via '==' is highly unreliable.
    So after loosing almost 2 days for debugging and trial & error, I ended up using your idea of using a "full green" which omits the rounding errors when dealing with floating point numbers (colors) in Godot's shader language. ;)

    • @_yep_
      @_yep_  11 หลายเดือนก่อน +1

      This is so cool !!
      I'm so glad this actually did help someone ! What kind of game are you working on ? Is it the one on your channel ?
      Working with floats can be a real pain, yes ^^, especially with a variable type that contains 3 or 4 of them.... I just happened to notice there wasn't anything but green in those colors when working on the sprite, which got me thinking "mmm I wonder if this is intentional, what can I do with that ?". I then fiddled a bit with this until I kinda "found" that trick, shaders are so hard to comprehend sometimes....
      I kinda remember there was a "magic" function in Godot that was comparing 2 vectors and was returning true if they were "close enough" but I can't find it any more. Was it in Godot 3 ? Was it only for Vec2 or 3s ? Did I hallucinate this ? A quick search leads to the latter unfortunately, but I found a Stack Overflow thread called "How to compare two colors for similarity/difference" which is fascinating.
      I guess the Quick-and-Dirtyness of this method might still be a good compromise for game dev, where we always try to optimize and use little tricks like this to save on computation power. The only thing that still bothers me though is that "if" statement. I'm sure there a way to do the exact same thing without it, I just can't wrap my head around that shader logic sometimes, I work in web dev both front and back but this s*** is another level of abstraction from forms and http responses. Can really seem like black Voodoo magic the first time you get to it ^^

  • @Singleraxis
    @Singleraxis 7 หลายเดือนก่อน +1

    Thank u very much, this is a quality of life change. Was initially trying to make different sprites for each type of color. The real tough work is converting all the sprite indexes to any desired RGB value that isn't used.

  • @BrandonfromStLouis
    @BrandonfromStLouis 2 หลายเดือนก่อน +2

    Anyone who is interested in dropping the 'if' statement can instead use the following to accomplish the same thing but with a branchless programming condition instead:
    shader_type canvas_item;
    uniform vec4 target_color : source_color;
    void fragment(){
    vec4 current_color = texture(TEXTURE, UV);
    float get_green = step(current_color.r + current_color.b, current_color.g);
    COLOR.rgb = mix(current_color.rgb, target_color.rgb * current_color.g, get_green);
    }

  • @VaunaKiller
    @VaunaKiller 5 หลายเดือนก่อน

    In case you want change multile colors - DeveloperEzra channel has "How I Made Palette Pixel Shader From Scratch in Godot" video on that

  • @Toxic_Trash_0706
    @Toxic_Trash_0706 5 หลายเดือนก่อน

    I've looking for this specific tutorial

  • @pros_0143
    @pros_0143 6 หลายเดือนก่อน +1

    y'really have to dig up on youtube to find straightforward tutorials like these.

    • @_yep_
      @_yep_  21 วันที่ผ่านมา +1

      Thanks, I hate tutorials that take hours too.
      This video is already too long in my opinion, but that might be related to my bad English ^^

  • @VaunaKiller
    @VaunaKiller 5 หลายเดือนก่อน +1

    To avoid using "if" statement: I though maybe we can just replace it with equivalent in math operation.
    E.g. instead of "skipping" operation alltogether, we could ensure that "undersired" colors aren't affected.
    ChatGPT suggested the following code (I haven't tested it yet, but the gist of it looks alright):
    """
    uniform vec4 new_color;
    uniform sampler2D TEXTURE;
    in vec2 UV;
    out vec4 COLOR;
    void fragment() {
    vec4 current_color = texture(TEXTURE, UV);
    vec3 condition = vec3(equal(current_color.rgb, vec3(0.0, current_color.g, 1.0)));
    float factor = step(0.0, current_color.g) * condition.r * condition.b * condition.g;
    COLOR.rgb = mix(current_color.rgb, new_color.rgb * current_color.g, factor);
    COLOR.a = current_color.a;
    }
    """
    And the explanation:
    - `condition` checks if the current_color matches the criteria (0, current_color.g, 1).
    - `factor` is 1 if the `condition` is met and current_color.g is greater than 0, otherwise it is 0.
    - mix function blends current_color.rgb and new_color.rgb * current_color.g based on `factor`
    Not sure if that will boost the perf or degrade it though

    • @DrZ_5000
      @DrZ_5000 5 หลายเดือนก่อน

      if you want to dive deeper into this topic: It's called "branchless programming". Basically avoid if statements, since they use instruction prefetch at assembly code level. That may lead to less performant code (since lots of operations are actually never executed after prefetched by the CPU/GPU, in case the condition is false).

    • @VaunaKiller
      @VaunaKiller 5 หลายเดือนก่อน +1

      @@DrZ_5000 hey! Yeah, I'm aware of the concept, but thanks nonetheless ! :) Maybe someone else would stumble upon it here.
      To add to the topic: branchless programming is also relevant even in interpreted languaes / JIT (e.g. it does make sense both in Javascript and Java/JVM apps), since it allows interpreter (or compiler) to generate less branches -> that in turns leads to additional optimizations too.

  • @KazoWAR
    @KazoWAR 3 หลายเดือนก่อน

    when i try to do this, changing the color of one node effects them all. what do i have to do the make it only effect one node at a time?

    • @_yep_
      @_yep_  3 หลายเดือนก่อน

      Hi !
      I haven't used Godot in a while so I'm not sure how to do it, but your issue must be that you have only one instance of that node, and you duplicate it. You need to instanciate several different nodes. Here's the code if you need : github.com/EvilYep/Godot-RigidBodies/tree/main/ShaderDemo

  • @RhevoRamirez
    @RhevoRamirez 21 วันที่ผ่านมา

    Is it possible to make the same but with red and blue channels? I tried but seems that nothing happens

    • @_yep_
      @_yep_  21 วันที่ผ่านมา +1

      Well this method really relies on the sprite being used. Here, in the sprites, all the colors I want to change don't have any Red or Blue in them (I think it might have been designed that way), so it won't work if you work on the R or B channels.
      But you can design your sprites to only use R or B channels for the colors you need to change and that would work along the same principle.

  • @randomjimbitz512
    @randomjimbitz512 ปีที่แล้ว

    I have tried this with a different green sprite and it does nothing... it is added to the sprite, but the shader does not apply ... any help?

    • @_yep_
      @_yep_  ปีที่แล้ว

      Have you checked the RGB values of the "green" of your sprite ? It have to have a R and B value at 0 for the shader to work (though technically you should be able to use any value between r, g and b. You just need to have 2 channels at 0, while the other one will represent the "shadow" of the color)