1.一个简单的顶点/片元着色器基本结构

Shader "Unity Shaders Book/Chapter 5/Simple Shader" {
}
SubShader {
Pass {
CGPROGRAM
//告诉unity哪个函数包含了顶点着色器的代码
#pragma vertex vert
//告诉unity哪个函数包含了片元着色器的代码
#pragma fragment frag
//POSITION:告诉unity把模型的顶点坐标填充到v中;SV_POSITION:告诉unity顶点着色器输出的裁剪空间中的顶点坐标
float4 vert(float4 v:POSITION) : SV_POSITION{
return mul(UNITY_MATRIX_MVP,V);
}
//SV_Target:把用户的输出颜色存储到一个渲染目标中
fixed4 frag() : SV_Target {
return fixed4(1.0,1.0,1.0,1.0);
}
ENDCG
}
}
}

2.为顶点着色器定义一个新的传入参数,使用结构体

Shader "Unity Shaders Book/Chapter 5/Simple Shader" {
}
SubShader {
Pass {
CGPROGRAM
//告诉unity哪个函数包含了顶点着色器的代码
#pragma vertex vert
//告诉unity哪个函数包含了片元着色器的代码
#pragma fragment frag
        //a:应用;v:顶点着色器;a2v:把数据从应用阶段传递到顶点着色器
struct a2v {
// POSITION:告诉unity使用模型空间的顶点坐标填充vertex变量
float4 vertex : POSITION;
// NORMAL:告诉unity使用模型空间的法线方向填充normal
float3 normal : NORMAL;
// TEXCOORD:告诉unity使用模型的第一套纹理坐标填充texcoord变量
float texcoord : TEXCOORD;
} //POSITION:告诉unity把模型的顶点坐标填充到v中;SV_POSITION:告诉unity顶点着色器输出的裁剪空间中的顶点坐标
float4 vert(a2v v) : SV_POSITION{
return mul(UNITY_MATRIX_MVP,V.tertex);
}
//SV_Target:把用户的输出颜色存储到一个渲染目标中
fixed4 frag() : SV_Target {
return fixed4(1.0,1.0,1.0,1.0);
}
ENDCG
}
}
}

POSITION,NORMAL,TEXCOORD中的数据由使用该shader的材质的MeshRender组件提供。在每帧调用Draw Call时,Mesh Render组建会把它负责渲染的模型书记发送给shader。

3。为片元着色器定义一个新的传入参数,使用结构体

Shader "Unity Shaders Book/Chapter 5/Simple Shader" {
}
SubShader {
Pass {
CGPROGRAM
//告诉unity哪个函数包含了顶点着色器的代码
#pragma vertex vert
//告诉unity哪个函数包含了片元着色器的代码
#pragma fragment frag struct a2v {
// POSITION:告诉unity使用模型空间的顶点坐标填充vertex变量
float4 vertex : POSITION;
// NORMAL:告诉unity使用模型空间的发现方向填充normal
float3 normal : NORMAL;
// TEXCOORD:告诉unity使用模型的第一套纹理坐标填充texcoord变量
float texcoord : TEXCOORD;
}
struct v2f {
// SV_POSITION:告诉unity ,pos里包含了顶点在裁剪空间中的位置信息
float4 pos : SV_POSITION;
// COLOR:存储颜色信息
fixed3 color : COLOR0;
} //POSITION:告诉unity把模型的顶点坐标填充到v中;SV_POSITION:告诉unity顶点着色器输出的裁剪空间中的顶点坐标
v2f vert(a2v v) : SV_POSITION{
//声明输出结果
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
//v.normal包含了顶点的法线方向,其分量范围在[-1.0,1.0]
//下麦呢的代码把分量范围映射到了[0.0,1.0]
//存储到o.color中传递给片元着色器
o.color = v.normal*0.5 + fixed3(0.5, 0.5, 0.5);
return o;
}
//SV_Target:把用户的输出颜色存储到一个渲染目标中
fixed4 frag(v2f i) : SV_Target {
//将插值后的i.color显示到屏幕上
return fixed4(i.color,1.0);
}
ENDCG
}
}
}

v2f用于顶点着色器和片元着色器之间传递信息。

4。添加属性,方便在面板上直接控制模型在屏幕上显示的颜色

