看很多人实现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之半兰伯特漫反射的更多相关文章

  1. 【Unity Shader学习笔记】Unity光照基础-半兰伯特光照

    在光照无法达到的区域,模型的外观通常是全黑的,没有任何明暗变化,这会使模型的背光区域看起来就像一个平面. 使用半兰伯特光照可以解决这个问题. 逐顶点光照技术也被称为兰伯特光照模型.因为它符合兰伯特定律 ...

  2. Unity shader学习之半兰伯特光照模型

    半兰伯特光照模型,为Valve公司在开发游戏<半条命>时提出的一种技术,用于解决漫反射光无法到达区域无任凭明暗变化,丢失模型细节表现的问题. 其公式如下: Cdiffuse = Cligh ...

  3. Unity3D Shader 半兰伯特光照模型

    //效果预览 //Shader代码 Shader "Unlit/HalfLambert" { Properties { _MainTex ("Texture", ...

  4. Lambert (兰伯特)光照模型

    Lambert (兰伯特)光照模型 是光源照射到物体表面后,向四面八方反射,产生的漫反射效果.这是一种理想的漫反射光照模型.如下图:这个是顶点函数处理后的该光照模型,因此看起来像素不够平滑. 漫反射 ...

  5. 兰伯特余弦定理(Lambert)

    兰伯特余弦定理(Lambert) 1.漫反射,是投射在粗糙表面上的光向各个方向反射的现象.当一束平行的入射光线射到粗糙的表面时,表面会把光线向着四面八方反射,所以入射线虽然互相平行,由于各点的法线方向 ...

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

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

  7. 求解轨道力学二体意义下的Lambert方程(兰伯特方程)的Fortran程序

    轨道力学中二体问题下求解兰伯特方程. 老外写的Matlab程序,我把它转成了Fortran程序. !************************************************** ...

  8. Unity3D 开发之shader教程(浅谈光照之漫反射diffuse)

    在游戏开发过程中,光照应该是必不可少部分,当然,这是指大多数的稍微大型一些的3D游戏会需要,给模型或者山山水水加上光照,会看上去更加的真实,获得更好的体验.一个本身不发光物体显示什么颜色,在于本身反射 ...

  9. Unity Shader入门精要学习笔记 - 第6章 开始 Unity 中的基础光照

    转自冯乐乐的<Unity Shader入门精要> 通常来讲,我们要模拟真实的光照环境来生成一张图像,需要考虑3种物理现象. 首先,光线从光源中被发射出来. 然后,光线和场景中的一些物体相交 ...

随机推荐

  1. form表单的ajax验证2

    form表单的ajax验证2: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"&g ...

  2. ajax提交到后台是中文乱码

    运行程序时遇到用ajax的url中传递数据,后台用request.getParamet()时出现中文乱码 $.ajax({ type: "POST", url: g_sBasePa ...

  3. Button动态样式取代xml

    还在为 textview以及button 的各种样式而烦恼的童鞋们请往这里看~~~~ 一次性解决 textview以及button的样式,再也不用写xml了!!! 全部动态预设置,拒绝堆代码,拒绝xm ...

  4. Java中引用的浅复制和深复制

    Java中除了基本类型int,char,double等的赋值是按照值传递之外,其余的类型和对象都是按照引用进行传递的. 下面来看一个关于引用的例子. package referenceCopy;// ...

  5. etcd raft library设计原理和使用

    早在2013年11月份,在raft论文还只能在网上下载到草稿版时,我曾经写过一篇blog对其进行简要分析.4年过去了,各种raft协议的讲解铺天盖地,raft也确实得到了广泛的应用.其中最知名的应用莫 ...

  6. (转载)开源ckplayer 网页播放器, 跨平台(html5, mobile),flv, f4v, mp4, rtmp协议. webm, ogg, m3u8 !

    文章链接:http://justcoding.iteye.com/blog/2110275 CKplayer,其全称为超酷flv播放器,它是一款用于网页上播放视频的软件,支持的格式有:http协议上的 ...

  7. rownumber和rowid伪劣用法

    select rownum ,deptno,dname loc from  dept; select deptno,dname,loc from dept where rownum=1; select ...

  8. Servlet中 End event threw exception,错误404 的解决方法

    End event threw exception    SEVERE: End event threw exceptionjava.lang.reflect.InvocationTargetExce ...

  9. 野村证券伦敦分部面试 - Java岗位

    第一轮 1. 笔试 30 mins 一共六道大题,前两题有4-5个小题. 第一道大题主要是考察Java Collections: a. LinkedList和ArrayList的区别 b. Set和L ...

  10. 关于Docker中的Images与Containers

    Docker engine提供了启动Images和containers核心的技术的支持.当你运行docker run hello-world 命令时,实际上可分为三个部分: 告诉你操作系统你正在使用的 ...