Egret 5 配置puremvc

今天更新了egret 5.1,安装了下第三方的puremvc,发现网上的一些教程过时了,按照以前的做法会报错。

步骤蛮简单的(官方文档有坑,更新不及时):

1.把附件中的文件考到/libs/puremvc文件夹中(手动创建)

2.修改egretproperties.json,添加

{
“name”:”puremvc”,
“path”: “libs/puremvc”
}

puremvc附件

Height Map Terrain

我在做飞行模拟游戏的时候,有这样的需求:飞机在高空中俯瞰地表。

这时我遇到两个问题:

1.飞机飞十分钟会飞出上百公里,那么这个地表模型谁来做?需要多长时间?

2.这个地表模型有多少面,GPU能扛得住吗?

对,如果我们按照传统思维实现这个功能的话,一定会遇到这两个问题,第二个问题也许还好点,毕竟我们有lod系统,但是第一个问题- -#

那么今天我给大家提供一个新的思路:用shader实现基于高度图的地形系统,我给它命名为“Height Map Terrain”。

先上个效果图:

基本原理如下:

1.输入一张高度图和一张地表贴图。

2.在fragment shader中根据uv映射取地表贴图的颜色,并调整成自己想要的整体色调。

3.在fragment shader中根据uv映射取高度图中的高度值,并经过光照计算出软影子。

4.将2和3混合。

5.输出到屏幕或者Quad。

这个方法有如下几个优点:

1.支持无限大地图

2.不需要人工制作复杂的地形,只要用ps生成高度图和地表贴图即可。

3.没有vertex的计算开销,最多只渲染两个三角形。

实现方法:

1.在场景中创建一个Quad。

2.创建一个空的shader再把附件中的代码考进去。

3.把附件中的水贴图和噪音图考到项目中,并指定给上面创建的shader。

4.把shader拖到上面创建的Quad中。

5.运行。

附件:

Water Effect – Swimming Pool

水面效果是一种常见的特效,在游戏场景中有大量的应用。我们常用的编辑器(Unity、UE)都自带水特效shader。通常来说自带的效果已经做够好了,应该可以直接拿来用。但是我们做移动应用时,受到了gpu和耗电量的限制,自带特效往往不能达到性能平衡点,因此各种五花八门的简化特效出现了。
这里我提供一个水特效,shader计算量非常小,适合做泳池等在固定容器内的水效果。

游泳池特效

这个特效是用Fragment Animation实现的,一般水特效多少都会有sin cos这样的操作以实现波的效果,而这特效利用噪声图来实现,有效的降低了计算量。具体说明见代码注释。

实现方法:

1.在场景中创建一个Quad。

2.创建一个空的shader再把附件中的代码考进去。

3.把附件中的水贴图和噪音图考到项目中,并指定给上面创建的shader。

4.把shader拖到上面创建的Quad中。

5.运行。

附件:

 

水贴图
噪音图

Interpreter JIT AOT

Interpreter JIT AOT是三种程序运行模式。需要明白一个大前提:CPU只能执行机器码指令。

首先给大家引入Interpreter和Compiler这两个概念。

Interpreter表示解释器,程序运行中通过对高级语言解释一行执行一行来实现运行(如JavaScript),亦或者将高级代码转变为性能更高的中间码再执行(如php的opcode)。JavaScript是非常典型的解释型语言,你修改一下本地html中的JavaScript,然后直接刷新浏览器就可以看到结果。因此解释器的第一个优点就是构造简单,你不需要掌握什么计算机原理就能写代码,写JavaScript的时候有个记事本就行,什么额外的环境都不需要安装,所以JavaScript是很多学校的入门语言;它的另一个优点就是代码与硬件平台无关,你写的代码可以在任何带解释器的平台上运行,浏览器依然是最好的例子。当然其不足之处就是因为每次运行都要解释,导致效率低下,无法实现cpu密集运算的应用。

Compiler表示编译器,把高级语言编译成可直接执行的机器码,因此其运行效率远高于解释器。编译器又分为两大类:JIT和AOT。

