Unity Shader 漫反射的实现

模型的漫反射可以在两个函数中实现,一个是顶点函数,另外一个就是片元函数。而这两个函数的区别又决定了漫反射实现出来的效果,那就是精细度。

因为顶点函数是逐顶点调用,漫反射在顶点函数实现时,对于在一个三角面(三个顶点包含的面)中的像素值是通过插值得到的。所以模型显示的每个像素不是最细化的。

而片元函数是逐像素调用的,若漫反射在片元函数中调用,则会仔细涉及到每个像素,漫反射出来的效果也会更好一些。

下面我就直接放两种Shader代码的实现了。在这里我在片元函数的漫反射直接使用了半兰伯特光照模型。

顶点函数的漫反射(兰伯特光照模型)

 1 // 顶点函数漫反射的编写
 2 // 兰伯特光照模型
 3 // Diffuse = 直射光颜色 * max(cos(反射光,法线),0)
 4 Shader "TMoon/02-Diffuse Vertex" {
 5     Properties{
 6         _Diffuse("Diffuse Color",Color) = (1,1,1,1)
 7     }
 8
 9     SubShader{
10
11         Pass{
12
13             Tags {"LightMode" = "ForwardBase"}
14
15             CGPROGRAM
16
17             // 类似C#的 using 引用类库或者文件
18             // 这里引用了Unity内置的光照的类库
19             // 配合"LightMode" = "ForwarBase"得到Unity场景中的光照信息
20             #include "Lighting.cginc"
21
22             #pragma vertex vert
23             #pragma fragment frag
24
25             //获得面板参数
26             fixed4 _Diffuse;
27
28             // 这里使用第二种方法传值 结构体
29             // application to vertex
30             // 由应用程序传递给顶点函数的参数
31             struct a2v {
32                 float4 vertex : POSITION; //应用程序将模型的顶点坐标填充到vertex
33                 float3 normal : NORMAL; //应用程序将模型的顶点法线填充到normal
34             };
35
36             // vertex to fragment
37             // 由顶点函数传递给片元函数的参数
38             struct v2f {
39                 float4 position : SV_POSITION; //模型裁剪空间下的顶点坐标
40                 float3 color : COLOR0;    //COLOR0,COLOR1...这些类型一般是中介,用于存储和传递数据,有时并没有什么实际意义,就是中介而已。
41             };
42
43             v2f vert(a2v v) {
44                 v2f f;
45                 // 将模型顶点坐标变换到裁剪空间的坐标并赋值给v2f.position
46                 f.position = mul(UNITY_MATRIX_MVP, v.vertex);
47
48                 // UNITY_LIGHTMODEL_AMBIENT用来获取环境光
49                 // 获取Unity环境光的颜色值
50                 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rag;
51
52                 // 将模型顶点的法线转换到空间坐标下,方便一致计算
53                 // UnityObjectToWorldNormal 把法线方向 模型空间 ——> 世界空间
54                 fixed3 normalDir = normalize(UnityObjectToWorldNormal(v.normal));
55
56                 // _WorldSpaceLightPos0 空间坐标下光的方向
57                 // 对于每个顶点来说 光的位置就是光的方向 ,因为光是平行光
58                 // 在这里我直接理解为了反射光
59                 fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
60
61                 // 兰伯特光照模型
62                 // _LightColor0.rab 直射光颜色
63                 fixed3 diffuse = _LightColor0.rab * max(dot(normalDir, lightDir),0) * _Diffuse.rgb;
64
65                 // 将漫反射加上环境光的影响
66                 f.color = diffuse + ambient;
67
68                 return f;
69             }
70
71             float4 frag(v2f f) : SV_Target{
72                 return fixed4(f.color,1);
73             }
74
75             ENDCG
76         }
77     }
78
79     Fallback "VertexLit"
80 }

Diffuse Vertex

