一、GPU:图形处理器,Graphics Processing Unit
显卡的处理器就是图形处理器。与CPU类似。
 
GPU和CPU的区别?
1.CPU主要是为了串行指令设计,GPU则是为了大规模的秉性的计算而设计。
2.从并行的角度来看,CPU并行针对于指令集并行,而GPU的并行是针对大规模运算的。
3.同样面积的芯片:CPU上更多的放置缓存和控制部件,而GPU上放置的是更多的运算单元。
 
二、渲染管线
渲染管线也叫渲染流水线,就是告诉GPU一堆数据,然后得到一个二维的图像。
渲染管线主要分三个阶段:应用程序阶段、几何阶段、光栅化阶段
 
1.应用程序阶段(CPU)
主要是CPU将模型身上的顶点信息(顶点坐标、纹理坐标、法线等),组成一个图元,告诉GPU。
 
2.几何阶段(GPU)(顶点函数在这个阶段)
几何阶段的主要工作是“变换三维顶点坐标”。主要是将图元信息的顶点坐标变化到屏幕坐标中,传给光栅化阶段。
几何阶段涉及的几个空间:
Object Space(模型坐标空间),以模型原点为参考
World Space(世界坐标空间),三维
Eye Space(观察坐标空间)
Clip anf Project Space(剪裁和屏幕坐标空间),二维
1)从Object Space到World Space
模型在导入到场景中,只有一些模型身上的顶点信息。需要把顶点坐标转换到世界坐标空间下,我们才知道模型在世界中的哪一个位置。
2)从World Space到Eye Space
我们模型显示到屏幕是需要摄像机的,所有的观察坐标空间,就是以摄像机为原点,
摄像机的右方为观察坐标系的+X轴的方向,
摄像机的上方为观察坐标系的+Y轴的方向,
摄像机的正前方为观察坐标系的-Z轴的方向。
Unity的观察坐标系是右手坐标系。
3)从Eye Space到Clip anf Project Space
就是一个裁剪(视锥体以外的部分)和投影的过程
 
3.光栅化阶段(GPU)(片元函数在这个阶段)
使用上一个阶段生成的数据渲染出最终的图像。
 
三、Shader着色器:GPU上运行实现图像渲染的程序

 
图像编程接口
OpenGL,苹果
DirectX,微软

 
着色器的语言:
按照3D渲染的图像编程接口来区分
GLSL:OpenGL Shading Language(支持OpenGL API)
HLSL:High Level Shader Language(支持DX API)
Cg语言:C for Graphics(支持两种编程接口)

 
着色器的分类:
固定管线着色器:效果差,难度小,适用各种硬件,老旧显卡,手机显卡
顶点/片段着色器(可编程顶点/片段处理器):Cg语言,效果好,新型显卡,可编程,更灵活
表面着色器(固定功能着色器):Unity自己的,对Cg语言的封装,较顶点/片段着色器复杂,包括光影的运算
 
着色器的结构:
1.需要一个定义
Shader"着色器的名字"{ },这个名字是可以带有层级化结构的,并且名字可以与Shader的名字不一致。
 
