顶点/片元 shader 总结
Cg顶点程序必须在结构中传递顶点数据。几种常用的顶点结构定义在文件UnityCG.cginc中,有如下三种结构体:
1、appdata_base: 包含顶点位置,法线和一个纹理坐标。
2、appdata_tan:包含顶点位置,切线,法线和一个纹理坐标。
3、appdata_full:包含位置、法线、切线、顶点色和两个纹理坐标。
struct appdata_base {
float4 vertex : POSITION; //顶点坐标
float3 normal : NORMAL;//法线
float4 texcoord : TEXCOORD0;//UV
};
struct appdata_tan {
float4 vertex : POSITION;
float4 tangent : TANGENT;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
};
struct appdata_full {
float4 vertex : POSITION;//顶点坐标
float4 tangent : TANGENT;//正切
float3 normal : NORMAL;//法线
float4 texcoord : TEXCOORD0;//第一层UV
float4 texcoord1 : TEXCOORD1; //第二层UV
fixed4 color : COLOR; //颜色
};
注:顶点坐标和正切线为什么是float4,这有点意思,因为这里它表示是齐次坐标,比如我们这样表示一个float4(x,y,z,w),当w = 1的时候它表示点(x,y,z),当w= 0的时候它表示一个向量(x,y,z)。区别就在这里,当W为1时表示点,当W为0时表示向量。
texcoord0和texcoord1分别表示两层UV,有时候我们模型上的贴图需要多个图片一起贴在一处,那么贴两层就会有两层UV。
以上三种类型为Unity内置的顶点Shader传入结构体,如果想自定义也是可以的,但是自定义结构体里面的属性,必须是基于appdata_full的,这样才能识别出来,也就是自定义的结构里的属性必须到appdata_full里的属性里去选。
下面给一个简单的顶点/片元 shader 事例:
Shader "Custom/Example" {
Properties {
_MainTex ("Texture", 2D) = "white" { } //引号里面的"Texture"则是Unity检视面板中对应显示的属性名称
}
SubShader
{
pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
//_MainTex_ST的ST应该是SamplerTexture的意思 ,就是声明_MainTex是一张采样图,也就是会进行UV运算。
//如果没有这句话,是不能进行TRANSFORM_TEX的运算的。_MainTex_ST.xy为 图中的Tiling,zw为图中的offset.
float4 _MainTex_ST;
struct v2f {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
} ;
v2f vert (appdata_base v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP,v.vertex); //MVP矩阵变换,将裁剪空间坐标转换为相对屏幕位置的UV坐标
o.uv = TRANSFORM_TEX(v.texcoord,_MainTex); //TRANSFORM_TEX的作用是用顶点的UV v.texcoord和材质球的采样图片_MainTex做运算,确保顶点材质球里的缩放和偏移是正确的。等价于o.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
return o;
}
float4 frag (v2f i) : COLOR
{
float4 texCol = tex2D(_MainTex,i.uv);
float4 outp = texCol;
return outp;
}
ENDCG
}
}
}
其中SV_POSITION,SV_前缀的变量代表system value,在DX10以后的语义绑定中被使用代表特殊的意义,和POSITION用法并无不同。唯一区别是 SV_POSTION一旦被作为vertex shader的输出语义,那么这个最终的顶点位置就被固定了(不能tensellate,不能再被后续改变它的空间位置?),直接进入光栅化处理,如果作为fragment shader的输入语义那么和POSITION是一样的,代表着每个像素点在屏幕上的位置(这个说法其实并不准确,事实是fragment 在 view space空间中的位置,但直观的感受是如括号之前所述一般)
最后这个回答者说了,在DX10版本之前没有引入SV_的预定义语义,POSITION被用作vertex shader的输入,输出,fragment shader的输入参数。但DX10之后就推荐使用SV_POSITION作为vertex shader的输出和fragment shader的输入了,注意vertex shader的输入还是使用POSITION!切记。但是DX10以后的代码依旧兼容POSITION作为全程表达,估计编译器会自动判断并替换的吧。
另外,给一点编写shader的建议:
1、只计算需要计算的东西;
2、通常,需要渲染的像素比顶点数多,而顶点数又比物体数多很多。所以如果可以,尽量将运算从PS移到VS,或直接通过script来设置某些固定值;
3、在使用Surface Shader时,可以通过一些指令让shader优化很多。
通常情况下,Surface shader的很多默认选项都是开启的,以适应大多数情况,但是很多时候,你可以关闭其中的一些选项,从而让你的shader运行的更快:
(1) approxview 对于使用了view direction的shader,该选项会让view dir的normalize操作per-vertex进行,而不是per-pixel。这个优化通常效果明显。
(2) halfasview 可以让Specular shader变得快一些,使用一个介于光照方向和观察方向之间的half vector来代替真正的观察方向viewDir来计算光照函数。
(3) noforwardadd Forward Render时,完全只支持一盏方向光的per-pixel渲染,其余的光照全部按照per-vertex或SH渲染。这样可以确保shader在一个pass里渲染完成。
(4) noambient 禁掉ambient lighting和SH lighting,可以让shader快一点儿。
4、浮点数精度相关:
float:最高精度,通常32位
half:中等精度,通常16位,-60000到60000,
fixed:最低精度,通常11位,-2.0到2.0,1/256的精度。
尽量使用低精度。对于color和unit length vectors,使用fixed,其他情况,根据取值范围尽量使用half,实在不够则使用float。
在移动平台,关键是在fragment shader中尽可能多的使用低精度数据。另外,对于多数移动GPU,在低精度和高精度之间转换是非常耗的,在fixed上做swizzle操作也是很费事的。
5、Alpha Test
Alpha test和clip()函数,在不同平台有不同的性能开销。
通常使用它来cull那些完全透明的像素。
但是,在ios和一些android上使用的PowerVR GPUs上面,alpha test非常的昂贵。
6、Color Mask
在移动设备上,Color Mask也是非常昂贵的,所以尽量别使用它,除非真的是需要。
最后推荐两篇不错的博客,
https://onevcat.com/2013/07/shader-tutorial-1/
http://blog.csdn.net/ring0hx/article/details/46440037
顶点/片元 shader 总结的更多相关文章
- 关于Unity中顶点片元Shader实例
补充 float4 fixed4 _Time 1: float4是内置向量 (x, y, z, w); float4 a; 访问单独成员a.x, a.y, a.z, a.w;2: fixed4 是内置 ...
- Unity3D学习笔记(三十五):Shader着色器(2)- 顶点片元着色器
Alpha测试 AlphaTest Great:大于 AlphaTest Less:小于 AlphaTest Equal:等于 AlphaTest GEqual:大于等于 AlphaTest LEqu ...
- 图形学基础教程02--顶点数据和SHADER寄存器 (带演示程序)
本文系原创,欢迎转载,请标明链接 http://www.cnblogs.com/luming1979 有问题欢迎加qq群讨论:366239605
- 【Android 应用开发】OpenGL ES 2.0 -- 制作 3D 彩色旋转三角形 - 顶点着色器 片元着色器 使用详解
最近开始关注OpenGL ES 2.0 这是真正意义上的理解的第一个3D程序 , 从零开始学习 . 案例下载地址 : http://download.csdn.net/detail/han120201 ...
- OpenGL ES 2.0 -- 制作 3D 彩色旋转三角形 - 顶点着色器 片元着色器 使用详解
最近开始关注OpenGL ES 2.0 这是真正意义上的理解的第一个3D程序 , 从零开始学习 . 案例下载地址 : http://download.csdn.net/detail/han120201 ...
- unity shader入门(二)语义,结构体,逐顶点光照
下为一个逐顶点漫反射光照shader Shader "study/Chapter6/vertexShader"{ Properties{_Diffuse("Diffuse ...
- shader之顶点着色器
Vertex Shader 是渲染管道中一个可编程的模块,用于处理独立的顶点.Vertex Shader接收Vertex Attribute Data,由定点数组对象通过渲染指令来生成. Vertex ...
- Unity Shader (四)顶点程序示例
1.在顶点函数中实现凸起效果 Shader "Custom/Example" { properties { _R(,))= //圆的半径,也是凸起的范围 _OX(,))= //x轴 ...
- Shader 学习笔记
Shader "Custom/Diffuse Texture" { // Shader的开始,双引号内饰该Shader的名字 Properties { _MainTex (&quo ...
随机推荐
- shell,bash,zsh,console,terminal到底是什么意思,它们之间又是什么关系?
原文链接 终端(terminal,或者叫物理终端):是一种设备,不是一个程序,一般说的就是能提供命令行用户界面的设备,典型的是屏幕和键盘,或其他的一些物理终端.虚拟终端:屏幕和键盘只是一个终端,可能不 ...
- Django学习(1)一首情诗
Django是Python中Web开发的最有代表性的框架之一.本文将简单介绍如何入门Django开发. 首先确保你的linux系统已安装django模块.打开Python3,利用以下命令可找到djan ...
- linux使用mysql给一个用户赋予一个权限
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '123456' WITH GRANT OPTION;
- 音频传输之Jitter Buffer设计与实现
在语音通信中Jitter Buffer(下面简称JB)是接收侧一个非常重要的模块,它是决定音质的重要因素之一.一方面它会把收到的乱序的语音包排好序放在buffer里正确的位置上,另一方面它把接收到的语 ...
- object 覆盖 div 在IE 和Firefox 的解决方案
问题描述 公司产品需要在三维(3D)控件上显示弹框,按钮等,然而三维控件的object覆盖了div,弹框和按钮不能显示 firefox 解决方案 最外层div的背景使用不透明背景色,必须是不透明的哦 ...
- MySQL-Select语句高级应用
1.1 SELECT高级应用 1.1.1 前期准备工作 本次测试使用的是world数据库,由mysql官方提供下载地址: https://dev.mysql.com/doc/index-other.h ...
- SQL多表关联查询
在创建关系型数据表时,根据数据库范式的要求,为了降低数据的冗余,提供数据维护的灵活性 将数据分成多个表进行存储,实际工作当中,需要多个表的信息,需要将多个表合并显示 --内连接 selec ...
- 运行期以索引获取tuple元素-C++14(原创)
在编译期很容易根据索引来获取对应位置的元素,因为 tuple 的帮助函数 std::get<N>(tp) 就能获取 tuple 中第 N 个元素.然而我们却不能直接在运行期通过变量来获取 ...
- Cairo-Dock 系统关机无效
正文 背景 Cairo-Dock 设置为开机自己主动启动后.系统菜单条里的关机选项就无效了,命令行里能够使用命令关机. 搜索过程 这次google找到的结果让我非常失望,于是仅仅好百度了. 在百度贴吧 ...
- 用KMP算法实现strStr()
strStr()函数的用途是在一个字符串S中寻找某个字串P第一次出现的位置.并返回其下标,找不到时返回-1.最简单的办法就是找出S全部的子串和P进行比較,然而这种方法比較低效.假设我们从S的下标0和P ...