《Unity着色器圣经》4.1.0. | Clamp function.

目录索引

译文

当我们想要限制运算的结果时,可以使用这个函数。默认情况下,它允许我们通过设置最小值和最大值来定义数值范围内的值。

当我们写一个函数时,我们会遇到一些运算,这些运算会导致数字小于0或大于1,例如,在计算网格法线和照明方向之间的点积时,我们可以获得-1.0f和1.0f之间的范围。由于负值会在最终效果中产生颜色伪影,使用clamp,我们可以把结果限制在0.0f和1.0f之间。

其语法如下:

float clamp (float a, float x, float b)
{
    return max(a, min(x, b));
}

float2 clamp (float2 a, float2 x, float2 b);
float3 clamp (float3 a, float3 x, float3 b);
float4 clamp (float4 a, float4 x, float4 b);

在上面的函数中,参数“a”表示最小返回值,而参数“b”表示范围内的最大返回值。至于自变量,“x”对应于我们想要根据a和b限制的值。这意味着什么?让我们假设“a”和“b”有一个集合范围,x是一个可以变化的数字。

当“x”等于1.0f时,如果参数“a”等于0.1f,参数“b”等于0.9f,则“x”的最大返回值将为0.9f;为什么?因为“b”定义了操作的最大值。

图片[1]-《Unity着色器圣经》4.1.0. | Clamp function.-软件开发学习笔记

相反的情况也是如此。当“x”等于0.0f时,返回值为0.1f,因为“a”定义了“x”的最小返回值。

图片[2]-《Unity着色器圣经》4.1.0. | Clamp function.-软件开发学习笔记

为了深入理解这个概念,我们将做以下工作:首先,我们将创建一个新的着色器类型“Unlit shader”,我们将其称为USB_function_CLAMP,并在其属性中声明三个带范围的float变量,每个参数一个。

Shader "USB/USB_function_CLAMP"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Xvalue ("X", Range(0, 1)) = 0
        _Avalue ("A", Range(0, 1)) = 0
        _Bvalue ("B", Range(0, 1)) = 0
    }
}

然后我们声明全局变量,将它们连接到程序。

Pass
{
   ...
    sampler2D _MainTex;
    float4 _MainTex_ST;
    float _Xvalue;
    float _Avalue;
    float _Bvalue;
   ...
}

我们将使用刚刚创建的着色器来增加或减少主纹理的gamma颜色。因此,在这一点上,我们可以做两件事:

在我们的程序中生成一个简单的函数,将值限制在一个范围内。

或者使用Cg/HLSL语言中包含的函数“clamp”。

我们将首先声明一个新函数。为此,我们将自己定位在顶点着色器和片段着色器阶段之间,并编写一个新方法,称为“ourClamp”。

v2f vert(appdata v) { ... }

float ourClamp(float a, float x, float b)
{
    return max(a, min(x, b));
}

fixed4 frag(v2f i) : SV_Target { ... }

正如我们在前面函数的实现中所看到的,ourClamp将限制一个值(浮点x)在两个已确定的数字(浮点a和浮点b)之间。

然后,在片段着色器阶段,我们创建一个名为“dark”的浮动变量,并使其等于我们的新函数。作为参数,我们将按照上述顺序传递上面声明的属性。

float ourClamp(float a, float x, float b) { ... }

fixed4 frag(v2f i) : SV_Target
{
    float darkness = ourClamp(_Avalue, _Xvalue, _Bvalue);
    fixed4 col = tex2D(_MainTex, i.uv);

    UNITY_APPLY_FOG(i.fogCoord, col);
    return col;
}

dark变量是浮动/标量类型,这意味着它只有一个维度。因此,将col向量乘以上述变量将影响向量col(RGBA)的四个通道。

float ourClamp(float a, float x, float b) { ... }

fixed4 frag(v2f i) : SV_Target
{
    float darkness = ourClamp(_Avalue, _Xvalue, _Bvalue);
    fixed4 col = tex2D(_MainTex, i.uv) * darkness;

    UNITY_APPLY_FOG(i.fogCoord, col);
    return col;
}

我们可以通过包含“clamp”函数来简化上述操作。

// float ourClamp(float a, float x, float b) { ... }

fixed4 frag(v2f i) : SV_Target
{
    // Cg and HLSL include the clamp function.
    float darkness = clamp(_Avalue, _Xvalue, _Bvalue);
    fixed4 col = tex2D(_MainTex, i.uv) * darkness;

    UNITY_APPLY_FOG(i.fogCoord, col);
    return col;
}

总之,我们现在可以为着色器中的输出颜色定义最大和最小gamma。


原文对照

This function is handy when we want to limit the result of an operation. By default, it allows us to define a value within a numerical range by setting a minimum and a maximum.
As we develop functions, we will encounter some operations that result in a number less than “zero” or greater than “one,” e.g., In the calculation of the dot product between the mesh normals and the illumination direction, we can obtain a range between -1.0f and 1.0f. Since a negative value would generate color artifacts in the final effect, with clamp, we can limit and redefine the range between 0.0f and 1.0f.


Its syntax is the following:

float clamp (float a, float x, float b)
{
    return max(a, min(x, b));
}

float2 clamp (float2 a, float2 x, float2 b);
float3 clamp (float3 a, float3 x, float3 b);
float4 clamp (float4 a, float4 x, float4 b);

In the above function, the argument “a” refers to the minimum return value, while the argument “b” refers to the maximum return value within the range. As for the argument, “x” corresponds to the value we want to limit according to a and b. What does this mean? Let’s assume a set range for “a” and “b” and a variable number for x.
When “x” is equal to 1.0f, if argument “a” is equal to 0.1f and argument “b” is equal to 0.9f, the maximum return value for “x” will be 0.9f; why? Because “b” defines the highest limit value for the operation.

图片[1]-《Unity着色器圣经》4.1.0. | Clamp function.-软件开发学习笔记

The same happens in the opposite case. When “x” is equal to 0.0f, the return value will be
0.1f, because “a” defines the minimum return value for “x”.

图片[2]-《Unity着色器圣经》4.1.0. | Clamp function.-软件开发学习笔记

To understand this concept in-depth, we will do the following: First, we will create a new shader type, “Unlit Shader”, which we will call USB_function_CLAMP, and in its properties, we will declare three floating ranges; one for each argument.

Shader "USB/USB_function_CLAMP"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Xvalue ("X", Range(0, 1)) = 0
        _Avalue ("A", Range(0, 1)) = 0
        _Bvalue ("B", Range(0, 1)) = 0
    }
}

Then we declare the global or connection variables to connect them to the program.

Pass
{
   ...
    sampler2D _MainTex;
    float4 _MainTex_ST;
    float _Xvalue;
    float _Avalue;
    float _Bvalue;
   ...
}

We will use the shader we have just created to increase or decrease the gamma color of the main texture. Therefore, at this point, we can do two things:

  1. Generate a simple function within our program that limits a value within a range.
  2. Or use the included function “clamp” that is in the Cg/HLSL language.

We will start by declaring a new function. To do this, we position ourselves between the vertex shader and the fragment shader stage and write a new method that we will call “ourClamp”.

v2f vert(appdata v) { ... }

float ourClamp(float a, float x, float b)
{
    return max(a, min(x, b));
}

fixed4 frag(v2f i) : SV_Target { ... }

As we can see in the implementation of the previous function, ourClamp will limit a value
(float x) between two established numbers (float a and float b).
Then, in the fragment shader stage, we create a floating variable called “darkness” and make it equal to our new function. As arguments, we will pass the properties that we declared above, following the mentioned order.

float ourClamp(float a, float x, float b) { ... }

fixed4 frag(v2f i) : SV_Target
{
    float darkness = ourClamp(_Avalue, _Xvalue, _Bvalue);
    fixed4 col = tex2D(_MainTex, i.uv);

    UNITY_APPLY_FOG(i.fogCoord, col);
    return col;
}

The darkness variable is of floating/scalar type, meaning that it has only one dimension. Therefore, multiplying the col vector by the mentioned variable will affect the four channels of the vector col (RGBA).

float ourClamp(float a, float x, float b) { ... }

fixed4 frag(v2f i) : SV_Target
{
    float darkness = ourClamp(_Avalue, _Xvalue, _Bvalue);
    fixed4 col = tex2D(_MainTex, i.uv) * darkness;

    UNITY_APPLY_FOG(i.fogCoord, col);
    return col;
}

We can simplify the above operation by including the “clamp” function in the language we are applying.

// float ourClamp(float a, float x, float b) { ... }

fixed4 frag(v2f i) : SV_Target
{
    // Cg and HLSL include the clamp function.
    float darkness = clamp(_Avalue, _Xvalue, _Bvalue);
    fixed4 col = tex2D(_MainTex, i.uv) * darkness;

    UNITY_APPLY_FOG(i.fogCoord, col);
    return col;
}

In conclusion, we can now define a maximum and minimum gamma for the output color in the shader.

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容