https://zhuanlan.zhihu.com/p/27966138

ShadowGun虽然是2011年的移动平台的游戏demo,但是里面的很多优化技巧到现在来看都是很值得学习的,毕竟是上过西瓜大会的。

网上现存的两份代码一个是shadow gun sample level,一个游戏场景,没法玩,只有一个摄像机动画,asset store上已经找不到了,另外一个是Shadowgun: Deadzone GM's Kit,带服务器,可以玩,asset store上还可以下载到。

下面就通过阅读demo中的代码来一起学习下。

飘动的旗帜

用的就是GPUGems里面的技术Vegetation Procedural Animation and Shading in Crysis,基本原理就是在mesh的顶点色中刷入权重,利用GPU顶点动画来模拟布料被风吹的效果。

在maya里看下mash的顶点色

Shader里面

输入的参数

Properties {_MainTex ("Base (RGB) Gloss (A)", 2D) = "white" {}//刮风的方向(世界坐标系下)_Wind("Wind params",Vector) = (1,1,1,1)//风的频率_WindEdgeFlutter("Wind edge fultter factor", float) = 0.5//风的频率的缩放_WindEdgeFlutterFreqScale("Wind edge fultter freq scale",float) = 0.5
}

_Time是Unity的一个内置 float4变量(t/20, t,t*2, t*3),专门用来做shader动画的,

看下vert里面的关键代码

//计算风的一些参数

//计算风的一些参数
float4  windParams  = float4(0,_WindEdgeFlutter,bendingFact.xx);
float2  windTime = _Time.y * float2(_WindEdgeFlutterFreqScale,1);
float4  mdlPos  = AnimateVertex2(v.vertex,v.normal,windParams,wind,windTime);
//mvp矩阵变换
o.pos   = mul(UNITY_MATRIX_MVP,mdlPos);

所以最核心的函数就是AnimateVertex2,看下它是怎么将模型里面的位置v.vertex转换到被风吹动的mdlPos。

inline float4 AnimateVertex2(float4 pos, float3 normal, float4 animParams,float4 wind,float2 time)
{   // animParams stored in color// animParams.x = branch phase// animParams.y = edge flutter factor// animParams.z = primary factor// animParams.w = secondary factorfloat fDetailAmp = 0.1f;float fBranchAmp = 0.3f;// Phases (object, vertex, branch)float fObjPhase = dot(_Object2World[3].xyz, 1);float fBranchPhase = fObjPhase + animParams.x;float fVtxPhase = dot(pos.xyz, animParams.y + fBranchPhase);// x is used for edges; y is used for branchesfloat2 vWavesIn = time.yy  + float2(fVtxPhase, fBranchPhase );// 1.975, 0.793, 0.375, 0.193 are good frequenciesfloat4 vWaves = (frac( vWavesIn.xxyy * float4(1.975, 0.793, 0.375, 0.193) ) * 2.0 - 1.0);vWaves = SmoothTriangleWave( vWaves );float2 vWavesSum = vWaves.xz + vWaves.yw;// Edge (xz) and branch bending (y)float3 bend = animParams.y * fDetailAmp * normal.xyz;bend.y = animParams.w * fBranchAmp;pos.xyz += ((vWavesSum.xyx * bend) + (wind.xyz * vWavesSum.y * animParams.w)) * wind.w; // Primary bending// Displace positionpos.xyz += animParams.z * wind.xyz;return pos;
}

关键思想是分层blend,首先计算了由主体到枝干再到顶点的震动系数,edge指旗子的边缘和自身xz方向的震动,branch指的是旗子整体的y方向的上下移动,接下来用了一些很trick的方法算出了一个float2的位移值,这个值就是顶点的位置,然后是将顶点的位移blend到主干上去,接着是主干上的位移blend到代码有点不讲道理,最后再把结果在风的方向上位移一定系数的距离。

UVAnimation

UVAnimation可以分为三个讲,滚滚浓烟,分层滚动天空盒,水面波纹

先说最简单的天空盒,就是两套UV速度,以不同的速率变化

