在平行光照中加入Cookie遮罩
- 作者:admin
- /
- 时间:2019年07月05日
- /
- 浏览:2911 次
- /
- 分类:厚积薄发
1)在平行光照中加入Cookie遮罩
2)ToLua table使用耗时优化
3)关于镜面反射的一些优化
4)在Unity中用BVH做一个动态遮挡剔除插件
5)PlayableBehaviour类中某个类内部的变量的问题
这是第166篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题,建议阅读时间10分钟,认真读完必有收获。
UWA 问答社区:answer.uwa4d.com
UWA QQ群2:793972859(原群已满员)
Rendering
Q:我们自己写的Shader,一般的平行光能接受光照和阴影的处理。但美术想在灯光上加一个Cookie遮罩,结果模型就是暗暗的。
Pass
{
Name "FORWARD"
Tags { "LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "AutoLight.cginc"
…
uniform fixed4 _LightColor0;
…
…
struct VertexInput
{
UNITY_VERTEX_INPUT_INSTANCE_ID
half4 vertex : POSITION;
half3 normal : NORMAL;
half2 texcoord : TEXCOORD0;
};
struct VertexOutput
{
half4 pos : SV_POSITION;
half2 uvMain : TEXCOORD0;
half3 normalDir : TEXCOORD1;
LIGHTING_COORDS(2, 3)
};
…
fixed4 frag(VertexOutput i) : SV_Target
{
在这里取_LightColor0.rgb,如果有Cookie,则这里全是000全黑的;没有设Cookie,则取到的就是灯光的颜色。
这是怎么回事,一定要再加一个ForwardAdd Pass来处理吗?
美术想要一个外加的光影变化,渲染氛围(比如:森林里明暗错落的感觉),但又不想DrawCall翻倍,有好的实现方式吗?谢谢。
下面一张图没加Cookie就比较平面、呆板。
A:目前的思路只能参考一个简化迷雾的方式,因为这边地图还算平,所以可以用这个方式。和地面一样高度放个Mesh面片,然后Shader渲染层级调成这样:
Tags{ “Queue” = “Transparent+150” “IgnoreProjector” = “True” “RenderType” = “Transparent”}
这么想来这个方式稍微改改,还能做简单的多云天气效果。(混合方式可能还得改改,美术说建筑有些颜色失真)
Shader "Studio1/Flow2"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_MashAlpha("阴影透明度",Range(0.00, 1.00)) = 0.60
[KeywordEnum(OFF, ON)] _MoveUV("uv移动", Float) = 0
_MoveSpeed("uv移动速度",Float) = 1
}
SubShader
{
Tags{ "Queue" = "Transparent+150" "IgnoreProjector" = "True" "RenderType" = "Transparent" }
LOD 100
Blend SrcAlpha OneMinusSrcAlpha
ZWrite Off
ZTest Off
Cull Back
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#pragma multi_compile _MOVEUV_OFF _MOVEUV_ON
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float _MashAlpha;
#ifdef _MOVEUV_ON
float _MoveSpeed;
#endif
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// sample the texture
fixed2 tep=i.uv;
#ifdef _MOVEUV_ON
//让uv随时间变化
tep.x +=_Time.y * _MoveSpeed;
tep.y +=_Time.y * _MoveSpeed;
#endif
fixed4 col = tex2D(_MainTex,tep);
col = fixed4(col.rgb, col.a*_MashAlpha);
// apply fog
UNITY_APPLY_FOG(i.fogCoord, col);
return col;
}
ENDCG
}
}
}
感谢题主真木@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5cfdd15f18013226f621cc3d
Lua
Q:一般来说会觉得Lua的table缓存起来用比较好。但我自己打印试了一下感觉Vector3这种小容量的table,New起来比用缓存起来改值的开销小很多。请问一下,这两种用法的不同对性能的影响大吗?平时需要去关注吗?
附图:(左边是缓存的耗时,右边是New的耗时竟然有8倍的差距)
A1:你写成如下代码就好了:
local VSet = Vector.Set
for i = 1, 100000000 do
VSet(c, a.x+b.x, a.y+b.y, a.z+b.z)
end
你的案例比较的是通过Metatable调用函数以及直接调用函数看谁更快。因为主流的Lua面向对象实现,使用obj:XXX()方式调用函数,都是通过Metatable去完成的,这种做法虽然很适合支持继承,但是多了一次Metatable的查找,性能肯定是会变差的。把Vector.Set缓存一下,就节省了这些查找时间。
另外:
local VNew = Vector.New
也比直接Vector.New要快,节省了一次字段查找时间(在Vector里查找New字段)。
这种优化可以用在任何有函数调用的地方,在消耗比较高的地方做就好了,不需要整个代码都这样。
感谢招文勇@UWA问答社区提供了回答
A2:这涉及到测试方法的问题:
1、测试前后必须要GC一下,防止前面积累的内存在后面阶段的测试造成影响。
2、测试的量级要和游戏内运行的量级要一致。量级太大或太小都不利于反映影响程度。
3、减少外部调用,可以把外部的实现直接写在循环里。如果非要用外部的接口,应该对此类接口也做好性能评估。最后,说一下我最近做这一块的性能测试结论:复用Vector比New一个更快,并且不会造成内存分配和GC造成的耗时。
感谢hy@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5d0a221d9ca82b592a9d393a
Rendering
Q:现在游戏里某些场景的地面用了实时镜面反射,反射的开销有点大,面数峰值有20多万。
用FrameDebugger看了下,发现某些不太需要的部分也做了反射,导致DrawCall和面数增加了不少,例如:
1、角色描边,假设一个角色6000面,描边6000,反射角色6000,反射描边6000,一个角色就要24000面。反射描边这部分根本看不见,完全可以去掉。
2、模型LOD,反射贴图本身清晰度并不高,用低级的模型LOD也可以。
针对这两个问题,我想了下解决方法:
1、在渲染反射贴图的OnWillRenderObject方法里,把Shader.globalMaximumLOD强制改成100,LOD100的Shader没有描边,计算也少很多,渲染完再改回原来的。
2、在渲染反射贴图的OnWillRenderObject方法里,把QualitySettings.lodBias强制改成0,让摄像机用低级模型LOD渲染,渲染完再改回原来的。
现在我的问题是,实时镜面反射贴图每帧都要渲染,也就是说每帧我都会修改Shader.globalMaximumLOD和QualitySettings.lodBias的值,这个操作会不会导致什么问题?
自己打了个包试了下,Profiler里看来回设置Shader.globalMaximumLOD和QualitySettings.lodBias的时间,比节省下来渲染的时间还多。
那么有没有什么别的优化方法呢?除了控制反射物体的层级以外。(这个打算做,在目前项目的情况下还有一些难点要解决)
A1:不知道这个能不能帮助到题主,Material.SetShaderPassEnabled在反射相机渲染的时候关闭描边的那个Pass,不知道性能如何,仅提供个思路。
感谢王宇@UWA问答社区提供了回答
A2:我后来想了个办法,用ReplacementShader。用一个只有diffuse的Shader Replace,这样1是没有描边,并且能降低计算量;2是只会渲染不透明物体,可以少掉特效和3D UI的DrawCall。
感谢题主deviljz@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5d0b4f5f20084a38c25ecfbc
Culling
Q:本人项目中物体都是动态加载的,所以Unity自带的遮挡剔除功能用不了,也用过一些动态遮挡提出的插件InstantOC等,但是这些插件都是基于射线检测所有的物体,所以在项目中CPU的计算消耗时间很长,有点得不偿失。
所以打算在Unity中用BVH做一个动态遮挡提出插件,请问有什么思路可以提供吗?谢谢。
A:自己用BVH算的话也是算遮挡关系的吧?要结合视线做较为准确的计算,消耗应该也不少。
不知道题主的场景物件动态加载只是动态加载,还是加载完成之后就不动了,还是说场景重点物体都是动态的,或者场景是随机生成的。如果是前者,遮蔽关系也是可以预先离线计算好的;如果是后者,可能的确只能用动态计算了。
这块消耗大,可能还不如直接暴力的距离剔除和LOD。看你截图,不透的东西也比较多,所以遮挡剔除主要还是减少DrawCall,省下来的CPU时间,看看和做剔除的时间哪个更多吧。
感谢贾伟昊@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5ce7977efd7bd665736194d0
Timeline
Q:Timeline播放可以录制变量变化,俗称手K帧。我看到例子里可以记录PlayableBehaviour类内部的变量变化,比如浮点、向量等等,目前希望实现在自定义的PlayableBehaviour内维护自定义的config类实例。但是使用时发现,如果录制过config实例里的变量有修改,播放时config实例为空引用,所以想请教如何正确操作?是否是因为config的初始化时机不正确。没有K帧操作时,config作为成员变量不用写New来初始化,这时没有报错或运行的问题。
A:在Unity论坛也发帖子问了下,自定义的Behaviour里不能用内部类来录制变化,必须使用结构体。
感谢题主赵东玥@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5ceacd47fd7bd665736194ec
今天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题也许都只是冰山一角,我们早已在UWA问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入,也许你的方法恰能解别人的燃眉之急;而他山之“石”,也能攻你之“玉”。
官网:www.uwa4d.com
官方技术博客:blog.uwa4d.com
官方问答社区:answer.uwa4d.com
UWA学堂:edu.uwa4d.com
官方技术QQ群:793972859(原群已满员)