片元函数的漫反射(半兰伯特光照模型)

 1 // 片元函数漫反射的编写  细节更多 边缘过渡更顺    可以对比顶点函数漫反射
 2 // 半兰伯特光照模型  阴影部分不会全黑,如果全黑对玩家不太友好  可以对比兰伯特光照模型  在02-Diffuse Vertex把环境光去掉即可明显对比
 3 // Diffuse = 直射光颜色 * (cos(反射光,法线)*0.5+0.5)
 4 Shader "TMoon/03-Diffuse Fragment" {
 5     Properties{
 6         _Diffuse("Diffuse Color",Color) = (1,1,1,1)
 7     }
 8
 9     SubShader{
10
11         Pass{
12
13             Tags {"LightMode" = "ForwardBase"}
14
15             CGPROGRAM
16
17             // 类似C#的 using 引用类库或者文件
18             // 这里引用了Unity内置的光照的类库
19             // 配合"LightMode" = "ForwarBase"得到Unity场景中的光照信息
20             #include "Lighting.cginc"
21
22             #pragma vertex vert
23             #pragma fragment frag
24
25             //获得面板参数
26             fixed4 _Diffuse;
27
28             // application to vertex
29             // 由应用程序传递给顶点函数的参数
30             struct a2v {
31                 float4 vertex : POSITION; //应用程序将模型的顶点坐标填充到vertex
32                 float3 normal : NORMAL; //应用程序将模型的顶点法线填充到normal
33             };
34
35             // vertex to fragment
36             // 由顶点函数传递给片元函数的参数
37             struct v2f {
38                 float4 position : SV_POSITION; //模型裁剪空间下的顶点坐标
39                 float3 worldNormalDir : COLOR0;    //COLOR0,COLOR1...这些类型一般是中介,用于存储和传递数据,有时并没有什么实际意义,就是中介而已。
40             };
41
42             v2f vert(a2v v) {
43                 v2f f;
44
45                 // 将模型顶点坐标变换到裁剪空间的坐标并赋值给v2f.position
46                 f.position = mul(UNITY_MATRIX_MVP, v.vertex);
47
48                 // 将模型顶点的法线转换到空间坐标下,方便一致计算
49                 // UnityObjectToWorldNormal 把法线方向 模型空间 ——> 世界空间
50                 f.worldNormalDir = normalize(UnityObjectToWorldNormal(v.normal));
51
52                 return f;
53             }
54
55             float4 frag(v2f f) : SV_Target{
56
57                 // 反射光
58                 fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
59
60                 // 半兰伯特光照模型
61                 fixed3 diffuse = _LightColor0.rab * (dot(f.worldNormalDir, lightDir)*0.5+0.5) * _Diffuse.rgb;
62
63                 return fixed4(diffuse,1);
64             }
65
66             ENDCG
67         }
68     }
69
70     Fallback "VertexLit"
71 }

Diffuse Fragment

这里通过截图显示一下兰伯特光照模型和半兰伯特光照模型的区别。

通过背面就很明显看得出了。这篇文章就到这里了。

时间: 2024-12-24 00:45:50

Unity Shader 漫反射的实现的相关文章

Unity Shader编程(1)漫反射着色