2.向引擎公布一些自己的公共的属性(可以存在,也可以不存在)
Properties{ //属性的集合},Properties向下融合
 
3.至少包括一个计算过程
SubShader{ //计算过程}
计算过程可以是多个,也可以是一个,SubShader多个的情况下,机器会从上至下往下找,只有一个会执行,这个可以执行的SubShader是机器可以容忍的着色器代码,从上至下找到一个自己可以容忍可以执行的SubShader,那么就执行这个。
表面着色器的代码不需要写在Pass块里,但固定管线着色器和顶点/片段着色器的代码都需要写在pass块里
一个SubShader可以有多个Pass块,Pass块效果会叠加。
 
4.最后是在所有的SubShader都失效的情况下执行的一个方案
FallBack"最好写默认的着色器代码",编写时最好把FallBack注释掉,避免系统默认调用,无法显示粉色错误
FallBack "Diffuse"//Unity自带的LegacyShaders的Diffuse
5.对于多个Pass块的情况,机器会依次向下执行每一个Pass,一般情况下最后一个Pass的效果会覆盖前面的Pass,但是也有特殊的情况。
 
ShaderLab结构

 
注意:
shader依赖材质球,材质球依赖物体身上的Mesh Render
材质球的粉色:是报错的颜色
 
着色器的属性:
定义:<属性的变量名>("Inspactor显示的名字", 数据类型) = <必须初始化>
类型:
Color:颜色
_Color ("颜色", Color) = (,,,)

Float:数字

_Float ("数字", float) = 0.1//不用加f

Vector:四维向量

_Vector ("向量", Vector) = (,,,)

Range:区间

_Range ("区间", Range(, )) = //注意区间里要设置最大值和最小值

2D:2D纹理

_2D ("2D纹理", 2D) = "white"{}//纹理使用字符串加花括号形式赋初值

Rect:矩形纹理(少用)

_Rect ("矩形纹理", Rect) = "white"{}
Cube:立方体纹理(一般用于天空盒)
_Cube ("立方体纹理", Cube) = "white"{}
对于纹理来说,没办法对其进行指定的纹理作为默认值,可以使用{}表示空纹理,{}前的字符串表示的是当使用空纹理时,使用的颜色,"white"、"red"、"gray"。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SetMat : MonoBehaviour {
public Texture tex;
//如果要修改Shader属性面板的值
//首先需要获取使用这个Shader材质
private Material mat;
private MeshRenderer mr;
// Use this for initialization
void Start () {
mr = GetComponent<MeshRenderer>();
//获取MeshRenderer里的材质
mat = mr.material;
//修改颜色,第一个参数是属性面板的变量名,第二个参数是想要设置的值
mat.SetColor("_Color", Color.blue);
//修改数字、区间
mat.SetFloat("_Float", );
mat.SetFloat("_Range", );
//修改向量
mat.SetVector("_Vector", Vector4.one);
//修改纹理
mat.SetTexture("_2D", tex);
//修改纹理的Tiling和Offset
mat.SetTextureScale("_2D", Vector2.zero);//Tiling
mat.SetTextureOffset("_2D", Vector2.one);//Offset
}
}
 
SubShader
Unity提供的一些渲染的控制命令
注意:
1.所有的命令后都不可以带分号结尾
2.所有的命令必须给值,值分为常量值和变量值。如果想要使用属性面板的变量,命令[变量名]。使用常量值,命令 (1,1,1,1)或数字
 
灯光命令
Lighting off/on
on表示支持灯光,off表示不理会灯光
 
固定颜色
Color(r,g,b,a)或Color[变量名]
r,g,b,a的取值范围0-1
注意:如果开启的灯光控制,该命令无效,如果想要命令有效,那么必须关闭灯光控制。
Shader "Lesson/FixedColor" {
Properties{
_Color("Color", Color) = (,,,)
}
SubShader{
//固定管线着色器要写在Pass里
Pass
{
//关闭灯光
Lighting off
//固定颜色
//Color (1,0,0,1)//使用常量值的颜色
Color[_Color]//使用变量值的颜色
}
//FallBack "Diffuse"
}
 
灯光处理块
Material{//处理各种灯光}
 
Diffuse:Color控制基本的漫反射的颜色:Diffuse(r,g,b,a)或Diffuse[颜色变量名]
Specular:Color控制镜面反射的颜色:Specular(r,g,b,a)或Specular[颜色变量名]
Shininess:Number控制高光的锐利度,一般取值范围在0-1之间,0高光最大,1高光最小。Shininess 数字或Shininess[区间或float变量名]
Emisson:Color控制物体自发光颜色。Emisson(r,g,b,a)或Emisson[颜色变量名]
Ambient:Color控制环境光颜色。Ambient(r,g,b,a)或Ambient[颜色变量名]
 
SeparateSpecular on/off 开启独立的镜面反射,只有开启了这个命令,Specular高光命令才有效。
 
最终颜色 = Ambient 控制的颜色 * 引擎设置的环境光颜色 + 光照颜色 *  Diffuse + 光照颜色 * Specular + Emisson
Shader "Lesson/FixedDiffuse" {
Properties {
_Diffuse("漫反射颜色", Color) = (,,,)
_Specular("高光颜色", Color) = (,,,)
_Shininess("高光系数", Range(, )) = 0.2
_Emission("自发光颜色", Color) = (,,,)
_Ambient("环境光颜色", Color) = (,,,)
}
SubShader {
Pass
{
//先把灯光打开
Lighting on
//开启独立的镜面反射
SeparateSpecular on //在这个里去写一些灯光处理控制的命令
Material
{
//灯光产生的漫反射的影响
//漫反射光照命令
Diffuse [_Diffuse]
//高光颜色的命令
Specular [_Specular]
//高光系数 数字0~1
Shininess [_Shininess]
//自发光 相加
Emission [_Emission]
//环境光 相乘,乘以Environment Light的数值,一般情况下设置为(1,1,1,1)
Ambient [_Ambient]
}
}
}
//FallBack "Diffuse"
}

环境光设置

 
纹理显示:
SetTexture[纹理的属性变量名]{//纹理计算命令}
Combine:告诉引擎开始进行颜色混合
texture:纹理贴图的原始颜色
constantColor:定义一个常量的颜色
constant:使用这个常量的颜色
primary:使用灯光的颜色
double:使灯光的颜色变成二倍
quad:使灯光的颜色变成四倍
previous:代表颜色缓冲区(帧缓存)当前的颜色
 
Combine texture:显示图片的原始色
Combine texture * constant:使用一个常量颜色与纹理的原始颜色混合
Combine texture * primary:使用灯光颜色与纹理的原始颜色混合
Shader "Lesson/FixedDiffuse" {
Properties {
_Tex("纹理", 2D) = "white"{}
}
SubShader {
Pass {
SetTexture[_Tex]//可以有多个,效果叠加
{
//计算命令的选项
Combine texture//显示纹理的原始颜色
//如果想与原始颜色进行混合
//定义一个常量色
constantColor[_Color]
//常量色与纹理的原始颜色
Combine texture * constant
//灯光颜色与纹理的原始颜色混合
//double代表双倍的意思
Combine texture * primary double
Combine texture * previous + constant
}
}
}
//FallBack "Diffuse"
}

Shader "Custom/FixedSetTexture" {
Properties {
_MainTex("主纹理贴图", 2D) = ""{}
_SecTex("主纹理贴图", 2D) = ""{}
_Color("颜色", Color) = (,,,)
}
SubShader {
Pass
{
SetTexture[_MainTex]
SetTexture[_SecTex]
{
//语法:Combine src1 lerp (scr2)scr3
//使用scr2的alpha值进行颜色插值,当scr2的alpha值为1的时候,显示scr1的颜色,当scr2的alpha值为0的时候,显示scr3的颜色
//如果scr2的某个像素的alpha值为0.5的时候,那么就是scr1的颜色和scr3的颜色进行1:1的混合
Combine texture lerp (texture)previous
}
SetTexture[_SecTex]
SetTexture[_MainTex]
{
ConstantColor[_Color]
//语法:Combine src1 * scr2 + scr3 用scr1的颜色 * scr2的 alpha 值 + scr3
Combine texture * previous + constant
}
}
}
FallBack "Diffuse"
}
 
网格面的裁剪
Cull off/back/front
Cull off:关闭网格面的裁剪:双面显示
Cull back:裁剪掉背面网格,默认开启的是裁剪掉背面网格
Cull front:裁剪掉正面网格,可以用作天空盒
 
渲染队列命令,这个命令与Pass是同级的
控制谁先渲染谁后渲染!渲染队列值,值越大越后渲染,最终显示在屏幕上的颜色是由渲染队列深度深度比较等同时决定的。
 
"Queue"="BackGround",代表的渲染队列值1000,一般用于背景层,第一批渲染
"Queue"="Geometry",代表的渲染队列值2000,一般用于不透明的游戏物体
"Queue"="AlphaTest",代表的渲染队列值2450
"Queue"="Transparent",代表的渲染队列值3000
"Queue"="Overlay",代表的渲染队列值4000,一般用于镜头的处理
 
如果想设置3200的渲染队列
"Queue"="Transparent+200",注意加号左右不允许有空格
Shader "Lesson/FixedCull" {
Properties {
_MainTex("Albedo (RGB)", 2D) = "white" {}
}
SubShader {
//设置渲染队列的值
Tags{ "Queue" = "BackGround" }
Tags{ "Queue" = "Geometry" }
Tags{ "Queue" = "AlphaTest" }
Tags{ "Queue" = "Transparent" }
Tags{ "Queue" = "Overlay" } Pass
{
//网格面的裁剪
Cull off SetTexture[_MainTex]
{
Combine texture
}
}
}
//FallBack "Diffuse"
}
什么是深度?
游戏物体距离摄像机的距离我们叫做深度。
深度测试:当前物体的对应像素颜色的深度与深度缓冲区里的深度做比价的过程就是深度测试
深度缓冲:开启了深度缓冲,证明当比较成功之后,要把新的深度写入到深度缓冲区里去
 
ZTest深度测试
ZTest Less:小于,默认就是小于比较
Greater:大于
Equal:等于
LEqual:小于等于
GEqual:大于等于
NotEqual:不等于
off:关闭,深度测试关闭时,当跟深度缓冲区里做比较时,直接通过。
 
深度写入
ZWrite off/on:关闭或者开启深度写入
如果深度写入关闭,即使比较成功了,深度不会写入深度缓冲区,但是颜色会写入到深度缓冲区。
 
1.深度测试通过,深度写入开启,深度写入深度缓冲区,颜色写入颜色缓冲区
2.深度测试通过,深度写入关闭,深度不写入深度缓冲区,颜色写入颜色缓冲区
3.深度测试失败,深度写入开启,深度不写入深度缓冲区,颜色不写入颜色缓冲区
4.深度测试失败,深度写入关闭,深度不写入深度缓冲区,颜色不写入颜色缓冲区
5.深度测试关闭,深度写入开启,深度写入深度缓冲区,颜色写入颜色缓冲区
Shader "Lesson/ZTestR" {
Properties {
}
SubShader {
//红色 3000
Tags{ "Queue" = "Transparent" } Pass
{
//深度测试变为小于比较
ZTest Less //深度写入关闭
ZWrite off Color(,,,)
}
}
//FallBack "Diffuse"
}

补充内容
快速添加材质球的方法:在Shader脚本上右键新建Material,会自动根据Shader脚本的路径命名

Unity3D学习笔记(三十四):Shader着色器(1)的更多相关文章

  1. Unity3D学习笔记(十四):Animation旧动画

        animator(新动画系统):骨骼动画,骨骼驱动,格式化编辑,动画机图形化 animation(旧动画系统):物理系统,帧动画 一.如何建立动画文件 Animation Clip 手动添加动 ...

  2. tensorflow学习笔记(三十四):Saver(保存与加载模型)

    Savertensorflow 中的 Saver 对象是用于 参数保存和恢复的.如何使用呢? 这里介绍了一些基本的用法. 官网中给出了这么一个例子: v1 = tf.Variable(..., nam ...

  3. PHP学习笔记三十四【记录日志】

    <?php function my_error2($errno,$errmes) { echo "错误号:".$errno; //默认时区是格林威治相差八个时区 //设置 1 ...

  4. angular学习笔记(三十)-指令(10)-require和controller

    本篇介绍指令的最后两个属性,require和controller 当一个指令需要和父元素指令进行通信的时候,它们就会用到这两个属性,什么意思还是要看栗子: html: <outer‐direct ...

  5. angular学习笔记(三十)-指令(2)-restrice,replace,template

    本篇主要讲解指令中的 restrict属性, replace属性, template属性 这三个属性 一. restrict: 字符串.定义指令在视图中的使用方式,一共有四种使用方式: 1. 元素: ...

  6. VSTO学习笔记(十四)Excel数据透视表与PowerPivot

    原文:VSTO学习笔记(十四)Excel数据透视表与PowerPivot 近期公司内部在做一种通用查询报表,方便人力资源分析.统计数据.由于之前公司系统中有一个类似的查询使用Excel数据透视表完成的 ...

  7. Python学习笔记(十四)

    Python学习笔记(十四): Json and Pickle模块 shelve模块 1. Json and Pickle模块 之前我们学习过用eval内置方法可以将一个字符串转成python对象,不 ...

  8. angular学习笔记(三十)-指令(7)-compile和link(2)

    继续上一篇:angular学习笔记(三十)-指令(7)-compile和link(1) 上一篇讲了compile函数的基本概念,接下来详细讲解compile和link的执行顺序. 看一段三个指令嵌套的 ...

  9. angular学习笔记(三十)-指令(7)-compile和link(1)

    这篇主要讲解指令中的compile,以及它和link的微妙的关系. link函数在之前已经讲过了,而compile函数,它和link函数是不能共存的,如果定义了compile属性又定义link属性,那 ...

  10. angular学习笔记(三十)-指令(6)-transclude()方法(又称linker()方法)-模拟ng-repeat指令

    在angular学习笔记(三十)-指令(4)-transclude文章的末尾提到了,如果在指令中需要反复使用被嵌套的那一坨,需要使用transclude()方法. 在angular学习笔记(三十)-指 ...

随机推荐

  1. Block 实践

    OC版 函数中无参无返回值 /* 作为函数参数类型的格式 返回值类型 (^)(形参列表) */ CZPerson.h - (void) test:(void (^)(void))block; CZPe ...

  2. UITableView 的坑

    1.cell的view和contentView的区别 1.1 addSubView UITableViewCell实例上添加子视图,有两种方式:[cell addSubview:view]或[cell ...

  3. python os.path.dirname()

    ----返回文件所在的路径 ----如果path变量直接是文件名则返回空

  4. sqoop从hive导入数据到mysql时出现主键冲突

    今天在将一个hive数仓表导出到mysql数据库时出现进度条一直维持在95%一段时间后提示失败的情况,搞了好久才解决.使用的环境是HUE中的Oozie的workflow任何调用sqoop命令,该死的o ...

  5. sqoop使用经验总结及问题汇总

    问题导读1.导入数据到HDFS,需要注意什么?2.在测试sqoop语句的时候,如何限制记录数量?3.sqoop导入时什么情况下会多导入一条数据? 一.sqoop 导入数据到HDFS注意事项 分割符的方 ...

  6. 算法提高 c++_ch02_01 (强制类型转换)

    编写一个程序,利用强制类型转换打印元音字母大小写10种形式的ASCII码. 输出的顺序为:大写的字母A,E,I,O,U的ASCII码,小写的字母a,e,i,o,u的ASCII码.所有的ASCII码都用 ...

  7. C#——WebApi 接口参数传参详解

    本篇打算通过get.post.put.delete四种请求方式分别谈谈基础类型(包括int/string/datetime等).实体.数组等类型的参数如何传递. 一.get请求 对于取数据,我们使用最 ...

  8. (2018干货系列十)最新android开发学习路线整合

    怎么学Android Android是一个以Linux为基础的半开源操作系统,主要用于移动设备,由Google和开放手持设备联盟开发与领导.据2011年初数据显示仅正式上市两年的操作系统Android ...

  9. python-数据分析与展示(Numpy、matplotlib、pandas)---3

    笔记内容整理自mooc上北京理工大学嵩天老师python系列课程数据分析与展示,本人小白一枚,如有不对,多加指正 0.pandas基于Numpy实现的,前者注重应用,后者注重结构 1.Series类型 ...

  10. 删去k个数字后的最小值

    public static String removeKDigits(String num,int k) { //新整数的最终长度=原长度 - k int newLength=num.length() ...