数值条件永远不会为真?
Numerical condition never true?
概览
上周我在 HLSL
中创建了一个基于条件的像素着色器。目标是只为满足特定条件的像素着色。在我的例子中,条件是基于 "time",我说得比较笼统,因为它不是我们认为的传统时间。我在 3D space 中渲染一条线,这是一项微不足道的任务。但是,根据当前用户选择的时间,应该只显示一定百分比的行。
我创建了一个 Line
class 并在我的表单中添加了一个 SliderControl
以允许用户控制当前时间点。这很容易完成,就像设置所有底层代码一样。
问题
在创建底层代码时,我在时间类型上犯了一个简单的错误。在当前时间的常量缓冲区中,我使用了 double
;在我的 Vertex
结构(任意定义和输入,以及像素着色器输入)中,我使用了 float
。这导致我的像素着色器中的条件始终导致 false
。差异的原因是原始数据的类型是 double
,但我最终选择 float
来匹配代码中的所有其他内容,而且使用 [=14= 存在某种问题] 输入 HLSL
.
HLSL
代码非常简单:
cbuffer TimeBuffer : register(b4) {
double CurrentTime;
}
struct VertexInput {
float Time;
//...
}
struct PixelInput {
float Time;
//...
}
float4 PSMain(PixelInput input) : SV_Target {
float4 result = 0;
if (input.Time < CurrentTime)
result = input.Diffuse;
return result;
}
问题
为什么永远不会呈现该行?
这里的问题是由于输入的 cbuffer
和 struct
之间的类型差异造成的。只需使类型匹配:
cbuffer TimeBuffer : register(b4) {
float CurrentTime;
}
struct VertexInput {
float Time;
//...
}
struct PixelInput {
float Time;
//...
}
float4 PSMain(PixelInput input) : SV_Target {
float4 result = 0;
if (input.Time < CurrentTime)
result = input.Diffuse;
return result;
}
只需将 result
的初始赋值更改为 float4(0, 1, 0, 0)
或其他一些纯色即可显示该行确实正在渲染,但条件永远不会评估为 true
。
可以找到一个很好的彻底回答为什么这是一个这样的问题 here。我最初不明白这是一个问题,因为我假设 double
和 float
可以像任何其他数字类型一样进行比较。但是我错了,正如上面链接的 post 所述:
The important factors under consideration with float or double numbers are:
Precision: The precision of a floating point number is how many digits it can represent without losing any information it contains.
Rounding: There is a non-obvious differences between binary
and decimal (base 10)
numbers. Consider the fraction 1/10
. In decimal
, this can be easily represented as 0.1
, and 0.1
can be thought of as an easily representable number. However, in binary, 0.1
is represented by the infinite sequence: 0.00011001100110011…
.
然而,这似乎也与 int
和 float
相关,而不是 double
和 float
。
概览
上周我在 HLSL
中创建了一个基于条件的像素着色器。目标是只为满足特定条件的像素着色。在我的例子中,条件是基于 "time",我说得比较笼统,因为它不是我们认为的传统时间。我在 3D space 中渲染一条线,这是一项微不足道的任务。但是,根据当前用户选择的时间,应该只显示一定百分比的行。
我创建了一个 Line
class 并在我的表单中添加了一个 SliderControl
以允许用户控制当前时间点。这很容易完成,就像设置所有底层代码一样。
问题
在创建底层代码时,我在时间类型上犯了一个简单的错误。在当前时间的常量缓冲区中,我使用了 double
;在我的 Vertex
结构(任意定义和输入,以及像素着色器输入)中,我使用了 float
。这导致我的像素着色器中的条件始终导致 false
。差异的原因是原始数据的类型是 double
,但我最终选择 float
来匹配代码中的所有其他内容,而且使用 [=14= 存在某种问题] 输入 HLSL
.
HLSL
代码非常简单:
cbuffer TimeBuffer : register(b4) {
double CurrentTime;
}
struct VertexInput {
float Time;
//...
}
struct PixelInput {
float Time;
//...
}
float4 PSMain(PixelInput input) : SV_Target {
float4 result = 0;
if (input.Time < CurrentTime)
result = input.Diffuse;
return result;
}
问题
为什么永远不会呈现该行?
这里的问题是由于输入的 cbuffer
和 struct
之间的类型差异造成的。只需使类型匹配:
cbuffer TimeBuffer : register(b4) {
float CurrentTime;
}
struct VertexInput {
float Time;
//...
}
struct PixelInput {
float Time;
//...
}
float4 PSMain(PixelInput input) : SV_Target {
float4 result = 0;
if (input.Time < CurrentTime)
result = input.Diffuse;
return result;
}
只需将 result
的初始赋值更改为 float4(0, 1, 0, 0)
或其他一些纯色即可显示该行确实正在渲染,但条件永远不会评估为 true
。
可以找到一个很好的彻底回答为什么这是一个这样的问题 here。我最初不明白这是一个问题,因为我假设 double
和 float
可以像任何其他数字类型一样进行比较。但是我错了,正如上面链接的 post 所述:
The important factors under consideration with float or double numbers are:
Precision: The precision of a floating point number is how many digits it can represent without losing any information it contains.
Rounding: There is a non-obvious differences between
binary
anddecimal (base 10)
numbers. Consider the fraction1/10
. Indecimal
, this can be easily represented as0.1
, and0.1
can be thought of as an easily representable number. However, in binary,0.1
is represented by the infinite sequence:0.00011001100110011…
.
然而,这似乎也与 int
和 float
相关,而不是 double
和 float
。