第一个简单的顶点vert/片元frag着色器

     1)打开Unity 5.6编辑器,新建一个场景后ctrl+s保存命名为Scene_5。默认创建的场景是包含了一摄像机,一平行光,且场景背景是一天空盒而非纯色。在这里菜单中选择 Window->lighting->settings,会弹出一个光照选项设置框如下图:

     

     点击箭头处选择“None”资源即可去掉天空盒,看到一个纯色背景。

     2)右键create一C# script,命名为shader_5,放置脚本到shader文件夹。(相当于定义了如何“穿衣服”)

     3)右键新建shader/Standard Surface Shader,命名为shaderMat_5,放置到Material文件夹。(相当于定了一“外表衣服”) 然后把2)中的shader文件赋给它(注意:这里我们的shader文件全部都放到shader文件夹统一管理,那每个shader代码编写命名要“shader/xxx”,如下图)。

  

  

     4)右键create一个Capsule柱体,把第3)的材质拖到这个Sphere球体,渲染这个柱体的时候就能运行自定义的shader代码。(相当于告诉对象,按照shader定义的‘穿衣方式’给对象穿上材质衣服)

     5)使用standard shader原有默认代码,渲染的效果如下:

    

     复制粘贴以下的代码到shader文件,

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

Shader "shader/shader_5" {
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, , , );
} ENDCG
}
}
}

     运行看到的效果如下:

    

     下面详细分析,代码第一行通过“../文件夹名/shader文件名”形式定义了每个u shader的名字,有利于为材质球选择shader时右键快速找到自定义的shader文件(“/”控制shader文件在材质面板中出现的位置)。在Unity ShaderLab结构中,主要是PropertiesSubShaderFallback等。

     <1>Properties,顾名思义即“属性”,通俗点说就是提供在编辑器材质面板上让开发者输入接收属性调整各种材质属性的直接调试的机会。 因需要在shader程序中访问这些属性赋值,所以每个需要有一唯一的名字(Name),这个Name的用途仅是在shader程序中做区分。在Unity中,属性名字通常由一下划线开始。显示的名称display name)则是出现在材质面板上的名字,显然要对其指定类型(PropertyType)。为了第一次把Unity shader赋给某材质时,材质面板上能显示初始值,所以需要为每个属性指定一个默认值。

    

     如在上述代码中添加属性Property,

