《UnityShader入门精要》学习4

news2025/1/10 1:39:01

一个最简单的顶点/片元着色器

一个最简单的顶点/片元着色器

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

一个简单的代码:

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

Shader  "Unity  Shaders  Book/Chapter  5/Simple  Shader"  {
    SubShader{
      Pass  {
          CGPROGRAM

          #pragma  vertex  vert
          #pragma  fragment  frag

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

          fixed4  frag() : SV_Target  {
              return  fixed4(1.0,  1.0,  1.0,  1.0);
          }

          ENDCG
      }
    }
}

效果:

讲解:

代码的第一行通过Shader语义定义了这个Unity Shader的名字——“Unity Shaders Book/Chapter 5/Simple Shader

Properties语义并不是必需的,我们可以选择不声明任何材质属性

两条编译指令:

#pragma vertex vert

#pragma fragment frag

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

更一般的形式:

#pragma vertex name

#pragma fragment name   //其中name 就是我们指定的函数名

        float4  vert(float4  v  :  POSITION)  :  SV_POSITION  {
            return  mul  (UNITY_MATRIX_MVP,  v);
        }

这就是本例使用的顶点着色器代码,它是逐顶点执行的。vert函数的输入v包含了这个顶点的位置,这是通过POSITION语义指定的。它的返回值是一个float4类型的变量,它是该顶点在裁剪空间中的位置,POSITION和SV_POSITION都是CG/HLSL中的语义(semantics),它们是不可省略的,这些语义将告诉系统用户需要哪些输入值,以及用户的输出是什么

例如这里,POSITION将告诉Unity,把模型的顶点坐标填充到输入参数v中,SV_POSITION将告诉Unity,顶点着色器的输出是裁剪空间中的顶点坐标

return 执行的代码的意思是:把顶点坐标从模型空间转换到裁剪空间中。UNITY_MATRIX_MVP矩阵是Unity内置的模型·观察·投影矩阵

        fixed4  frag()  :  SV_Target  {
            return  fixed4(1.0,  1.0,  1.0,  1.0);
        }

在本例中,frag函数没有任何输入。它的输出是一个fixed4类型的变量,并且使用了SV_Target语义进行限定。SV_Target也是HLSL中的一个系统语义,它等同于告诉渲染器,把用户的输出颜色存储到一个渲染目标(render target)中,这里将输出到默认的帧缓存中。片元着色器中的代码很简单,返回了一个表示白色的fixed4类型的变量。片元着色器输出的颜色的每个分量范围在[0, 1],其中(0, 0,0)表示黑色,而(1, 1, 1)表示白色。

模型数据从哪里来

为了自建一个自定义的结构体,我们必须使用如下格式来定义它:

        struct  StructName  {
            Type  Name  :  Semantic;
            Type  Name  :  Semantic;
            .......
        };

其中,语义是不可以被省略的

我们修改了vert函数的输入参数类型,把它设置为我们新定义的结构体a2v。通过这种自定义结构体的方式,我们就可以在顶点着色器中访问模型数据。

在Unity中,填充到POSITION, TANGENT, NORMAL这些语义中的数据是由使用该材质的Mesh Render组件提供的。在每帧调用Draw Call的时候,Mesh Render组件会把它负责渲染的模型数据发送给Unity Shader

我们知道,一个模型通常包含了一组三角面片,每个三角面片由3个顶点构成,而每个顶点又包含了一些数据,例如顶点位置、法线、切线、纹理坐标、顶点颜色等

顶点着色器和片元着色器之间如何通信

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

        Shader  "Unity  Shaders  Book/Chapter  5/Simple  Shader"  {
            SubShader  {
              Pass  {
                  CGPROGRAM

                  #pragma  vertex  vert
                  #pragma  fragment  frag

                  struct  a2v  {
                      float4  vertex  :  POSITION;
                      float3  normal  :  NORMAL;
                      float4  texcoord  :  TEXCOORD0;
                  };

                  // 使用一个结构体来定义顶点着色器的输出
                  struct  v2f  {
                      // SV_POSITION语义告诉Unity, pos里包含了顶点在裁剪空间中的位置信息
                      float4  pos  :  SV_POSITION;
                      // COLOR0语义可以用于存储颜色信息
                      fixed3  color  :  COLOR0;
                  };

                  v2f  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);
                      return  o;
                  }

                  fixed4  frag(v2f  i)  :  SV_Target  {
                      // 将插值后的i.color显示到屏幕上
                      return  fixed4(i.color,  1.0);
                  }

                  ENDCG
              }
            }
        }