AOT(Ahead Of Time),叫作静态编译器,通过ahead这个单词可以辨别它是在程序运行前编译,直接生成机器码,运行的时候执行机器码即可,这样可以保证最大化效率。世界上性能最高的语言就是基于AOT的,对,我说的就是C和C++。AOT的缺点之一是如果要在多个硬件平台上运行(比如x86、x64、arm),那么需要在每个平台下重新进行编译才可以使用;另一个缺点是占用空间比较大,当然在这个动不动以T为单位存储的年代,这缺点根本不算什么了。因此AOT也是典型的空间换时间的手法。

JIT(Just In Time),叫作动态编译器,通过Just这个单词可以辨别它是在程序运行的过程中编译。话说前面有性能最强大的AOT了,还要这个干甚?你还记得一句广告词嘛?一次编译到处运行,对我说的就是JAVA。一个jar的helloworld能让你在手机、pc、服务器横行,你无须考虑运行平台的问题。它是通过在不同平台的jit虚拟机实现一边编译一边运行。JIT并不一定是执行一行编译一行,假设每行代码只执行一次,那么极有可能这种方式比解释器还慢- -#,因此产生了methodbased jit、trace based jit、region based jit这几种编译策略,来实现接近AOT的性能,由于篇幅有限不在这里细说。编译策略的存在往往意味着JIT会捆绑解释器一起使用,以保证没有编译的部分依然可以正常执行(比如methodbased jit只有同一个方法执行多次才会进行编译,否则交由解释器执行)。近似AOT的强大性能,和拥有强大可移植性就是JIT存在的意义。UNITY3D是非常有代表性的JIT产品。

提问:PHP为什么是最好的语言?

Docker^^

今天给我一台atom525的机器上装了docker,安了一套NetDisk程序,页面秒开。atom不支持虚拟化技术,不能用kvm、xen。只能用ovz和docker。然而ovz等于同时跑两个以上系统,cpu很有可能压不住,而且所有环境都需要重新编译(atom编译lnmp需要1小时以上)。

不知道是不是vlan的问题,docker network一直没有成功,现在还是在docker run里人工指定外网ip实现静态ip分配。另外分配ip前还需要建立虚拟网卡。

UnityShader之假体积光

1.什么是体积光?

体积光就是白天在你昏暗的房间里打开窗户,一道光顺着窗口照到你的房间。就像这个样子:

“volume lighting”的图片搜索结果

2.体积光如何实现?

常见的体积光实现方法往往会用到深度缓冲和阴影贴图。

比如我通过基本光照公式计算好场景中的阴影区域,那么我就知道光线可以打到阴影以外的任何位置。由于光线会随着距离不断衰减,那么利用深度缓冲我们就可以让体积光看起来更真实。那么我就可以通过后处理方式在非阴影区域混合一个白雾效果,再利用深度缓冲控制雾的强弱,那么最终效果看起来就是上图那样。

3.假体积光

由于体积光的实现会消耗大量的gpu资源,很多设备无法承受这个开销,特别是手机。所以有人用了一些tricky的手法,用相对简单的计算实现近似的体积光效果。这种方法就叫做假体积光。

下面我提供一个假体积光算法:

把FVLController.cs绑在摄像机上就可以运行了。在运行过程中你会发现一些瑕疵,对这就是假体积光,希望有大神能把近似做成完美。

下面放两张效果图

UnityShader之简单描边效果

经常玩3d游戏的小朋友们经常会看到下图这样的效果:一个被选中的人物轮廓被不同颜色的线条包围来表示敌友关系。

“cs go character outline”的图片搜索结果

明明是3d模型,程序怎么知道我从眼睛看到的边缘在哪?程序怎么探测到模型最外面那个像素的?

现在我带大家一起一步步实现这个从传统三维知识的角度看起来无从下手的效果。

解决这个问题确实用的不是什么复杂的技术^^而是一种视觉欺骗,而且只需要2步就能完成的简单效果:

1.先画一个比原始尺寸略大的模型,涂成和描边同样颜色的色块。

2.再把真正的模型盖在上面,因为色块比真正的模型大一点,所以看起来就是模型外面描了一圈边。

先上代码,后面慢慢解释:

 

代码说明:

1.为了适配多个硬件平台,我把逻辑写在了2个subshader中,下面我们仅拿第一个解说。

2.为了让vert再可以在多个subshader中重用,我用CGINCLUDE把它提取出来。

3.如何绘制比实际模型大一点的色块?

答:假设我们有个这样的场景,一个球体和一个相机。

