这是一个非常简单的着色器,
float4 vert (float4 vertex :POSITION, out PositionHolder o) :SV_POSITION
{
UNITY_INITIALIZE_OUTPUT(PositionHolder,o);
o.localPos = vertex;
return UnityObjectToClipPos(vertex);
}
fixed4 frag (PositionHolder IN) :SV_Target
{
if (IN.localPos.y > -.2)
return _UpperColor;
else
return _LowerColor;
}
(因此,如果在四边形上,它只用一种颜色绘制前70%,用另一种颜色绘制底部条纹。)
请注意,vert
唯一能做的就是沿着网格顶点位置传递局部。
这是执行此操作的结构
struct PositionHolder
{
float3 localPos;
};
但是,(在Unity中,无论如何)它将需要一个float3的语义。
回顾Unity的doco,他们当然没有,但是有一个链接
https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/dx-graphics-hlsl-semantics
(旁白 - 正如我所理解的那样,它专门用于D3D,但是,我想这仍然是语法/语义?)
我读到的情况,
建议你应该用say,
struct PositionHolder
{
float3 localPos :POSITION1;
};
或者实际上,您还没有使用任何数字作为资源。
关于什么,
struct PositionHolder
{
float3 localPos :POSITION8;
};
为了好运。
(令人困惑的是,它们似乎只是从空白到9,我不知道这是否反映了硬件现实,或者只是某种地方的劣质 - 或者是什么。但无论如何,基本上“任何数字1到9你还没有在别处使用。)
POSITION
是一个float4,我的float3真的可以吗?对于通用浮动3,是否有比POSITION更好的东西? (我注意到,如果你只是使用,比如说,颜色,它也可以正常工作。这有关系吗?)假设您的开发平台是iOS。
iOS有自己的着色器语言 - 金属着色语言。
为了让着色器在iOS上工作,Unity将它们从HLSL编译为Metal。因此,如果我们要编译以下着色器部分:
HLSL:
float4 localPos: POSITION1;
这是编译结果:
金属:
float4 POSITION1 [[ user(POSITION1) ]];
根据Metal Shading Language Specification
属性[[user(name)]]语法还可用于为任何用户定义的变量指定属性名称。
Unity3d将您的HLSL语义字段“name”转换为Metal Language属性[user(name)]。因此,如果你写下:[POSITION1或HelloWorld或Fattie],只要它是唯一的并且不使用保留关键字就没关系。因此,在编译以下着色器之后
HLSL:
float4 localPos: Fattie;
这将是结果:
金属:
float4 Fattie0 [[ user(Fattie0) ]];
对于矢量数据类型,矢量类型[float,float2,float3,float4等]并不特定于您的自定义语义名称。使用float3编译此着色器
HLSL:
float3 localPos: Fattie;
给出以下结果:
金属:
float3 Fattie0 [[ user(Fattie0) ]];
1:GPU寄存器是基于硬件的,它们总是大小为4的向量(float4等),语义只是用于将变量绑定到名称,以便所有数据最终都在正确的位置。 GPU上的所有向量操作都使用SIMD(单个指令,多个数据),因此对向量执行计算与使用标量一样快。但是,我不确定POSITION,通常这个名称只填充输入变量的函数 - 对于你自己的任意输出变量,你应该使用TEXCOORD0-N。 COLOR内插器具有8位精度,并且还可以将值钳位到0-1的范围内。
2:您可以使用的插补器寄存器数量取决于支持的着色器模型(您可以使用#pragma target 4.0来支持最多32个插值器,代价是需要最少的Direct3D 10)。但是,是的,您可以使用0或8或4或其他任何东西。
3:你试过了吗?实际上,语义只是用于为编译器提供关于我们想要哪些数据的提示/标签。但是对于大多数值而言,使用哪个寄存器无关紧要,明确键入寄存器实际上只是过去的遗留问题。我从来没有见过任何人随机写东西作为着色器语义!
就个人而言,我认为构建输入和输出更直观,如下所示:
struct VertexInput {
// Here we use POSITION to tell the compiler that we want the vertex coords to be written to this variable.
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct VertexOutput {
float4 clipPos : SV_POSITION;
// Here we use TEXCOORD0-1, since these are just variables to be interpolated.
float3 localPos : TEXCOORD0;
float3 normal : TEXCOORD1;
};
VertexOutput Vert(VertexInput v) {
VertexOutput o;
o.clipPos = UnityObjectToClipPos(v.vertex);
o.localPos = v.vertex;
o.normal = UnityObjectToWorldNormal(v.normal);
return o;
}
fixed4 Frag(VertexOutput o) : SV_Target {
half3 normal = normalize(o.normal); // Interpolated values are not necessarily normalized
half NdotL = saturate(dot(normal, _WorldSpaceLightPos0.xyz));
return fixed4((fixed3)NdotL, 1); // Basic lambert lighting as an example
}