o.uv = TRANSFORM_TEX(v.texcoord.xy,_MainTex) + frac(float2(_ScrollX, _ScrollY) * _Time);
o.uv2 = TRANSFORM_TEX(v.texcoord.xy,_DetailTex) + frac(float2(_Scroll2X, _Scroll2Y) * _Time);

最后又叠了一个颜色用来调节明暗关系。

fixed4 frag (v2f i) : COLOR
{fixed4 o;fixed4 tex = tex2D (_MainTex, i.uv);fixed4 tex2 = tex2D (_DetailTex, i.uv2);o = (tex * tex2) * i.color;return o;
}

晚上竟然又月亮。

滚滚浓烟

还是用了顶点色

看下Mesh

地下的红色,和烟的颜色叠起来,表现火焰的感觉。

贴图是两张不同的烟,用来表现层次感。

Shader和天空盒的基本一致。

不要觉得上面两个shader比较简单就没人用了,可以自习对比下cfm的运输船

“Volumetric” effects

所谓的体效果包括了Glow,Light Shafts,Fog Plane,Emissive BillBoards

为了模拟光从窗户投射进来,用了一个透明的片来表现

但不是单纯地半透明片,它是View distance based fade out,有下面两个特点

1) 随着视角的接近,透明的程度变大,离得特别远得时候,透明度也会变大

2) Mesh的位置会随着摄像机的位置变化,接近的时候有一种推开的感觉(减少overdraw)

减少overdraw的同时,规避了透明片插在摄像机里的问题。

都是vertex shader 干的

核心的代码

float3   viewPos = mul(UNITY_MATRIX_MV,v.vertex);
float       dist        = length(viewPos);
float       nfadeout    = saturate(dist / _FadeOutDistNear);
float       ffadeout    = 1 - saturate(max(dist - _FadeOutDistFar,0) * 0.2);

关于saturate函数:camps the specified value within the range of 0 to 1.

简单的说就是跟据面片到摄像机的距离计算出淡入淡出的系数。具体计算可以参考这里

面片涂了顶点色

在计算位置的时候会根据alpha值来计算推开的距离

float4 vpos = v.vertex;
vpos.xyz -=   v.normal * saturate(1 - nfadeout) * v.color.a * _ContractionAmount;

官方的说法是这样

Vertex color alpha determines which vertices are moveable and which are not (in our case, vertices with black alpha stays, those with white alpha moves).

Vertex normal determines the direction of movement.

The shader then evaluates distance to the viewer and handles surface fade in/out appropriately.

为了实现这些效果,渲染了一大推的半透明物体,在移动平台上,会引起严重的overdraw。为了解决overdraw的问题,做了下面几点

1. 使用最简单的fragmentshader,基本上就只采样一张贴图。如果插值的结果不太好就用密一些的网格。

2. 减少半透明的面积,这个在shader里面已经体现了

还有几个用来模拟灯的地方


特点是会随机闪动。

Mesh方面还是刷了顶点色

插在面片上的两个长条三角形目测是为了防止在摄像机靠近的时候被culling掉。

闪动的原理是在vertexshader中利用sin函数计算出一个随机系数乘以o.color.

具体的计算代码如下

float    fracTime    = fmod(time,_TimeOnDuration + _TimeOffDuration);
float   wave        = smoothstep(0,_TimeOnDuration * 0.25,fracTime)  * (1 - smoothstep(_TimeOnDuration * 0.75,_TimeOnDuration,fracTime));
float   noiseTime   = time *  (6.2831853f / _TimeOnDuration);
float   noise       = sin(noiseTime) * (0.5f * cos(noiseTime * 0.6366f + 56.7272f) + 0.5f);
float   noiseWave   = _NoiseAmount * noise + (1 - _NoiseAmount);wave = _NoiseAmount < 0.01f ? wave : noiseWave;
o.color = nfadeout * _Color * _Multiplier * wave;

具体的原理可以参考这一篇的分析

Billboarding

用来表现Glow的感觉,用了两个片来模拟

Shader方面,除了前面的View distance based fade out和闪动特性之外,有加了billboarding。

