Shader学习笔记
Shader学习笔记
例子:
Shader "SrfShader1"{
//定义显示在Inspector中的变量,并从Inspector中获取值
Properties{
_Color("Color",Color)=(1,1,1,1) //用来融合漫反射或2d纹理的颜色
_MainTex("MainTex (RGB)",2D)="white"{} //主2d纹理图片色
_Gloss("Gloss",Range(1,100)) = 10
}
//可以多个SubShader块(渲染方案),从第一个开始匹配,直到可用,否则匹配FallBack方案
SubShader{
Pass{
Tags{"LightMode"="ForwardBase"}//标签
CGPROGRAM
//引入unity内置的文件,取得第一个直射光源(这样可以访问它的属性:颜色_LightColor0,法线_World2Object,位置_WorldSpaceLightPos0)
#include "Lighting.cginc"
//声明两个函数,顶点函数和片元函数(系统自动调用这两个函数)
#pragma vertex vert
#pragma fragment frag
//定义变量,从Properties中获得的材质球的颜色
fixed4 _Color;
sampler2D _MainTex; //2d纹理
float4 _MainTex_ST; //该2d纹理的缩放和偏移
half _Gloss;
//定义结构体(定义了一个顶点的3个属性:顶点坐标、法线方向、纹理贴图中的坐标)
struct a2v{
float4 vertex:POSITION; //告诉Unity把模型空间下的顶点坐标填充给该变量vertex
float3 normal:NORMAL; //告诉Unity把模型空间下的法线方向填充给normal
float4 texcoord:TEXCOORD0; //告诉Unity把第一套纹理坐标UV填充给texcoord
};
struct v2f{
float4 position:SV_POSITION; //填充为剪裁空间的坐标
float3 worldNormal:COLOR0;
float3 worldVertex:COLOR1;
float2 uv:TEXCOORD1;
};
//定义顶点函数(对模型的每个顶点调用,把结构a2v中的值赋值给f,把返回值应用到每个顶点,根据顶点之间的插值来填充非顶点位置)
//把逻辑写在这里,表示使用逐顶点计算的光照色
v2f vert(a2v v){
v2f f;
//把把模型空间下的顶点坐标转换为剪裁空间的顶点坐标
f.position = mul(UNITY_MATRIX_MVP,v.vertex);
f.worldNormal = mul(v.normal,(float3x3)_World2Object);
//f.worldNormal = UnityObjectToWorldNormal(v.normal);//也可以使用UnityCG.cginc中一些常用的函数
f.worldVertex = mul(v.vertex,_World2Object).xyz;
f.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw; //取到贴图的UV坐标的缩放倍数+偏移
return f;
}
//定义片元函数(对剪裁空间下的模型上的每个像素点调用,把返回值颜色应用到每个对应的像素点)
//把逻辑写在这里,表示使用逐像素计算的光照色
fixed4 frag(v2f f):SV_Target{
//把把模型空间下的法线方向转换为模型空间的法线方向,并取得该法线的单位向量
fixed3 normalDir = normalize(f.worldNormal);
//取得光的位置(这里是平行光)的单位向量
fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
//取得纹理贴图当前像素点的颜色,并和指定颜色融合
fixed3 texture2dColor = tex2D(_MainTex,f.uv.xy)*_Color.rgb;
//1.取得漫反射的颜色(使用半兰伯特光照模型),融合贴图颜色
fixed3 diffuse = _LightColor0.rgb * (dot(normalDir,lightDir)*0.5+0.5) * texture2dColor;
//取得反射光的方向,利用reflect()方法,根据入射光和法线来取
//fixed3 reflectDir = normalize(reflect(-lightDir,normalDir));
//取得视野方向,_WorldSpaceCameraPos表示视野位置
fixed3 viewDir = normalize( _WorldSpaceCameraPos.xyz - f.worldVertex );
//取得平行光和视野方向的平分线方向单位向量(两个向量相加除2就等于平分线向量)
fixed3 halfDir = normalize(lightDir+viewDir);
//2-1.取得反射光颜色(Blinn光照模型)
//fixed3 specular = _LightColor0.rgb * pow(max(dot(reflectDir,viewDir),0),_Gloss);
//2-2.取得反射光颜色(Blinn-Phong光照模型)
fixed3 specular = _LightColor0.rgb * pow(max(dot(normalDir,halfDir),0),_Gloss);
//3.各种影响的颜色叠加:漫反射 + 高光反射 + Unity内置环境光颜色与贴图色融合(融合后效果更好,不会只是变亮或变暗)
fixed3 tempColor = diffuse + specular + UNITY_LIGHTMODEL_AMBIENT.rgb*texture2dColor;
return fixed4(tempColor,1);
}
ENDCG
}
}
FallBack "Diffuse"
}
Mesh Filter : 存储一个Mesh(网格,模型的网格,就是模型的由哪些三角面组成,组成一个什么样子的模型,三角面的一些顶点信息)
Mesh Renderer:用来渲染一个模型的外观,就是样子, 按照 mesh给它皮肤,给它颜色
通过Material(材质)控制模型渲染的样子
Material贴图(可以没有,可以是一个单纯的颜色)
书籍
unity shader 入门精要(乐乐程序猿)
unity 3d shaderlab开发实战详解(第二版)
unity 5.x shaders and effects cookbook(中文版 unity着色器和屏幕特效开发秘籍)
CG语言教程官网
http://http.developer.nvidia.com/CgTutorial/cg_tutorial_frontmatter.html
一些网站
www.shadertoy.com
http://blog.csdn.net/poem_qianmo?viewmode=contents
数学函数在线演示
http://zh.numberempire.com/graphingcalculator.php
UnityCG.cginc中一些常用的函数,这个文件默认会自动引入
//摄像机方向(视角方向)
float3 WorldSpaceViewDir(float4 v) 根据模型空间中的顶点坐标 得到 (世界空间)从这个点到摄像机的观察方向
float3 UnityWorldSpaceViewDir(float4 v) 世界空间中的顶点坐标==》世界空间从这个点到摄像机的观察方向
float3 ObjSpaceViewDir(float4 v) 模型空间中的顶点坐标==》模型空间从这个点到摄像机的观察方向
//光源方向
float3 WorldSpaceLightDir(float4 v) 模型空间中的顶点坐标==》世界空间中从这个点到光源的方向
float3 UnityWorldSpaceLightDir(float4 v) 世界空间中的顶点坐标==》世界空间中从这个点到光源的方向
float3 ObjSpaceLightDir(float4 v) 模型空间中的顶点坐标==》模型空间中从这个点到光源的方向
//方向转换
float3 UnityObjectToWorldNormal(float3 norm) 把法线方向 模型空间==》世界空间
float3 UnityObjectToWorldDir(float3 dir) 把方向 模型空间=》世界空间
float3 UnityWorldToObjectDir(float3 dir) 把方向 世界空间=》模型空间
什么是OpenGL、DirectX
shader可以认为是一种渲染命令 ,由opengl 或者dx进行解析,来控制渲染丰富多彩的图形
OpenGL 使用GLSL 编写shader
DirectX 使用HSSL 编写shader
英伟达 CG 编写shader(跨平台)
Unity Shader的分类
使用的是ShaderLab编写Unity中的Shader
1,表面着色器 Surface Shader
2,顶点/片元着色器 Vertex/Fragment Shader
3,固定函数着色器 Fixed Function Shader
Unityshader中属性的类型有哪些
_Color("Color",Color)=(1,1,1,1)
_Vector("Vector",Vector)=(1,2,3,4)
_Int("Int",Int)= 34234
_Float("Float",Float) = 4.5
_Range("Range",Range(1,11))=6
_2D("Texture",2D) = "red"{}
_Cube("Cube",Cube) = "white"{}
_3D("Texure",3D) = "black"{}
传递步骤:1-3
1.从应用程序传递到顶点函数的语义有哪些a2v
POSITION 顶点坐标(模型空间下的)
NORMAL 法线( 模型空间下)
TANGENT 切线(模型空间)
TEXCOORD0~n 纹理坐标(0-1的值)
COLOR 顶点颜色
2.从顶点函数传递给片元函数的时候可以使用的语义
SV_POSITION 剪裁空间中的顶点坐标(一般是系统直接使用)
COLOR0 可以传递一组值 4个
COLOR1 可以传递一组值 4个
TEXCOORD0~7 传递纹理坐标
3.片元函数传递给系统
SV_Target 颜色值,显示到屏幕上的颜色
声明两个函数,顶点函数和片元函数(系统自动调用这两个函数)
#pragma vertex vert
#pragma fragment frag
逐顶点计算光照,效果较差,顶点之间的过度迹象明显,但渲染速度较快
v2f vert(a2v v){.....}
逐像素计算光照,效果较好,平滑过渡,但渲染速度较慢
fixed4 frag(v2f f):SV_Target{...}
什么是光照模型
光照模型就是一个公式,使用这个公式来计算在某个点的光照效果(模拟现实中的效果)
标准光照模型
在标准光照模型里面,我们把进入摄像机的光分为下面四个部分
1.自发光
2.高光反射(根据法线直接反射,类似镜子)
3.漫反射 Diffuse = 直射光颜色 * max(0,cos夹角(光和法线的夹角) ) cosθ = 光方向· 法线方向
4.环境光
Tags{ "LightMode"="ForwardBase" }
只有定义了正确的LightMode才能得到一些Unity的内置光照变量
#include "Lighting.cginc"
引入unity的内置的文件,取得第一个直射光源(这样可以访问它的属性)
normalize() 用来把一个向量,单位化(原来方向保持不变,长度变为1),单位向量
max() 用来取得函数中最大的一个
dot 用来取得两个向量的点积
_WorldSpaceLightPos0 取得平行光的位置
_LightColor0取得平行光的颜色
UNITY_MATRIX_MVP 这个矩阵用来把一个坐标从模型空间转换到剪裁空间
_World2Object 这个矩阵用来把一个方向从世界空间转换到模型空间
UNITY_LIGHTMODEL_AMBIENT 用来获取环境光,可在Window>>Linghting菜单里面的Ambient Source设置
融合:两个颜色相乘,融合后混合了两种颜色,但亮度可能变暗
叠加:两个颜色相加,相加后亮度一般会增强
漫反射:
兰伯特光照模型:背光部分是纯黑的
Diffuse = 直射光颜色 * max(0, cosθ) ,其中cosθ = dot(光方向,法线方向),即:点积
半兰伯特光照模型:背光部分不会全黑
Diffuse = 直射光颜色 (cosθ0.5 +0.5)
高光反射:
Blinn光照模型
Specular= 直射光 * pow(max(cosθ,0),10) θ:是反射光方向和视野方向的夹角
Blinn-Phong光照模型
Specular=直射光 * pow(max(cosθ,0),10) θ:是法线和x的夹角 x 是平行光和视野方向的平分线
shader中的各种空间坐标
http://blog.csdn.net/lyh916/article/details/50906272
什么是切线空间(法线贴图使用切线空间,就可以通用于不同模型)
http://blog.csdn.net/bonchoix/article/details/8619624
法线贴图:显示为蓝色的图片,使用切线空间
法线坐标处理为像素值:
pixel = (normal+1)/2
像素值处理为法线坐标:
normal = pixel*2 - 1
法线贴图的使用(凹凸调节+透明度)
Shader "Rock Alpha"{
Properties{
//_Diffuse("Diffuse Color",Color) = (1,1,1,1)
_Color("Color",Color) = (1,1,1,1)
_MainTex("Main Tex",2D) = "white"{}
_NormalMap("Normal Map",2D) = "bump"{} //法线贴图
_BumpScale("Bump Scale",Float)=1 //用来调节凹凸
_AlphaScale("Alpha Scale",Float)=1 //调节透明度
}
SubShader{
//用于透明度渲染
Tags{ "Queue"="Transparent" "IngnoreProjector"="True" "RenderType"="Transparent" }
Pass{
Tags{ "LightMode" = "ForwardBase" }
//以下两个用于透明度渲染
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#include "Lighting.cginc"
#pragma vertex vert
#pragma fragment frag
//fixed4 _Diffuse;
fixed4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _NormalMap;
float4 _NormalMap_ST;
float _BumpScale;
float _AlphaScale;
struct a2v {
float4 vertex:POSITION;
float3 normal:NORMAL;
float4 tangent:TANGENT;//tangent.w是用来确定切线空间中坐标轴的方向的
float4 texcoord:TEXCOORD0;
};
struct v2f {
float4 svPos:SV_POSITION;
//float3 worldNormal:TEXCOORD0;
//float4 worldVertex:TEXCOORD1;
float3 lightDir : TEXCOORD0;
float4 uv:TEXCOORD1; //贴图坐标存在xy,法线贴图存在zw
};
v2f vert(a2v v) {
v2f f;
f.svPos = mul(UNITY_MATRIX_MVP, v.vertex);
//f.worldNormal = UnityObjectToWorldNormal(v.normal);
//f.worldVertex = mul(v.vertex, _World2Object);
f.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
f.uv.zw = v.texcoord.xy * _NormalMap_ST.xy + _NormalMap_ST.zw;
TANGENT_SPACE_ROTATION;//调用这个宏之后,会得到一个矩阵 rotation 这个矩阵用来把模型空间下的方向转换成切线空间下
//ObjSpaceLightDir(v.vertex)//得到模型空间下的平行光方向
f.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex)); //得到切线空间下的平行光方向
return f;
}
fixed4 frag(v2f f) :SV_Target{
//fixed3 normalDir = normalize(f.worldNormal);
fixed4 normalColor = tex2D(_NormalMap,f.uv.zw);
fixed3 tangentNormal = UnpackNormal(normalColor);//UnpackNormal()转换为切线空间下的法线
tangentNormal.xy = tangentNormal.xy*_BumpScale;//调节凹凸
tangentNormal = normalize(tangentNormal);
fixed3 lightDir = normalize(f.lightDir);
fixed4 texColor = tex2D(_MainTex, f.uv.xy)*_Color;
fixed3 diffuse = _LightColor0.rgb * texColor.rgb * max(dot(tangentNormal, lightDir), 0);
fixed3 tempColor = diffuse + UNITY_LIGHTMODEL_AMBIENT.rgb*texColor;
return fixed4(tempColor,_AlphaScale*texColor.a );//透明度混合了_AlphaScale和texColor.a
}
ENDCG
}
}
Fallback "Specular"
}
Shader学习笔记的更多相关文章
- Unity Shader学习笔记-1
本篇文章是对Unity Shader入门精要的学习笔记,插图大部分来自冯乐乐女神的github 如果有什么说的不正确的请批评指正 目录 渲染流水线 流程图 Shader作用 屏幕映射 三角形遍历 两大 ...
- u3d shader学习笔记1
促使我学习SHADER的重要原因是希望深入理解3D渲染的机制,在此基础上可以灵活达到某种效果与性能的平衡,开发出具有良好体验的VR应用. 因为VR应用体验的好坏,直接由游戏的帧率决定,而游戏的帧率则受 ...
- 【Unity Shader学习笔记】Unity基础纹理-单张纹理
1 单张纹理 1.1 纹理 使用纹理映射(Texture Mapping)技术,我们把一张图片逐纹素(Texel)地控制模型的颜色. 美术人员建模时,会在建模软件中利用纹理展开技术把纹理映射坐标(Te ...
- Shader 学习笔记
Shader "Custom/Diffuse Texture" { // Shader的开始,双引号内饰该Shader的名字 Properties { _MainTex (&quo ...
- Unity3D Shader 学习笔记(一):初识Shader
第一节:图形处理器简史 GPU发展简史 GPU英文全称Graphic Procssing Unit. T&L变换和光照流水线 可编程GPU GPU的优点和缺点 第二节:Unity Shader ...
- Unity3D Shader 学习笔记(二):ShaderLab的结构和基本属性
(一) ShaderLab: 什么是ShaderLab: Unity3D支持的Shader种类包括: 1.Surface Shader:表面着色器 2.Vertex & Fragment Sh ...
- Unity Shader学习笔记 - 用UV动画实现沙滩上的泡沫
这个泡沫效果来自远古时代的Unity官方海岛Demo, 原效果直接复制3个材质球在js脚本中做UV动画偏移,这里尝试在shader中做动画并且一个pass中完成: // Upgrade NOTE: r ...
- Unity Shader 学习笔记(一)
_MainTex_ST (1)简单来说,TRANSFORM_TEX(tex,name) (tex.xy * name##_ST.xy + name##_ST.zw)主要作用是拿顶点的uv去和材质球的t ...
- unity shader学习笔记(1) shader基础结构以及Properties面板
首先是shader的基础结构: Shader "Custom/Example { Properties//变量属性面板 { } SubShader { Tags { "Render ...
随机推荐
- windows下go调用内存dll
有时候我们希望将dll嵌入到程序内部,以提高程序的安全性,这里我写的一个开源memorydll模块. 首先 go get github.com/nkbai/go-memorydll 然后在需要的时候 ...
- Jquery Plugins Jquery Validate
Jquery Validate 一.什么是Jquery Validate: jQuery Validate 插件为表单提供了强大的验证功能. 二.常用值: 1 required:true 必须输入 ...
- WebStrom背景色设置
Ctrl Alt S快速打开setting:
- C++ TIM或者QQ 自动发送消息
简单写了一下 很简单的demo 闲着没事干 #include "stdafx.h" #include <thread> #include <Windows.h&g ...
- 浅谈Spring的两种配置容器
浅谈Spring的两种配置容器 原文:https://www.jb51.net/article/126295.htm 更新时间:2017年10月20日 08:44:41 作者:黄小鱼ZZZ ...
- iOS 查看代码总行数
1.打开终端 2.cd 拖入工程 回车 3.输入命令 find . "(" -name "*.m" -or -name "*.mm" -or ...
- NSProcessInfo系统进程信息
前言 NSProcessInfo 类中包含一些方法,允许你设置或检索正在运行的应用程序(即进程)的各种类型的信息. 1.获取系统进程信息 // 创建系统进程信息对象 NSProcessInfo *pr ...
- [SinGuLaRiTy] 树链问题
[SinGuLaRiTy-1035] Copyright (c) SinGuLaRiTy 2017. All Rights Reserved. 关于树链 树链是什么?这个乍一看似乎很陌生的词汇表达的其 ...
- 开启和查看mysql的bin-log日志
[root@VM_0_7_centos data]# vim /etc/my.cnf [root@VM_0_7_centos data]# vim /etc/my.cnf [root@VM_0_7_c ...
- 0.jQuery选择器
左边的是jQuery用法 右边是js用法 $("tag") == document.getElementsByTagName("tag"); $(". ...