看很多人实现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
}
}
}

最新文章

  1. [转]NandFlash和NorFlash的区别
  2. Tomcat:云环境下的Tomcat设计思路——Tomcat的多实例安装
  3. C++ Pirmer : 第十五章 : 面向对象程序设计之基类和派生的定义、类型转换与继承与虚函数
  4. OOP-ECMAScript - 深入理解Javascript
  5. spring 学习的开源项目
  6. WebLogic: The Definitive Guide examined WebLogic's security mechanisms--reference
  7. PHP命名空间理解
  8. 浅析final关键字
  9. Android群英传笔记——第八章:Activity与Activity调用栈分析
  10. angular.injector()
  11. bootstrap-fileinput多图片上传
  12. 分布式系统-主键唯一id,订单编号生成-雪花算法-SnowFlake
  13. js- caller、 callee
  14. 开发工具-Eclipse
  15. java代码执行顺序
  16. 使用Ubuntu的Crontab定时任务需要注意的地方
  17. 洛谷P3826 蔬菜 [NOI2017] 贪心
  18. QQ消息无限发送!源代码
  19. HTTP所承载的货物(图像、文本、软件等)要满足的条件
  20. PHP------TP命名空间

热门文章

  1. Ruby-随机数
  2. EF架构~通过EF6的DbCommand拦截器来实现数据库读写分离~终结~配置的优化和事务里读写的统一
  3. UNABLE TO PURGE A RECORD(二)
  4. SharePoint配置搜索服务和指定搜索范围
  5. favicon.ico的制作
  6. swift学习笔记之-函数
  7. 绘制复数图形和双y轴图形
  8. 一个android的各种控件库
  9. tomcat部署应用的几种方式
  10. 广州Uber优步司机奖励政策(1月25日~1月31日)
  11. 分享内容到微博、QQ空间、人人网、开心网等社区
  12. 【剑指offer】面试题25:二叉树中和为某一值的路径
  13. BZOJ 1631: [Usaco2007 Feb]Cow Party( 最短路 )
  14. 关于md5的使用方法
  15. Python内置函数(16)——ord
  16. 暑假第二弹:基于docker的hadoop分布式集群系统的搭建和测试
  17. 2018-2019-2 20175204 张湲祯 实验二《Java面向对象程序设计》实验报告
  18. Python request 在linux上持续并发发送HTTP请求遇到 Failed to establish a new connection: [Errno 11] Resource temporarily unavailable
  19. JRockit检测Tomcat内存溢出JAVA内存泄漏问题
  20. Windows下编译安装 FFmpeg