Metal着色语言中texture的read与sample函数的区别及适用场景
Core Differences Between
read() and sample() in Metal Shading Language Great question! Let’s break down the key distinctions between these two texture access methods, along with clear use cases for each.
1. Coordinate System & Sampling Logic
read(): Uses integer texel coordinates to directly fetch a single, unmodified texel (texture pixel) from the texture. There’s no filtering here—you’re grabbing the exact value stored at that specific location. For example,texture.read(uint2(15, 25))pulls the texel at column 15, row 25, no questions asked. You can also specify a mipmap level withread(uint2 pos, uint lod), but even then, it just fetches the exact texel from that mip level without interpolation.sample(): Uses normalized floating-point coordinates (ranging from0.0to1.0, mapping to the texture’s top-left to bottom-right corners). It relies on a boundsamplerobject to apply filtering rules—like linear interpolation, mipmapping, or anisotropic filtering. For example,texture.sample(mySampler, float2(0.3, 0.7))will blend nearby texels (or pick the right mip level) based on how you configured the sampler.
2. Dependencies & Supported Textures
read(): Doesn’t require a sampler. However, it only works with non-compressed textures—since compressed textures store data in blocks, you can’t directly access individual texels. It’s also commonly used in compute shaders for random, direct texel access.sample(): Mandates a sampler (you define its properties like filtering mode, address mode, etc.). It supports both compressed and non-compressed textures, as the sampler handles decoding and filtering of compressed blocks.
When to Use Each Method
Use read() If:
- You need pixel-perfect, unfiltered access to individual texels. This is ideal for pixel-level image processing (e.g., histogram calculation, per-pixel color correction) or reading texture-stored metadata (like lookup tables or game state data).
- You’re working in a compute shader and need random, direct access to specific texels—compute shaders often operate on discrete texel data without needing smoothing.
- You want to avoid the overhead of sampler logic, or your use case explicitly calls for raw, unmodified texel values (e.g., pixel-art rendering where you don’t want blurring).
Example (Compute Shader):
kernel void processTexture( texture2d<float, access::read> inputTex, texture2d<float, access::write> outputTex, uint2 gid [[thread_position_in_grid]] ) { // Read the exact texel at the thread's grid position float4 rawPixel = inputTex.read(gid); // Apply a simple grayscale conversion float gray = dot(rawPixel.rgb, float3(0.2126, 0.7152, 0.0722)); outputTex.write(float4(gray, gray, gray, rawPixel.a), gid); }
Use sample() If:
- You need texture filtering to smooth out jagged edges or handle distant objects (via mipmapping). This is standard in 3D rendering, where texture coordinates on a model don’t align perfectly with texel boundaries.
- You’re working in a vertex/fragment shader for texture mapping—UV coordinates are normalized, and sampling with filtering ensures the texture looks smooth on curved or distant surfaces.
- You need to use address modes (e.g., repeating a texture across a surface, clamping it to the edge) or advanced filtering like anisotropic filtering.
Example (Fragment Shader):
fragment float4 textureShader( float2 uv [[texture_coord]], texture2d<float> inputTex [[texture(0)]] ) { // Define a sampler with linear filtering and repeat address mode const sampler texSampler( coord::normalized, address::repeat, filter::linear ); // Sample the texture with smoothing return inputTex.sample(texSampler, uv); }
内容的提问来源于stack exchange,提问作者Deepak Sharma
相关产品推荐
相关产品推荐

