Yeah that’s how I was using them too, but I was kind of confused by how you’re using your function, but I guess “pbr” is a struct you’re processing the values into. That is definitely a bit awkward for my needs, so I think I’ve come up with a sort of simpler solution.
Normally, UNITY_SAMPLE_TEX2DWHATEVER will infer the name of the sampler by tacking on “sampler_” to the input texture’s variable name, and this is normally fine when done from within the actual shader program because that variable name is exposed to that area of the code. But in a custom function, your texture name would be whatever the local input parameter name definition for it is, and thus sampler_arrayParameterName ends up pointing to a variable that doesn’t exist anywhere and the compiler throws an error.
So instead, I define my own version of their macro that doesn’t tack on the “sampler” part.
#define T3X_SAMPLE_TEX2DARRAY_SAMPLER(tex,samplertex,coord) tex.Sample (samplertex,coord)
#define T3X_SAMPLE_TEX2DARRAY_SAMPLER_LOD(tex,samplertex,coord,lod) tex.SampleLevel (samplertex,coord,lod)
Now I can create and chain functions to feed my textures and arrays into, passing them around without the need for spaghetti code. I’ll use part of your code as an example:
UNITY_DECLARE_TEX2DARRAY(_Overlay);
UNITY_DECLARE_TEX2DARRAY_NOSAMPLER(_OverlayNorm);
UNITY_DECLARE_TEX2DARRAY_NOSAMPLER(_OverlayPacked);
void FillPBR(PBR pbr, Texture2DArray albedo, Texture2DArray norm, Texture2DArray metal, SamplerState samp, float2 uv, int slice)
{
float3 slice = float3(uv, slice);
pbr.Albedo = T3X_SAMPLE_TEX2DARRAY_SAMPLER(albedo, samp, slice);
pbr.Packed = T3X_SAMPLE_TEX2DARRAY_SAMPLER(metal, samp, slice);
pbr.Normal = SampleArrayNormalUnpacked(norm, samp, slice);
}
float3 SampleArrayNormalUnpacked(Texture2DArray normArray, SamplerState samp, float3 uvSlice)
{
return UnpackNormal(T3X_SAMPLE_TEX2DARRAY_SAMPLER(normArray, samp, uvSlice));
}
void surf (Input IN, inout SurfaceOutputStandard o) {
{
FillPBR(pbr, _Overlay, _OverlayNorm, _OverlayPacked, sampler_Overlay, IN.uv, someSliceValue);
}
These functions and defines could be placed into a CGINC file for global usage by any of your shaders that implement the CGINC file, so all sorts of utility functions could be built around the processing of texture arrays like this, only requiring an extra input parameter or two for manually referencing the sampler.
I have to do a lot of iterating and blending between various sets of dynamically sized texture arrays, so being able to re-use an array blending and processing function like this across different shaders will be quite helpful.