学习目标:

  • 漫反射Diffuse Shader,逐顶点计算和逐像素计算。
  • 半兰伯特(HalfLambert)光照模型。
  • 结合材质自身的色彩(Material Color)及环境光(Ambient)。

漫反射计算公式:

漫反射Diffuse颜色 = 直射光颜色 * max(0, cos(光源方向和法线方向夹角)) * 材质自身色彩

其中max(0, cos(光源方向和法线方向夹角))部分可以改用半兰伯特光照模型以增强背光面的光照效果。


逐顶点漫反射

Shader "Custom/04-Diffuse Vertex" { // 逐顶点漫反射
    Properties{_Diffuse("Diffuse Color", Color) = (1,1,1,1) // 可在编辑器面板定义材质自身色彩
    }SubShader{Pass {// 只有定义了正确的LightMode才能得到一些Unity的内置光照变量Tags{"LightMode" = "ForwardBase"}CGPROGRAM// 包含unity的内置的文件,才可以使用Unity内置的一些变量
#include "Lighting.cginc" // 取得第一个直射光的颜色_LightColor0 第一个直射光的位置_WorldSpaceLightPos0(即方向)
#pragma vertex vert
#pragma fragment fragfixed4 _Diffuse; // 使用属性struct a2v{float4 vertex : POSITION;    // 告诉Unity把模型空间下的顶点坐标填充给vertex属性float3 normal : NORMAL;      // 告诉Unity把模型空间下的法线方向填充给normal属性float4 texcoord : TEXCOORD0; // 告诉Unity把第一套纹理坐标填充给texcoord属性                // POSITON、NORMAL、TEXCOORD0都是Unity内置的变量
            };struct v2f{float4 position : SV_POSITION; // 声明用来存储顶点在裁剪空间下的坐标float3 color : COLOR; // 用于传递计算出来的漫反射颜色         // SV_POSITION、COLOR都是Unity内置的变量
            };// 计算顶点坐标从模型坐标系转换到裁剪面坐标系
            v2f vert(a2v v){v2f f;f.position = mul(UNITY_MATRIX_MVP, v.vertex); // UNITY_MATRIX_MVP是内置矩阵。该步骤用来把一个坐标从模型空间转换到剪裁空间// 环境光fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;// 法线方向。把法线方向从模型空间转换到世界空间fixed normalDir = normalize(mul(v.normal, (float3x3)unity_WorldToObject)); // 反过来相乘就是从模型到世界,否则是从世界到模型// 光照方向fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz); // 对于每个顶点来说,光的位置就是光的方向,因为光是平行光// 漫反射Diffuse颜色 = 直射光颜色 * max(0, cos(光源方向和法线方向夹角)) * 材质自身色彩fixed3 diffuse = _LightColor0 * max(0, dot(normalDir, lightDir)) * _Diffuse; // 融合材质自身色彩用乘法// 加上环境光f.color = diffuse + ambient; // 颜色叠加用加法(通常亮度会增加)return f;}// 计算每个像素点的颜色值
            fixed4 frag(v2f f) : SV_Target {return fixed4(f.color, 1); // f.color是float3已经包含了三个数值
            }ENDCG}}FallBack "Diffuse"
}

如果去掉自定义的_Diffuse(材质自身色彩)属性和环境光(Ambient),漫反射颜色值将仅由光源颜色来决定。白色光源的显示效果如下:

现在想要融合材质自身的颜色值来显示,编辑器面板选择一个材质自身的色彩,显示效果如下:

最后再加上环境光(UNITY_LIGHTMODEL_AMBIENT),能看到变白变亮了,效果如下:


逐像素漫反射