float3 centerOffs      = float3(float(0.5).xx - v.color.rg,0) * v.texcoord1.xyy;
float3  centerLocal = v.vertex.xyz + centerOffs.xyz;
float3  viewerLocal = mul(_World2Object,float4(_WorldSpaceCameraPos,1));
float3  localDir            = viewerLocal - centerLocal;localDir[1] = lerp(0,localDir[1],_VerticalBillboarding);float     localDirLength=length(localDir);
float3  rightLocal;
float3  upLocal;CalcOrthonormalBasis(localDir / localDirLength,rightLocal,upLocal);float        distScale       = CalcDistScale(localDirLength) * v.color.a;
float3  BBNormal        = rightLocal * v.normal.x + upLocal * v.normal.y;
float3  BBLocalPos  = centerLocal - (rightLocal * centerOffs.x + upLocal * centerOffs.y) + BBNormal * distScale;BBLocalPos += _ViewerOffset * localDir;

在Mesh里面的顶点色是这样的

大概的思路是通过顶点色构建一个坐标系,然后算顶点的偏移。具体的实现可以参考这里

角色阴影

实现方法是在脚下放一个面片,render queue是 transparent – 15,基本是再所有透明物体的之前渲染。然后在面片的vertex shader中算人的AO。

在计算AO的时候,将人近似成球体

Shader里面的代码也很简单

#if 1// quite suprisinly this looks better (probably there is some error in AO calculation)ao = 1 - saturate(SphereAO(_Sphere0,wrldPos,wrldNormal) + SphereAO(_Sphere1,wrldPos,wrldNormal) + SphereAO(_Sphere2,wrldPos,wrldNormal));
#elseao = 1 - max(max(SphereAO(_Sphere0,wrldPos,wrldNormal),SphereAO(_Sphere1,wrldPos,wrldNormal)),SphereAO(_Sphere2,wrldPos,wrldNormal));
#endifao = max(ao,1 - _Intensity) + (1 - v.color.r);o.color = fixed4(ao,ao,ao,ao);#endif

_Sphere0;_Sphere1;_Sphere2;是由外面传进来的三个近似球体的位置,关键看下SphereAO函数

float SphereAO(float4 sphere,float3 pos,float3 normal)
{float3 dir = sphere.xyz - pos;float   d   = length(dir);float    v;dir /= d;v = (sphere.w / d);return dot(normal,dir) * v * v;
}

就是跟据顶点的位置,法线以及球体的中心计算出一个ao值,具体原理参见大神的文章sphere ambient occlusion

参考

Rendering techniques and optimization challenges\

Fast Mobile Shaders\

ShadowGun: Optimizing for Mobile Sample Level\

sphere ambient occlusion\

【Unity Shaders】ShadowGun系列\

ShadowGun 的学习笔记 - GodRays

转载于:https://www.cnblogs.com/alps/p/8367291.html

