LWRP Custom Function with tex2dlod

Hello! I made this custom function in the shader graph but I seem to keep getting the following error:
4516594--417880--upload_2019-5-8_13-15-6.png

I’ve tried both float4(uv, 0, 0) and float4(uv.x, uv.y, 0, 0) but I still keep getting the same error. I’m not quite sure what the problem is. Any help will be greatly appreciated!

That function requires a sampler state as the first input, not the texture 2d asset: tex2Dlod - Win32 apps | Microsoft Learn

1 Like

Ah, I see. It was just weird for me since in the shader graph, it’s called SamplerState, while in the scripts, it’s called sampler2D. I thought those were two different things. Thanks for the help!

@alexandral_unity 's comment and link is misleading here, unless you actually read the entire page all the way to the bottom.

SamplerState and sampler2D are different things. A SamplerState is a Direct3D 11 thing and is the sampler state alone (i.e.: filtering & wrapping settings), and you need a separate Texture2D (which is the texture object by itself) to sample from. Where as sampler2D is a Direct3D 9 thing and is the sampler state and texture combined. When you use a sampler2D, you need to call tex2D(sampler2D, uv). When you use SamplerState, you need to call Texture2D.Sample(SampleState, uv). You cannot use tex2D() with a SamplerState or Texture2D, and you cannot use .Sample() without a Texture2D and SamplerState.

Shader Graph is written with D3D11 in mind, so it uses Texture2D and SamplerState objects and not sampler2D objects, so you cannot call tex2D() and have it work.*

* BIG ASTERIKS HERE, because it can work if you were compiling directly to OpenGL ES 2.0. And, in fact, if you were to use .Sample() and try to build to an OpenGL ES 2.0 target it would fail because that API does not support separate SamplerState and Texture2D objects, so it needs to use sampler2D and tex2D().

So the real answer is you shouldn’t use either. Instead you should be using the macros Unity provides for the SRPs which handles all of that weirdness for you.

fixed4 color = **SAMPLE_TEXTURE2D**(Texture2D, SamplerState, uv);

Or in your case instead of tex2Dlod or .SampleLevel use SAMPLE_TEXTURE2D_LOD.

Here’s a full list of all of these kinds of macros that the SRPs use:
https://github.com/Unity-Technologies/ScriptableRenderPipeline/blob/master/com.unity.render-pipelines.core/ShaderLibrary/API/D3D11.hlsl

Here’s what a working Custom Function node looks like:
4517542--418027--upload_2019-5-8_13-51-16.png

One oddity to be aware of, notice it is working even without a sampler state defined. In this case the sampler state used is not the one defined by the texture asset, but a new unique “bilinear repeat” sampler state. The shader does actually define a SamplerState for each texture property, and that is what gets used by their Sample Texture 2D nodes when no override is supplied, but currently there is no way to access that sampler state in a generic way using a Custom Function node. This doesn’t really cause any issues, it’s just something to be aware of. Plus, if you use multiples of the “same” Custom Function node in your Shader Graph without a connected Sampler State node, each one will use a unique SamplerState, each using up one of the max of 16 total allowed per shader.

13 Likes

I’m want to use SAMPLE_TEXTURE2D_LOD with URP-mobile , have you any advice?

Either use the existing Sample Texture 2D LOD Node, or use the above Shader Graph Custom Function example as is. Unity should hopefully translate that to the appropriate SamplerState-less version needed for mobile. If you’re aiming for OpenGLES 2.0, you can’t use it, period. Otherwise report it as a bug.

I’m using with Custom Function,it’s working on Editor but when i’m testing on android , i can’t see the object.
My graphic api is OpenGLES3.

Yep, no idea. As far as I know that should work, but I’ve never played with mobile Shader Graph / SRP stuff.

Hello. What if I use 2dArrays? There is only two macros
UNITY_SAMPLE_TEX2DARRAY(name,uv)
UNITY_SAMPLE_TEX2DARRAY_LOD(name,uv,lod)
Both of them don’t use samplers state…

Looking at the file here, we can find the following macros for you to use:

#define SAMPLE_TEXTURE2D_ARRAY(textureName, samplerName, coord2, index)                  textureName.Sample(samplerName, float3(coord2, index))
#define SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod)         textureName.SampleLevel(samplerName, float3(coord2, index), lod)
#define SAMPLE_TEXTURE2D_ARRAY_BIAS(textureName, samplerName, coord2, index, bias)       textureName.SampleBias(samplerName, float3(coord2, index), bias)
#define SAMPLE_TEXTURE2D_ARRAY_GRAD(textureName, samplerName, coord2, index, dpdx, dpdy) textureName.SampleGrad(samplerName, float3(coord2, index), dpdx, dpdy)

I see in the HLSL reference there are 2 tex2D methods. It seems everyone in this thread is referencing tex2D(samplerState, UV)…I’m looking to use the tex2D that takes 4 arguments (sampler state, UV, dx, dy). is there a Direct3D 11 Unity macro or alternative .Sample() method that is equivalent to this tex2D (HLSL reference) - Select the mip level - Win32 apps | Microsoft Learn

Thanks in advance for any help

tex2D(tex, uv, dx, dy) is an override that is equivalent to tex2Dgrad(tex, uv, dx, dy). The DX11 equivalent is tex.SampleGrad(s, uv, dx, dy)

Can we talk about how to use SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, coord2, index, lod) textureName.SampleLevel(samplerName, float3(coord2, index), lod) exactly in a Custom Function shader graph node, provided with an hlsl file?

I am also attempting to instance the Texture2DArray.

So, in my hlsl file:

#pragma target 3.5
UNITY_INSTANCING_BUFFER_START(HeightmapProps)
    UNITY_DEFINE_INSTANCED_PROP(Texture2DArray, _Heightmaps)
    UNITY_DEFINE_INSTANCED_PROP(int, _HeightmapIndices)
UNITY_INSTANCING_BUFFER_END(HeightmapProps)

void GetHeight_float(float2 uv, UnitySamplerState ss, out float4 rgbaOut)
{
    rgbaOut = SAMPLE_TEXTURE2D_ARRAY_LOD(UNITY_ACCESS_INSTANCED_PROP(HeightmapProps, _Heightmaps), ss.samplerstate, uv, UNITY_ACCESS_INSTANCED_PROP(HeightmapProps, _HeightmapIndices), 0);
}

The parameters in the SAMPLE_TEXTURE2D_ARRAY_LOD call as I understand them are as follows:

  • Getting the instanced Texture2DArray
  • Using the given UnitySamplerState ss and accessing the SamplerState within it as .samplerstate
  • Using the given float2 uv coordinate
  • Getting the instanced index to specify the slice of the texture 2D array to use
  • Using 0 as the lod

This compiles, but fails at runtime with the error:
Shader error in 'Shader Graphs/InstancingTestShader': sampler array index must be a literal expression at Assets/Scenes/Test/TestInstancingScene/HeightmapInstancing.hlsl(20) (on d3d11)

Should I be using the sampler state differently? Or, how should I be using the instanced _HeightmapIndices array exactly?

1 Like