Shader semantics //Shader语义


Shader semantics

When writing HLSL shader programs, input and output variables need to have their “intent” indicated via semantics. This is a standard concept in HLSL shader language; see the Semantics documentation on MSDN for more details.

在编写HLSL着色程序时,输入和输出变量需要通过语义来表示它们的“意图”。这是HLSL着色语言中的一个标准概念;请参阅MSDN上的语义文档,了解更多细节。

You can download the examples shown below as a zipped Unity project, here.


Vertex shader input semantics 顶点着色器输入语义

The main vertex shader function (indicated by the #pragma vertex directive) needs to have semantics on all of the input parameters. These correspond to individualMesh data elements, like vertex position, normal mesh, and texture coordinates. See vertex program inputs for more details.

主顶点着色函数(由编译器顶点指令表示)需要在所有输入参数上都有语义。这些数据对应于单个网格的数据元素,比如顶点位置、普通网格和纹理坐标。更多细节请参见顶点程序输入。

Here’s an example of a simple vertex shader that takes vertex position and a texture coordinate as an input. The pixel shader visualizes the texture coordinate as a color.

这是一个简单的顶点着色器的例子,它接受顶点位置和纹理坐标作为输入。像素着色器将纹理坐标可视化为一种颜色。

Shader "Unlit/Show UVs"
{
    SubShader
    {
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            struct v2f {
                float2 uv : TEXCOORD0;
                float4 pos : SV_POSITION;
            };

            v2f vert (
                float4 vertex : POSITION, // vertex position input
                float2 uv : TEXCOORD0 // first texture coordinate input
                )
            {
                v2f o;
                o.pos = UnityObjectToClipPos(vertex);
                o.uv = uv;
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                return fixed4(i.uv, 0, 0);
            }
            ENDCG
        }
    }
}

Instead of spelling out all individual inputs one by one, it is also possible to declare a structure of them, and indicate semantics on each individual member variable of the struct. See shader program examples to learn how to do this.

不需要逐一说明所有的输入,也可以声明它们的结构,并在结构体的每个成员变量上显示语义。请参阅着色程序示例,以学习如何做到这一点。

Fragment shader output semantics 

片段着色器输出语义

Most often a fragment (pixel) shader outputs a color, and has an SV_Target semantic. The fragment shader in the example above does exactly that:

大多数情况下,一个片段(像素)着色器输出一个颜色,并且有一个svtarget语义。上面的例子中的片段着色器就是这样做的:

fixed4 frag (v2f i) : SV_Target

The function frag has a return type of fixed4 (low precision RGBA color). As it only returns a single value, the semantic is indicated on the function itself, : SV_Target.

函数frag有一个返回类型的fixed4(低精度RGBA颜色)。因为它只返回一个值,所以在函数本身上表明了语义:sv_target。

It is also possible to return a structure with the outputs. The fragment shader above could be rewritten this way too, and it would do exactly the same:

还可以返回带有输出的结构。上面的片段着色器也可以这样改写,而且它也会做同样的事情:

struct fragOutput {
    fixed4 color : SV_Target;
};            
fragOutput frag (v2f i)
{
    fragOutput o;
    o.color = fixed4(i.uv, 0, 0);
    return o;
}

Returning structures from the fragment shader is mostly useful for shaders that don’t just return a single color. Additional semantics supported by the fragment shader outputs are as follows.

从片段着色器返回的结构对于不只是返回单一颜色的着色器来说是非常有用的。片段着色输出支持的附加语义如下。

SV_TargetN: Multiple render targets SV_TargetN:多个渲染目标

SV_Target1SV_Target2, etc.: These are additional colors written by the shader. This is used when rendering into more than one render target at once (known as the Multiple Render Targets rendering technique, or MRT). SV_Target0 is the same as SV_Target.

