榨干GPU 使用顶点颜色信息来创建千千万的高性能植被

gdc vertex color

之前做Terrain Brush Grass 的时候一直被它的性能折磨,稍微密集一些的植被,帧数直接变为个位数。 而GDC上使用顶点动画的想法瞬间给了我许多启发。

说干,就干。
在 Unity 中拖出一个 Cube 拉伸出 草的模样,然后给顶点上色。 像这样
红色表示可以被晃动的顶点
绿色表示晃动的幅度

两个颜色叠加在一起的时候,就变成屎黄了。。。
不过根部没有颜色呈现黑色可以看出过度

vertex color1

最后在Shader如下

v2f vert (appdata v)
            {
                v2f o;
                float scale = cos(_Time.y * _Speed) * v.color.r * (v.color.g);

                float szControl = randValue > 0.5;
                v.vertex.z += scale * szControl;
                v.vertex.x += scale * (1.0 - szControl);

                float4 worldPos = mul(_Object2World, v.vertex);
               
                o.normal = normalize(mul(_Object2World, v.normal));
                o.worldPos = worldPos;
                o.pos = mul(UNITY_MATRIX_VP, worldPos);
                o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
               
                return o;
            }
           
            fixed4 frag (v2f i) : SV_Target
            {
                float3 lightDir = normalize(WorldSpaceLightDir(i.worldPos));
                float3 viewDir = normalize(_WorldSpaceCameraPos - i.worldPos);
                float3 halfDir = normalize(lightDir + viewDir);
                float3 diffuse = tex2D(_MainTex, i.uv) * max(0, dot(i.normal, lightDir));
                float3 specular = _LightColor0.rgb * pow(max(0, dot(i.normal, halfDir)), _Shiness);
                float4 finalCol = float4(diffuse + specular + UNITY_LIGHTMODEL_AMBIENT, 1.0);
   
                return finalCol;
            }

最后我在场景中放了 2.0w 根草, 随机摆动 draw call 1, 25帧
使用Terrain 的 Grass Brush 2000个草,就已经在 2.5帧了
grass

Unity3D 中的贴花效果

这周研究一下,以前从 Stage3D 时代就想做的效果 -> 贴花

具体是怎样的呢

decay3

就是可以贴合模型全新纹理,差不多是这样
于是我做了个 动态贴花插件,这样美术童鞋在做场景的时候就比较直观咯

decayCircle

具体应用的美术场景,可以看看这个图
decay1

decay2

贴花做法其实就是复制要贴花模型的某一部分三角形,然后绘制新的纹理
decay4

如何截取三角形呢

继续阅读“Unity3D 中的贴花效果”

半色调抖动与近景透明


Dithering4

话说,上个月神秘海域4 出了开发者日志, 其中的半色调近景透明技术让我非常感兴趣, 毕竟非常多游戏要用到这个功能, 比如很多RPG游戏,近景的墙壁如果遮挡住主角,就会半透明。 而且半透明又是很消耗性能的,这篇日志也提到使用半色调技术是因为性能考虑。

开发者日志地址 : http://www.paopaoche.net/tv/99983.html

之前一直没空,在研究了2天半色调技术后,终于渲染出了我的半色调皮卡丘!!
Dithering

之后,上周看 火猫tv 的 dota2 马尼拉比赛直播的时候,发现 dota2的新地图也用到了类似的技术, 如图中的柱子 😀
我想估计这个技术应该会慢慢铺开,不过玩家能不能马上接受这种像素风的半透明效果就另说咯。

Dithering2Dithering3

— 未完待续, 周末有空的话, 会补充 贝尔矩阵的求解过程,可以自己计算任意 偶次方长度的矩阵。

Unity3d ddx ddy 法线

最近摸到一个很神奇的API -> DDX, DDY (DX) 或者 FDX, FDY (Opengl)

ddxddy normal

三角面片这么明显的法线有木有

在Nvidia 文档说, ddx/ddy 是求一个近似偏导函数, 以对齐屏幕分辨率的值进行取值

看了好几遍,不懂,然后仔细一想一阶求导不就是斜率嘛, 那么斜率是什么呢,就是平面向量啊。
于是测试了 ddx(worldSpaceVertex.xyz) ddy(worldSpaceVertex.xyz) 可以求出 ddx[(x,x) – (x+1,x)] , ddy[ (y,y) – (y-y)] 即隔壁像素所在三角形和当前像素的斜率差,或者说当前像素到隔壁像素的斜率

x轴 斜率表示前进方向向量, 和 y 轴斜率表示右手方向向量,就可以求 三角面的法线
normalize(ddx) cross normalize(ddy) = normal;
normal = normalize(normal);

这个时候,如果直接输出fixed4(normal,1.0) 就是这样
ddxddy normal fragment

继续阅读“Unity3d ddx ddy 法线”

Unity3d Compute Shader

=。= 准备开始花1个小时探讨这个复杂的 Compute Shader的, 结果从家里拷贝做的 Demo 在女朋友的小霸王笔记本上运行不起来。。只能明天回家在写了。。

就是这个破显卡 🙁 Intel HD Graphics 3000

—–

I’m back…

