项目中美术使用了Unity自带的Mobile/Diffuse这个shader制作了一部分场景素材,这个shader会依赖场景中的动态实时光源,比较耗费。

于是自己手动重写一份,简化shader的消耗,但同时保持美术已经制作场景的效果。

Shader "Mobile/Diffuse"
{
Properties
{
_MainTex ("Base (RGB)", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD CGPROGRAM
#pragma surface surf Lambert noforwardadd nolightmap noshadow novertexlights nodynlightmap nodirlightmap sampler2D _MainTex; struct Input
{
float2 uv_MainTex;
}; void surf (Input IN, inout SurfaceOutput o) {
fixed4 c = tex2D(_MainTex, IN.uv_MainTex);
o.Albedo = c.rgb;
o.Alpha = c.a;
}
ENDCG
} Fallback "Mobile/VertexLit"
}

我在原始shader上添加了一些编译选项用来关闭一些特性,但编译出来的shader还是有很多非必要的运算。

手动实现一份noforwardadd的(只有一个pass)版本:

Shader "James/Scene/Mesh Lighting"
{
Properties
{
_MainTex ("Base (RGB)", 2D) = "white" {}
} SubShader
{
Tags { "RenderType"="Opaque" "Queue"="Geometry" }
LOD Pass
{
Tags { "LightMode"="ForwardBase" }
// Lighting Off CGPROGRAM
#pragma fragmentoption ARB_precision_hint_fastest #pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase
#pragma multi_compile_fog #include "UnityCG.cginc" float4 _LightColor0; uniform sampler2D _MainTex;
uniform half4 _MainTex_ST; struct vertexIN_base
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float2 texcoord : TEXCOORD0;
}; struct v2f_base
{
float4 pos : SV_POSITION;
fixed3 vertexLight : COLOR;
half2 uv : TEXCOORD0;
float3 normal : TEXCOORD1;
float3 lightDir : TEXCOORD2;
UNITY_FOG_COORDS()
}; v2f_base vert(vertexIN_base v)
{
v2f_base o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
o.normal = v.normal;
o.lightDir = ObjSpaceLightDir(v.vertex); half3 worldNormal = UnityObjectToWorldNormal(v.normal);
float3 shlight = ShadeSH9(float4(worldNormal, 1.0));
o.vertexLight = shlight;
#ifdef VERTEXLIGHT_ON
o.vertexLight += Shade4PointLights (
unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
unity_LightColor[].rgb, unity_LightColor[].rgb, unity_LightColor[].rgb, unity_LightColor[].rgb,
unity_4LightAtten0, worldPos, worldNormal
);
#endif UNITY_TRANSFER_FOG(o,o.pos);
return o;
} fixed4 frag(v2f_base i) : COLOR
{
i.lightDir = normalize(i.lightDir);
i.normal = normalize(i.normal); float diffuse = max(, dot(i.normal, i.lightDir)); fixed4 mainColor = tex2D(_MainTex, i.uv);
fixed4 clr = mainColor * _LightColor0 * diffuse;
clr.rgb += mainColor.rgb * i.vertexLight; UNITY_APPLY_FOG(i.fogCoord,clr); return clr;
}
ENDCG
}
}
FallBack Off
}

上述shader和Mobile Diffuse效果基本一致(场景中光照并不复杂),并且默认的效果也是不带forward add的。

但这个shader还是依赖了场景中的实施光源数据。

于是乎,进一步,将场景中的实时光源全部移除,并将光源的颜色和方向信息直接写在shader的属性中,得到了下面的去光源版本:

Shader "James/Scene/Mesh Diffuse"
{
Properties
{
_MainTex ("Base (RGB)", 2D) = "white" {} _MainLightColor("主光颜色", Color) = (,,,)
_MainLightDir("主光方向", Vector) = (,,,) _SecondLightColor("辅光颜色", Color) = (,,,)
_SecondLightDir("辅光方向", Vector) = (,,,)
_SecondLightBrightness ("辅光强度", Range(, )) = 0.9
} SubShader
{
Tags { "RenderType"="Opaque" "Queue"="Geometry" }
LOD Pass
{
Tags { "LightMode"="ForwardBase" }
Lighting Off CGPROGRAM
#pragma fragmentoption ARB_precision_hint_fastest #pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fog #include "UnityCG.cginc" float4 _MainLightColor;
float4 _MainLightDir;
float4 _SecondLightColor;
float4 _SecondLightDir;
float _SecondLightBrightness; uniform sampler2D _MainTex;
uniform half4 _MainTex_ST; struct vertexIN_base
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float2 texcoord : TEXCOORD0;
}; struct v2f_base
{
float4 pos : SV_POSITION;
half2 uv : TEXCOORD0;
float3 normal : TEXCOORD1;
float3 lightDir : TEXCOORD2;
float3 lightDir2 : TEXCOORD3;
UNITY_FOG_COORDS()
}; v2f_base vert(vertexIN_base v)
{
v2f_base o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
o.normal = v.normal; o.lightDir = mul(unity_WorldToObject, _MainLightDir).xyz;
o.lightDir2 = mul(unity_WorldToObject, _SecondLightDir).xyz; UNITY_TRANSFER_FOG(o,o.pos);
return o;
} fixed4 frag(v2f_base i) : COLOR
{
i.lightDir = normalize(i.lightDir);
i.lightDir2 = normalize(i.lightDir2);
i.normal = normalize(i.normal); float diffuse = max(, dot(i.normal, i.lightDir));
float diffuse2 = max(, dot(i.normal, i.lightDir2)); fixed4 mainColor = tex2D(_MainTex, i.uv);
fixed4 clr = mainColor * _MainLightColor * diffuse;
clr += _SecondLightBrightness * (mainColor * _SecondLightColor * diffuse2); UNITY_APPLY_FOG(i.fogCoord,clr); return clr;
}
ENDCG
}
}
FallBack Off
}

  这个版本支持两个光源信息,然后按照同样的Lambert光照方式来计算光照信息,其中辅光给了一个强度的调节因子。

  注:这里没有完全按照默认的计算方式来计算主光以外的光照信息,是因为half3 ShadeSH9 (half4 normal)所以来的unity_SHAr unity_SHAg unity_SHAb的计算方式不明确。

    // normal should be normalized, w=1.0
half3 SHEvalLinearL0L1 (half4 normal)
{
half3 x; // Linear (L1) + constant (L0) polynomial terms
x.r = dot(unity_SHAr,normal);
x.g = dot(unity_SHAg,normal);
x.b = dot(unity_SHAb,normal); return x;
} // normal should be normalized, w=1.0
half3 SHEvalLinearL2 (half4 normal)
{
half3 x1, x2;
// 4 of the quadratic (L2) polynomials
half4 vB = normal.xyzz * normal.yzzx;
x1.r = dot(unity_SHBr,vB);
x1.g = dot(unity_SHBg,vB);
x1.b = dot(unity_SHBb,vB); // Final (5th) quadratic (L2) polynomial
half vC = normal.x*normal.x - normal.y*normal.y;
x2 = unity_SHC.rgb * vC; return x1 + x2;
} // normal should be normalized, w=1.0
// output in active color space
half3 ShadeSH9 (half4 normal)
{
// Linear + constant polynomial terms
half3 res = SHEvalLinearL0L1 (normal); // Quadratic polynomials
res += SHEvalLinearL2 (normal); # ifdef UNITY_COLORSPACE_GAMMA
res = LinearToGammaSpace (res);
# endif return res;
}

  Unity是怎么计算出unity_SHAr unity_SHAg  unity_SHAb这几个变量的,又知道的小伙伴可以告知一下哈。

  下面是基于以上三个shader的实时渲染效果,其中"James/Scene/Mesh Diffuse"不依赖场景光源。

  

  让美术直接在材质球上面手动输入light dir,其实非常的不直观,于是写了一个工具,直接把场景中的lighting对应的shader中的方向值给打印出来:

    private void WriteLightingDir()
{
Object obj = Selection.activeGameObject;
if (obj is GameObject == false) return;
Debug.Log(-(obj as GameObject).transform.forward);
}

  选中场景中的Lighting对象,然后执行上面的编辑期代码即可打印出方向值。

  添加环境光:

  如果只有场景光照,模型会有一些暗角,因此还需要加上自定义环境光的光照亮度。

  首先通过代码设置全局的环境光,方便shader访问:

using System.Collections;
using System.Collections.Generic;
using UnityEngine; [ExecuteInEditMode]
public class GlobalShaderSetting : MonoBehaviour
{
public Color GlobalAmbientColor = new Color(0.5f, 0.5f, 0.5f, 1f);
public float GlobalAmbientBrightness = ;
public Vector4 GlobalWindDirection = new Vector4(0.5f, 0.5f, 0.5f, 1f); [ContextMenu("Set")]
private void Awake()
{
Shader.SetGlobalColor("_GlobalAmbientColor", GlobalAmbientColor);
Shader.SetGlobalFloat("_GlobalAmbientBrightness", GlobalAmbientBrightness);
Shader.SetGlobalVector("_GlobalWindDirection", GlobalWindDirection);
}
}

  然后添加一个cginc的通用文件:

