# 如何在Unity中实现黑客帝国数字雨效果

Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
2020-11-15 •

# 如何做到演示效果

## 2D的效果

### 文字的随机变化

``````
// Each #kernel tells which function to compile; you can have many kernels
#pragma kernel Generate_White_Noise

// The below macro is used to get a random number which varies across different generations.
#define rnd(seed, constant)  wang_rnd(seed +triple32(_session_rand_seed) * constant)

uint triple32(uint x)
{
x ^= x >> 17;
x ^= x >> 11;
x *= 0xac4c1b51U;
x ^= x >> 15;
x *= 0x31848babU;
x ^= x >> 14;
return x;
}

float wang_rnd(uint seed)
{
uint rndint = triple32(seed);
return ((float)rndint) / float(0xFFFFFFFF);  // 0xFFFFFFFF is max unsigned integer in hexa decimal
}

// Create a RenderTexture with enableRandomWrite flag and set it
// with cs.SetTexture
RWTexture2D<float4> _white_noise;
uint                _session_rand_seed;

#define image_dimension 512

[numthreads(8,8,1)] // 16 in 16 image.
{

uint  pixel_unique_id     = id.x + id.y * image_dimension;
float rand_x              = rnd(pixel_unique_id, 1);
float rand_y              = rnd(pixel_unique_id, 861);
_white_noise[id.xy] = float4(rand_x, rand_y, 0.0, 0.0);

}

``````

``````
{
{
Tags { "RenderType"="Opaque" }
LOD 100

Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag

#include "UnityCG.cginc"

struct appdata
{
float4 vertex : POSITION;
float2 uv     : TEXCOORD0;
};

struct v2f
{
float2 uv     : TEXCOORD0;
float4 vertex : SV_POSITION;
};

uint      _screen_width;
uint      _screen_height;

sampler2D _white_noise;
sampler2D _font_texture;

v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv     = v.uv;

return o;
}

float text(float2 coord)
{
float2 uv    = frac (coord.xy/ 16.);  // 获取当前block的uv
float2 block = floor(coord.xy/ 16.);  // 获取当前block的ID. 左下角是(0,0),右上角是(15,15)
uv = uv * 0.7 + .1;  // 做点缩放让字符更大

float2 rand  = tex2D(_white_noise,    // 从变化的白噪声贴图中获取随机值
block.xy/float2(512.,512.)).xy;       // 512 是白噪声贴图的宽度. 除以宽度让每个block对应噪声贴图的一个像素

rand  = floor(rand*16.);              // 每个随机值被用于在16列的font_texture中采样
uv   += rand;   // 让uv做随机偏移

uv   *= 0.0625;   // 将uv从0-16. 映射成0到1，以便从font_texture中采样
uv.x  = -uv.x;
return tex2D(_font_texture, uv).r;
}

#define scale 0.6
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = float4(0.,0.,0.,1.);
col.xyz = text(i.uv * float2(_screen_width, _screen_height)*scale);
return col;
}
ENDCG
}
}
}

``````

### 下雨的矩形列

``````
float3 rain(float2 fragCoord)
{
fragCoord.x  = floor(fragCoord.x/ 16.);  // 得到列号
float offset = sin (fragCoord.x*15.);    // 每一列雨柱需要有不同的起点，对列号取sin值作为偏移
float speed  = cos (fragCoord.x*3.)*.15 + .35; // 列号取cos值得到不同的速度.加上0.35保证是正数
float y      = frac((fragCoord.y / _screen_height)  // 这一行让y映射成0到1
+ _Time.y * speed + offset);    // 给y加上不同的速度和偏移

return float3(.1, 1., .35) / (y*20.);               // y值越大越暗
}

#define scale 0.6
fixed4 frag (v2f i) : SV_Target
{
fixed4 col     = float4(0.,0.,0.,1.);
col.xyz = rain(i.uv * float2(_screen_width, _screen_height)*scale);
return col;
}

``````

``````fixed4 frag (v2f i) : SV_Target
{
fixed4 col     = float4(0.,0.,0.,1.);
col.xyz = text(i.uv * float2(_screen_width, _screen_height)*scale)*rain(i.uv * float2(_screen_width, _screen_height)*scale);
return col;
}
``````

## 应用到场景中

``````
fixed4 frag (v2f i) : SV_Target
{
fixed4 col      = float4(0.,0.,0.,1.);
float3 colFront = MatrixEffect(i.worldPos.xy + sin(i.worldPos.zz));
float3 colSide  = MatrixEffect(i.worldPos.zy + sin(i.worldPos.xx));
float3 colTop   = MatrixEffect(i.worldPos.xz + sin(i.worldPos.yy));

float3 blendWeight  = pow(normalize(abs(i.normal)), sharpness);
blendWeight /= (blendWeight.x+ blendWeight.y+ blendWeight.z);
col.xyz      = colFront * blendWeight.z +
colSide  * blendWeight.x +
colTop   * blendWeight.y;

float distance_to_center = distance(i.worldPos.xyz, _Global_Effect_center.xyz);
float control_value      = saturate(_Global_Transition_value);
if (control_value * 60.0f < distance_to_center) col = col * 0.0f;

float2 screenPos = i.screenPos.xy / i.screenPos.w;
col      *= split_from_midle(screenPos.x, _Global_Transition_value, 0.0f);
col       = min(1.5,col);
return col;
}

``````

# 资源

https://github.com/IRCSS/MatrixVFX

https://www.ronja-tutorials.com/2018/05/11/triplanar-mapping.html