Shader "Unity Shaders Book/Chapter 5/Simple Shader" {
Properties{
//声明一个Color类型的属性
_Color("Color",Color) = (1.0,1.0,1.0,1.0)
}
SubShader{
Pass {
CGPROGRAM #pragma vertex vert
#pragma fragment frag //在CG代码中,需要定义一个与属性名称和类型都匹配的变量
fixed4 _Color; struct a2v {
float4 vertex : POSITION;
float3 normal : NORMAL;
float texcoord : TEXCOORD;
}
struct v2f {
float4 pos : SV_POSITION;
fixed3 color : COLOR0;
} v2f vert(a2v v) : SV_POSITION{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.color = v.normal*0.5 + fixed3(0.5, 0.5, 0.5);
return o;
}
fixed4 frag(v2f i) : SV_Target {
fixed3 c = i.color;
//使用_Color属性来控制输出颜色
c *= _Color.rgb;
return fixed4(c,1.0);
}
ENDCG
}
}
}

SV代表系统数值,对于有特殊含义的变量最好以SV开头的语义进行修饰。

5.添加内置的包含文件

6.Unity支持的语义

颜色分量中任何大于1的数值将会被这是为1,而任何小于0的数值都会被设置为0。

7.shader整洁之道

(1).数值类型

(2).避免不必要的计算

避免在shader'(尤其是片元着色器)中进行大量计算,不然很可能出席拿一下错误:

(3)慎用分支和循环语句

  尽量把计算向流水线上端移动,例如:把放在片元着色器中的计算放到顶点着色器中,或直接在CPU中进行预计算,再把结果传递给shader。

  当不可避免使用分支语句进行计算时:

(4)不要除以0

8.漫反射光照模型

(1)高光反射:表示物体表面是如何反射光线的。

(2)漫反射:表示有多少光线会被折射,吸收和散射出表面。

(3)标准光照模型的4部分:自发光,高光反射,漫反射(兰伯特光照模型),环境光

注意:在计算法线和光源方向时,应选择同一坐标系

(4)在片元着色器中计算光照模型-----逐像素光照,又称为Phong着色

    在顶点着色器中计算光照模型-----逐顶点光照,Gouraud Shading

(5).逐顶点漫反射光照模型

Shader "MyShader" {
Properties {
_Diffuse ("Diffuse", Color) = (, , , )
}
SubShader {
Pass {
Tags { "LightMode"="ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
       #include "Lighting.cginc"
fixed4 _Diffuse;
struct a2v {
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f {
float4 pos : SV_POSITION;
fixed3 color : COLOR;
};
v2f vert(a2v v) {
v2f o;
o.pos = mul(UNITY_MATRIX_MVP,v.tvertex);
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
         //世界空间下的法线
         o.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject);//方法一
         o.worldNormal = UnityObjectToWorldNormal(v.normal);//方法二
         fixed3 worldNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject)); fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz); fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir)); o.color = ambient + diffuse; return o; } fixed4 frag(v2f i) : SV_Target { return fixed4(i.color, 1.0); } ENDCG } } FallBack "Diffuse" }

 (6).逐像素漫反射光照模型

Shader "MyShader" {
Properties {
_Diffuse ("Diffuse", Color) = (, , , )
}
SubShader {
Pass {
Tags { "LightMode"="ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
       #include "Lighting.cginc"
fixed4 _Diffuse;
struct a2v {
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f {
float4 pos : SV_POSITION;
fixed3 worldNormal : TEXCOORD0;
};
v2f vert(a2v v) {
v2f o;
          //将顶点坐标从模型空间转换到裁剪空间
o.pos = mul(UNITY_MATRIX_MVP,v.tvertex);//方法一
          o.pos = mul(UNITY_MATRIX_MVP,v.tvertex);//方法二
o.worldNormal = mul(v.normal, (float3x3)_World2Object);
return o;
}
fixed4 frag(v2f i) : SV_Target {
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;//世界空间下环境光颜色
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);//世界空间下的光照方向
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir));//saturate函数:把参数截取到[0,1]的范围。
fixed3 color = ambient + diffuse;
return fixed4(color, 1.0);
}
ENDCG
}
}
FallBack "Diffuse"
}

半兰伯特光照模型与兰伯特光照模型的区别在于:兰伯特光照模型使用saturate函数把saturate(dot(worldNormal, worldLightDir))截取到[0,1]的范围。半兰伯特使用dot(worldNormal, worldLightDir)*0.5+0.5截取到[-1,1]的范围。

半兰伯特光照模型(逐像素):

