1
\$\begingroup\$

I'm converting old shader code to be a bit more modern. So far this works out great, but I'm having a though time figuring out how to convert shader code that works with cubic textures.

In the old code I would declare a generic texture in HLSL and create a samplerCube to do the sampling. Then I would use the intrinsic texCube function to actual sample in the direction of the normal N.

texture Irradiance;
samplerCUBE irradianceSampler = sampler_state
{
    Texture = (Irradiance);
    MinFilter = LINEAR;
    MagFilter = LINEAR;
    MipFilter = LINEAR;
    AddressU = Clamp;
    AddressV = Clamp;
    AddressW = Clamp;
};

float3 N;
float4 irradiance = texCUBE(irradianceSampler, N);

In the updated shader I would like to use the texture objects. In case of a cubic texture I would assume I'd have to use the TextureCube type. This type has a regular Sample method but that method does not accept a samplerCube only a sampler. Using a regular sampler I have no idea how to pass the normal argument N to look up the pixels.

To summarize in code, this is the code that I expected to have to write

TextureCube Irradiance;
samplerCube irrandianceSampler = sampler_state {...};

float3 N;
float irradiance = Irradiance.Sample(irradianceSampler, N);

But that doesn't compile because samplerCube does not conform to the first argument of Irradiance.Sample.

TLDR

Who can show me the right syntax to sample from a TextureCube in HLSL Shader Model 5+.

\$\endgroup\$
2
  • \$\begingroup\$ This looks like it's documented here. Have you tried passing a regular SamplerState as the first argument, instead of a samplerCube? \$\endgroup\$ – DMGregory Apr 13 at 18:07
  • \$\begingroup\$ It didn't click for me that the regular texture object's Sample method would also apply here. Since it was two separate things before. It does work now though :D. \$\endgroup\$ – Roy T. Apr 13 at 19:12
3
\$\begingroup\$

This doesn't work the way you're expecting because texture slots and sampler slots are decoupled in D3D10/SM4+. So unlike legacy code, you can have a texture at slot x, a sampler state at slot y (and remember that sampler state slots are no longer the same as texture slots) and combine them to sample that texture. You can also use the same sampler state at slot y to sample other textures at other texture slots, and even sample your original texture at slot x with other sampler states at other sampler slots.

If that sounds complicated and confusing - don't panic. It's actually quite simple and clean when you see it in code.

Here's a definition for a bunch of samplers (note: I'm not using Effects here):

sampler samLinearWrap : register(s0);
sampler samLinearClamp : register(s1);
sampler samPointWrap : register(s2);
sampler samPointClamp : register(s3);

I've just named these according to the state configured for each, and explicitly specified their slots using the register keyword.

Here's a diffuse texture (don't worry, I'll come to cubemaps before too long):

Texture2D<float4> mainTexture : register(t0);

So I can now sample this texture like so:

float2 texcoords = ....
float4 diffuse = mainTexture.Sample (samLinearWrap, texcoords);

I could just as easily declare any other texture at any other slot number, and likewise sample it using the same samLinearWrap. So, for example, if I was doing some lightmapping:

Texture2D<float4> lmapTexture : register(t1);
float2 lmcoords = ....
float4 lightmap = lmapTexture.Sample (samLinearWrap, lmcoords);

Same sampler, different texture, and it all works.

Of course I can also use a different sampler if I wish:

float4 lightmap = lmapTexture.Sample (samLinearClamp, lmcoords);

This seamlessly extends to cubemaps, array textures and other texture types. Obviously for cubemaps it makes more sense to use a clamp sampler state, but otherwise it works the very same:

TextureCube<float4> cubeTexture : register(t2);
float3 cubemapcoords = ....
float4 cubetex = cubeTexture.Sample (samLinearClamp, cubemapcoords);

And just for completeness, and to have this answer be more generally useful:

Texture2DArray<float4> arrayTexture : register(t3);
float3 arraycoords = ....
float4 arraytex = arrayTexture.Sample (samLinearClamp, arraycoords);

(Again notice: same sampler object, different texture objects, and the fact that I used samLinearClamp for my second lightmap/2D texture example doesn't prevent me using it for cubemaps, array textures or any other type).

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Ah this made it click, I thought I actually tried this already, and I was aware of how the decoupling works for regular Texture2D, but it didn't click for me that I could also use the new SamplerStates like this. Thanks! \$\endgroup\$ – Roy T. Apr 13 at 19:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.