Shader "Custom/05-Diffuse Fragment" { // 逐像素漫反射
    Properties{_Diffuse("Diffuse Color", Color) = (1,1,1,1) // 可在编辑器面板定义材质自身色彩
    }SubShader{Pass {// 只有定义了正确的LightMode才能得到一些Unity的内置光照变量Tags{"LightMode" = "ForwardBase"}CGPROGRAM// 包含unity的内置的文件,才可以使用Unity内置的一些变量
#include "Lighting.cginc" // 取得第一个直射光的颜色_LightColor0 第一个直射光的位置_WorldSpaceLightPos0(即方向)
#pragma vertex vert
#pragma fragment fragfixed4 _Diffuse; // 使用属性struct a2v{float4 vertex : POSITION;    // 告诉Unity把模型空间下的顶点坐标填充给vertex属性float3 normal : NORMAL;        // 告诉Unity把模型空间下的法线方向填充给normal属性float4 texcoord : TEXCOORD0;// 告诉Unity把第一套纹理坐标填充给texcoord属性
            };struct v2f{float4 position : SV_POSITION; // 声明用来存储顶点在裁剪空间下的坐标float3 worldNomalDir : COLOR;  // 用于存储世界空间下的法线方向
            };// 计算顶点坐标从模型坐标系转换到裁剪面坐标系
            v2f vert(a2v v){v2f f;f.position = mul(UNITY_MATRIX_MVP, v.vertex); // UNITY_MATRIX_MVP是内置矩阵。该步骤用来把一个坐标从模型空间转换到剪裁空间// 法线方向。把法线方向从模型空间转换到世界空间f.worldNomalDir = (mul(v.normal, (float3x3)unity_WorldToObject)); // 反过来相乘就是从模型到世界,否则是从世界到模型return f;}// 计算每个像素点的颜色值
            fixed4 frag(v2f f) : SV_Target {// 环境光fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;// 法线方向。fixed normalDir = normalize(f.worldNomalDir); // 单位向量// 光照方向。fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz); // 对于每个顶点来说,光的位置就是光的方向,因为光是平行光// 漫反射Diffuse颜色 = 直射光颜色 * max(0, cos(光源方向和法线方向夹角)) * 材质自身色彩fixed3 diffuse = _LightColor0 * max(0, dot(normalDir, lightDir)) * _Diffuse; // 颜色融合用乘法// 加上环境光fixed3 tempColor = diffuse + ambient; // 颜色叠加用加法(亮度通常会增加)return fixed4(tempColor, 1); // tempColor是float3已经包含了三个数值
            }ENDCG}}FallBack "Diffuse"
}

如下图,左边逐像素计算,右边逐顶点计算,在观察背光面阴影边缘时能看出明显差别,逐顶点计算的阴影过度呈块状的。


半兰伯特(HalfLambert)光照模型

  • http://www.cnblogs.com/2Yous/p/4206959.htm

直接修改上面frag函数中漫反射Diffuse颜色的计算公式。

