项目中美术使用了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. 单片机软件proteus的汉化步骤

    整体思想:把汉化包里的文件替换软件的英文的软件 右键打开文件安装的位置,找到Translations文件夹,打开它等待被替换. 打开这个找到Translations文件夹,把下面的文件全部复制替换上面 ...

  2. [CC-INVENTRY]Arranging the Inventory

    [CC-INVENTRY]Arranging the Inventory 题目大意: 有一排长度为\(n(\sum n\le10^6)\)的格子,有些格子是空的,有些格子上有一个箱子. 现在你要用最小 ...

  3. koa2框架设置响应和请求头

    https://koa.bootcss.com/#response 请耐心翻到网页下端,可以看到 设置响应头: ctx.set('Content-Type', 'application/zip') 添 ...

  4. [BZOJ2863]愤怒的元首

    Description: Pty生活在一个奇葩的国家,这个国家有n个城市,编号为1~n. ​ 每个城市到达其他城市的路径都是有向的. ​ 不存在两个城市可以互相到达. 这个国家的元首现在很愤怒,他大喊 ...

  5. 数据结构 Sunday算法

    Sunday算法是Daniel M.Sunday于1990年提出的字符串模式匹配算法.相对比较KMP和BM算法而言,简单了许多. Sunday算法的思想类似于BM算法中的坏字符思想,有点像其删减版.差 ...

  6. C#数组,ArrayList,List

    一.数组声明方式 1,声明一个未经初始化的数组引用,以后可以把这引用初使化为一个数组实例 int[] int_array; int_array = new int[2]; 注:数组的引用必须以相同或相 ...

  7. linux使用Anaconda管理多个版本的Python环境

    1.下载(直接到清华镜像下载) 下载链接,选择合适的版本,我试了几个,选择了一个下载最快的,原谅我的渣渣网速, 官网在国外,必须找镜像,不然很慢很慢,,,,,, 此步骤真的很慢,重新选择下载网址,这个 ...

  8. dedecms在后台替换文章标题、内容、摘要、关键字

    dedecms在后台替换文章标题.内容.摘要.关键字所在的字段为: 后台替换文章内容 数据表:dede_addonarticle 字段:body 后台替换文章摘要内容 数据表:dede_archive ...

  9. react-native 报错 RawText "" must be wrapped in an explicit <Text> component

    刚才又遇到了一个坑,找了好久,问题如下: 开始以为是Text标签怎么有问题了,结果是下面的原因影响的: 上图第二行,标签和注释中间多了一个空格,就会报这个错误. 解决办法 1.将空格删掉 <Re ...

  10. Vue(二十三)vuex + axios + 缓存 运用 (以登陆功能为例)

    (一)axios 封装 (1)axios拦截器 可以在axios中加入加载的代码... (2)封装请求 后期每个请求接口都可以写在这个里面... (二)vuex user.js import { lo ...