当前位置: 首页 > news >正文

《UnityShader入门精要》学习4

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

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

Unity Shader的基本结构。它包含了Shader、Properties、SubShader、Fallback等语义块。顶点/片元着色器的结构与之大体类似

        Shader  "MyShaderName"  {Properties  {// 属性}SubShader  {// 针对显卡A的SubShaderPass  {// 设置渲染状态和标签// 开始CG代码片段CGPROGRAM// 该代码片段的编译指令,例如:#pragma  vertex  vert#pragma  fragment  frag// CG代码写在这里ENDCG// 其他设置}// 其他需要的Pass}SubShader  {// 针对显卡B的SubShader}// 上述SubShader都失败后用于回调的Unity ShaderFallback  "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  fragfloat4  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  fragstruct  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.lryc.cn/news/192662.html

相关文章:

  • kaggle新赛:写作质量预测大赛【数据挖掘】
  • 导入导出Excel
  • C# Thread.Sleep(0)有什么用?
  • 二十四、【参考素描三大面和五大调】
  • 【Python 千题 —— 基础篇】进制转换:十进制转二进制
  • [ spring boot入门 ] java: 错误: 无效的源发行版:17
  • 【计算机组成体系结构】电路基本原理与加法器设计
  • MyBatisPlus之基本CRUD、常用注解
  • 采集EtherNET/IP转Profinet在西门子plc中的应用
  • Paddle build_cinn_pass_test源码阅读(fluid目录下)
  • 函数调用:为什么会发生stack overflow?
  • git log
  • 在面试提问环节应该问那些内容
  • 【vb.net】轻量JSON序列及反序列化
  • 【Vue】vue2与netcore webapi跨越问题解决
  • SpringSecurity + jwt + vue2 实现权限管理 , 前端Cookie.set() 设置jwt token无效问题(已解决)
  • 【21】c++设计模式——>装饰模式
  • 【博客707】模版化拆解并获取victoriametrics的metricsql各个元素
  • nodejs + express 实现 http文件下载服务程序
  • Qt多文本编辑器项目实战
  • CVE-2017-7529 Nginx越界读取内存漏洞
  • 力扣每日一题136:只出现一次的数字
  • 导航栏参考代码
  • 区块链(11):java区块链项目之页面部分实现
  • RootSIFT---SIFT图像特征的扩展
  • ChatGPT角色扮演教程,Prompt词分享
  • zabbix监控——自定义监控内容
  • 中断机制-中断协商机制、中断方法
  • three.js入门 —— 实现第一个3D案例
  • 《动手学深度学习 Pytorch版》 8.4 循环神经网络