#ifndef JAMES_LIGHTING_H
#define JAMES_LIGHTING_H float4 _GlobalAmbientColor;
float _GlobalAmbientBrightness;
float4 _GlobalWindDirection; #define AMBIENT_COLOR _GlobalAmbientColor * _GlobalAmbientBrightness #endif

  在需要添加环境光的shader中添加环境光的影响即可:

clr += mainTex * AMBIENT_COLOR;

  

优化实现Mobile Diffuse动态直接光照shader的更多相关文章

  1. 【Jquery mobile】动态加载ListView 转

    [Jquery mobile]动态加载ListView 分类: Jquery Mobile2011-12-01 09:04 13984人阅读 评论(1) 收藏 举报 jquerylistviewmob ...

  2. jquery mobile Checkbox动态添加刷新及事件绑定

    jquery mobile Checkbox动态添加刷新及事件绑定 在微信项目中,涉及到一个多选功能.数据来自后台数据库,需要动态加载. 项目结构:微信api+web app.使用jquery mob ...

  3. 优化实现Mobile/Bumped Diffuse

    在上一篇帖子的基础上增加一张法线贴图即可: Shader "James/Scene/Bumped_Diffuse" { Properties { _MainTex ("B ...

  4. 【Unity Shaders】Diffuse Shading——漫反射光照改善技巧

    本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...

  5. 【Unity Shaders】Diffuse Shading——在Surface Shader中使用properties

    本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...

  6. Diffuse Shading——漫反射光照改善技巧

    转:http://www.narkii.com/club/thread-355113-1.html 我们会列出两种方法:使用Half Lambert lighting model(半兰伯特光照模型)和 ...

  7. HTTPS 传输优化详解之动态 TLS Record Size

    笔者在过去分析了诸多可以减少 HTTPS 传输延迟的方法,如分布式 Session 的复用: 启用 HSTS,客户端默认开启 HTTPS 跳转:采用 HTTP/2 传输协议:使用 ChaCha20-P ...

  8. 【Unity Shaders】Diffuse Shading——向Surface Shader添加properties

    本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...

  9. [Unity优化]批处理02:动态批处理

    参考链接: https://docs.unity3d.com/Manual/DrawCallBatching.html 原理: cpu每帧把可以进行动态批处理的网格进行合并,再把合并后的数据传给gpu ...

随机推荐

  1. 1171 Big Event in HDU 01背包

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=1171 题意:把商品分成两半,如不能均分,尽可能的让两个数相接近.输出结果:两个数字a,b且a>=b. ...

  2. 潭州课堂25班:Ph201805201 django 项目 第四十四课 项目部署 (课堂笔记)

    项目部署 稳定,并发,效益, 一.Django配置 1.settings.py配置 复制全局settings.py配置文件,创建一个副本命名为MyBlog/pro_settings.py,修改DEBU ...

  3. SW加载标准库时出现failed to create Toolboxlibrary object怎么办?

    友情提示:Windows+r打开  输入smd 注意操作前要关闭solidworks, 重新打开软件. 下面就可以找到很多标准件了.

  4. [CF961E] Tufurama

    Description: 有一天Polycarp决定重看他最喜爱的电视剧<Tufurama>.当他搜索"在线全高清免费观看Tufurama第3季第7集"却只得到第7季第 ...

  5. 基于socketserver模块并发套接字

    1.基于tcp协议 服务端: import socketserverclass MyHandler(socketserver .BaseRequestHandler ): def handle(sel ...

  6. android Resources 类的使用

    使用 R.<resource_type>.<resource_name> 获取的是资源的一个 id (int 类型), 但有时候我们需要获取资源本身,这时候我们可以通过 Res ...

  7. layer.load的使用

    在ajax请求和回调返回的过程中,我们一般都要用到layer.load这个方法 例如: //loading层 var index = layer.load(1, { shade: [0.1,'#fff ...

  8. PAT Basic 1004

    1004 成绩排名 (20 分) 读入 n(>0)名学生的姓名.学号.成绩,分别输出成绩最高和成绩最低学生的姓名和学号. 输入格式: 每个测试输入包含 1 个测试用例,格式为 第 1 行:正整数 ...

  9. 3_主流部署方式介绍-Django+gunicorn+nginx

    下载python wgethttps://www.python.org/ftp/python/3.4.3/Python-3.4.3.tgz 报错 Cannot find a valid baseurl ...

  10. linux 下通过xhost进入图形界面,经常会出现报错“unable to open display”

    linux 下通过xhost进入图形界面,经常会出现报错“unable to  open display” linux下的操作步骤如下: [root@localhost ~]# vncserver N ...