sv_target1、sv_target2等:这些是由着色器编写的附加颜色。在一次渲染多个渲染目标时使用这个(称为多重渲染目标渲染技术,或者MRT)。sv_target0与sv_target相同。

SV_Depth: Pixel shader depth output sv_depth:像素着色深度输出

Usually the fragment shader does not override the Z buffer value, and a default value is used from the regular triangle rasterization. However, for some effects it is useful to output custom Z buffer depth values per pixel.

通常,片段着色器不会覆盖Z缓冲区值,并且使用常规三角形光栅化的默认值。但是,对于某些效果,输出定制Z缓冲区的每个像素的深度值是很有用的。

Note that on many GPUs this turns off some depth buffer optimizations, so do not override Z buffer value without a good reason. The cost incurred by SV_Depthvaries depending on the GPU architecture, but overall it’s fairly similar to the cost of alpha testing (using the built-in clip() function in HLSL). Render shaders that modify depth after all regular opaque shaders (for example, by using the AlphaTest rendering queue.

注意,在许多GPU上,这会关闭一些深度缓冲区优化,因此,如果没有充分的理由,不要覆盖Z缓冲区的值。svdepth千差万别的成本取决于GPU架构,但是总的来说,它与alpha测试的成本相当(在HLSL中使用内置的clip()函数)。渲染着色器,在所有常规的不透明着色器之后修改深度(例如,通过使用AlphaTest渲染队列。

The depth output value needs to be a single float.

深度输出值需要为单个浮点数。

Vertex shader outputs and fragment shader inputs 顶点着色输出和碎片着色输入

A vertex shader needs to output the final clip space position of a vertex, so that the GPU knows where on the screen to rasterize it, and at what depth. This output needs to have the SV_POSITION semantic, and be of a float4 type.

顶点着色器需要输出顶点的最终剪辑空间位置,这样GPU就能知道屏幕上的哪个位置来拉化它,以及在什么深度上。这个输出需要具有sv仓位语义,并且是浮动4类型的。

Any other outputs (“interpolators” or “varyings”) produced by the vertex shader are whatever your particular shader needs. The values output from the vertex shader will be interpolated across the face of the rendered triangles, and the values at each pixel will be passed as inputs to the fragment shader.

顶点着色器产生的任何其他输出(“插值器”或“varyings”)都是您特定的着色器所需要的。顶点着色器的值将会在被渲染的三角形的表面进行插值,每个像素的值将作为对片段着色器的输入传递。

Many modern GPUs don’t really care what semantics these variables have; however some old systems (most notably, shader model 2 GPUs on Direct3D 9) did have special rules about the semantics:

许多现代gpu并不真正关心这些变量的语义,但是一些旧的系统(最明显的是,在Direct3D 9上的着色模型2 gpu)对于语义有特殊的规则:

  • TEXCOORD0TEXCOORD1 etc are used to indicate arbitrary high precision data such as texture coordinates and positions.
  • COLOR0 and COLOR1 semantics on vertex outputs and fragment inputs are for low-precision, 0–1 range data (like simple color values).
  • TEXCOORD0、TEXCOORD1等被用来表示任意精度高的数据,比如纹理坐标和位置。 在顶点输出和片段输入上的色彩0和色彩1语义是低精度的,0-1范围的数据(比如简单的颜色值)。

For best cross platform support, label vertex outputs and fragment inputs as TEXCOORDn semantics.

对于最好的跨平台支持,将顶点输出和片段输入作为TEXCOORDn语义。

See shader program examples for examples.

参见着色器程序示例。

Interpolator count limits 插入器数限制

There are limits to how many interpolator variables can be used in total to pass the information from the vertex into the fragment shader. The limit depends on the platform and GPU, and the general guidelines are:

在总数中,可以使用多少插值器变量来将信息从顶点传递到片段着色器中。这个限制取决于平台和GPU,一般的指导方针是:

  • Up to 8 interpolators: OpenGL ES 2.0 (iOS/Android), Direct3D 11 9.x level (Windows Phone) and Direct3 9 shader model 2.0 (old PCs). Since the interpolator count is limited, but each interpolator can be a 4-component vector, some shaders pack things together to stay within limits. For example, two texture coordinates can be passed in one float4 variable (.xy for one coordinate, .zw for the second coordinate).
  • 最多有8个插值器:OpenGL ES 2.0(ios/android),Direct3D 11 9。x级(Windows Phone)和Direct3 9着色器2.0(旧pc)。因为插值器计数是有限的,但是每个插值器可以是一个4个分量的矢量,一些着色器把东西打包在一起,以保持在限制之内。例如,可以在一个浮动4变量中传递两个纹理坐标(.。一个坐标的xy。第二个坐标的zw)。
  • Up to 10 interpolators: Direct3D 9 shader model 3.0 (#pragma target 3.0).
  • Up to 10 interpolators:争取Direct3D shader 9 pragma #(3.0成为3.0)。
  • Up to 16 interpolators: OpenGL ES 3.0 (iOS/Android), Metal (iOS).
  • 最多16个插值器:OpenGL ES 3.0(iOS/android),金属(iOS)。
  • Up to 32 interpolators: Direct3D 10 shader model 4.0 (#pragma target 4.0).
  • 最多32个插值器:Direct3D 10着色器4.0(编译目标4.0)。

Regardless of your particular target hardware, it is generally a good idea to use as few interpolators as possible for performance reasons.

无论您的目标硬件是什么,通常都是一个好主意,因为性能原因,尽可能少地使用插值器。

Other special semantics 其他特殊语义

Screen space pixel position: VPOS 屏幕空间像素位置:VPOS

A fragment shader can receive position of the pixel being rendered as a special VPOS semantic. This feature only exists starting with shader model 3.0, so the shader needs to have the #pragma target 3.0 compilation directive.

一个片段着色器可以接收被渲染为特殊的VPOS语义的像素位置。这个特性只存在于着色器3.0的开始,所以着色器需要有编译器目标3.0的编译指令。

On different platforms the underlying type of the screen space position input varies, so for maximum portability use the UNITY_VPOS_TYPE type for it (it will be float4on most platforms, and float2 on Direct3D 9).

在不同的平台上,屏幕空间位置输入的底层类型是不同的,因此最大可移植性使用unityvpostype类型(它在大多数平台上都是浮动的,在Direct3D 9上是浮动的)。

Additionally, using the pixel position semantic makes it hard to have both the clip space position (SV_POSITION) and VPOS in the same vertex-to-fragment structure. So the vertex shader should output the clip space position as a separate “out” variable. See the example shader below:

此外,使用像素位置语义使得在相同的ver纹理-片段结构中很难同时拥有剪贴空间位置(svposition)和VPOS。因此,顶点着色器应该将剪贴空间位置输出为一个单独的“out”变量。请看下面的例子:

Shader "Unlit/Screen Position"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma target 3.0

            // note: no SV_POSITION in this struct
            struct v2f {
                float2 uv : TEXCOORD0;
            };

            v2f vert (
                float4 vertex : POSITION, // vertex position input
                float2 uv : TEXCOORD0, // texture coordinate input
                out float4 outpos : SV_POSITION // clip space position output
                )
            {
                v2f o;
                o.uv = uv;
                outpos = UnityObjectToClipPos(vertex);
                return o;
            }

            sampler2D _MainTex;

            fixed4 frag (v2f i, UNITY_VPOS_TYPE screenPos : VPOS) : SV_Target
            {
                // screenPos.xy will contain pixel integer coordinates.
                // use them to implement a checkerboard pattern that skips rendering
                // 4x4 blocks of pixels

                // checker value will be negative for 4x4 blocks of pixels
                // in a checkerboard pattern
                screenPos.xy = floor(screenPos.xy * 0.25) * 0.5;
                float checker = -frac(screenPos.r + screenPos.g);

                // clip HLSL instruction stops rendering a pixel if value is negative
                clip(checker);

                // for pixels that were kept, read the texture and output it
                fixed4 c = tex2D (_MainTex, i.uv);
                return c;
            }
            ENDCG
        }
    }
}
Face orientation: VFACE 面对取向:VFACE

A fragment shader can receive a variable that indicates whether the rendered surface is facing the camera, or facing away from the camera. This is useful when rendering geometry that should be visible from both sides – often used on leaves and similar thin objects. The VFACE semantic input variable will contain a positive value for front-facing triangles, and a negative value for back-facing ones.

一个碎片着色器可以接收一个变量,这个变量表示渲染的表面是面对摄像机,还是远离摄像机。这在渲染几何图形时是很有用的,这些几何图形应该从两边都可以看到——通常是在叶子和类似的薄物体上使用。VFACE语义输入变量将包含正面三角形的正值,以及对后面三角形的负值。

This feature only exists from shader model 3.0 onwards, so the shader needs to have the #pragma target 3.0 compilation directive.

这个特性只存在于着色器3.0以后,所以着色器需要有编译器的目标3.0编译指令。

Shader "Unlit/Face Orientation"
{
    Properties
    {
        _ColorFront ("Front Color", Color) = (1,0.7,0.7,1)
        _ColorBack ("Back Color", Color) = (0.7,1,0.7,1)
    }
    SubShader
    {
        Pass
        {
            Cull Off // turn off backface culling

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma target 3.0

            float4 vert (float4 vertex : POSITION) : SV_POSITION
            {
                return UnityObjectToClipPos(vertex);
            }

            fixed4 _ColorFront;
            fixed4 _ColorBack;

            fixed4 frag (fixed facing : VFACE) : SV_Target
            {
                // VFACE input positive for frontbaces,
                // negative for backfaces. Output one
                // of the two colors depending on that.
                return facing > 0 ? _ColorFront : _ColorBack;
            }
            ENDCG
        }
    }
}

The shader above uses the Cull state to turn off backface culling (by default back-facing triangles are not rendered at all). Here is the shader applied to a bunch of Quad meshes, rotated at different orientations:

上面的着色器使用了筛选状态来关闭反人脸的选择(默认情况下,反面三角形根本没有呈现)。这个着色器应用于一组四轴网格,在不同的方向旋转:

Vertex ID: SV_VertexID 顶点 ID: SV_VertexID

A vertex shader can receive a variable that has the “vertex number” as an unsigned integer. This is mostly useful when you want to fetch additional per-vertex data from textures or ComputeBuffers.

顶点着色器可以接收一个具有“顶点数”作为无符号整数的变量。当您希望从纹理或计算缓冲区中获取额外的每个顶点数据时,这一点非常有用。

This feature only exists from DX10 (shader model 4.0) and GLCore / OpenGL ES 3, so the shader needs to have the #pragma target 3.5 compilation directive.

这个特性只存在于DX10(着色器4.0)和GLCore/OpenGL ES 3中,因此着色器需要有一个编译目标3.5编译指令。

Shader "Unlit/VertexID"
{
    SubShader
    {
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma target 3.5

            struct v2f {
                fixed4 color : TEXCOORD0;
                float4 pos : SV_POSITION;
            };

            v2f vert (
                float4 vertex : POSITION, // vertex position input
                uint vid : SV_VertexID // vertex ID, needs to be uint
                )
            {
                v2f o;
                o.pos = UnityObjectToClipPos(vertex);
                // output funky colors based on vertex ID
                float f = (float)vid;
                o.color = half4(sin(f/10),sin(f/100),sin(f/1000),0) * 0.5 + 0.5;
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                return i.color;
            }
            ENDCG
        }
    }
}

(You can download the examples shown above as a zipped Unity project, here)


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值