Glsl mod 与 Hlsl fmod
我已经在 HLSL 中实现了 这个问题中描述的螺旋 GLSL 着色器,但结果并不相同。我认为这是因为我将 GLSL 中的 mod
函数翻译为 HLSL 中的 fmod
。我怀疑只有当 fmod 函数的输入中有负数时才会出现此问题。
我尝试将对 mod
的调用替换为对我所做的函数的调用,该函数执行 GLSL 文档 它的工作原理:
mod
返回x
对y
取模的值。计算公式为x - y * Floor(x/y)
。
我使用的代替 fmod
的工作代码是:
float mod(float x, float y)
{
return x - y * floor(x/y)
}
与 GLSL mod
相比,MSDN 说 HLSL fmod
函数执行以下操作:
浮点余数的计算方式为
x = i * y + f
,其中i
是一个整数,f
有与x
符号相同,且f
的绝对值小于y
的绝对值。
我使用了HLSL 到 GLSL 转换器,并且 fmod
函数是翻译为mod
。但是,我不知道是否可以假设 mod
转换为 fmod
。
问题
- GLSL
mod
和 HLSLfmod
之间有什么区别? - 如何将 MSDN 对
fmod
的神秘描述转换为伪代码实现?
GLSL 着色器
uniform float time;
uniform vec2 resolution;
uniform vec2 aspect;
void main( void ) {
vec2 position = -aspect.xy + 2.0 * gl_FragCoord.xy / resolution.xy * aspect.xy;
float angle = 0.0 ;
float radius = length(position) ;
if (position.x != 0.0 && position.y != 0.0){
angle = degrees(atan(position.y,position.x)) ;
}
float amod = mod(angle+30.0*time-120.0*log(radius), 30.0) ;
if (amod<15.0){
gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );
} else{
gl_FragColor = vec4( 1.0, 1.0, 1.0, 1.0 );
}
}
HLSL 着色器
struct Psl_VertexShaderInput
{
float3 pos : POSITION;
};
struct Psl_VertexShaderOutput
{
float4 pos : POSITION;
};
struct Psl_PixelShaderOutput
{
float4 Output0 : COLOR0;
};
float3 psl_positionOffset;
float2 psl_dimension;
Psl_VertexShaderOutput Psl_VertexShaderFunction(Psl_VertexShaderInput psl_input)
{
Psl_VertexShaderOutput psl_output = (Psl_VertexShaderOutput)0;
psl_output.pos = float4(psl_input.pos + psl_positionOffset, 1);
return psl_output;
}
float time : TIME;
float2 resolution : DIMENSION;
Psl_PixelShaderOutput Psl_PixelShaderFunction(float2 pos : VPOS)
{
Psl_PixelShaderOutput psl_output = (Psl_PixelShaderOutput)0;
float2 aspect = float2(resolution.x / resolution.y, 1.0);
float2 position = -aspect.xy + 2.0 * pos.xy / resolution.xy * aspect.xy;
float angle = 0.0;
float radius = length(position);
if (position.x != 0.0 && position.y != 0.0)
{
angle = degrees(atan2(position.y, position.x));
}
float amod = fmod((angle + 30.0 * time - 120.0 * log(radius)), 30.0);
if (amod < 15.0)
{
psl_output.Output0 = float4(0.0, 0.0, 0.0, 1.0);
return psl_output;
}
else
{
psl_output.Output0 = float4(1.0, 1.0, 1.0, 1.0);
return psl_output;
}
}
technique Default
{
pass P0
{
VertexShader = compile vs_3_0 Psl_VertexShaderFunction();
PixelShader = compile ps_3_0 Psl_PixelShaderFunction();
}
}
I've implemented the spiral GLSL shader described in this question in HLSL, but the results are not the same. I think it's because of the mod
function in GLSL that I've translated to fmod
in HLSL. I suspect that this problem only happens when we have negative numbers in the input of the fmod
function.
I've tried replacing the call to mod
by a call to a function that I've made which does what is described in the GLSL documentation and it works:
mod
returns the value ofx
moduloy
. This is computed asx - y * floor(x/y)
.
The working code I use instead of fmod
is:
float mod(float x, float y)
{
return x - y * floor(x/y)
}
By contrast to GLSL mod
, MSDN says the HLSL fmod
function does this:
The floating-point remainder is calculated such that
x = i * y + f
, wherei
is an integer,f
has the same sign asx
, and the absolute value off
is less than the absolute value ofy
.
I've used an HLSL to GLSL converter, and the fmod
function is translated as mod
. However, I don't know if I can assume that mod
translates to fmod
.
Questions
- What are the differences between GLSL
mod
and HLSLfmod
? - How can I translate MSDN's cryptic description of
fmod
to a pseudo-code implementation?
GLSL Shader
uniform float time;
uniform vec2 resolution;
uniform vec2 aspect;
void main( void ) {
vec2 position = -aspect.xy + 2.0 * gl_FragCoord.xy / resolution.xy * aspect.xy;
float angle = 0.0 ;
float radius = length(position) ;
if (position.x != 0.0 && position.y != 0.0){
angle = degrees(atan(position.y,position.x)) ;
}
float amod = mod(angle+30.0*time-120.0*log(radius), 30.0) ;
if (amod<15.0){
gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );
} else{
gl_FragColor = vec4( 1.0, 1.0, 1.0, 1.0 );
}
}
HLSL Shader
struct Psl_VertexShaderInput
{
float3 pos : POSITION;
};
struct Psl_VertexShaderOutput
{
float4 pos : POSITION;
};
struct Psl_PixelShaderOutput
{
float4 Output0 : COLOR0;
};
float3 psl_positionOffset;
float2 psl_dimension;
Psl_VertexShaderOutput Psl_VertexShaderFunction(Psl_VertexShaderInput psl_input)
{
Psl_VertexShaderOutput psl_output = (Psl_VertexShaderOutput)0;
psl_output.pos = float4(psl_input.pos + psl_positionOffset, 1);
return psl_output;
}
float time : TIME;
float2 resolution : DIMENSION;
Psl_PixelShaderOutput Psl_PixelShaderFunction(float2 pos : VPOS)
{
Psl_PixelShaderOutput psl_output = (Psl_PixelShaderOutput)0;
float2 aspect = float2(resolution.x / resolution.y, 1.0);
float2 position = -aspect.xy + 2.0 * pos.xy / resolution.xy * aspect.xy;
float angle = 0.0;
float radius = length(position);
if (position.x != 0.0 && position.y != 0.0)
{
angle = degrees(atan2(position.y, position.x));
}
float amod = fmod((angle + 30.0 * time - 120.0 * log(radius)), 30.0);
if (amod < 15.0)
{
psl_output.Output0 = float4(0.0, 0.0, 0.0, 1.0);
return psl_output;
}
else
{
psl_output.Output0 = float4(1.0, 1.0, 1.0, 1.0);
return psl_output;
}
}
technique Default
{
pass P0
{
VertexShader = compile vs_3_0 Psl_VertexShaderFunction();
PixelShader = compile ps_3_0 Psl_PixelShaderFunction();
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
正如您所指出的,它们是不同的。 GLSL
mod
始终具有与y
相同的符号,而不是x
。否则它是相同的——一个值f
,使得x = i*y + f
,其中i
是一个整数,而|f | < |y|
。如果您尝试制作某种重复模式,GLSLmod
通常就是您想要的。为了进行比较,HLSL
fmod
相当于x - y * trunc(x/y)
。当x/y
为正数时它们是相同的,当x/y
为负数时它们不同。As you've noted, they're different. The GLSL
mod
will always have the same sign asy
rather thanx
. Otherwise it's the same -- a valuef
such thatx = i*y + f
wherei
is an integer and|f| < |y|
. If you're trying to make a repeating pattern of some kind, the GLSLmod
is generally what you want.For comparison, the HLSL
fmod
is equivalent tox - y * trunc(x/y)
. They're the same whenx/y
is positive, different whenx/y
is negative.