话说, Compute Shader 能做什么呢,可以把大量的并行计算丢到GPU去计算,因为GPU并行计算的能力爆表
举例来说呢
1.大规模粒子特效,计算粒子的位置,大小,颜色等等(当然传统粒子也可以做到这点,通过传入时间值和带有时间的公式来计算位置,但是Compute Shader 可以实现带有逻辑更复杂的效果, 而且编码更加简单)
2.烟雾,液体的模拟
3.可以做贪食蛇 =.= 像这样
ComputeSnake

继续阅读“Unity3d Compute Shader”

Unity3D 中的高度雾

fog
图中有2个效果, 分别是 HDR(做法在这里uniy3d-hdr_bloom/, 高度5的白色高度雾
不过除了雾以外,其他都不重要.

unity3d 一直都有一个距离雾,也可以说是深度雾,随着物体的远近慢慢渐变颜色,设置在 Window->Lightning->Fog(Unity 5.x)

这次来实现一个u3d中没有的,从低到高,而不是从远到近的雾效 – 高度雾。

之前做这个效果之前,有查阅些资料,有看到某外国的大大做了个类似的效果,地址在这里 altitude-fog
我们将要做的效果和这个差不多,但是区别在于,老外的做法是需要场景中的每个物体都添加一个雾效材质,这个雾效Shader是判断物件顶点Y轴在世界坐标系中的位置,然后 (FogEnd – 物体Y) / (FogEnd – FogStart) 算出一个在Y轴方向的雾效颜色比例,最后差值一下。

继续阅读“Unity3D 中的高度雾”

Unity3D Geomerty Shader

Geomerty Shader 是 SM4.0 Directx 9.0c 中引用的新技术, 它的位置位于 Vertex Shader 和 Fragment Shader 之间, 可以对一组(多个)顶点进行编程

Geometry Shader 可以自定义输出方式
PointStream
LineStream
TriangleStream
分别是 点,线,面
这样如果想做线框模式渲染,就非常的简单

上个线框模式图
LineStream

继续阅读“Unity3D Geomerty Shader”

Unity3d 中的 HDR_BLOOM

虽然u3d标准资源包自带这货,但是我就喜欢重复造轮子,你奈我何

unity3d_hdr_bloom

简单来说 hdr_bloom 就3个Shader
第一个是shader, 筛选出像素亮度
第二个shader, 对像素进行模糊
第三个shader, 合并原始纹理 + 模糊亮度的纹理

第一个Shader
筛选亮度的算法

float brightness = col.r * 0.299 + col.g * 0.587 + col.b * 0.114;

之后我们给 Shader 一个 uniform 参数,作为亮度的调节参数即可

之后,为了让亮度周围出现光晕,我们将亮度纹理绘制在一张特别小的纹理上,然后再将这张小纹理进行拉伸,使其出现像素马赛克效果,这样处理后,迈赛克的亮度部分就会比原始纹理的明亮部分范围更大了,初步的光晕范围就出来了。
但是这部分光晕因为是马赛克,于是要将其进行模糊处理

绘制到缩小纹理再拉伸的效果是这样的

unity3d_hdr_bloom_2

继续阅读“Unity3d 中的 HDR_BLOOM”

Unity3D 中的 X-Ray 透视效果

unity_xray

感觉是第三次写Xray了,最早是 stage3d, 然后是 havok, 现在是u3d… 真是闲的蛋疼。。。
不过u3d 写shader 真是比 havok 方便多了, 比如混合模式,深度检测方式都可以直接和 shader一起写,而havok 中还要去shader外部配置。。

直接上完整shader好了,渲染2次,1次深度测试以小于缓冲区的深度通过,绘制透视部分, 第二次正常渲染

继续阅读“Unity3D 中的 X-Ray 透视效果”

浅谈 Unity3D 的 RenderQueue

突然发现换了阿里云的空间就支持 wp的 中文链接了,好赞。。

言归正传,今天做了一个 光晕的效果, 参考的是Nehe 的Opengl教程, 以前一直没做过这个东西就有点好奇,做完后,发现效果特别赞,又简单,但是遇到了 RenderQueue 的一些bug,记录一下。

unity3d_overlay2

有人肯定会说Unity3d 自身可以创建 LensFlare 效果,为什么还要自己搞,我看了下,貌似 LensFlare必须绑定到 Light 上才有效果,而且准备素材的时候很麻烦,简单的黑白图调色都不行,还是自己写吧。

再说说 Nehe教程中判断 某点 是否在视野内, 是通过获取相机的视椎体,然后监测某点是否在视椎体的6个平面内。。。 感觉这个真麻烦,直接将 点 通过 mvp 矩阵转换到屏幕空间,然后判断该点坐标是否 x,y > 0 && x,y < 1 即可。 好吧,又跑题了。。。 u3d_overlay_1

如图,编写了一个Shader, RenderQue=”Overlay” ZWrite Off ZTest Off
发现在场景有其他 GameObject 的地方,图片都能正确的挡住它们,但是当背景为天空盒的时候,确被天空盒挡住了, 根据常识理解这不应该, 天空盒应该是在实体层渲染的, 不应该会挡住, 然后在 Shader 中就算改成 Overlay+99999 也是毫无效果。。。

继续阅读“浅谈 Unity3D 的 RenderQueue”