【Aladdin Unity3D Shader编程】之一 基本入门
OpenGL、DirectX以及GLSL、HLSL、CG
- OpenGL和DirectX是图像应用编程接口,用于渲染二维或者三维图形。
- GLSL着色语言是用来在OpenGL中着色编程的语言,有点在于跨平台性,可以再Windows、Linux、Mac甚至移动平台上工作。
- HLSL是微软控制着色的编译,几乎只支持微软自己的产品,如Windows,XBox等,其他平台没有可编译HLSL的编译器。
- CG是有英伟达公司出的真正意义上的跨平台着色器语言。
GPU渲染管线概述
1.顶点着色器
顶点着色器是流水线的第一个阶段,它的输入来自于CPU。顶点着色器的处理单位是顶点,也就是说输入进来的每个顶点都会调用一次顶点着色器。
顶点着色器需要完成的工作主要有:坐标变换和逐顶点光照。当然,除了这两个主要任务外,顶点着色器还可以输出后续阶段所需的数据。
坐标变换,顾名思义,就是对顶点的坐标进行某种变换。例如我们可以通过改变顶点位置来模拟水面,布料等。
一个最基本的顶点着色器必须完成的一个工作是:把顶点坐标从模型空间转换到齐次剪裁空间。类似下面代码:
2.裁剪
由于我们的场景可能会很大,而摄像机的视野范围很有可能不会覆盖所有的场景物体,一个很自然的想法就是,那些不在摄像机视野范围内的物体不需要被处理,而裁剪就是为了完成这个目的而被提出来的。
一个图元和摄像机的关系有3种:
- 完全在视野里
- 部分在视野里
- 完全在是野外
部分在视野内的图元需要裁剪,例如一条线段的一个顶点在视野内,而另一个顶点在视野外,那么视野外部的顶点应该使用一个新的顶点来代替,这个新的顶点位于这条线段和视野边界的交点处。
3.屏幕映射
这一步输入的坐标仍然是三维坐标系。屏幕映射的任务是把每个图元的x和y坐标转换到屏幕坐标系下,屏幕坐标系是一个二维坐标系,它和我们用于显示画面的分辨率有很大关系。
屏幕映射得到的屏幕坐标决定了这个顶点对应屏幕上哪个像素以及距离这个像素有多远。
opengl的屏幕坐标原点是左下角,而directx是左上角,如果你发现你得到的图像是倒转的,那么很有可能就是这个原因造成的。
4.三角形设置
由这一步就进入了光栅化阶段,从上一个阶段输出的信息是屏幕坐标下的顶点位置以及和它们相关的额外信息,如深度值、法线方向、视角方向等,光栅化有两个最重要的目标:计算每个图元覆盖了哪些像素,以及为这些像素计算他们的颜色。光栅化的第一个流水线阶段是三角形设置,这个阶段会计算光栅化一个三角网格所需的信息。
具体来说,上一个阶段输出的都是三角网格的顶点,即我们得到的是三角网格每条边的两个端点。但如果要得到整个三角网格对像素的覆盖情况,我们就必须计算每条边上的像素坐标。为了能够计算边界像素的坐标信息,我们就需要得到三角形边界的表示方式。这样一个计算三角形网格表示数据的过程就叫做三角形设置,它的输出是为了下一个阶段做准备。
5.三角形遍历
三角形遍历阶段将会检查每个像素是否被一个三角形网格所覆盖。如果被覆盖的话,就会生成一个片元,而这样一个找到哪些像素被三角网格覆盖的过程就是三角形遍历,这个阶段也被称为扫描变换。
三角形遍历阶段会根据上一个阶段的计算结果来判断一个三角网格覆盖了哪些像素,并使用三角网格3个顶点的顶点信息对整个覆盖区域的像素进行插值。
6.片元着色器
片元着色器是另一个非常重要的可编程着色器阶段,片元着色器的输入是上一个阶段对顶点信息插值得到的结果,更具体来说,是根据那些从顶点着色器输出的数据插值得到的。而它的输出是一个或多个颜色值。
这一阶段可以完成很多重要的的渲染技术,其中最重要的技术之一就是纹理采样。为了在片元着色器中进行纹理采样,我们通常会在顶点着色器阶段输出每个顶点对应的纹理坐标,然和经过光栅化阶段对三角网格的3个顶点对应的纹理坐标进行插值后,就可以得到其覆盖的片元的纹理坐标了。
7.逐片元操作
逐片元操作是opengl中的说法,在directx中,这一阶段被称为输出合并阶段。
这一阶段有几个主要任务:
- 决定片元的可见性。涉及很多测试工作,如深度测试,模版测试等。
- 如果一个片元通过了所有的测试,就需要把这个片元的颜色值和已经存储在颜色缓冲区中的颜色进行合并
Unity Shader的分类
- 表面着色器 Surface Shader
- 顶点/片元着色器 Vertex/Fragment Shader
- 固定函数着色器 Fixed Function Shader (已弃用) 在一些低端设备使用
表面着色器是对顶点/片元着色器做的一层封装。
Unity Shader的基本结构
Shader "Aladdin/01 First Shader" //指定Shader路径和名字
{
Properties //属性
{
_Color("Color",Color)=(1,1,1,1)
}
SubShader //SubShader可以写很多个 显卡运行效果的时候 从第一个开始,如果第一个SubShader里面的效果都可以实现就使用第一个SubShader,如果显卡这个SubShader有的实现不了会往下找支持的SubShader
{
//至少含有一个Pass
Pass {
//在这里编写Shader代码 HLSLPROGRAM
CGPROGRAM
//使用CG语言编写Shader代码
ENDCG
}
}
FallBack "VertexLit" //如果上面SubShader都不支持 则执行默认的Shader效果
}
Unity Shader属性和使用
属性
常用属性
_Color("Color",Color)=(1,1,1,1)
_Vector("Vector",Vector)=(1,2,3,4)
_Int("Int",Int)=2
_Float("Float",Float)=12.3 //不用加f
_Range("Range",Range(1.0,10.0))=1.0 //范围类型
_2D("Texture",2D)="white"{} //white是默认值,如果不选图的话 就是默认白色的图
_Cute("Cute",Cube)="red"{} //如果用天空盒就用Cube 立方体纹理
_3D("Texture",3D)="black"{} //3D纹理
使用
float4 _Color;//float4就是四个值 _Color要跟上面属性名字保持一致
float4 _Vector;
float _Int;
float _Range;
sampler2D _2D;
samplerCube _Cube;
sampler3D _3D;
float、half和fixed类型区别
float也可以用half和fixed代替
float 32位来存储
half 16位来存储 -6万~+6万
fixed 11位来存储 一般都是用fixed
顶点、片元函数编写
vert函数
//顶点函数定义 这里只是声明了顶点函数的函数名
//基本作用是完成顶点坐标从模型空间到剪裁空间的转换(从游戏环境到视野相机屏幕上)
#pragma vertex vert
//通过语义告诉系统我这个参数是干嘛的比如POSITION是模型坐标语义,告诉系统我需要顶点参数坐标 SV_POSITION是剪裁坐标语义
float4 vert(float4 v:POSITION) :SV_POSITION
{
return mul(UNITY_MATRIX_MVP, v); //计算模型坐标转换成剪裁坐标
}
fragment函数
//片源函数定义 这里只是声明了片元函数的函数名
//基本作用是返回模型对应屏幕上的每一个像素颜色
#pragma fragment frag
//片元函数定义
float4 frag():SV_Target //SV_target是返回颜色语义
{
return fixed4(1,1,1,1);
}
片元可以理解成一个像素,每一个像素都会经过片元函数的处理
NORMAL、TEXCOORD0语义
//a2v application to vertex
struct a2v
{
//顶点坐标
float4 vertex:POSITION; //添加上POSITION语义,这样操作系统才知道给这个变量赋值模型坐标变量
//法线
float3 normal:NORMAL; //告诉unity把模型空间下的法线方向向量填充给normal变量
//纹理坐标(模型坐标对应贴图的坐标)
//纹理坐标一般都是0-1 不按照实际的像素来的
float4 texcoord:TEXCOORD0; //告诉unity把模型空间下的纹理坐标填充给texcoord变量
};
//通过语义告诉系统我这个参数是干嘛的比如POSITION是模型坐标语义,告诉系统我需要顶点参数坐标 SV_POSITION是剪裁坐标语义
float4 vert(a2v v) :SV_POSITION
{
return mul(UNITY_MATRIX_MVP, v.vertex); //计算模型坐标转换成剪裁坐标
}
片元函数和顶点函数之间传数据
使用结构体作为参数和返回值,这样可以添加任意多个返回值或者传入值,会更方便一些。
为什么要传参?
因为有些参数只能比如顶点、法线等只能在顶点函数中访问到,片元函数是访问不到的,如果片元函数要访问顶点法线等参数只能从顶点函数中返回并且作为参数传入给片元函数才行。
Shader "AladdinShader/03 Struct Shader"
{
Properties
{
}
SubShader {
Pass
{
CGPROGRAM
// Upgrade NOTE: excluded shader from DX11; has structs without semantics (struct v2f members tempNormal)
#pragma exclude_renderers d3d11
#pragma vertex vert
#pragma fragment frag
//a2v application to vertex
struct a2v
{
//顶点坐标
float4 vertex:POSITION; //添加上POSITION语义,这样操作系统才知道给这个变量赋值模型坐标变量
//法线
float3 normal:NORMAL; //告诉unity把模型空间下的法线方向向量填充给normal变量
//纹理坐标(模型坐标对应贴图的坐标)
//纹理坐标一般都是0-1 不按照实际的像素来的
float4 texcoord:TEXCOORD0; //告诉unity把模型空间下的纹理坐标填充给texcoord变量
};
//v2f vertex to fragment
struct v2f
{
float4 position:SV_POSITION;
float3 tempNormal:COLOR0;
};
//通过语义告诉系统我这个参数是干嘛的比如POSITION是模型坐标语义,告诉系统我需要顶点参数坐标 SV_POSITION是剪裁坐标语义
v2f vert(a2v v)
{
v2f f;
f.position = mul(UNITY_MATRIX_MVP, v.vertex);//计算模型坐标转换成剪裁坐标
f.tempNormal = v.normal;//将法线数据放到返回结构体里面供片元函数调用
return f;
}
//SV_target是返回颜色语义
fixed4 frag(v2f f):SV_Target
{
return fixed4(f.tempNormal,1);
}
ENDCG
}
}
FallBack "VertexLit"
}
效果的计算放在片元函数里面效果更好但计算量也大,片元函数的调用比顶点函数调用也多的多。
顶点之间的点的数值是经过插值运算得到的。
效果图:
解释:三个方向上的法线向量依次是(1,0,0)(0,1,0)(0,0,1),对应的颜色就是红绿蓝,也就是如图所示的效果图。
Unity中常用语义
从应用程序传递到顶点函数的语义有哪些a2v
POSITION顶点坐标(模型空间下的)
NORMAL法线(模型空间下)
TARGET切线(模型空间)
TEXCOORD0~n纹理坐标
COLOR顶点颜色
从顶点函数传递给片元函数的时候可以使用的语义
SV_POSITION剪裁空间中的顶点坐标(一般是系统直接使用)
COLOR0可以传递一组值 四个值
COLOR1可以传递一组值 四个值
TEXCOORD0~7传递纹理坐标
片元函数传递给系统
SV_TARGET颜色值,显示到屏幕上的颜色
Shader学习交流群:
316977780
【Aladdin Unity3D Shader编程】之一 基本入门的更多相关文章
- 【Aladdin Unity3D Shader编程】之三 光照模型(二)
高光反射模型 Specular=直射光*pow(cosθ,高光的参数) θ:是反射光和视野方向的夹角 编写高光反射Shader Shader "AladdinShader/07 Specul ...
- 【Aladdin Unity3D Shader编程】之四 贴图纹理
关于纹理贴图介绍 纹理坐标也叫UV坐标,UV坐标都是0~1,并不是我们所理解的像素坐标,相当于是一个百分比. 编写shader映射纹理 将纹理的颜色取代漫反射的颜色 Shader "Alad ...
- 【Aladdin Unity3D Shader编程】之二 光照模型(一)
光照模型 光照模型就是一个公式,使用这个公式来计算在某个点的光照效果. 在标准光照模型里面,我们把进入摄像机的光分为下面四个部分: 自发光 类似生活中的萤火虫等自己能够发光 高光反射 类似生活中的镜子 ...
- 【浅墨Unity3D Shader编程】之一 夏威夷篇:游戏场景的创建 & 第一个Shader的书写
本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/40723789 作者:毛星云(浅墨) ...
- 【浅墨Unity3D Shader编程】之二 雪山飞狐篇:Unity的基本Shader框架写法&颜色、光照与材质
本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/40955607 作者:毛星云(浅墨) ...
- 【浅墨Unity3D Shader编程】之中的一个 夏威夷篇:游戏场景的创建 & 第一个Shader的书写
本系列文章由@浅墨_毛星云 出品.转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/40723789 作者:毛星云(浅墨) ...
- 【浅墨Unity3D Shader编程】之三 光之城堡篇:子着色器、通道与标签的写法 & 纹理混合
本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://hpw123.net/a/C__/kongzhitaichengxu/2014/1117/120.html 作者:毛星云 ...
- [Unity3D]Shader编程之动态屏幕遮罩
转载 https://blog.csdn.net/u012741077/article/details/78425834 屏幕可视范围跟随目标物体移动,可修改可视范围大小,边缘渐变大小.以及遮罩颜色, ...
- shader 编程入门(一)
本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/40723789 作者:毛星云(浅墨) ...
随机推荐
- JVM(五)内存(Heap)分配
前面的两小节,我分享了一下JVM的垃圾回收算法和垃圾回收器,本节中,我们来看看JVM的内存分配到底是如何进行的,作为对前面两节内存回收的补充. 从前面的内存回收中我们了解到,Hotspot JVM中的 ...
- MySql join on 和 where
原文:http://www.cnblogs.com/Jessy/p/3525419.html left join :左连接,返回左表中所有的记录以及右表中连接字段相等的记录. right join : ...
- 使用jquery的方法和技巧
1.下载一个jquery.js的文件 2.引入jquery.js文件 <script type="text/javascript" src="__PUBLIC__/ ...
- 51 nod 1624 取余最长路 思路:前缀和 + STL(set)二分查找
题目: 写这题花了我一上午时间. 下面是本人(zhangjiuding)的思考过程: 首先想到的是三行,每一行一定要走到. 大概是这样一张图 每一行长度最少为1.即第一行(i -1) >= 1, ...
- hdu 5952 连通子图
Counting Cliques Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) ...
- HDU1698 线段树(区间更新区间查询)
In the game of DotA, Pudge's meat hook is actually the most horrible thing for most of the heroes. T ...
- 斐波那契数列第N项f(N)[矩阵快速幂]
矩阵快速幂 定义矩阵A(m*n),B(p*q),A*B有意义当且仅当n=p.即A的列数等于B的行数. 且C=A*B,C(m*q). 例如: 进入正题,由于现在全国卷高考不考矩阵,也没多大了解.因为遇到 ...
- util包里的一些类的使用
好几天没有更新我的博客了 .国庆放假出去玩了一趟,这回来应该收心回到我的事业上了,哈哈哈!废话不多说,开始学习吧!首先今天来学习一些例子,这些例子可以回顾假期遗忘的知识,还能提高自己的能力.程序也会相 ...
- 纯CSS3实现轮播图
前言 纯css3实现的轮播图效果,和JavaScript控制的相比,简单高效了很多,但是功能也更加单一,只有轮播不能手动切换. 用什么实现的呢?页面布局 + animation动画 HTML部分 &l ...
- C#线程池多线程Socket通讯 服务器端和客户端示例
using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; ...