Shader "Unity Shaders Book/Chapter 6/Half Lambert" {
Properties {
_Diffuse ("Diffuse", Color) = (, , , )
}
SubShader {
Pass {
Tags { "LightMode"="ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _Diffuse;
struct a2v {
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f {
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD0;
};
v2f vert(a2v v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject);
return o;
}
fixed4 frag(v2f i) : SV_Target {
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
fixed halfLambert = dot(worldNormal, worldLightDir) * 0.5 + 0.5;
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * halfLambert;
fixed3 color = ambient + diffuse;
return fixed4(color, 1.0);
}
ENDCG
}
}
FallBack "Diffuse"
}

9.高光反射光照模型

逐顶点:

Shader "Unity Shaders Book/Chapter 6/Specular Vertex-Level" {
Properties {
_Diffuse ("Diffuse", Color) = (, , , )
_Specular ("Specular", Color) = (, , , )
_Gloss ("Gloss", Range(8.0, )) =
}
SubShader {
Pass {
Tags { "LightMode"="ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _Diffuse;
fixed4 _Specular;
float _Gloss;
struct a2v {
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f {
float4 pos : SV_POSITION;
fixed3 color : COLOR;
};
v2f vert(a2v v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 worldNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject));
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir));
// 世界空间下反射光方向
fixed3 reflectDir = normalize(reflect(-worldLightDir, worldNormal));
// 世界空间下视野方向
fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - mul(unity_ObjectToWorld, v.vertex).xyz);
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir, viewDir)), _Gloss);
o.color = ambient + diffuse + specular;
return o;
}
fixed4 frag(v2f i) : SV_Target {
return fixed4(i.color, 1.0);
}
ENDCG
}
}
FallBack "Specular"
}

逐像素:

Shader "Unity Shaders Book/Chapter 6/Specular Pixel-Level" {
Properties {
_Diffuse ("Diffuse", Color) = (, , , )
_Specular ("Specular", Color) = (, , , )
_Gloss ("Gloss", Range(8.0, )) =
}
SubShader {
Pass {
Tags { "LightMode"="ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _Diffuse;
fixed4 _Specular;
float _Gloss;
struct a2v {
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f {
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
};
v2f vert(a2v v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject);
         // 传统计算光照方向的方法(1)
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
return o;
}
fixed4 frag(v2f i) : SV_Target {
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 worldNormal = normalize(i.worldNormal);
          // 使用UnityCG.cginc中的函数计算光照方向的方法(2)
          fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
          fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir));
// 世界空间下反射光方向
fixed3 reflectDir = normalize(reflect(-worldLightDir, worldNormal));
// 世界空间下视野方向---传统方法(1)
fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
         //采用unity内置函数(2)
          fixed3 viewDir=normalize(UnityWorldSpaceViewDir(i.worldPos));
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir, viewDir)), _Gloss); return fixed4(ambient + diffuse + specular, 1.0);
}
ENDCG
}
}
FallBack "Specular"
}

10.Blinn-Phong光照模型

逐像素:

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)' Shader "Unity Shaders Book/Chapter 6/Blinn-Phong" {
Properties {
_Diffuse ("Diffuse", Color) = (, , , )
_Specular ("Specular", Color) = (, , , )
_Gloss ("Gloss", Range(8.0, )) =
}
SubShader {
Pass {
Tags { "LightMode"="ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _Diffuse;
fixed4 _Specular;
float _Gloss;
struct a2v {
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f {
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD0;
float3 worldPos : TEXCOORD1;
};
v2f vert(a2v v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject);
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
return o;
}
fixed4 frag(v2f i) : SV_Target {
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * max(, dot(worldNormal, worldLightDir));
// Get the view direction in world space
fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
// Get the half direction in world space
fixed3 halfDir = normalize(worldLightDir + viewDir);
// Compute specular term
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(, dot(worldNormal, halfDir)), _Gloss);
return fixed4(ambient + diffuse + specular, 1.0);
}
ENDCG
}
}
FallBack "Specular"
}

注意:

1。在实际的渲染中,绝大多数情况选择Blinn-Phong光照模型。

2。上例中计算光源方向的方法只适用于平行光。

