Search Unity

Question Is there a better way to "hide" parts of a mesh than what I did via Shader Graph?

Discussion in 'Shader Graph' started by wheee09, Mar 20, 2021.

  1. wheee09

    wheee09

    Joined:
    May 21, 2018
    Posts:
    68
    EDIT - ran into a really odd issue with passing in certain float values to the shader graph and the mod not working. For some odd reason, passing in values of 3, 7, 13 via a float array or a vector3 array don't get passed to the Modulo node properly. Very mind boggling. If I pass in 2, 5, 11, things work as expected. If I hardcode the values of 3, 7, 13, the shader graph works as expected. One workaround is to not use those values and pass in different prime numbers. I'm guessing there might be some floating point precision weirdness. I tried to floor/ceiling the values that were passed in but that didn't help either.

    As a result, I decided to just use conditionals (Branch node) and pass in simple numbers from 1 to 6 instead. I figured the number of calculations I was doing with the modulo wasn't all that different from the dual set of calculations required by the Branch node anyway. And since we're talking about simple meshes that will get culled by the fulcrum, this pre-emptive performance was doubly unnecessary (if it was even that much more performant).



    Hi there,

    The crux of my question is really about using conditionals in a shader/graph. I've read that it's not ideal or efficient to use if/else statements because the GPU goes through both if/else paths and discards one.

    Not sure if this is still true or perhaps the consequences are negligible.

    Problem:
    The problem I'm trying to solve is drawing borders of a hexagon and preventing specific sides of the hexagon from being drawn (via marching squares) using the Shader/graph.

    For example, here's a simple hexagon (border) mesh with all sides showing:

    Screen Shot 2021-03-19 at 8.08.17 PM.png

    Here's the same hexagon but only with the North, South and NorthWest sides showing:


    I did solve it using prime numbers and the modulo operator, but I'm wondering if there's a smarter solution out there or perhaps I should just use conditionals.

    My solution:
    What I did was generate the hexagon mesh with the 6 sides, and each side has a UV2 x-coordinate of a prime number. This means:
    • North side has a UV2 x-coordinate of 2
    • NorthEast side has a UV2 x-coordinate of 3
    • SouthEast side has a UV2 x-coordinate of 5
    • South side has a UV2 x-coordinate of 7
    • SouthWest side has UV2 x-coordinate of 11
    • NorthWest side has UV2 x-coordinate of 13

    Note that I'm using GPU instancing to render these meshes, which means I will be sending over a marching square value over to the shader so that it can process each instance and based on the marching square value, hide or show the sides.

    Ignoring the use of marching squares, just know that I will pass over 6 numeric values (one for each side) to the shader graph.

    The 6 values represent whether to show or hide each side. Each value must be one of the prime numbers used previously (2, 3, 5, 7, 11, 13) which would indicate that we want to show the corresponding side or 99 (arbitrarily large number) to indicate we want to hide it.

    So going back to the 2 hex images above:
    1. To show all sides, I would need to pass over [2, 3, 5, 7, 11, 13] to the Shader Graph
    2. To only show N, S, NW, I would need to pass over [2 (N), 99, 99, 7 (S), 99, 13 (NW)]
    3. To show no sides, I would pass over [99, 99, 99, 99, 99, 99]
    The order of the numbers doesn't really matter, but I'm going clockwise, starting with North.

    In the shader graph, I basically use the modulo operator. The main facts to realize are:
    1. 2 % 2 = 0 (the same number mod with itself equals 0)
    2. 2 % 99 = some non-0 value
    3. 2 % 3 (other prime number) = some non-0 value
    Thus why prime numbers are handy.

    I then multiply the results together, 1-minus it and then clamp it between 0 and 1 and send it to the alpha to hide or show that part of the mesh.

    For example, if I want to only show the North side of the hex, then I would pass over [2, 99, 99, 99, 99, 99] to the Shader graph. When the graph is sampling the UV2 coordinate, it will run into 6 different situations where the UV2 x-coordinate is 2, 3, 5, 7, 11, or 13.

    In the case that the UV2 x-coordinate is 2 then the calculation becomes:
    • (2%2) * (2%99) * (2%99) * (2%99) * (2%99) * (2%99) = 0 (because 2%2 = 0)
    • 1-minus 0 = 1
    • 1 clamped between 0 and 1 = 1
    • Therefore Alpha = 1
    The 5 other scenarios will generate the same result, but using UV2 x-coordinate of 3:
    • (2%3) * (2%99) * (2%99) * (2%99) * (2%99) * (2%99) = large non-zero value, let's say it's 323.
    • 1-minus 323 = -322
    • -323 clamped between 0 and 1 = 0
    • Therefore Alpha = 0

    Here's the shader graph:



    To reiterate, is there a more performant way to do this?

    If you got this far, then thanks for taking the time!
     

    Attached Files:

    Last edited: Mar 20, 2021