[UnityShader入门精要读书笔记]06.顶点/片元着色器基本结构

2023-11-12

Unity Shader基本结构包含Shader,Properties,SubShader,FallBack等语义块。结构如下:

Shader "MyShaderName"{

       Properties{

             //属性

       }

       SubShader{

              //针对显卡A的SubShader

              Pass{

                      //设置渲染状态金和标签

                     //开始CG代码片段

                     CGPROGRAM

                      //该代码片段的编译指令,例如:

                       #pragma vertex vert

                       #pragma fragment frag

                       //CG代码写这里

                      ENDCG

                      //其他设置 

              }

              //其他需要的Pass

       }

       SubShader{

                 //针对显卡B的SubShader

       }

      //上述SubShader都失败后用于回调的Unity Shader

     FallBack  "VertexLit"

}

其中,最重要的就是Pass语义块。由CGPROGRAM 和ENDCG所包围的CG代码片段,里边有两条非常重要的渲染指令,

#pragma vertex vert

#pragma fragment frag

它将告诉Unity ,哪个函数包含了顶点着色器的代码,哪个函数包含了片元着色器的代码。

这两个函数不一定是,vert和frag,但通常使用这两个名字命名,首先看下vert函数的定义:

float4 vert(float4 v : POSITION) : SV_POSITION{

         return mul(UNITY_MATRIX_MVP, v);

}

顶点着色器是逐顶点执行的,vert函数的输入v包含了这个顶点的位置,这是通过POSITION语义指定的。它的返回值是一个float4类型的变量,它是该顶点在裁剪空间中的位置,POSITION和SV_POSITION都是CG/HLSL中的语义,他们是不可省略的。POSITION将告诉Unity,把模型的顶点坐标填充到输入参数v中,SV_POSITION将高速Unity,顶点着色器的输出是裁剪空间中的顶点坐标。

再看下frag函数的定义:

fixed4 frag() : SV_Target{

     return fixed4(1.0,1.0,1.0,1.0);

例子中,frag函数没有任何输入,它的输出是一个fixed4类型的变量。并且使用了SV_Target语义进行限定。SV_Target也是HLSL中的一个系统语义,它等同于告诉渲染器,把用户的输出颜色存储到一个渲染目标中,这里将输出到默认的帧缓存中。

Shader "Unlit/simple shader"
{
    SubShader
    {
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            struct a2v
            {
                //POSITION语义告诉 UNITY,用模型空间的顶点坐标填充vertex变量。
                float4 vertex : POSITION;
                //NORMAL语义告诉 UNITY,用模型空间的法线方向填充normal变量。
                float3 normal : NORMAL;
                //TEXCOORD0语义告诉  UNITY,用模型的第一套纹理坐标填充texcoord变量。
                float4 texcoord : TEXCOORD0;
            };

            
            float4 vert (a2v v) : SV_POSITION
            {
                //使用v.vertex来访问模型空间的顶点坐标。
                return mul(UNITY_MATRIX_MVP,v.vertex);
            }
            
            fixed4 frag () : SV_Target
            {
                return fixed4(1.0,1.0,1.0,1.0);
            }
            ENDCG
        }
    }
}
在上面的代码中,我们定义了一个新的结构体a2v,它包含了顶点着色器需要的模型数据,在a2v的定义中,我们用到了更多UNITY支持的语义。如NORMAL和TEXCOORD,当它们作为顶点着色器输入时都有特定含义的,因为Unity会根据这些语义来填充这个结构体,对于顶点着色器的输出,Unity支持的语义有:POSITION,TANGENT,NORMAL,TEXCOORD0,TEXCOORD1,TEXCOORD2,TEXCOORD3,COLOR等。

在实践中,我们希望从顶点着色器输出一些数据,例如把模型的法线、纹理坐标等传递给片元着色器。

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "Unlit/simple shader"
{
    SubShader
    {
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            struct a2v
            {
                //POSITION语义告诉 UNITY,用模型空间的顶点坐标填充vertex变量。
                float4 vertex : POSITION;
                //NORMAL语义告诉 UNITY,用模型空间的法线方向填充normal变量。
                float3 normal : NORMAL;
                //TEXCOORD0语义告诉  UNITY,用模型的第一套纹理坐标填充texcoord变量。
                float4 texcoord : TEXCOORD0;
            };
            
            struct v2f {
                //SV_POSITION语义告诉UNITY,Pos里包含了顶点在裁剪空间中的位置信息。
                float4 pos:SV_POSITIO;
                //COLOR0语义用于存储颜色信息。
                fixed3 color : COLOR0;
            };
            
            float4 vert (a2v v) : SV_POSITION
            {
                v2f o;
                o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
                //v.normal包含了顶点的法线方向,其分量范围在[-1.0,1.0]
                //下面的代码把分量范围映射到了[0.0,1.0]
                //存储o.color中传递给片元着色器
                o.color = v.normal * 0.5 + fixed3(0.5, 0.5, 0.5, 0.5);
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                //将插值后的i.color显示到屏幕上
                return fixed4(i.color,1.0);
            }
            ENDCG
        }
    }
}
在上面的代码中,我们声明了一个新的结构体v2f。v2f用在顶点着色器和片元着色器之间传递信息。同样的,v2f中也需要指定每个变量的语义。在本例中,我们使用了SV_POSITION和COLOR语义。顶点着色器的输出结构中,必须包含一个变量,它的语义是SV_POSITION。否则,渲染器将无法得到裁剪空间中的顶点坐标,也就无法把顶点渲染到屏幕上。COLOR0语义中的数据则可以由用户自定义,但一般都是存储颜色。

顶点着色器是逐顶点调用的,而片元着色器是逐片元调用的。片元着色器中的输入实际上是把顶点着色器的输出进行插值后得到的结果。