ShadowGun 图形技术分析相关推荐

  1. 图形测试分析毫无头绪HarmonyOS图形栈测试技术帮你解决

    应用开发以后无法知道性能瓶颈的根因是什么?滑动卡顿.白块产生的原因是什么?代码写完之后,不知道如何优化让它表现地更好-- 我们发现,如今测试人员的需求已经不只是停留在应用层面的测试数据了,而是需要数据 ...

  2. Turing渲染着色器网格技术分析

    Turing渲染着色器网格技术分析 图灵体系结构通过使用 网格着色器 引入了一种新的可编程几何着色管道.新的着色器将计算编程模型引入到图形管道中,因为协同使用线程在芯片上直接生成紧凑网格( meshl ...

  3. NVIDIA FFmpeg 转码技术分析

    NVIDIA FFmpeg 转码技术分析 所有从 Kepler 一代开始的 NVIDIA GPUs 都支持完全加速的硬件视频编码,而从费米一代开始的所有 GPUs 都支持完全加速的硬件视频解码.截至 ...

  4. java超线程_超线程多核心下Java多线程编程技术分析

    在学习编程的过程中,我觉得不止要获得课本的知识,更多的是通过学习技术知识提高解决问题的能力,这样我们才能走在最前方,本文主要讲述超线程多核心下Java多线程编程技术分析,更多Java专业知识,广州疯狂 ...

  5. G少爷上证技术分析 8月31日

    Gieno  G少爷上证技术分析 8月31日 上周五仍然有一个向下(↓)の趋势,可以看到Slow Stochastic cross和MACD间の相互支撑~ 从整体上看,市场应该会在10月份左右试探38 ...

  6. 技术分析在于少而精,多则惑

    虽然是炒股心得,其实我很早就没有心得可谈了,能不断获得心得的时期是炒股的初级阶段,越往后你就越知道,股市就这么回事,哪有这么多心得可言. 但是我可以站在今天这个角度为大家梳理我从前的心得,哪些是炒股的 ...

  7. 期货商品技术分析(期货市场技术分析)

    什么是期货交易的技术分析? 期货技术分析是指以期货市场行为为研究对象,判断期货市场趋势,跟踪趋势的周期性变化而做出期货交易决策的方法总和. 自期货市场出现以来,人们就开始探索期货投资理论,形成了各种期 ...

  8. 《星际争霸2》【技术分析】星际争霸2的一些技术特性

    我一直认为后处理技术将会被越来越多的游戏所重用, 星际2的出炉在一定程度上验证了这点,把光照,阴影都移到后处理中去,这给场景渲染带来最大的灵活性,当然也带来了很多难以克服的问题.翻译这篇文章的主要目的 ...

  9. 可视化指标计算公式_股票交易数据可视化:技术分析常用指标绘制

    分析股票时,通常会观察市场软件上的股票图表,并使用图表的技术指标来确定未来股票价格变化的方向. 对于中小型股东,技术指标的分析似乎比基本面分析更为可靠,因为中小型股东很难解释该政策的实质是正面还是负面 ...

  10. 投资入门第 3 步:技术分析法(常用技术分析)

    1.OX图 1.绘制方法 OX图不是坐标表现价格的变化,而是通过小方格来表现价格的变化,其主要内容如下: ×=价格上升,O=价格下降.方格中的数字表示月份,图左边的数字表示单位价格. (1)当每次股票 ...

最新文章

  1. 最爱莫乎生命,其次是“你”
  2. 20145209 2016-2017-2 《Java程序设计》第8周学习总结
  3. GraphPad Prism9 将正态分布拟合至频率分布
  4. matplotlib新版本下的霍兰德人格分析雷达图
  5. 托管与非托管的混合编程问题
  6. php中的point用法,php strnatcmp()函数的用法总结
  7. 找出有序数组X和Y中所有元素的中位数(X,Y分别含n个元素)(算法导论第三版9.3-8)
  8. 人工智能时代号角已吹响 COMPUTEX如何凝聚AI这股力量?
  9. python算法与程序设计基础(第二版)第八章实训答案_Python算法与程序设计基础(第2版)...
  10. rust投递箱连接箱子_一种用于防盗的牛奶投递箱的制作方法
  11. 记一次服务器执行MySQL耗时问题
  12. Jakarta EE工作组正式成立
  13. Linux安装配置tomcat
  14. 在CMakeLists.txt文件中包含Eigen
  15. python自动化面试提问_Python自动化测试笔试面试题精选
  16. GeoServer的安装与数据服务发布
  17. ITIL4中的三个基本概念
  18. 计算机模拟求解流体力学方程,计算流体力学CFD及其应用
  19. 力扣刷题 DAY_73 回溯
  20. 基于proteus的计数器设计

热门文章

  1. 机器学习原理与实践(Python版)
  2. java 添加jbutton_在java中怎样在JLabel上添加JButton呢
  3. VAD自适应算法降噪控制毕业论文【matlab】
  4. mtk android高级工具,Android6.0 MTK6737 DCT 工具介绍 · Younix’s Studio
  5. 易优cms eyoucms登陆后台提示验证码错误
  6. fences 桌面整理,超赞,强烈推荐
  7. matlab gui伪色彩增强,基于Matlab GUI的医学灰度图像伪彩色增强判读系统
  8. 缓存框架 EhCache 使用 2
  9. 易语言dchp服务器,易语言模拟DHCP报文源码
  10. API接口文档编写--易文档