修正着色器上的“语义”标签只是为了浮动3?

问题描述 投票:2回答:2

这是一个非常简单的着色器,

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的语义。

enter image description here

回顾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你还没有在别处使用。)

  1. 请注意,无论如何,POSITION是一个float4,我的float3真的可以吗?对于通用浮动3,是否有比POSITION更好的东西? (我注意到,如果你只是使用,比如说,颜色,它也可以正常工作。这有关系吗?)
  2. “1 on the end”系统实际上是否正确?那么,POSITION1好转吗?我不是在熔化gpu或其他一些?
  3. 嗯,我注意到你可以在那里输入任何东西(比如说“abcd1”)。但当然它实际上并不是硬件注册的东西???
unity3d shader cg
2个回答
1
投票

假设您的开发平台是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
投票

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
}
© www.soinside.com 2019 - 2024. All rights reserved.