有时CG变量前边会有一个uniform关键字,例如

uniform fixed4 _Color;

uniform关键词是CG中修饰变量和参数的一种修饰词,它仅仅用于提供一些关于该变量的初始值是如何指定和存储的相关信息,在UnityShader中,uniform可以省略。

 

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

[UnityShader入门精要读书笔记]06.顶点/片元着色器基本结构 的相关文章

  • 基于画布canvas进行图片压缩

    Canvas 压缩图片的原理主要是通过重新绘制图片 调整图片质量或大小来达到压缩图片的目的 具体实现步骤如下 1 使用 JavaScript 中的 Image 对象将图片加载到内存中 var img new Image img src im
  • mkp勒索病毒怎么处理

    目录 前言 简介 一 mkp勒索病毒的特征 二 mkp后缀勒索病毒是如何传播的 三 如何预防与处理mkp勒索病毒攻击 前言 简介 当今 勒索病毒已成为企业网络安全的一大威胁 而其中mkp勒索病毒则是一种新近出现的变种 与其他勒索病毒一样 m
  • 关于redis密码

    如何更改密码 直接配置文件里更改 配置文件里开放 requirepass 之后客户端更改 用Redis命令查询密码 可以使用以下Redis命令来查询密码 config get requirepass 得到的结果第一行固定是requirepa
  • 设计模式-备忘录模式(Memento Pattern)

    文章目录 前言 一 备忘录模式的概念 二 备忘录模式的实现 三 备忘录优缺点 优点 缺点 总结 前言 备忘录模式 Memento Pattern 是一种行为型设计模式 它用于捕获和存储对象的内部状态 以便在以后可以恢复到先前的状态 备忘录模
  • pthread_detach函数

    int pthread detach pthread t thread 成功 0 失败 错误号 作用 从状态上实现线程分离 注意不是指该线程独自占用地址空间 线程分离状态 指定该状态 线程主动与主控线程断开关系 线程结束后 不会产生僵尸线程
  • jwt编码解码

    import jwt 创建 JWT payload user id 1234 secret key your secret key 密钥 用于签名和验证 algorithm HS256 签名算法 token jwt encode paylo
  • NPM导入模块报错

    npm WARN enoent ENOENT no such file or directory open C Program Files nodejs package json 找不到package json文件 一般情况下npm安装时都
  • python 删除文件、清空目录的方法总结

    Python os remove 方法 os remove 方法用于删除指定路径的文件 如果指定的路径是一个目录 将抛出OSError 在Unix Windows中有效 以下实例演示了 remove 方法的使用 usr bin python
  • python---面向对象(一)

    类和对象 面向对象编程的2个非常重要的概念 类和对象 对象是面向对象编程的核心 在使用对象的过程中 为了将具有共同特征和行为的一组对象抽象定义 提出了另外一个新的概念 类 类就相当于制造飞机时的图纸 用它来进行创建的飞机就相当于对象 类是抽
  • Visual Prompt

    始于NLP 简单来讲 Prompt就是对原来的输入文本进行一定的处理 使得在不改变预训练模型参数的情况下 相应任务的性能变高 例如 原输入文本为 I received the offer from ETH 对于文本分类 我们将其修改为I r
  • cassandra ssdb mongodb

    IM系统 数据量大了mongodb性能有瓶颈 cassandra ssdb 配合使用来搞IM 写扩散 其实是双写 历史消息走cassandra ssdb保留7天的离线消息 cassandra ssdb mongodb
  • 简单的解压缩算法(华为od考试)

    题目描述 现需要实现一种算法 能将一组压缩字符串还原成原始字符串 还原规则如下 1 字符后面加数字N 表示重复字符N次 例如 压缩内容为A3 表示原始字符串为AAA 2 花括号中的字符串加数字N 表示花括号中的字符重复N次 例如压缩内容为
  • 12面魔方公式图解法_【高级篇】(三)三阶魔方CFOP高级玩法之——F2L

    一 F2L这一步要干什么 1 先了解一下 棱角对 和 槽位 的概念 棱角对 即由一个棱块和一个角块构成 是F2L的基本单元 共四组 槽位 给 棱角对 预留的位置 即 棱角对 最后需要插入的地方 棱角对 和 槽位 的概念 2 棱角对 是如何插
  • 在 Android Studio 2.2 中愉快地使用 C/C++

    使用 Android studio 你可以将 C 和 C 代码编译成 native library 然后打包到你的 APK 中 你的 Java 代码可以通过 Java Native Interface JNI 调用 native libra
  • Lite Git (II) - Initialize

    Lite Git II Initialize 前言 本专栏名为Lite Git 主要想与Pro Git对应 后者为Git官方指南 有兴趣 或者想了解更多细节的同学 请移步官网下载PDF版 本专栏主要为了让初出茅庐的同学更快 更合理地掌握Gi
  • RxJS——异步数据流的响应式编程库(适合新手入门)

    文章目录 RxJS概述 Redux VS RxJS RxJS核心概念解析 热观察和冷观察 merge combine合流 RXJS6 的变化 RxJS概述 RxJS 全称 Reactive Extensions for JavaScript
  • 产线发现扣上电池就开机问题分析

    作者 AirCity 2020 3 1 Aircity007 sina com 本文所有权归作者Aircity所有 现象 某SDM630平台手机项目首件 扣上电池 没有按Power键 主板立即开机 问题分析 初步排查开机信号 VBUS信号
  • 前端面试常问题(持续整理中)

    1 js的运行机制 js主要用途是和用户互动 用来操作DOM 所以js是单线程的 避免了同时操作同一个DOM的矛盾问题 2 arguments对象是什么 它是一个类数组对象 它有length属性 但是没有数组的方法 它是如何转化成数组的呢

随机推荐