在上面的代码中,我们声明了一个新的结构体v2f。v2f用于在顶点着色器和片元着色器之间传递信息。同样的,v2f中也需要指定每个变量的语义。在本例中,我们使用了SV_POSITION和COLOR0语义。顶点着色器的输出结构中,必须包含一个变量,它的语义是SV_POSITION。否则,渲染器将无法得到裁剪空间中的顶点坐标,也就无法把顶点渲染到屏幕上。COLOR0语义中的数据则可以由用户自行定义,但一般都是存储颜色,例如逐顶点的漫反射颜色或逐顶点的高光反射颜色

如何使用属性

        Shader  "Unity  Shaders  Book/Chapter  5/Simple  Shader"  {
            Properties  {
              // 声明一个Color类型的属性
              _Color  ("Color  Tint",  Color)  =  (1.0,1.0,1.0,1.0)
            }
            SubShader  {
              Pass  {
                  CGPROGRAM

                  #pragma  vertex  vert
                  #pragma  fragment  frag

                  // 在CG代码中,我们需要定义一个与属性名称和类型都匹配的变量
                  fixed4  _Color;

                  struct  a2v  {
                      float4  vertex  :  POSITION;
                      float3  normal  :  NORMAL;
                      float4  texcoord  :  TEXCOORD0;
                  };

                  struct  v2f  {
                      float4  pos  :  SV_POSITION;
                      fixed3  color  :  COLOR0;
                  };

                  v2f  vert(a2v  v)  :  SV_POSITION  {
                      v2f  o;
                      o.pos  =  mul(UNITY_MATRIX_MVP,  v.vertex);
                      o.color  =  v.normal  *  0.5  +  fixed3(0.5,  0.5,  0.5);
                      return  o;
                  }

                  fixed4  frag(v2f  i)  :  SV_Target  {
                      fixed3  c  =  i.color;
                      // 使用_Color属性来控制输出颜色
                      c  *=  _Color.rgb;
                      return  fixed4(c,  1.0);
                  }

                  ENDCG
              }
            }
        }

在上面的代码中,我们首先添加了Properties语义块中,并在其中声明了一个属性_Color,它的类型是Color,初始值是(1.0,1.0,1.0,1.0),对应白色。为了在CG代码中可以访问它,我们还需要在CG代码片段中提前定义一个新的变量,这个变量的名称和类型必须与Properties语义块中的属性定义相匹配。

强大的援手:Unity提供的内置文件和变量

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1093180.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

安全隐患随手拍小程序搭建-人人都是安全员活动

各生产型企业都会组织开展“安全隐患随手拍”活动,目的就是使广大职工积极发现身边的安全隐患,从而提高自身安全意识,重视安全生产,营造“人人查安全、人人保安全”的良好氛围。 可传统靠微信群组或QQ邮箱上报隐患方式&#xff0c…

Linux服务器快速搭建pytorch

Linux服务器搭建pytorch 文章目录 Linux服务器搭建pytorch一、使用FileZilla传输Anaconda二、激活Anaconda环境1.创建一个虚拟环境2.使用已有项目生成requirements.txt3.在虚拟环境中使用requirements.txt安装其他项目相关库 总结 一、使用FileZilla传输Anaconda 提示&#xf…

微信小程序获取当前日期时间

一、直接使用方式 在小程序中获取当前系统日期和时间,可直接拿来使用的常用的日期格式 //1. 当前日期 YYYY-MM-DDnew Date().toISOString().substring(0, 10)new Date().toJSON().substring(0, 10)//2. 当前日期 YYYY/MM/DDnew Date().toLocaleDateString()//3.…

计算机图形学(有效边表算法)用知识,改变命运的秘密【Morty深度干货】视频学习

目录 1.你所身处的世界,其实并非是一个真实的世界 3、哪些知识,会真正影响到我们的人生 你要用大量的精力去学习对于你的人生能产生实际价值的领域的知识 历史 经济学 金融与投资 心理学 永远不要去相信人,而是要去相信人性 成长的路…

2023年中国禽流感疫苗产量、需求量及市场规模分析[图]

禽流感疫苗是以甲型流行性感冒病毒H5N1、H9N2等毒株经处理后制备的灭活疫苗。用于预防人感染高致病性禽流感病毒感染,控制禽流感的流行。 从产业链来看,禽流感疫苗行业上游为原材料市场,主要有非免蛋、血清、佐剂等。禽流感疫苗行业下游主要为…

博客系统(java,MySQL,HTML)

项目展示: 1.输入 http://127.0.0.1:8080/blog_system/login.html 即可进入登录页面 2.输入正确的用户名和密码后进入博客列表页 要是用户名或密码输入错误,会弹出错误提示框 3.点击查看全文,可以进入博客详情页查看详细信息 4.点击写博客&a…

Studio One6.5中文版本下载安装步骤

在唱歌效果调试当中,我们经常给客户安装的几款音频工作站。第一,Studio One 6是PreSonus公司开发的一款功能强大的音频工作平台,具有丰富的音频处理功能和灵活的工作流程。以下是Studio One6的一些主要特点: 1.多轨录音和编辑&…

树模型(三)决策树

决策树是什么?决策树(decision tree)是一种基本的分类与回归方法。 长方形代表判断模块 (decision block),椭圆形成代表终止模块(terminating block),表示已经得出结论,可以终止运行。从判断模块引出的左右箭头称作为分支(branch)…

lc42接雨水详解

1 42. 接雨水 接雨水 2 推荐阅读的解析 《接雨水》详细通俗的思路分析,多解法 推荐观看方法:二、三和四 3 不懂的地方-方法四的一个判断条件 以下是疑问的地方 height [ left - 1] 是可能成为 max_left 的变量, 同理,height…

隧道代理-

文章目录 代理代理使用场景VPS建立隧道frpMSF木马生成监听开启frp服务端和客户端执行exe木马文件 代理 实验环境: 攻击机kali:192.168.160.32(NAT模式)模拟的公网服务器(本机):10.9.75.214失陷…

SQL Server远程登录失败

SQL Server远程登录失败 检查SQL SERVER 是否允许远程访问. 具体步骤: 1)在远端SQL Server主机上,打开SSMS并连接数据库 2)在相应”数据库”上单击右键,选择”属性” 3)选择”连接”选项卡,检查”远程服务器连接”下,RPC服务是否选择. 设置SQL Server相关TCP连接 1.打开SQL Se…

代码随想录算法训练营第天十六天丨 二叉树part04

文档讲解:代码随想录 状态:已完成 513.找树左下角的值 思路 递归 分析一下题目:在树的最后一行找到最左边的值。 首先要是最后一行,然后是最左边的值。 如果使用递归法,如何判断是最后一行呢,其实就是…

为数据列表的每条记录生成对应的二维码

效果图&#xff1a; 一、前端 <!DOCTYPE html> <html lang"zh" xmlns:th"http://www.thymeleaf.org" xmlns:shiro"http://www.pollix.at/thymeleaf/shiro"> <head><th:block th:include"include :: header(固定资产…

CA与区块链之数字签名详解

CA与区块链验证本质上都是数字签名&#xff0c;首先&#xff0c;我们看一下什么是数字签名&#xff01; 数字签名 数字签名是公钥密码学中的一种技术&#xff0c;用于验证信息的完整性和发送者的身份。简而言之&#xff0c;数字签名是一种确认信息来源和信息完整性的手段。它通…

沉睡的木乃伊:var_export() 与可解析字符串

文章目录 参考环境var_export()概念应用场景数据持久化调试 函数 var_export() 自定义类__set_state() 魔术方法设置 __set_state 魔术方法的逻辑以复原对象注意事项 通用内置空类 stdClassstdClass对 __set_state() 的天然支持 参考 项目描述搜索引擎Bing、GoogleAI 大模型文…

UI自动化测试 —— Jenkins配置

前一段时间帮助团队搭建了UI自动化环境&#xff0c;这里将Jenkins环境的一些配置分享给大家。 背景&#xff1a; 团队下半年的目标之一是实现自动化测试&#xff0c;这里要吐槽一下&#xff0c;之前开发的测试平台了&#xff0c;最初的目的是用来做接口自动化测试和性能测试&…

数睿通2.0:高效的数据处理,主数据与数据表功能全面升级

引言 八天很短&#xff0c;七天很长&#xff0c;数睿通 2.0 数据中台也随之迎来了新一轮的版本迭代&#xff0c;本次更新主要包括&#xff1a; 主数据模型&#xff08;可视化建模&#xff09;主数据派发&#xff08;支持派发主数据到下游数据表&#xff0c;rabbitMq&#xff…

字节码学习之常见java语句的底层原理

文章目录 前言1. if语句字节码的解析 2. for循环字节码的解析 3. while循环4. switch语句5. try-catch语句6. i 和i的字节码7. try-catch-finally8. 参考文档 前言 上一章我们聊了《JVM字节码指令详解》 。本章我们学以致用&#xff0c;聊一下我们常见的一些java语句的特性底层…

苍穹外卖(四) AOP切面公共字段自动填充及文件上传

一.AOP切面公共字段填充 问题分析 如果都按照上述的操作方式来处理这些公共字段, 需要在每一个业务方法中进行操作, 编码相对冗余、繁琐&#xff0c;那能不能对于这些公共字段在某个地方统一处理&#xff0c;来简化开发呢&#xff1f; 答案是可以的&#xff0c;我们使用AOP切…

Redis订阅和发布

Redis订阅和发布 一、订阅者和发布者二、使用示例三、常用命令 一、订阅者和发布者 发布者&#xff1a;publish&#xff0c;发送消息订阅者&#xff1a;subscribe&#xff0c;接收消息 如下图所示&#xff0c;可以有多个订阅者订阅同一个频道&#xff0c;如果该频道发送消息&…