Search Unity

Bug Custom Function with Texture2D not working

Discussion in 'Shader Graph' started by Slock20969, Nov 13, 2020.

  1. Slock20969

    Slock20969

    Joined:
    Nov 18, 2015
    Posts:
    15
    Hi All, I'm trying to create a Custom Function Node with Texture2Ds. However, even the simplest function won't compile. I created a node with 1 Texture2D as input (A) and 1 as output (C). Then in the String field I put:
    C = A;

    This is as simple as I can figure, but no matter what I put in there I get the same unhelpful error: cannot convert from 'int' to 'struct SurfaceDescription' at line 39 (on d3d11)

    I've tried creating a custom node that does the same thing as above but with Vectors and it compiles fine.
     
  2. Olmi

    Olmi

    Joined:
    Nov 29, 2012
    Posts:
    1,553
    Hi,

    Which render pipeline are you using? URP or HDRP? At least on URP I don't have problems with Texture2D inputs. However, I'm not sure if you can pass out a Texture2D. But you can definitely load in one, sample it, and output a color (for example.)

    I assume there's a specific reason why you would need to be able to pass forward a Texture2D, but I fail to guess what you're trying to do. Perhaps someone more knowledgeable might be able to help.
     
  3. briankendall

    briankendall

    Joined:
    Nov 25, 2017
    Posts:
    3
    I'm having precisely the same issue! I'm trying to make a custom function -- any custom function -- that takes a Texture2D as an input and output, and I can't even come close to getting it working. Haven't found any docs that help.

    edit: I'm using URP
     
    Last edited: Nov 16, 2020
  4. briankendall

    briankendall

    Joined:
    Nov 25, 2017
    Posts:
    3
    I can also say that in my case I'm trying to implement basic gaussian blur in a custom function node so that I can use it to blur a texture in a shader graph. In order to do that I'd need to be able to sample the texture at various points, which at least means taking a Texture2D as an input. (Maybe I can use a vector4 as an output though? I'm not sure.)
     
  5. Oxeren

    Oxeren

    Joined:
    Aug 14, 2013
    Posts:
    121
    Maybe I'm missing something, but I'm not sure why you would need to output a Texture2D, since you can't modify it in the custom function anyway, so you can just output the resulting vector4.
    As for the input, if you need to sample a texture in your custom function and you have it defined as a property in your graph's blackboard, you can just use the regular macro SAMPLE_TEXTURE2D(_TextureReference, sampler_TextureReference, uv) without the need to make any additional steps (just replace _TextureReference with the reference of the texture you've defined on the blackboard), since everything from the blackboard will be added to the property block of the compiled shader.
     
    Olmi likes this.
  6. briankendall

    briankendall

    Joined:
    Nov 25, 2017
    Posts:
    3
    You are correct -- the source of the error is having a Texture2D as an output. It seems that having one as an input is fine. Once I changed my function to output a float4 then it started compiling successfully.

    You are correct that you can do things this way, and of course in some use cases this will be the best option. But for me it's a lot less flexible than taking a texture as an input. Fortunately, I did figure out the correct way to do that:
    Code (CSharp):
    1. void ThingyDoodle_float(Texture2D Tex, SamplerState SS, float2 UV, out float4 Out) {
    2.     Out = SAMPLE_TEXTURE2D(Tex, SS, UV);
    3. }
    4.  
    That will just a pass a texture through without any changes. The custom function node needs to have a Texture2D, SampleState and float2 as inputs.
     
  7. Olmi

    Olmi

    Joined:
    Nov 29, 2012
    Posts:
    1,553
    @briandkendall Texture object and sampled color are two different things. So you are really not passing forward the "Texture" when you output a float4 or something. But OP didn't explain what he is trying to do, or if it was a misunderstanding or such.
     
  8. Slock20969

    Slock20969

    Joined:
    Nov 18, 2015
    Posts:
    15
    I am using HDRP. I would like to input several Texture2D and then based on the input UVs, select the correct texture and change the UVs. I was assuming I could then output the correct Texture2D and the updated UVs and then pass those to a Sampler Node. But based on the following replies, it seems I'll have to do the sampling myself.
     
  9. Slock20969

    Slock20969

    Joined:
    Nov 18, 2015
    Posts:
    15
    All, I just want to thank you for the above discussions, they were superhelpful. I will say, if you can not pass out a Texture2D that should be removed from the Custom Function's OUTPUT Dropdown.

    Based on the above discussions, I did re-format how I did things to get the result I wanted and incase anyone gets here via Google, this is how I did it.
    1. Combined my textures into a Texture2DArray asset
      1. This is not intuitive, there doesn't seem to be a Unity Editor way to do this. You have to do it via code. This was very helpful in doing that https://forum.unity.com/threads/creating-texture2darray-as-asset.425461/
    2. Created a HDRP Graph with a Texture2D Array as a Property
      1. You can either upload your Texture2DArray asset at launch via C# and the array's Reference name or just drop your asset into the default. Both worked.
    3. Create a Custom Node Function that maps the UVs to hte correct index of the Texture2D array and updated UV you want. Pass the outputs of that into a Texture2DArray Sampler which outputs a color

    Here is the test I wrote that works. The re-mapping will just re-map two side by side textures to be next to eachother. You can go NxM, you just have to divide and modulo by the correct amount.

    Code (CSharp):
    1. #ifndef ARRAYCHOOSER_INCLUDED
    2. #define ARRAYCHOOSER_INCLUDED
    3.  
    4. void TextureArrayChooser_float(float2 uvs, out float1 arrayIndex, out float2 updatedUVs)
    5. {
    6.     float xLon = uvs.x;
    7.     float yLat = uvs.y;
    8.     arrayIndex = floor(uvs.x * 2);
    9.    
    10.     float remappedX = fmod(xLon, 0.50000);
    11.     float updatedX = remappedX / 0.50000;
    12.     float updatedY = yLat;
    13.     updatedUVs = float2(updatedX, updatedY);
    14.  
    15. }
    16.  
    17. #endif // ARRAYCHOOSER_INCLUDED