shader之半兰伯特漫反射
看很多人实现shader都用插件shader force,那我还学shader干X!!!???
好了,废话不多说,学习shader去。。。。
漫反射在shader里算是最基础的知识了。入手shader,你必须可以信手拈来一个漫反射吧??什么叫信手拈来,就是不查阅资料的前提下吧
那我就信手拈来一个半兰伯特漫反射效果吧(瞄了一眼资料,好像没人看见)。
正常的漫反射公式(Lambert)是这样的:
C(diffuse) = C(light) * M(diffuse)max(0,n*I)
C(light):入射光的颜色和强度
M(diffuse):材质的漫反射系数
n:世界坐标系下的表面法线
I:世界坐标系下的光源方向(反射点指向光源的矢量)
max函数:,将结果截取到0,防止法线与光源方向的点乘为负值,被背后的光源照亮的错误效果
而笔者会比较喜欢一个毫无依据的半兰伯特公式:
C(diffuse) = (C(light) * M(diffuse))(0.5(n*l)+0.5)
这个公式实现的漫反射效果看起来更真实一些(据说是让亮度更亮一点,特别是比较暗的地方)
好了,又要放代码了:
笔者是在顶点着色器中计算空间法线和空间灯光矢量,为的是让效果更佳精确点
但是同样笔者也有个疑问:我尝试在顶点着色器里面对贴图纹理进行采样,但是报错了,不知道为什么不能这样做?
Shader "CharmingShader/Wangzhe/Diffuse"
{
Properties
{
_MainTex("Main Tex",2D) = "white"{}
_DiffuseColor("Diffuse Color",Color) = (,,,)
}
SubShader
{
Tags{"Queque" = "Opaque"}
Pass
{
Tags{"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc" sampler2D _MainTex;
float4 _MainTex_ST;
float4 _DiffuseColor; struct a2v
{
float4 vertex : POSITION;
float4 texcoord : TEXCOORD0;
float3 normal :NORMAL;
};
struct v2f
{
float4 pos : SV_POSITION;
//float3 color : COLOR;
float halfLambert : TEXCOORD0;
float2 uv : TEXCOORD1;
}; v2f vert(a2v v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
float3 worldNormal = normalize(UnityObjectToWorldNormal(v.normal));
float3 worldPos = mul(unity_ObjectToWorld, o.pos);
float3 worldLightDir = normalize(UnityWorldSpaceLightDir(worldPos));
o.halfLambert = dot(worldNormal, worldLightDir)*0.5 + 0.5; return o;
} float4 frag(v2f f) : SV_Target
{
float3 col = tex2D(_MainTex, f.uv).rgb;
float3 diffuse = col * _DiffuseColor.rgb;
float3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb * col;
float3 color = ambient + _LightColor0.rgb * diffuse * f.halfLambert;
return float4(color,);
} ENDCG
}
}
}
这里要注意一点,不管是在pass前面的tags还是pass里面的tags都是尤为重要的。
Tags标签是一个键值对,它们告诉Unity的渲染引擎如何及何时去渲染这个对象
这里用到的Tags{"LightMode" = "FarwordBase"},在官方文档是这样解释的:
Details
Tags are basically key-value pairs. Inside a Pass tags are used to control which role this pass has in the lighting pipeline (ambient, vertex lit, pixel lit etc.) and some other options. Note that the following tags recognized by Unity must be inside Pass section and not inside SubShader!
LightMode tag
LightMode tag defines Pass’ role in the lighting pipeline. See render pipeline for details. These tags are rarely used manually; most often shaders that need to interact with lighting are written as Surface Shaders and then all those details are taken care of.
Possible values for LightMode tag are:
- Always: Always rendered; no lighting is applied.
- ForwardBase: Used in Forward rendering, ambient, main directional light, vertex/SH lights and lightmaps are applied.
- ForwardAdd: Used in Forward rendering; additive per-pixel lights are applied, one pass per light.
- Deferred: Used in Deferred Shading; renders g-buffer.
- ShadowCaster: Renders object depth into the shadowmap or a depth texture.
- MotionVectors: Used to calculate per-object motion vectors.
- PrepassBase: Used in legacy Deferred Lighting, renders normals and specular exponent.
- PrepassFinal: Used in legacy Deferred Lighting, renders final color by combining textures, lighting and emission.
- Vertex: Used in legacy Vertex Lit rendering when object is not lightmapped; all vertex lights are applied.
- VertexLMRGBM: Used in legacy Vertex Lit rendering when object is lightmapped; on platforms where lightmap is RGBM encoded (PC & console).
- VertexLM: Used in legacy Vertex Lit rendering when object is lightmapped; on platforms where lightmap is double-LDR encoded (mobile platforms).
意思是:LightMode标签是在Pass里面,管理处在光照管道中的pass和其它选项。注意LightMode标签必须处在Pass里面而不是SubShader里面。
由于时间的关系,我就只翻译一下ForwardBase:ForwardBase用在Forward渲染中,渲染时可以应用到环境光、主平行光、顶点光和球谐光照以及光照贴图。
之前一直忽视了这个标签的作用,导致如何调效果都灰常暗。
下面放两张对比图吧:
普通贴图效果------------------------------------------------->半兰伯特漫反射效果


虽然半兰伯特效果看起来更自然点,但是相对的亮度也比较暗了,反而没有图一看起来惊艳,而仅仅是更写实了点。
(有一位小萌同事也提出了这个问题:喵~~脸这么黑,哪里好看了!
我当时心里嘀咕到:想要怎样就怎样,哪有这么好的事情哦?)
(后来一次机缘巧合,得到了一块秘籍残片)咳咳,哪有这么神话。也就是我想装逼翻译文章遇到很多不会的名词,比如说SH Lights,
然后我就贴到Unity Shader群里问了问, 当时有个头衔为话痨id为落俗的小伙伴很热情的为我解答,并且贴出一段能让这个漫反射更好
看的代码。
SH Lights就是球谐光照,利用球谐光照技术可以实时重现面积光源下3D模型的全局光照效果(好吧,我也不懂,我就记住一个球)
代码是这样的(据说要有天空盒才会有效果):
在v2f结构体里定义sh

在顶点着色器里面计算sh,注意这里要对v2f o进行一次初始化

最后在片源着色器输出颜色里加上对sh的处理

Ctrl+S跳转界面,噔噔噔噔,有没被惊艳到= =

这里贴上完整的代码:
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject' // Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld' Shader "CharmingShader/Wangzhe/Diffuse"
{
Properties
{
_MainTex("Main Tex",2D) = "white"{}
_DiffuseColor("Diffuse Color",Color) = (,,,)
}
SubShader
{
Tags{"Queque" = "Opaque"}
Pass
{
Tags{"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc" sampler2D _MainTex;
float4 _MainTex_ST;
float4 _DiffuseColor; struct a2v
{
float4 vertex : POSITION;
float4 texcoord : TEXCOORD0;
float3 normal :NORMAL;
};
struct v2f
{
float4 pos : SV_POSITION;
//float3 color : COLOR;
float halfLambert : TEXCOORD0;
float2 uv : TEXCOORD1;
#if UNITY_SHOULD_SAMPLE_SH
float3 sh : TEXCOORD2;
#endif
}; v2f vert(a2v v)
{
v2f o = (v2f);
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
float3 worldNormal = normalize(UnityObjectToWorldNormal(v.normal));
float3 worldPos = mul(unity_ObjectToWorld, o.pos);
float3 worldLightDir = normalize(UnityWorldSpaceLightDir(worldPos));
#ifndef LIGHTMAP_ON
#if UNITY_SHOULD_SAMPLE_SH
o.sh = ShadeSHPerVertex(worldNormal, o.sh);
#endif
#endif
o.halfLambert = dot(worldNormal, worldLightDir)*0.5 + 0.5; return o;
} float4 frag(v2f f) : SV_Target
{
float3 col = tex2D(_MainTex, f.uv).rgb;
float3 diffuse = col * _DiffuseColor.rgb;
float3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb * col;
float3 color = ambient + _LightColor0.rgb * diffuse * f.halfLambert + diffuse * f.sh;
return float4(color,);
} ENDCG
}
}
}
shader之半兰伯特漫反射的更多相关文章
- 【Unity Shader学习笔记】Unity光照基础-半兰伯特光照
在光照无法达到的区域,模型的外观通常是全黑的,没有任何明暗变化,这会使模型的背光区域看起来就像一个平面. 使用半兰伯特光照可以解决这个问题. 逐顶点光照技术也被称为兰伯特光照模型.因为它符合兰伯特定律 ...
- Unity shader学习之半兰伯特光照模型
半兰伯特光照模型,为Valve公司在开发游戏<半条命>时提出的一种技术,用于解决漫反射光无法到达区域无任凭明暗变化,丢失模型细节表现的问题. 其公式如下: Cdiffuse = Cligh ...
- Unity3D Shader 半兰伯特光照模型
//效果预览 //Shader代码 Shader "Unlit/HalfLambert" { Properties { _MainTex ("Texture", ...
- Lambert (兰伯特)光照模型
Lambert (兰伯特)光照模型 是光源照射到物体表面后,向四面八方反射,产生的漫反射效果.这是一种理想的漫反射光照模型.如下图:这个是顶点函数处理后的该光照模型,因此看起来像素不够平滑. 漫反射 ...
- 兰伯特余弦定理(Lambert)
兰伯特余弦定理(Lambert) 1.漫反射,是投射在粗糙表面上的光向各个方向反射的现象.当一束平行的入射光线射到粗糙的表面时,表面会把光线向着四面八方反射,所以入射线虽然互相平行,由于各点的法线方向 ...
- 解读Unity中的CG编写Shader系列八(多光源漫反射)
转自http://www.itnose.net/detail/6117338.html 前文中完成最简单的漫反射shader只是单个光源下的漫反射,而往往场景中不仅仅只有一个光源,那么多个光源的情况下 ...
- 求解轨道力学二体意义下的Lambert方程(兰伯特方程)的Fortran程序
轨道力学中二体问题下求解兰伯特方程. 老外写的Matlab程序,我把它转成了Fortran程序. !************************************************** ...
- Unity3D 开发之shader教程(浅谈光照之漫反射diffuse)
在游戏开发过程中,光照应该是必不可少部分,当然,这是指大多数的稍微大型一些的3D游戏会需要,给模型或者山山水水加上光照,会看上去更加的真实,获得更好的体验.一个本身不发光物体显示什么颜色,在于本身反射 ...
- Unity Shader入门精要学习笔记 - 第6章 开始 Unity 中的基础光照
转自冯乐乐的<Unity Shader入门精要> 通常来讲,我们要模拟真实的光照环境来生成一张图像,需要考虑3种物理现象. 首先,光线从光源中被发射出来. 然后,光线和场景中的一些物体相交 ...
随机推荐
- 13.什么是javabean,以及使用原则
javabean简介 javabeans就是符合某种特定的规范的java类,使用javabeans的好处是解决代码的重复编写,减少代码 冗余,功能区分明确,提高了代码的维护性. javabean的设计 ...
- 插入多行数据的时候,一个insert插入多行
如:insert into t_users(a,b,c)value('1','2','3'),('3','4','5'),('6','7','8') ('1','2','3'),('3','4','5 ...
- 外部世界如何访问容器? - 每天5分钟玩转 Docker 容器技术(37)
上节我们学习了容器如何访问外部网络,今天讨论另一个方向:外部网络如何访问到容器? 答案是:端口映射. docker 可将容器对外提供服务的端口映射到 host 的某个端口,外网通过该端口访问容器.容器 ...
- input标签在只允许输入数字的时候添加的代码
oninput="this.value=this.value.replace(/\D/g, '')"
- 算法——蛮力法之选择排序和冒泡排序c++实现
这次实现的是蛮力法中的两个例子,选择排序法和冒泡排序法,使用的编译环境是vs2013,下面对这两个算法做一个简单介绍,然后是两个算法的c++实现代码. 选择排序法比较的范围是整个列表,每次扫描结束找出 ...
- App 组件化/模块化之路——构建开发架构思路
App 组件化/模块化开发架构思路 随着业务的发展 App 开发技术也越来越成熟,对开发者来说 App 代码量也迅速地增长到一个数量级.对于如何架构 App 已经每个开发者面临的实际问题.好的架构可以 ...
- 谈谈ES6箭头操作符
如果你会C#或者Java,你肯定知道lambda表达式,ES6中新增的箭头操作符=>便有异曲同工之妙.它简化了函数的书写.操作符左边为输入的参数,而右边则是进行的操作以及返回的值Inputs=& ...
- JavaWeb 后端 <九> 之 JDBC加强
一.大结果集的分页(重点,难点) 1.分批次查询:分页 2.基于数据库的分页:依赖的是数据库的分页语句(不同数据库是不同的) MySQL:每页显示10条. select * from XXX limi ...
- jsonp的原理和实现
什么是JSONP? javascript高级程序设计中是这样介绍jsonp的: jsonp是JSON with padding(填充式JSON或参数式JSON )的简写,是应用JSON的一种新方法,在 ...
- 实现一个栈类,类似STL中的栈
1.思路讲解 stack集合类是一个简单的堆栈的实现. 这里有两个模板参数,T和size,T用于指定堆栈中的元素类型,my_size用于表示堆栈中项数的最大值. 类中添加方法isempty.isful ...