学习目标:

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

漫反射计算公式:

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

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


逐顶点漫反射

Shader "Custom/04-Diffuse Vertex" { // 逐顶点漫反射
Properties{
_Diffuse("Diffuse Color", Color) = (,,,) // 可在编辑器面板定义材质自身色彩
}
SubShader{
Pass { // 只有定义了正确的LightMode才能得到一些Unity的内置光照变量
Tags{"LightMode" = "ForwardBase"} CGPROGRAM // 包含unity的内置的文件,才可以使用Unity内置的一些变量
#include "Lighting.cginc" // 取得第一个直射光的颜色_LightColor0 第一个直射光的位置_WorldSpaceLightPos0(即方向)
#pragma vertex vert
#pragma fragment frag fixed4 _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(, dot(normalDir, lightDir)) * _Diffuse; // 融合材质自身色彩用乘法
// 加上环境光
f.color = diffuse + ambient; // 颜色叠加用加法(通常亮度会增加) return f;
} // 计算每个像素点的颜色值
fixed4 frag(v2f f) : SV_Target
{
return fixed4(f.color, ); // f.color是float3已经包含了三个数值
} ENDCG
} }
FallBack "Diffuse"
}

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

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

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


逐像素漫反射

Shader "Custom/05-Diffuse Fragment" { // 逐像素漫反射
Properties{
_Diffuse("Diffuse Color", Color) = (,,,) // 可在编辑器面板定义材质自身色彩
}
SubShader{
Pass { // 只有定义了正确的LightMode才能得到一些Unity的内置光照变量
Tags{"LightMode" = "ForwardBase"} CGPROGRAM // 包含unity的内置的文件,才可以使用Unity内置的一些变量
#include "Lighting.cginc" // 取得第一个直射光的颜色_LightColor0 第一个直射光的位置_WorldSpaceLightPos0(即方向)
#pragma vertex vert
#pragma fragment frag fixed4 _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(, dot(normalDir, lightDir)) * _Diffuse; // 颜色融合用乘法
// 加上环境光
fixed3 tempColor = diffuse + ambient; // 颜色叠加用加法(亮度通常会增加) return fixed4(tempColor, ); // tempColor是float3已经包含了三个数值
} ENDCG
} }
FallBack "Diffuse"
}

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


半兰伯特(HalfLambert)光照模型

直接修改上面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, ); // tempColor是float3已经包含了三个数值
}

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


注意点:

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

学习资料:

【Unity Shader】三、漫反射Diffuse Shader例子的更多相关文章

  1. 解读Unity中的CG编写Shader系列八(多光源漫反射)

    转自http://www.itnose.net/detail/6117338.html 前文中完成最简单的漫反射shader只是单个光源下的漫反射,而往往场景中不仅仅只有一个光源,那么多个光源的情况下 ...

  2. [转]解读Unity中的CG编写Shader系列8——多光源漫反射

    前文中完成最简单的漫反射shader只是单个光源下的漫反射,而往往场景中不仅仅只有一个光源,那么多个光源的情况下我们的物体表面的漫反射强度如何叠加在一起呢?前文打的tag "LightMod ...

  3. [转]解读Unity中的CG编写Shader系列7——漫反射

    如果前面几个系列文章的内容过于冗长缺乏趣味着实见谅,由于时间原因前面的混合部分还没有写完,等以后再补充,现在开始关于反射的内容了.折射与反射在物理世界中,光的反射与折射往往是同时存在的,光源由真空或者 ...

  4. 【淡墨Unity3D Shader计划】五 圣诞用品: Unity在Shader三种形式的控制&混合操作编译

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

  5. Unity Shader (三)Surface Shader机制

    转自:http://blog.csdn.net/candycat1992/article/details/39994049 写在前面 一直以来,Unity Surface Shader背后的机制一直是 ...

  6. 【译】Unity3D Shader 新手教程(5/6) —— Bumped Diffuse Shader

    本文为翻译,附上原文链接. 转载请注明出处--polobymulberry-博客园. 动机 如果你满足以下条件,我建议你阅读这篇教程: 你想学习片段着色器(Fragment Shader). 你想实现 ...

  7. 【Unity Shaders】初探Surface Shader背后的机制

    转载请注明出处:http://blog.csdn.net/candycat1992/article/details/39994049 写在前面 一直以来,Unity Surface Shader背后的 ...

  8. 【Unity Shaders】Vertex & Fragment Shader入门

    写在前面 三个月以前,在一篇讲卡通风格的Shader的最后,我们说到在Surface Shader中实现描边效果的弊端,也就是只对表面平缓的模型有效.这是因为我们是依赖法线和视角的点乘结果来进行描边判 ...

  9. 【Unity Shader】五、Shader纹理映射,及纹理的缩放和偏移

    将漫反射的颜色改为从纹理贴图中获取,逐像素计算. Shader "Custom/11-Texture" { // 纹理贴图,BlinnPhong光照模型 Properties{ / ...

随机推荐

  1. eclipse导入class文件

    右键src文件夹->build path->config build path->library->add class folder->create new folder ...

  2. 记github上搭建独立域名的免费博客的方法过程

    前提:拥有github帐号,linux上安装好了git. 全局路线: 1. 设计一个你想要的二级域名,并在git上创建一个以[二级域名.github.com]作为项目名的repository. 过程详 ...

  3. 章节0:MySQl学前知识储备

    一.数据库基础: 1.数据库(database):保存有组织的数据的容器(通常是一个文件或一组文件). 2.数据库管理系统(DBMS):创建和操纵数据库的软件系统. 3.表(table):某种特定类型 ...

  4. 【转载】web网站css,js更新后客户浏览器缓存问题,需要刷新才能正常展示的解决办法

    原文:http://blog.csdn.net/csdn100861/article/details/50684438 问题描述 部署到服务器后访问发现页面展示不正常,但是刷新之后就会展示正常. 问题 ...

  5. android中碰撞屏幕边界反弹问题

    其实碰撞问题只是涉及到一点小算法而已,但在实际应用,尤其游戏中有可能会遇到,下面给出一个小示例,代码如下: MainActivity: package com.lovo; import android ...

  6. linux分享二:Linux如何修改字符集

    问题: 当在项目中用到服务器端导出并且查询条件中包含汉字时,总是导出失败,Excel中出现null字样,如何解决方法呢? 解决方法: 把linux的字符集改变一下. 路径:etc/sysconfig/ ...

  7. HTC T329手机如何删除系统自带的软件?HTC一键解锁、获取ROOT权限、豌豆荚删除系统软件

    手头一部HTC T329T手机,机上默认装载的软件实在太多了,居然占用了4页.用360手机卫士并不能删除系统软件(不能获取ROOT权限).查网上查询,总结要删除系统软件步骤如下(本人不刷机,只是想删除 ...

  8. [svc]Linux vmstat命令实战详解

    vmstat输出 注:是cpu 内存 磁盘 虚拟内存交换情况 io读写情况 vmstat命令是最常见的Linux/Unix监控工具,可以展现给定时间间隔的服务器的状态值,包括服务器的CPU使用率,内存 ...

  9. 【Unity】2.5 场景视图(Scene)

    分类:Unity.C#.VS2015 创建日期:2016-03-29 一.场景视图(Scene View)导航 场景视图 (Scene View) 是你的交互式沙箱.你可以使用场景视图 (Scene ...

  10. Linux系统Apache服务 - 配置 HTTP 的虚拟机主机

    接Linux系统Apache服务 - 配置HTTP的默认主页 1.创建/srv目录,作为httpd的文件目录,并创建/srv/default/www和/srv/www1.example.com/www ...