优化实现Mobile Diffuse动态直接光照shader
项目中美术使用了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的更多相关文章
- 【Jquery mobile】动态加载ListView 转
[Jquery mobile]动态加载ListView 分类: Jquery Mobile2011-12-01 09:04 13984人阅读 评论(1) 收藏 举报 jquerylistviewmob ...
- jquery mobile Checkbox动态添加刷新及事件绑定
jquery mobile Checkbox动态添加刷新及事件绑定 在微信项目中,涉及到一个多选功能.数据来自后台数据库,需要动态加载. 项目结构:微信api+web app.使用jquery mob ...
- 优化实现Mobile/Bumped Diffuse
在上一篇帖子的基础上增加一张法线贴图即可: Shader "James/Scene/Bumped_Diffuse" { Properties { _MainTex ("B ...
- 【Unity Shaders】Diffuse Shading——漫反射光照改善技巧
本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...
- 【Unity Shaders】Diffuse Shading——在Surface Shader中使用properties
本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...
- Diffuse Shading——漫反射光照改善技巧
转:http://www.narkii.com/club/thread-355113-1.html 我们会列出两种方法:使用Half Lambert lighting model(半兰伯特光照模型)和 ...
- HTTPS 传输优化详解之动态 TLS Record Size
笔者在过去分析了诸多可以减少 HTTPS 传输延迟的方法,如分布式 Session 的复用: 启用 HSTS,客户端默认开启 HTTPS 跳转:采用 HTTP/2 传输协议:使用 ChaCha20-P ...
- 【Unity Shaders】Diffuse Shading——向Surface Shader添加properties
本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...
- [Unity优化]批处理02:动态批处理
参考链接: https://docs.unity3d.com/Manual/DrawCallBatching.html 原理: cpu每帧把可以进行动态批处理的网格进行合并,再把合并后的数据传给gpu ...
随机推荐
- Java技能提升之路
James收集Java技能提升方面的资料,分为:基础篇.提高篇.高级篇… 给出“入口”,自我提升 1. Java工程师成神之路:http://www.hollischuang.com/archives ...
- DevC++出现[Error] ld returned 1 exit status,如何解决才好呢?
回答: 代码在vc中没问题,虽然没用过DevC++. 可以把 ld returned 1 exit status前面的详细出错说出来程序是没有问题的,可能的问题最有可能是以下2个1.是你的程序已经在运 ...
- shell脚本8--录制终端会话
准备: script -t 2> timing.log -a output.session type commands; ... . .. exit 回放: scriptreplay timin ...
- 类对象序列化为json串,json串反序列化为类对象
1.类对象序列化为json串: 方法一: class P(object): def __init__(self,name,age,sex): self.name=name self.age=age s ...
- selenium3 文件系列之------读取properties文件
一个eclipse工程会有很多配置文件,有的配置文件是写在properties里,也有写在xml文件里的.这个总结一下是自动化测试是如何读取properties文件. 一.准备config.prope ...
- elastic-job详解(三):Job的手动触发功能
elastic-job的任务都是使用quartz来触发的,quartz表达式一般都是定期执行.但有时候一些周期较长的任务,比如一天一次,几小时一次的任务,我们需要等待很久才能触发一次.如果我们需要测试 ...
- django之模版层(template)
上篇主要介绍了django的MTV模型,主要介绍了视图层之路由配置系统url分发和视图层之视图函数view,本篇主要讲解MTV模型中的模版层template. 本篇导论: 模版简介 模版之变量 模版之 ...
- pygame-KidsCanCode系列jumpy-part11-角色动画(下)
接上节继续,上节并没有处理向左走.向右走的动画效果,这节补上,看似很简单,但是有一些细节还是要注意: def jump(self): hits = pg.sprite.spritecollide(se ...
- C#静态代码检查工具StyleCode
C#静态代码检查工具StyleCode -- 初探 最近我们Advent Data Service (ADS) 在项目上需要按照代码规范进行代码的编写工作,以方便将来代码的阅读与维护. 但是人工检查起 ...
- 基于ping++聚合支付进行微信红包开发
1.微信方面的开发,一定要详细的阅读微信支付的开发文档. https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13 ...