Shader 语义

在书写HLSL shader程序时,输入和输出变量需要拥有他们 含义来表明语义。这在HLSL shader中是一个标准的做法。

Vertex shader 输入语义

主顶点着色器函数(被指令 #pragma vertex 标记)需要在所有的输入参数中加上语义。这些对应于单个网格数据元素,比如顶点位置,网格法线,还有贴图坐标等。简单例子如下:

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
        }
    }
}

Fragment shader 输出语义

大多数情况下,片段着色器输出一个额颜色,并且含有 SV_Target语义。就比如:

fixed4 frag(v2f i): SV_Target

函数 frag 有一个返回类型为 fixed4 的值。因为它只会返回一个值,那么语义就可以直接定义在函数上。

当然,输出返回一个结构体也是可以的。上面的片段着色器可以被重写为下面这个样子,并且他们的功能一致:

struct fragOutput
{
    fixed4 color : SV_Target;
};

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

从片段着色器中返回结构体,对于那些不单单返回一个颜色的着色器非常有用。支持片段着色器输出的额外的语义如下:

SV_TargetN: 多个渲染目标

  SV_Target1,SV_Target2等等:这些是shader输出的额外的颜色。这种做法在一次性渲染多个目标时使用(也叫作多重渲染目标渲染技术,MRT)。当然,SV_Target0 就等于SV_Target

SV_Depth:像素着色器深度输出

  通常情况,片段着色器不会覆写 Z 缓冲区的值,在三角形光栅化阶段,一般都用的是默认值。然而,对于一些特效,对每个像素使用自己的z缓冲区值是非常有帮助的。

  注意在许多GPU上,深度缓冲优化是关闭了的,所以在没有必须的理由时,最好不要重写深度缓冲区的值。由 SV_Depth 引发的性能消耗 根据GPU架构不同而不同,但是总体上来说这个消耗与alpha 测试相当。

Vertex shader 输出和 fragment shader 输入

一个vertex shader需要输出 一个顶点的 最终剪切空间坐标,这样GPU才知道在屏幕上的哪个地方、多少深度来光栅化它,这个输出需要有 SV_POSITION 语义,而且它的类型是一个 float4类型的数据。

vertex shader产生的任何其他输出都是你特殊着色器所需要的。从顶点着色器输出的值将被用来渲染三角形面,并且每个像素的值将被会作为输入数据传给片段着色器。

许多现代的GPU不需要真正关心这些变量有哪些语义;然而一些老系统却是需要一些特别的语义:

  TEXCOORD0,TEXCOORD1等等用来表明任意高精度数据,比如坐标或者位置。

  COLOR0,COLOR1 语义在顶点着色器输出和片段着色器输入中代表 低精度,0-1范围内的数据。

为了最好的跨平台支持, 在顶点着色器的输出与片段说色器的输入中,最好打上 TEXCOORDn语义标签。

插入器数量限制

将信息从顶点着色器传递到片段着色器中时,插入器变量可以使用的总量有着数量限制。限制数量与平台和GPU有关:

  • 最高8个:OpenGL ES 2.0 (iOS/Android), Direct3D 11 9.x level (Windows Phone) and Direct3 9 shader model 2.0 (old PCs).虽然插入器数量被限制了,但是每个插入器可以是一个4分量的向量,一些着色器将数据打包到一起来不超过限制。比如,两个贴图坐标可以被一个float4变量传递。
  • 最高10个:Direct3D 9 shader model 3.0 (#pragma target 3.0).
  • 最高16个:OpenGL ES 3.0 (iOS/Android), Metal (iOS).
  • 最高32个:Direct3D 10 shader model 4.0 (#pragma target 4.0).

为了性能着想,不管你是啥平台,最好都尽量使用更低数量的插入器。

其它特别的语义

Screen space pixel position:VPOS

一个片段着色器可以接受一个作为特别 VPOS语义呈现的像素的位置。这个特性只有在以 model 3.0开头的着色器中才存在。所以着色器需要编译指令:#pragma target 3.0

在不同的平台,屏幕空间位置的输入在底层上是不同的,所以为了最大限度的可移植性,在使用屏幕空间位置时,使用 UNITY_VPOS_TYPE标签。(大多数情况为float4,但是在D3D9 为float2)。

此外, 使用像素位置语义让在一个顶点到片段的结构体 同时拥有 剪切空间位置(SV_POSITION)和VPOS(屏幕空间位置)变得困难。所以顶点着色器需要将 剪切空间位置(SV_POSITION)作为一个单独的输出变量。请看下面的例子:

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修饰的 输入变量将会包含一个正值表明正对着的三角形,一个负数来表明背对这的三角形。

这个特性只有在 model 3.0 的着色器中才有,所以着色器必须包含编译指令: #pragma target 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
        }
    }
}

  

Vertex ID: SV_VertexID

顶点着色器可以接收一个具有顶点数作为无符号整数的变量。当你想从贴图或者计算缓冲区中拿到额外的每个顶点数据时,这样就非常有用。