unity shader 入门的更多相关文章

  1. Unity Shader入门

    Unity Shader入门 http://www.cnblogs.com/lixiang-share/p/5025662.html http://www.manew.com/blog-30559-1 ...

  2. Unity Shader入门精要读书笔记(一)序章

    本系列的博文是笔者读<Unity Shader入门精要>的读书笔记,这本书的章节框架是: 第一章:着手准备. 第二章:GPU流水线. 第三章:Shader基本语法. 第四章:Shader数 ...

  3. 【我的书】《Unity Shader入门精要》出版上市

    重要的事 先说重要的事,就是我的书籍<Unity Shader入门精要>在经过无数次跳票后,终于出版上市了(泪目-)! 购买传送门: 亚马逊 当当 京东 截止到我写这篇文章的时候,京东是没 ...

  4. Unity Shader入门精要之 screen post-processing effect

    本篇记录了学习Unity Shader入门精要的屏幕后处理的一些知识点. OnRenderImage(RenderTexture src, RenderTexture dest) 以上函数是Unity ...

  5. Unity Shader入门精要学习笔记 - 第17章 Unity的表面着色器探秘

    转自 冯乐乐的<Unity Shader 入门精要> 2010年的Unity 3 中,Surface Shader 出现了. 表面着色器的一个例子. 我们先做如下准备工作. 1)新建一个场 ...

  6. Unity Shader入门精要学习笔记 - 第16章 Unity中的渲染优化技术

    转自冯乐乐的 <Unity Shader 入门精要> 移动平台的特点 为了尽可能一处那些隐藏的表面,减少overdraw(即一个像素被绘制多次),PowerVR芯片(通常用于ios设备和某 ...

  7. Unity Shader入门精要学习笔记 - 第15章 使用噪声

    转载自 冯乐乐的 <Unity Shader 入门精要> 消融效果 消融效果常见于游戏中的角色死亡.地图烧毁等效果.这这些效果中,消融往往从不同的区域开始,并向看似随机的方向扩张,最后整个 ...

  8. Unity Shader入门精要学习笔记 - 第14章非真实感渲染

    转载自 冯乐乐的 <Unity Shader 入门精要> 尽管游戏渲染一般都是以照相写实主义作为主要目标,但也有许多游戏使用了非真实感渲染(NPR)的方法来渲染游戏画面.非真实感渲染的一个 ...

  9. Unity Shader入门精要学习笔记 - 第11章 让画面动起来

    转自 冯乐乐的 <Unity Shader入门精要> Unity Shader 中的内置变量 动画效果往往都是把时间添加到一些变量的计算中,以便在时间变化时画面也可以随之变化.Unity ...

  10. Unity Shader入门精要学习笔记 - 第10章 高级纹理

    转载自 冯乐乐的 <Unity Shader入门精要> 立方体纹理 在图形学中,立方体纹理是环境映射的一种实现方法.环境映射可以模拟物体周围的环境,而使用了环境映射的物体可以看起来像镀了层 ...

随机推荐

  1. nginx CRLF(换行回车)注入漏洞复现

    nginx CRLF(换行回车)注入漏洞复现 一.漏洞描述 CRLF是”回车+换行”(\r\n)的简称,其十六进制编码分别为0x0d和0x0a.在HTTP协议中,HTTP header与HTTP Bo ...

  2. 基于Ajax的前后端分离

    这种开发模式可以称为SPA (Single Page Application 单页面应用)时代. 这种模式下,前后端的分工非常清晰,前后端的关键协作点是 Ajax 接口.看起来是如此美妙,但回过头来看 ...

  3. 菜单(menu)

    菜单 menu ——菜单默认隐藏 ——实现菜单的接口: Menu,父接口,用于创建主菜单 SubMenu继承Menu接口,用于创建子菜单 ContextMenu接口继承Menu接口,用于创建上下文菜单 ...

  4. MicroPython TPYBoard v201 简易家庭气象站的实现过程

    转载请注明文章来源,更多教程可自助参考docs.tpyboard.com,QQ技术交流群:157816561,公众号:MicroPython玩家汇 前言 上一篇教程中我们实现了一个简单网页的显示.本篇 ...

  5. K8S 部署 Web UI

    在早期的版本中 Kubernetes可以在 Dashboard 中看到 heapster 提供的一些图表信息, 在后续的版本中会陆续移除掉 heapster,现在更加流行的监控工具是 promethe ...

  6. nginx 之负载均衡 :PHP session 跨多台服务器配置

    公司一个项目单点压力越来越大,考虑到稳定性和降压,使用nginx做负载均衡,将请求分发到多个docker上去,这里记录下PHP多服务器间的会话session共享问题,解决方案是把session单独存在 ...

  7. 小伙子,你真的清楚 JVM GC ?

    序 正文 如何确定垃圾? 前面已经提到 JVM 可以采用 引用计数法 与 可达性分析算法 来确定需要回收的垃圾,我们来具体看一下这两种算法: 引用计数法 该方法实现为:给每个对象添加一个引用计数器,每 ...

  8. 03、Swagger2和Springmvc整合详细记录(爬坑记录)

    时间 内容 备注 2018年6月18日 基本使用 spirngmvc整合swagger2 开始之前这个系列博文基本是,在项目的使用中一些模块的内容记录,但是后期逐渐优化,不单单是整合内容. swagg ...

  9. L1005矩阵取数游戏

    #include <bits/stdc++.h> using namespace std; typedef long long ll; #define rep(i, a, b) for ( ...

  10. Usaco Training [2.1] The Castle 搜索

    传送门 题目的输出的4个信息 前两个很容易,dfs,bfs都可以,图怎么建都可以 后两个在搜索的时候记录belong[i][j]和已有的size即可 代码应该比不少题解清晰吧 #include < ...