HLSL tex2d 采样器似乎使用不一致的舍入;为什么?
我的代码需要根据对象的位置以不同的方式渲染对象的区域。我正在尝试使用颜色图来定义这些区域。
问题是当我从颜色图中采样时,会发生碰撞。即,颜色图中具有不同颜色的两个区域获得从采样器返回的相同值。
我尝试过各种格式的颜色图。在每种情况下,我将每个区域的颜色设置为相距“5”;
- 索引颜色
- RGB、RGBA:区域 1 将具有 RGB 5%,5%,5%。区域 2 将有 RGB 10%、10%、10% 等。
- HSV 灰度:区域 1 的 HSV 为 0,0,5%。区域 2 将有 HSV 0,0,10% 等。
(在 The Gimp 中选择的值)
tex2D 采样器返回一个值 [0..1]。
[ 然后我打算从区域派生一个 int 数组索引。与此相关的代码是不相关的,因此已从问题中删除] 对
float region = tex2D(gColourmapSampler,In.UV).x;
“5%”颜色进行采样在 hlsl 中给出了 0.05098 的“区域”。 由此我假设 5% 代表 5/100*255 或 12.75,在存储在纹理中时四舍五入为 13。 (推理:0.05098 * 255 ~= 13)
按照这个逻辑,50%应该存储为127.5。
采样后,我得到 0.50196,这意味着它存储为 128。70
% 应存储为 178.5。
采样后,我得到 0.698039,这意味着它被存储为 178。
这里发生了什么舍入?
(127.5 变成 128,178.5 变成 178?!)
编辑:好的, http://en.wikipedia.org/wiki/Bankers_rounding#Round_half_to_even 显然这是“银行家的四舍五入”。我不知道为什么要使用它,但它解决了我的问题。显然,这是一个 Gimp 问题。
我正在使用 Shader Model 2 和 FX Composer。这是我的采样器声明;
//Colour map
texture gColourmapTexture <
string ResourceName = "Globe_Colourmap_Regions_Greyscale.png";
string ResourceType = "2D";
>;
sampler2D gColourmapSampler : register(s1) = sampler_state {
Texture = <gColourmapTexture>;
#if DIRECT3D_VERSION >= 0xa00
Filter = MIN_MAG_MIP_LINEAR;
#else /* DIRECT3D_VERSION < 0xa00 */
MinFilter = Linear;
MipFilter = Linear;
MagFilter = Linear;
#endif /* DIRECT3D_VERSION */
AddressU = Clamp;
AddressV = Clamp;
};
I have code that needs to render regions of my object differently depending on their location. I am trying to use a colour map to define these regions.
The problem is when I sample from my colour map, I get collisions. Ie, two regions with different colours in the colourmap get the same value returned from the sampler.
I've tried various formats of my colour map. I set the colours for each region to be "5" apart in each case;
- Indexed colour
- RGB, RGBA: region 1 will have RGB 5%,5%,5%. region 2 will have RGB 10%,10%,10% and so on.
- HSV Greyscale: region 1 will have HSV 0,0,5%. region 2 will have HSV 0,0,10% and so on.
(Values selected in The Gimp)
The tex2D sampler returns a value [0..1].
[ I then intend to derive an int array index from region. Code to do with that is unrelated, so has been removed from the question ]
float region = tex2D(gColourmapSampler,In.UV).x;
Sampling the "5%" colour gave a "region" of 0.05098 in hlsl.
From this I assume the 5% represents 5/100*255, or 12.75, which is rounded to 13 when stored in the texture. (Reasoning: 0.05098 * 255 ~= 13)
By this logic, the 50% should be stored as 127.5.
Sampled, I get 0.50196 which implies it was stored as 128.
the 70% should be stored as 178.5.
Sampled, I get 0.698039, which implies it was stored as 178.
What rounding is going on here?
(127.5 becomes 128, 178.5 becomes 178 ?!)
Edit: OK,
http://en.wikipedia.org/wiki/Bankers_rounding#Round_half_to_even
Apparently this is "banker's rounding". I have no idea why this is being used, but it solves my problem. Apparently, it's a Gimp issue.
I am using Shader Model 2 and FX Composer. This is my sampler declaration;
//Colour map
texture gColourmapTexture <
string ResourceName = "Globe_Colourmap_Regions_Greyscale.png";
string ResourceType = "2D";
>;
sampler2D gColourmapSampler : register(s1) = sampler_state {
Texture = <gColourmapTexture>;
#if DIRECT3D_VERSION >= 0xa00
Filter = MIN_MAG_MIP_LINEAR;
#else /* DIRECT3D_VERSION < 0xa00 */
MinFilter = Linear;
MipFilter = Linear;
MagFilter = Linear;
#endif /* DIRECT3D_VERSION */
AddressU = Clamp;
AddressV = Clamp;
};
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我从未使用过 HLSL,但不久前我确实使用过 GLSL(我必须承认它在我的脑海中非常遥远)。
我在纹理方面遇到的一个问题是 0 不是第一个像素。 1 不是第二个。 0 是纹理的边缘,1 是第一个像素的右边缘。这些值会自动插值,如果您需要的是精度(例如应用查找表而不是应用普通纹理),则可能会导致严重的问题。您需要瞄准像素的中间,因此要求 [0.5,0.5]、[1.5,0.5] 而不是 [0,0]、[1, 0] 等。
至少,GLSL 是这样的。
I never used HLSL, but I did use GLSL a while back (and I must admit it's terribly far in my head).
One issue I had with textures is that 0 is not the first pixel. 1 is not the second one. 0 is the edge of the texture and 1 is the right edge of the first pixel. The values get interpolated automatically and that can cause serious trouble if what you need is precision like when applying a lookup table rather than applying a normal texture. You need to aim for the middle of the pixel, so asking for [0.5,0.5], [1.5,0.5] rather than [0,0], [1, 0] and so on.
At least, that's the way it was in GLSL.
注意:levels[region] 中的区域向下舍入。当您在图像编辑器中看到 5 % 时,纹理 8b 表示中的实际值是 5/100*255 = 12.75,可能是 12 或 13。如果是 12,则向下舍入会影响您。如果您想四舍五入到最接近的值,则需要将其更改为levels[region+0.5]。
另一个可能让您印象深刻的类似内容(已经由 Louis-Philippe 编写)是纹理坐标舍入规则。您始终需要击中纹素中的某个点,以便不在两个纹素之间,否则结果定义不明确(您可能会随机获得两个纹素中的任何一个),并且某些源纹素可能会消失,而其他纹素可能会重复。这些规则对于双线和点采样是不同的,您可能需要在采样时添加一半的纹素大小来补偿这一点。
Beware: region in levels[region] is rounded down. When you see 5 % in your image editor, the actual value in the texture 8b representation is 5/100*255 = 12.75, which may be either 12 or 13. If it is 12, the rounding down will hit you. If you want rounding to nearest, you need to change this to levels[region+0.5].
Another similar thing (already written by Louis-Philippe) which might hit you is texture coordinates rounding rules. You always need to hit a spot in the texel so that you are not in between of two texels, otherwise the result is ill-defined (you may get any of two randomly) and some of your source texels may disapper while other duplicate. Those rules are different for bilinar and point sampling, you may need to add half of texel size when sampling to compensate for this.
GIMP 使用银行家舍入。显然。
这抛出了我的代码来导出区域索引。
GIMP uses banker's rounding. Apparently.
This threw out my code to derive region indicies.