Intrinsics2 min read

sample_grad

Samples a texture using explicit gradients for LOD calculation.

Reading Time
2 min
Word Count
193
Sections
12
Try It Live

Test sample_grad in a live shader

Open the playground, start from a visual preset, and wire sample_grad into the fragment stage to see how it behaves with real values.

Open Playground

Live Demo

The sample_grad function reads a texture using explicit screen-space gradients to compute the mip level, providing precise control over filtering.

Signature

bwsl
sample_grad :: (texture2D tex, sampler samp, float2 uv, float2 ddx, float2 ddy) -> float4 {...}
sample_grad :: (textureCube tex, sampler samp, float3 dir, float3 ddx, float3 ddy) -> float4 {...}

Parameters

ParameterTypeDescription
textexture*The texture to sample
sampsamplerSampler state
uvfloat2Texture coordinates
ddxfloat2/3Rate of change in screen-space x
ddyfloat2/3Rate of change in screen-space y

Return Value

Returns the filtered texel value with LOD computed from the gradients.

Example

bwsl
pipeline ParallaxMapping {
@fragment_only
fragment {
// Calculate base UV derivatives before parallax offset
float2 baseDx = ddx(input.uv);
float2 baseDy = ddy(input.uv);
// Apply parallax offset
float2 parallaxUV = input.uv + parallaxOffset;
// Sample with original derivatives to prevent mip artifacts
float4 color = sample_grad(albedoTex, parallaxUV, baseDx, baseDy);
output.color = color;
}
}

Common Use Cases

Parallax Mapping

bwsl
// Prevent gradient discontinuities at parallax edges
float2 dx = ddx(uv);
float2 dy = ddy(uv);
float2 offsetUV = parallaxOcclusionMap(uv, viewDir);
float4 albedo = sample_grad(albedoTex, offsetUV, dx, dy);

Triplanar Mapping

bwsl
// Consistent LOD across projection planes
float2 dxXY = ddx(worldPos.xy);
float2 dyXY = ddy(worldPos.xy);
float4 projXY = sample_grad(tex, worldPos.xy, dxXY, dyXY);

Flow Maps

bwsl
// Smooth flow animation without mip popping
float2 flowUV1 = uv + flow * time;
float2 flowUV2 = uv + flow * (time + 0.5);
float2 dx = ddx(uv);
float2 dy = ddy(uv);
float4 sample1 = sample_grad(tex, flowUV1, dx, dy);
float4 sample2 = sample_grad(tex, flowUV2, dx, dy);

UV Distortion Effects

bwsl
// Sample distorted UVs with original gradients
float2 distortedUV = uv + distortion;
float2 originalDx = ddx(uv);
float2 originalDy = ddy(uv);
float4 color = sample_grad(tex, distortedUV, originalDx, originalDy);

Anisotropic Manual Control

bwsl
// Custom anisotropic filtering direction
float2 majorAxis = normalize(flowDirection) * anisotropy;
float4 result = sample_grad(tex, uv, majorAxis, float2(0.0, 1.0));

Gradient Continuity

The primary use of sample_grad is to maintain correct filtering when UV coordinates have been modified (parallax, distortion) but you want mip selection based on the original surface coverage.

When to Use

Use sample_grad when:

  • Applying UV offsets that shouldn't affect mip level
  • Implementing parallax/relief mapping
  • Flow map animations
  • Any UV manipulation that could cause gradient discontinuities

Compiled Output

When compiled to GLSL:

glsl
textureGrad(tex, uv, ddx, ddy)

When compiled to HLSL:

hlsl
tex.SampleGrad(samplerState, uv, ddx, ddy)

See Also