项目中美术使用了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. MySql 5.7.20版本免安装版配置过程

    下载地址为: https://dev.mysql.com/downloads/mysql/ 最下面根据自己的操作系统选择合适的型号 下载完以后解压缩到自定义的路径.这里注意的是路径中不要存在中文. 解 ...

  2. HDU5518 : John's Fences

    求出平面图的对偶图,那么需要选择一些环,使得这些环可以异或出所有环. 对于两个不同的区域,需要用一个代价最小的环把它们区分开,这对应最小割. 那么求出对偶图的最小割树,所有树边之和就是把所有区域都区分 ...

  3. Redis设计与实现:读书笔记之一

    第一部分:数据结构与对象 Redis支持的数据类型 字符串对象 列表对象 Hash对象 集合对象 有序集合对象 2.数据结构 Redis的所有数据类型都是: key-value pair 对象 Red ...

  4. js间隔一段时间打印数据库中的值

    https://blog.csdn.net/qq_33599109/article/details/78417474

  5. Python 调用图像融合API

    Python 调用图像融合API 本文记录使用Python,调用腾讯AI开放平台的图像融合API.官网给出的Demo用的是PHP,博主作为Python的粉丝,自然想用它来和『最好的』的语言一较高下,顺 ...

  6. Python基础-字符串、集合类型、判断、深拷贝与浅拷贝、文件读写

    字符串 1.定义三个变量: 2.交换两个变量值 1)引入第三个变量: 2)Python引入第三方变量: 3)不引入第三方变量: 3. isalpha 是否是汉字或字母 4.Isalnum  是否是汉字 ...

  7. PHP01

    1.服务端开发基础 前端开发最终还是属于web端开发的一个分支,想要成为前端程序员,就要充分理解web的概念. 网站的概念: 可以在浏览器上通过一个地址直接访问使用 用于提供一种或多种特定服务的一系列 ...

  8. Mac添加自定义启动图标到Launchpad

    1.使用Automator进行录制 2.选择Application 3.使用运行shell脚本 4.保存在应用程序 5.效果 参考: https://apple.stackexchange.com/q ...

  9. 使用Spring AOP实现MySQL读写分离

    spring aop , mysql 主从配置 实现读写分离,下来把自己的配置过程,以及遇到的问题记录下来,方便下次操作,也希望给一些朋友带来帮助.mysql主从配置参看:http://blog.cs ...

  10. 大神们都在用的两个国外的免费离线下载:Rain&amp; LoadBT

    大神们都在用的两个国外的免费离线下载:Rain& LoadBT 最近QQ离线和迅雷离线也都挂了,115还死贵,所以分享两个国外免费的网站.希望可以为大家提供一些帮助,同时也借此机会同大家相互交 ...