Shader "shader/shader_5" {
Properties {
_testInt("fuckInt",Int) =
_testFloat("fuckFloat",Float) = 1.68
_testRange("fuckRange",Range(0.0, 10.0)) = 6.8 _testColor("fuckColor",Color) = (0.0, 1.0, 0.0, 0.0)
_testVector("fuckVector",Vector) = (,,,)
//定义2D贴图 2的阶数大小(256*318)之类的贴图,这张贴图在采样后被转为对应基于模型UV的每个像素的颜色最终显示
_test2D("2D贴图",2D) = ""{}
//定义立方体贴图 简单说就是6张有联系的贴图的组合,主要用来做反射效果(比如天空盒动态反射),也会被转换为对应点的采样
_testCube("Cube贴图",Cube) = "white"{}
//_test3D("fuck3D",3D) = "black"{}
} SubShader {
Pass {
CGPROGRAM fixed4 _testColor;//注意要使用Properties属性值时必须先声明 #pragma vertex vert
#pragma fragment frag float4 vert(float4 v : POSITION) : SV_POSITION {
return UnityObjectToClipPos(v);
} fixed4 frag() : SV_Target {
return _testColor;
} ENDCG
}
}
}

     效果如下图所示,颜色可直接在材质面板中调整:

    

     <2>SubShader和Pass语义块,用来说明如何渲染,每个shader文件可以包含多个SubShader语义块,当Unity加载这个shader文件时会按顺序从头扫描所有SubShader,然后选择第一个平台支持的SubShader文件,若都不支持则选择Fallback指定的shader。而每个Pass定义了一次完整的渲染流程,Pass数目较多会导致渲染性能的下降,所以尽量使用最少数量的Pass。  在SubShader和Pass中都可以设置渲染相关的状态(如是否开启混合和测试等)标签,但各自的标签内容不同的故不能共用,后面会分开说明。当在SubShader中设置了渲染状态,则会应用到所有的Pass块,否则要单独在Pass中声明。

    

     SubShader的标签是字符串组成的键值对,用来告诉unity引擎希望怎样以及何时渲染这个对象,标签值和Pass的不一样。编写格式是:  Tags {"tagName" = "value"  "tagName2" = "value2"}

    

     Pass语义块多了个name,用来区分每一个pass块,并且通过这个名称,可以使用UsePass命令来直接使用其他Unity Shader中的Pass块。例如在Pass中添加 Name "MyPassName",那在别的模块就能通过 UsePass “MyShader/MYPASSNAME" 进行一样的渲染处理,有利于提高代码的复用性。 要注意一点,使用UsePass指令时Pass的名称必须所有字母都是大写模式!

    

    

     在HelloWorld工程中不需要任何渲染设置和标签设置,只需要编写CG代码块片段,由CGPROGRAM开始到ENDCG结束包围。 首先,是两条以"#pragma标志的编译指令,将告诉unity哪个函数包含了顶点着色器的代码,哪个函数包含了片段着色器代码。 #pragma vertex name 这里name就是我们指定的函数名,不一定是vert或frag,可以是任何自定义的合法函数名。

     重点分析vert函数的定义:

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

      顶点着色器代码,是逐顶点执行的。这里POSITION和SV_POSITION都是CG中的语义,是不可忽略的,这些语义告诉unity用户需要哪些输入值,以及用户输出是什么。如POSITION将告诉Unity,把模型的顶点坐标填充到输入参数v中;SV_POSITION将告诉Unity顶点着色器的输出是裁剪空间中的顶点坐标 。如果没有语义说明,渲染器就完全不知道用户的输入输出是什么,会得到错误的效果。  运行程序,会发现unity会自动替换mul()函数为UnityObjectToClipPos,原因在于:所有内建的矩阵名字在Instanced Shader中都是被重定义过的,如果直接使用UNITY_MATRIX_MVP,会引入一个额外的矩阵乘法运算。推荐使用UnityObjectToClipPos / UnityObjectToViewPos函数,会把这一次额外的矩阵乘法优化为向量-矩阵乘法。

      同理,frag函数SV_Target语义告诉渲染器,把用户输出颜色存储到一个渲染目标中,这里将默认输出到默认的帧缓存中

     扩展模型输入数据

      上面的代码只能通过POSITION语义获得模型的顶点坐标,要是还想获得模型每个顶点的纹理坐标和法线方向,该怎么办呢?因为使用纹理坐标来访问对纹理采样,而用法线数据计算光照等都是很正常的需求,这就要求定义一新的输入参数(如结构体等),而不再是简单的一个数据类型。同理希望输出纹理坐标,法线等数据到fragment片元着色器,这也需要结构体。 修改的代码如下:

    SubShader {
Pass {
CGPROGRAM fixed4 _testColor;//注意要使用Properties属性值时必须先声明 #pragma vertex vert
#pragma fragment frag struct a2v
{
//POSITION语义:用模型空间的顶点坐标填充vertex变量
float4 vertex:POSITION;
//NORMAL语义:用模型空间的法线方向填充normal变量
float3 normal:NORMAL;
//TEXCOORD0语义:用模型的第一套纹理坐标填充texcoord变量
float4 texcoord:TEXCOORD0;
}; struct v2f
{
//SV_POSITION语义:把顶点在裁剪空间中位置信息填充pos变量
float4 pos:SV_POSITION;
//COLOR0语义:存储颜色信息
float3 color:COLOR0;
}; float4 vert(a2v v) : SV_POSITION {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.color = v.nonrmal * 0.5 + fixed3(0.5,0.5,0.5)
return o
} fixed4 frag(v2f i) : SV_Target {
return fixed4(i.color, 1.0);
} ENDCG
}
}

      其中,a2v表示把数据从应用阶段(application)传递到顶点着色器中。那填充到POSITION,NORMAL等语义中的数据是从哪来的呢?在Unity中,它们是由使用该材质的Mesh Render组件提供。在每帧调用draw Call的时候,Mesh Render组件会把它负责渲染的模型数据发送给Unity Shader。而一个模型通常包含一组三角面片,每个三角面片由3个顶点构成,每个顶点又包含一些数据,如顶点位置,法线,纹理坐标,顶点颜色等等。