// 计算每个像素点的颜色值
fixed4 frag(v2f f) : SV_Target
{// 环境光fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;// 法线方向。fixed normalDir = normalize(f.worldNomalDir); // 单位向量// 光照方向。fixed3 lightDir = normalize(_WorldSpaceLightPos0.xyz); // 对于每个顶点来说,光的位置就是光的方向,因为光是平行光// 半兰伯特光照float3 halfLambert = dot(normalDir, lightDir) * 0.5 + 0.5; // 使得背光面不至于为0全黑// 漫反射Diffuse颜色 = 直射光颜色 * max(0, cos(光源方向和法线方向夹角)) * 材质自身色彩fixed3 diffuse = _LightColor0 * halfLambert * _Diffuse; // 颜色融合用乘法// 加上环境光fixed3 tempColor = diffuse + ambient; // 颜色叠加用加法(亮度通常会增加)return fixed4(tempColor, 1); // tempColor是float3已经包含了三个数值}

可以看到在背光面也有了少量光照,明显没有旁边的对照组那么黑。


注意点:

  • 颜色融合是相乘,颜色叠加是相加(通常亮度会增加)。
  • 逐像素计算光照要比逐顶点计算光照更加消耗性能。

学习资料:

  • http://www.sikiedu.com/course/37/task/441/show#

【Unity Shader】三、漫反射Diffuse Shader例子相关推荐

  1. Unity 中用 Vertex Fragment Shader 实现 surface shader 中的 Diffuse 和 Decal

    自己体验了以后发现surface shader确实是隐藏了好多好多的内部实现呀,像我没有考虑的多光源,阴影,衰减等问题,在surface shader中都是被隐藏实现好了的,而且还是多平台适配的,Ve ...

  2. Unity Shader-兰伯特光照模型与Diffuse Shader

    简介 学了一段时间shader,然而一直在玩后处理,现在终于下定决心钻研一下真正的带光照的shader.从Diffuse到Specular.一个游戏的画面好坏,很大程度上取决于光照和贴图.现实世界中, ...

  3. Unity基础三: 什么是Shader

    什么是Shader Shader(着色器)是一段能够针对3D对象进行操作.并被GPU所执行的程序.Shader并不是一个统一的标准,不同的图形接口的Shader并不相同.OpenGL的着色语言是GLS ...

  4. unity 2020 怎么写shader使其接受光照?_如何在Unity中造一个PBR Shader轮子

    之前有业界大佬建议我去了解下Unity的PBR.说来惭愧,我查找了下资料才发现自己在这方面的知识居然是一片空白.经过几周的学习与尝试我对这一块算是有了初步的了解,于是写了这篇文章,一方面对自己学到的东 ...

  5. 【Unity3D Shader编程】之十一 深入理解Unity5中的Standard Shader(三)屏幕像素化特效的实现

    本系列文章由@浅墨_毛星云 出品,转载请注明出处.    文章链接:  http://blog.csdn.net/poem_qianmo/article/details/50095705 作者:毛星云 ...

  6. (十九)unity shader之——————基于物理的渲染技术(PBS):中篇(Unity 5中的Standard Shader的实现和使用)

    一.unity 5中的standard shader 在unity5中新创建一个模型或是新创建一个材质时,默认使用的着色器都是一个名为standard 的着色器.这个standard shader使用 ...

  7. Unity Shader 学习笔记(5)Shader变体、Shader属性定义技巧、自定义材质面板

    写在之前 Shader变体.Shader属性定义技巧.自定义材质面板,这三个知识点任何一个单拿出来都是一套知识体系,不能一概而论,本文章目的在于将学习和实际工作中遇见的问题进行总结,类似于网络笔记之用 ...

  8. Unity Shader - Making multiple shader program variants 制作shader程序多变体

    目录:Unity Shader - 知识点目录(先占位,后续持续更新) 原文:Making multiple shader program variants 版本:2019.1 Making mult ...

  9. unity 给图片边缘_Unity Shader 屏幕后效果——边缘检测

    关于屏幕后效果的控制类详细见之前写的另一篇博客: 这篇主要是基于之前的控制类,实现另一种常见的屏幕后效果--边缘检测. 概念和原理部分: 首先,我们需要知道在图形学中经常处理像素的一种操作--卷积. ...

最新文章

  1. 5月26 留言板练习题
  2. 李宏毅线性代数笔记6:矩阵的计算
  3. linux命令大全增删改查,crudini命令
  4. linux测试函数耗时tick数,C语言中怎样测验函数执行时间
  5. 小白必看——一位八年程序员的经验,赶紧看看!!
  6. LQR轨迹跟踪算法Python/Matlab算法实现_LQRmatrix推导(2)
  7. apache的php扩展名解析漏洞
  8. SQL vs NoSQL:异同比较
  9. 优质的vray视频教程素材推荐,不容错过
  10. 普洛斯库列科夫 线性代数习题集_转载)科大学长对数学系学弟学妹的忠告
  11. Java_语法基础_定义规范的接口类型
  12. harmonyos下载安装,HarmonyOS系统
  13. 二维码签到的几大优势,你了解几个?
  14. python flask教程
  15. RSA加密算法-非对称加密算法的使用
  16. 自动复制吱口令html,js随机复制多吱口令代码
  17. python flask ajax_Python flask+css+js+ajax 综合复习
  18. stats | 广义线性模型(三)——二元Logistic模型和Probit模型
  19. 清华刘知远、黄民烈团队力作:一个「PPT」框架,让超大模型调参变简单
  20. 第1章 Linux系统介绍与环境搭建准备

热门文章

  1. GDCM:Torture的测试程序
  2. GDCM:ReadUpToTag的测试程序
  3. boost::contract模块实现access的测试程序
  4. Boost:实现异步客户端
  5. DCMTK:dicom标签的基础类
  6. VTK:可视化之AssignCellColorsFromLUT
  7. VTK:绘图之HistogramBarChart
  8. VTK:图片之PickPixel
  9. OpenCV条形码识别
  10. QT的QOpenGLTexture类的使用