Unity Shader编程(1)漫反射着色 在Unity中创建如下工程: 我们把Shader拖到Material上.Meterial拖到Cube上.这就完成了一个着色器的着色过程. Shader "Custom/Shader" { Properties { _MainTex ("Base (RGB)", 2D) = "white" {} } SubShader { Tags { "RenderType"="Opaq

【Unity Shader编程】之十四 边缘发光Shader(Rim Shader)的两种实现形态

本系列文章由@浅墨_毛星云 出品,转载请注明出处.   文章链接:http://blog.csdn.net/poem_qianmo/article/details/51764028 作者:毛星云(浅墨)    微博:http://weibo.com/u/1723155442 本文工程使用的Unity3D版本: 5.2.1  这篇文章主要讲解了如何在Unity3D中分别使用Surface Shader和Vertex & Fragment Shader来编写边缘发光Shader. 一.最终实现的效果

Unity3D for VR 学习(9): Unity Shader 光照模型 (illumination model)

关于光照模型 所谓模型,一般是由学术算法发起, 经过大量实际数据验证而成的可靠公式 现在还记得2009年做TD-SCDMA移动通信算法的时候,曾经看过自由空间传播模型(Free space propagation Model),目的为了得出移动信号的传播损耗.当时是基于普通的PC实时运算,非常非常耗时–如北京五环内的传播模型渲染GIS图用了超过20分钟. 光照模型来源有2类: 一类是基于学术论文的算法,如Lambert模型.Phong模型. 另一类基于算法的变种–在实际生产实践中修正得到的模型,

Unity shader教程-第一课:写shader和应用shader的流程

这是我们Unity shader(着色器)教程的第一课,在这节课中,你会学到怎么样来用程序来编写一个在Unity中能使用的着色器:漫反射着色器.这节课的内容主要让我们熟悉创建shader和应用shader的流程. 准备工作: 安装Unity版本4.6以上 创建一个新的工程 菜单GameObject | 3D Object | Plane创建出一个平面,作为我们的地面 菜单GameObject | 3D Object | Sphere创建出球来,反复多次创建多个 注意: 1. 创建地面后选中该物体

《Unity Shader 与 计算机图形学》第二章

提示:本篇将会非常长~ 本系列文章分为 硬件 编程入门 工程实践 上一篇 主要介绍了GPU的特征工作原理 以及渲染的底层流程 其实对于新架构而言还有所不同 Shader描述了如何渲染物体的信息,包括: Texture Setup.纹理设置 Material Property.材质设置 Render State.渲染状态 Blend Setup.混合设置 Pixel Shader.像素着色 Vertex Shader.定点着色 Render Target Setup 渲染目标设置 Shader并不

【我的书】Unity Shader的书 — 目录(2015.09.04更新)

写在前面 感谢所有点进来看的朋友.没错,我目前打算写一本关于Unity Shader的书. 出书的目的有下面几个: 总结我接触Unity Shader以来的历程,给其他人一个借鉴.我非常明白学Shader的艰难,在群里也见了很多人提出的问题.我觉得学习Shader还是一件有规律可循的事情,但问题是中文资料难觅,而大家又不愿意去看英文...这对我有什么好处呢?强迫我对知识进行梳理,对细节问题把握更清楚. 第二个原因你懂的. 关于本书的定位问题: 面向Unity Shader初学者,但要: 有一定的

【我的书】Unity Shader的书 — 目录(2016.1.29更新)

写在前面 感谢所有点进来看的朋友.没错,我目前打算写一本关于Unity Shader的书. 出书的目的有下面几个: 总结我接触Unity Shader以来的历程,给其他人一个借鉴.我非常明白学Shader的艰难,在群里也见了很多人提出的问题.我觉得学习Shader还是一件有规律可循的事情,但问题是中文资料难觅,而大家又不愿意去看英文...这对我有什么好处呢?强迫我对知识进行梳理,对细节问题把握更清楚. 第二个原因你懂的. 关于本书的定位问题: 面向Unity Shader初学者,但要: 有一定的

【我的书】Unity Shader的书 — 文件夹(2015.12.21更新)

写在前面 感谢全部点进来看的朋友.没错.我眼下打算写一本关于Unity Shader的书. 出书的目的有以下几个: 总结我接触Unity Shader以来的历程,给其它人一个借鉴.我非常明确学Shader的艰难,在群里也见了非常多人提出的问题. 我认为学习Shader还是一件有规律可循的事情,但问题是中文资料难觅,而大家又不愿意去看英文...这对我有什么优点呢?强迫我对知识进行梳理,对细节问题把握更清楚. 第二个原因你懂的. 关于本书的定位问题: 面向Unity Shader刚開始学习的人,但要

Unity Shader 知识点总结(二)

紧接着上一篇文章的shader入门知识的总结,本文主要总结shader中的纹理贴图.透明度混合.顶点动画.后期特效处理等操作.如果有什么地方有错,请指出更正,谢谢.本文的代码主要来自开源书:unity入门精要 一.Unity shader中的纹理 1.简单纹理 在unity shader中,纹理的主要作用是用来给模型贴上一个外表,这样得到的模型颜色就具有纹理的颜色混合.在常见的一些shader上,都会有一个_MainTex的选项,这就是我们常常用的主纹理贴图.对于纹理贴图,其对应的需要有纹理坐标