小强学渲染之Unity Shader编程HelloWorld的更多相关文章

  1. 小强学渲染之Unity Shader噪声应用

    之前玩Tencent的仙剑4手游时,杀死boss会看到boss有“消融”的效果,就是身体上有多个洞洞然后往四周扩散直至尸体完全消失,但效果是没有关闭背面剔除的“穿帮”效果,可能也是考虑性能因素. em ...

  2. 小强学渲染之Unity Shader边缘描边加强

    项目开发遇到一个需求,就是当坦克的准心瞄准敌方(enemy tank 或 item box)时,要让选中的对象的轮廓高亮起来,这实际上是接下来要讲解的实时渲染中轮廓线的渲染应用.实现方式有多种,下面逐 ...

  3. 小强学渲染之OpenGL的CPU管线

    读到这里,应该对OpenGL渲染管线有了初步简单了解.下面着重分析CPU管线,即逻辑控制中心做了什么,这部分还是容易理解的.如下图: 一,将数据加载到显存中. 这是由GPU是访问显存中的数据决定的.因 ...

  4. 小强学渲染之OpenGL渲染管线详析

    什么是OpenGL? OpenGL是一套图形硬件的软件API接口库,它直接和GPU交互,将3D场景渲染绘制到2D屏幕上.总结说,OpenGL的功能是将程序中定义的各种2D或3D模型绘制到帧缓存中,或者 ...

  5. 小强学渲染之OpenGL的GPU管线

    GPU渲染流水线,是硬件真正体现渲染概念的操作过程,也是最终将图元画到2D屏幕上的阶段.GPU管线涵盖了渲染流程的 几何阶段 和 光栅化阶段,但对开发者而言,只有对顶点和片段着色器有可编程控制权,其他 ...

  6. 【Unity Shader编程】之十六 基于MatCap实现适于移动平台的“次时代”车漆Shader

    本系列文章由@浅墨_毛星云 出品,转载请注明出处.   文章链接:http://blog.csdn.net/poem_qianmo/article/details/55803629 渲染本文配图使用的 ...

  7. 小强学渲染之OpenGL状态机理解

    状态机是理论上的一种机器,呃这个说法非常非常的抽象.通俗一点理解,状态机描述了一个对象在其生命周期内所经历的各种状态,状态间的转变,发生转变的动因,条件及转变中所执行的活动.或者说,状态机是一种行为, ...

  8. 【浅墨Unity3D Shader编程】之一 夏威夷篇:游戏场景的创建 & 第一个Shader的书写

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/40723789 作者:毛星云(浅墨)  ...

  9. 【浅墨Unity3D Shader编程】之中的一个 夏威夷篇:游戏场景的创建 &amp; 第一个Shader的书写

    本系列文章由@浅墨_毛星云 出品.转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/40723789 作者:毛星云(浅墨)  ...

随机推荐

  1. Git常用的操作记录(自用)

    分支常用操作命令 $ git branch -a //查看分支 $ git checkout -b dev origin/master  //切换/创建分支 $ git branch -vv 或 gi ...

  2. 洛谷P1039 侦探推理(模拟)

    侦探推理 题目描述 明明同学最近迷上了侦探漫画<柯南>并沉醉于推理游戏之中,于是他召集了一群同学玩推理游戏.游戏的内容是这样的,明明的同学们先商量好由其中的一个人充当罪犯(在明明不知情的情 ...

  3. vscode中使用beautify插件格式化vue文件

    1.点击设置,找到beautify.language并在html一栏里加上vue "beautify.language": { "js": { "ty ...

  4. JAVA除法保留小数点后两位的两种方法

      1.(double) (Math.round(sd3*10000)/10000.0);  这样为保持4位 (double) (Math.round(sd3*100)/100.0); 这样为保持2位 ...

  5. Python数据类型的内置函数之tuple(元组),dict(字典),set(集合)

    Python数据类型内置函数 - str(字符串) - list(列表) - tuple(元组) - dict(字典) - set(收集) tuple(元组)的操作 - (count)统计元组中元素出 ...

  6. spring事务学习笔记

    事务管理器 default使用数据库默认的隔离级别

  7. LayaAir疑难杂症之一:List渲染无法生效

      问题描述 使用Laya的list来做图片列表展示,无法渲染list. 原因分析 根据官网提供的文档,要将list的renderType设置为render,如图所示: 完全按照官网示例做的,但是还是 ...

  8. Django基础回顾与补充(79-80)

    Django框架之回顾与补充(d79-80)一 HTTP协议:(重点)  1 请求   -请求首行    -GET /index HTTP/1.1   -请求头部(在django框架中,可以从META ...

  9. Target JRE version (1.7.0_79) does not match project JDK version (java version "1.8.0_171"), will use sources from JDK: 1.7

    IDEA不会自动匹配系统的JDK环境.如果在IDEA里面没有配置JDK,那么运行程序时就会报错 之前碰到这个问题卡了一下 顺手记录一下 出现此错误说明IDE中配置的jdk版本和你使用的jdk版本不一致 ...

  10. 一些最常见的SNMP的OID自动翻译成zabbix数字进行表示(华为9306)

    转载自:https://blog.51cto.com/davidbj/1173954 随着Zabbix 2.0版本的发布,很多企业开始用zabbix来代替之前的Nagio.Cacti等其它监控软件.至 ...