我正在开发一个CG着色器,它将在低端硬件上执行有限数量的顶点动画(或"变形")。 我将动画帧打包到额外的texcoords中(有限的分辨率对于我需要做的事情来说是可以接受的),并根据主机程序提供的控制值在运行时在它们之间进行插值 - 实际上是一个从姿势1到N的滑块(N可能是6,看起来像我必须玩的texcoord的数量)。
我知道如何在传统的编程上下文中实现 catmull 插值,但我不确定采用着色器的正确方法。以下是一些具体问题:
1)我看到了以代数和矩阵形式表示的catmull插值(此处为示例。 在 OGL-ES2 硬件上,一种形式是否可能比另一种形式性能更高?
2)我让代数形式适用于一系列浮点数;它工作正常。 但是,我似乎无法声明一个 float4 数组来保存 may 数据。 如果我在这个例子中更改行均匀浮点键[8]:
sampler2D _MainTex;
float _KeyTime;
uniform float Key[8];
struct v2f {
float4 pos : SV_POSITION;
float4 color : COLOR0;
};
float4 catmull (float p0, float p1, float p2, float p3, fixed t)
{
fixed t2 = pow(t, 2);
fixed t3 = pow(t, 3);
return .5 * ((2.0 * p1) + (-1 * p0 + p2) * t +
(2 * p0 - 5 * p1 + 4 * p2 - p3) * t2 +
(-1 * p0 + 3 * p1 - 3 * p2 + p3) * t3)
;
}
v2f vert (appdata_base v)
{
v2f o;
o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
Key[0] = float(1);
Key[1] = float(1);
Key[2] = float(.8);
Key[3] = float(.6);
Key[4] = float(.4);
Key[5] = float(.2);
Key[6] = float(.1);
Key[7] = float(.1);
int prior = trunc(_KeyTime);
o.color = catmull(Key[prior],
Key[prior + 1],
Key[prior + 2],
Key[prior + 3],
frac(_KeyTime));
return o;
到统一 float4[8] 键; 着色器仍在编译,但我从 Unity 收到一个错误,说"不能在此硬件上运行子着色器",我认为这是对其他东西的误导性反映(我还有很多其他着色器具有多通道等工作正常)。如果我在 vert 程序中声明数组而不是统一数组,则会出现一个错误,即具有非静态索引器的数组需要统一。那么,有没有办法摆脱这种混乱呢?
PS 我匆忙更改了 catmull 函数以处理浮点数,只是为了测试一个假设,即它是关于声明导致问题的 float4 数组的假设。
我注意到您在输入浮点时声明了 catrom 输出 float4。为什么?
尝试实际执行您计划执行的操作:将键值声明为输入顶点数据的一部分。在这种情况下将其声明为"统一"似乎很尴尬,并且可能会混淆编译器,只需使其成为输入结构的一部分,不要尝试覆盖着色器中的值。以这种方式在 texcoords 上声明额外的值对于动画蒙皮非常常见。
对于未来的读者:
解决方案是显然不想编译包含动态索引的着色器 - 这不适用于所有平台,因此编译器显然过于热心地决定在我瞄准的目标(IOS 6+/DX9)的情况下不允许它。 所以它是"设计使然"而不是错误,尽管这并没有让它不那么烦人。
我能想到的最好的解决方法是使用 Float4x4,就好像它们是 16 个单元的数组一样。 您可以使用 float4 向量获取正确的值,除了要选择的正确行和列之外,所有零。将列向量乘以矩阵(就像变换它一样),然后在行向量上点缀。这将给出 [行,列] 处的项目。 这是屁股解决方法中的痛苦,但它确实有效。 显然,可以使用相同的技巧来提取行,而无需点积步骤来仅将行提取为 float4。