如果要绘制一个大一点的色块,把球scale大一点再上色就行了。但是直接执行下scale就行么?你会发现你看到的不是描边,而是一颗麦丽素。那我们该怎么做?

请看下camera preview。我们需要的只是在xy轴扩大一点就行。模型扩大原理就是顶点沿法线正方向移动。camera preview对应的是View Space。

那么就有

然后在subshader中连续执行两个pass:

第一个pass画色块:

第二个pass绘制实体,并叠加在色块上:

最终效果:

描边有锯齿的锅在第28行。试试其它算子也许效果会更好,但是计算量也会更大。把描边宽度减小能减轻锯齿。

图形学有一句话:看起来是对的就是对的,背后可能完全没有任何数学、物理等科学依据。

UnityShader之顶点动画

我们在游戏中会经常看到这样的效果:翻滚的海浪、飘动的旗子。那么这些效果怎么实现?你的第一想法会是贴图动画?骨骼动画?物理引擎?粒子?

这里我给大家提供一种方案:不依赖于美术,在较低的计算量下实现波动效果效果。这个方案叫做顶点动画。

下面是代码:

拖一个plane到场景里然后绑定一下Material和Shader,再把input1/2/3分别调到0.3/1/1即可。如果你再加个旗子的贴图效果就更好了。

友情提示:顶点动画没有处理顶点变化造成的法线变化问题,所以如果要加光效还需要自己实时修正法线。如果顶点动画太复杂自己写不出对应的法线着色器,那么请调用mesh.RecalculateNormals()。

最终效果

 

UnityShader之滚动贴图

滚动贴图是一种常见的游戏技巧,无限滚动背景、传送带、广告牌和光束武器等都会用到这个技巧。实现这个效果的代码非常简单。
在场景里创建个UI Image再把下面这个shader拖上去就行了。

最终效果

要点说明:

1.什么是_Time?

答:_Time是float4类型,xyzw分别代表:

_Time.x = time / 20
_Time.y = time
_Time.z = time * 2
_Time.w = time * 3

2.什么是frac?

答:内置函数frac表示取float的小数部分。因为贴图的uv范围在0-1之间。这个例子不用frac也能正常运行,但是为了避免出现不可预期的结果,还是建议大家这么用。记住_Time和frac是一对好基友就行拉。

附贴图一张

 

前向渲染和延迟渲染的区别

前向渲染和延迟渲染是两种光照渲染模式。
假设有1个光源和1000个具有光照反射的三角形在view coordinate沿着z轴正方形延伸摆放,法线与z轴平行,即所有三角形xy全相同,只有z不同,但是这里增加一个条件:摆放顺序是无序的。
从屏幕上其实你只能看到一个带光照的三角形,其他的都被挡住了。

那么前向渲染会这样做:
1.遍历1000个三角形片元
2.进行深度检测,没通过的忽略
3.通过检测的进行光照计算
4.更新帧缓冲区
5.返回1继续直到遍历结束

由于上面的要求是无序摆放,那么如果运气差一点 1000次深度检测全部都能通过,那么光照会计算1000次,可是因为只能看见最上面的,那么999次光照计算都是多余的。如果光源越多第三步的重复次数越多,整体复杂度也会越高。

延迟渲染引入了GBuffer,它会这样做:
1.遍历1000个三角形片元
2.进行深度检测,没通过的忽略
3.通过的将坐标、光照等信息写入GBuffer
4.返回1继续直到遍历结束
5.遍历Gbuffer
6.利用Gbuffer中的数据进行光照计算
7.更新帧缓冲区
8.返回5继续直到遍历结束

延迟渲染先把可以显示在屏幕上的像素点的相关参数保存下来,然后只进行了一次光照计算就实现了最终效果。这样大大节约了光照计算复杂度。每增加一个光源,只会增加一次整体的光照计算。所以延迟渲染的好处显而易见了。

然而,世间无完美之事,GBuffer只能给屏幕上的每一个点保存一份光照数据,但是如果这些三角形都是半透明的怎么办?无解–# Blend已废。
由于Gbuffer存的都是像素值,无法体现出每个像素对应的原始模型,那么多重采样抗锯齿功能也无法实现。三角形可能还好点,画圆就悲剧了。

所以如果各位大哥对Blend混合和抗锯齿有要求,那么Gbuffer可能就不太适合了。