这个特性只有在DX10 和GLCore/OpenGL ES 3中才支持,所以需要引入编译指令 #pragma target 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
        }
    }
}

  

原文地址:https://www.cnblogs.com/leiGameDesigner/p/8456586.html

时间: 2024-08-05 03:55:47

Shader 语义的相关文章

Unity Shader入门精要学习笔记 - 第3章 Unity Shader 基础

来源作者:candycat   http://blog.csdn.net/candycat1992/article/ 概述 总体来说,在Unity中我们需要配合使用材质和Unity Shader才能达到需要的效果.一个最常见的流程是. 1)创建一个材质 2)创建一个Unity Shader,并把它赋给上一步创建的材质 3)把材质赋给要渲染的对象 4)在材质面板中调整Unity Shader的属性,以得到满意的效果 下图显示了Unity Shader和材质是如何一起工作来控制物体的渲染的. Uni

[Unity] Shader(着色器)输入输出和语义

在Unity5.x后, 已经支持了基于物理的光照模型,也就是常说的次时代引擎所必须具备的功能. 如果在Properties使用2D,CG里要用sampler2D,代表使用的是2维纹理 如果在Properties使用color, CG里要用fixed4 如果在Properties使用Range, CG里要用half,实际上描述的是一个float struct Input 用于描述UV坐标的结构体.在 Input 中, 变量名必须是 uv_ 开始, 变量名必须是官方文档中已经指定的名称(也就是说不可

【Unity Shader】--- 准确认识SubShader语义块结构、渲染状态设定、Tags标签

一[SubShader] 每个UnityShader文件可以包含多个SubShader语义块,但至少要有一个.当Unity需要加载这个UnityShader时,Unity会扫描所有的SubShader语义块,然后选择一个能够在目标平台上运行的SubShader.如果都不支持的话,Unity就会使用FallBack语义指定的UnityShader. Unity提供这种语义的原因在于,不同的显卡具有不同的能力.例如,一些旧的显卡仅能支持一定数目的操作指令,而一些高级的显卡可以支持更多的指令数,那么我

shader一些语义或术语的解释

1.unity内置的摄像机和屏幕参数: 2.unity中一些常用的包含文件: 3.unityCG.cginc中一些常用的结构体: 4.unityCG.cginc中一些常用的帮助函数: 5.从应用阶段传递模型数据给顶点着色器时,unity支持的常用语义: 6.从顶点着色器传递给片元着色器时unity使用的常用语义: 7.片元着色器输出时unity支持的常用语义:

unity shader笔记

clip函数可以用来切割mesh clip(var); var 的值小于0时就会被切割 表面着色器 其实就是生成了定点片元着色器,相当于一种包装和简化吧 标准的填充结构 struct SurfaceOutput { fixed3 Albedo; // diffuse color fixed3 Normal; // tangent space normal, if written fixed3 Emission; half Specular; // specular power in 0..1 r

关于Unity中Shader的使用

在游戏的开发过程中,程序员不太会自己去写shader,因为写起来很麻烦,而且只有Unity会报错,编译器也没有什么提示. 通常是拿别人的shader改一改,当然,程序员还是要能看懂和会一点shader Unity坐标系转换 1: transform.localToWorldMatrix 局部转世界的矩阵;2: transfrom.worldToLocalMatrix 世界坐标转局部坐标矩阵; MultiplyPoint, MultiplyPoint3x4 MultiplayVector 来进行坐

Cg入门1:输入输出和语义

知识点: 1.顶点和片段程序的输入输出 2.常用语义 3.编写一个简单的Shader 输入用:in 输出用:out 即使输入也是输出用:inout CG语法: CGPROGRAM 开始标识 ENDCG  结束标识 objPos:语义  语义关键字必须为全大写字母组成(objpos:POSITION 语义:objpos表示一个位置向量),语义只是代表一种运行环境 inout:表示可以把输入直接当成输出返回(顶点颜色输出col当成片段程序的输入,根据类型来匹配的,而不是根据名字来匹配的) 语义类型:

(译)Minimal Shader(最小的着色器)

(原文:https://en.wikibooks.org/wiki/Cg_Programming/Unity/Minimal_Shader) This tutorial covers the basic steps to create a minimal Cg shader in Unity. 本节课包含了在Unity中创建一个最小的Cg着色器的基本步骤. Starting Unity and Creating a New Project(打开Unity创建一个新工程) After downlo

[Unity] Shader - CG语言 和 HLSL语言

CG 跟 HLSL几乎是一摸一样的. (HLSL官方参考,包含语法格式,函数库,关键字,在这个地方: http://msdn.microsoft.com/en-us/library/bb509638(v=VS.85).aspx, 如果链接失效,用“Reference for HLSL”搜索.) Shader本身是一个单纯的单元,就是对输入(顶点或像素或物体)进行能做的算术运算,然后把结果送出的一个固件. 1.内置元类型 float: 32 bit浮点类型half:  16 bit浮点int: