问题描述
我创建了以下片段着色器,该片段着色器使用_Size
函数创建了大小为frac
的图块网格,并在每个图块之间绘制了一条小的分隔线,我将图块的ID保存在其{ {1}}值,以便以后可以根据其ID(uv.z
)来平铺图块。
uv.z
和_Size
可以通过检查器进行调整
_CurrentID
(请注意,网格从(0,0)左下角开始到(5,5)右上角开始)
要确定我的ID设置正确,我通过检查器设置了Shader "Unlit/Fractals"
{
Properties
{
[HideInInspector] _MainTex ("Texture",2D) = "white" {}
_Size ("Size",float) = 5
_CurrentID ("ID",float) = 0
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float _Size;
float _CurrentID;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv,_MainTex);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
_CurrentID = floor(_CurrentID);
//Create a tile grid that is of _Size * _Size (5 in example),and create an ID for it in the .z value based on its grid position
float3 uv = float3(frac(i.uv * _Size),(floor(i.uv.y * _Size) * _Size) + (floor(i.uv.x * _Size)));
//Create lines to seperate the tiles
float4 col = float4(1,1,1);
if ((uv.x > 0.98 && uv.x < 1) || (uv.y > .98 && uv.y < 1))
{
col *= float4(uv.x,uv.y,1);
}
else
{
col = float4(0,1);
}
//Loop through all the tiles based on the ID
if (uv.z == fmod(_CurrentID,((_Size) * (_Size))))
{
col = float4(0,1);
}
//This correctly goes through every grid tile once,confirming that uv grid ID 5 corresponds to grid position (0,1)
/*if (uv.z == _CurrentID)
{
col = float4(0,1);
}*/
return col;
}
ENDCG
}
}
}
的底值,遍历每个uv.z
值,当从0变为24时,该值会点亮每个图块一次(包括)。
_CurrentID
if (uv.z == _CurrentID)
{
col = float4(0,1);
}
照亮第8个图块的示例
现在仅使用_CurrentID = 7
意味着我只能浏览每个图块一次。为了使此重复性无论_CurrentID
有多大,我都应该能够在_CurrentID
上使用fmod
(以模为单位)(尽管使用%模运算符也会发生这种情况),这样它就可以循环_CurrentID
时为0。我(尝试)使用以下代码:
CurrnetID = 25
第一行(if (uv.z == fmod(_CurrentID,((_Size) * (_Size))))
{
col = float4(0,1);
}
> = 0 && _CurrentId,事情就会开始破裂,因为没有瓷砖会亮起,尽管以前能够确认_CurrentID = 5
会点亮网格(0,1)的瓷砖。当我设置_CurrentID = 5
时,适当的图块再次开始亮起(网格pos(1,1)),直到n(大于0)的网格(0,n)永远不会亮起。
一旦我的_CurrentID = 5
升至25以上,一切似乎开始破裂,那里似乎根本没有模循环。 As seen in this gyazo gif。似乎只是照亮了随机图块。
我开始怀疑自己,我仔细检查了WolframpAlpha上的模数学,这似乎是正确的。
我可以通过执行CurrentID
来“解决”它跳过每一行的第一个图块的问题,这将在第一次运行时正确遍历每个图块(包括(0,n)图块),但是现在我的模数开始在36处循环,之后它仍然会照亮gif中所示的随机图块。
我在做什么错了?
(Unity版本2020.1.1f1,在2019.3.13中确认了相同的行为)
解决方法
这可能是浮点精度问题,因为您正在比较浮点数是否相等。 除了这样做,您可以编写如下内容:
float id = _CurrentID % (_Size*_Size);
float epsilon = .0001f;
if (abs(uv.z - id) < epsilon)
{
col = float4(0,1,1);
}
或将整数用作ID。