笔者使用的是 Unity 2018.2.0f2 + VS2017,建议读者使用与 Unity 2018 相近的版本,避免一些因为版本不一致而出现的问题。

   【Unity Shader】(三) ------ 光照模型原理及漫反射和高光反射的实现
   【Unity Shader】(四) ------ 纹理之法线纹理、单张纹理及遮罩纹理的实现
   【Unity Shader】(五) ------ 透明效果之半透明效果的实现及原理
   【Unity Shader】(六) ------ 复杂的光照(上)
   【Unity Shader】(七) ------ 复杂的光照(下)

 

前言

关于纹理,之前在 【Unity Shader】(四) ------ 纹理之法线纹理、单张纹理及遮罩纹理的实现 已经解释过相关原理,不过那些是属于低维纹理,在高级纹理中,也有许多纹理是我们常见到的或常用的,同时它们能够实现十分精美的效果。受限于篇幅,本文主要介绍立方体纹理及其相关应用,下一篇中将继续介绍其它高级纹理。

一. CubeMap

单单看标题,读者可能会不太明白我要说什么,不过说到天空盒,读者应该就懂了。我们来看一下官方对 CubeMap 的定义:

可以简单理解为:CubeMap 是六个假想面的集合,这六个面对应着一个正方体的 6 个面,每个面表示沿着世界空间下的轴向观察所得的图像。整体代表着环境的反射。 CubeMap 正常用于捕捉环境反射,而读者熟悉的天空盒子和环境映射也是常常使用这种纹理

1.2 对立方体纹理的采样

我们先说如何采样,在详细说如何制作 CubeMap ,对立方体纹理采样需要提供一个三维的纹理坐标。这个坐标会表示一个方向(世界空间下),这个方向矢量从中心出发,向外延伸,然后和 6 个面相交,然后就可以通过交点来采样得到结果

1.3 使用立方体纹理的优劣

纹理不止一种,立方体纹理常用也是有其理由的,我们可以看到其优劣

  • 实现起来简单快速(稍后会解释),效果好
  • 不实时,加入新光源或物体时需重新生成
  • 不能模拟多次反射

当然,在现实中,我们在项目中使用普通的立方体纹理作为天空盒子等操作效果已经足够好了。

1.4 立方体纹理的布局

虽然名字中带有立方体,但纹理布局并不全然是一个立方体的展开。事实上,Unity 支持着数种布局的立方体纹理,而且大多数情况下,Unity 会自动检测它们。下面列举几种常见的布局

常见的:

圆柱形布局(全景图常用)

球形布局

默认情况下,Unity 会查看纹理的宽高比以确定最合适的布局

1.5 如何制作立方体纹理

制作立方体纹理有三种方法,下面我们逐一介绍

1.5.1 CubeMap 特殊布局纹理制作

制作立方体纹理,最简单的方法就是在纹理图的 Inspector 面板中设置为 Cube,如图

这张纹理就变成了立方体纹理了,然后把这张纹理赋给一个材质便可。

官方也是推荐使用这种方法,因为这种方法可以

  • 压缩纹理数据
  • 修正边缘,光泽反射卷积(光滑反射)
  • 支持HDR

我们来欣赏一下HDR制作的天空盒子

1.5.2 使用 6 张纹理制作

使用 6 张独立不同的纹理手动创建立方体纹理也是常见的一种方法。创建一个材质,shader 设置为 Skybox / 6 Sided 。

要注意的是:

  • 每张纹理都是独立的,且要注意其对应的位置
  • Wrap Mode 设置为 Clamp ,防止在边界处出现不匹配的现象
  • Exposure 代表天空盒子的亮度

就可以实现以下的效果:

谨记:每张纹理都必须正确对应其对应的位置

1.5.3 脚本生成纹理

第三种方法比较特殊,前面两张方法都是使用定义好的贴图,制作出来的立方体纹理也是全局共享的。而第三种方法不使用准备好的图像,而是依赖于脚本,由物体在不同的位置生成。核心方法为 Camera.RenderToCubeMap ,这个方法可以从任意位置观察到的图像存储到 6 张图像中,从而创建当前位置的立方体纹理。我们可以在 Unity 官方脚本手册中找到其解释及用法。

当然需要注意的是:

  • Camera.RenderToCubeMap (Cubemap cubemap, int faceMask“静态” 的方法。当场景变化时,立方体纹理不会变化,从效果上看,类似 “烘焙”。
  • RenderToCubemap (RenderTexture cubemap, int faceMask) 是 “动态” 的方法,能够实时渲染,但同时也需要注意资源的消耗。

对于这种方法实现的立方体纹理,我不打算在这里赘述了,因为本文重点在后文,感兴趣的读者可以自行实现一下。

二. 光线反射

2.1 何为光线反射

反射是光现象中最为常见的一种,且遵循光的反射定律,即光射到一个界面时,其入射光线与反射光线成相同角度。光入射到不同介质的界面上会发生折射,如图

反射时会出现以下情况:

  • 反射线跟入射线和法线在同一平面
  • 反射线和入射线分居法线两侧,并且与界面法线的夹角(分别叫做入射角和反射角)相等
  • 反射角等于入射角

前文介绍了如何制作立方体纹理,现在我们需要用上它来实现一些效果。反射是光现象中最为常见的一种,而使用了反射效果的物体看起来就像在表面镀了一层金属膜一样。要模拟反射效果也是比较简单的,理论上只要使用入射光线的方向和表面法线方向计算出反射方向,再用反射方向对立方体纹理采样就行。现在我们来实现一下

2.2 反射的实现

I. 创建一个场景,天空盒使用在 1.5.1 或 1.5.2 中制作的立方体纹理;创建一个 Cube 和一个 Material,一个 shader,命名为 Reflection 。编辑 shader

II. 先定义 Properties 块

其中 _ReflectAmount 控制整体反射程度,_Cubemap 表示要输入的立方体纹理,用来存储反射结果。

III. 包含相关的头文件和声明与 Properties 块 相匹配的属性

其中,要注意的是,立方体纹理的类型为 samplerCUBE

IV. 定义输入输出结构体

在输出结构体中多定义了一个反射方向,所以 SHADOW_COORDS 中的插值寄存器变为 4

V. 定义顶点着色器

顶点着色器里面的操作我们之前已经说过很多次了,这里主要是多了一个计算反射方向的步骤,我们使用 reflect 函数,有关 reflect 函数我在  【Unity Shader】(三) ------ 光照模型原理及漫反射和高光反射的实现中已经介绍过了,读者可以翻看一下

VI. 定义片元着色器

场景中只有平行光,光照计算比较简单,这里不再赘述。而对立方体纹理采样,我们则是用了  texCUBE 函数,我们可以在MSDN上找到它的定义

在使用该函数时,我们也没有对  i.worldReflect 进行归一化,是因为这里的参数仅仅是作为一个方向变量(笔者测试过归一化的情况,结果一样)。

将所有计算结果混合得到最终颜色返回,再加上一个  FallBack "Reflective/VertexLit"  完成。

VII. 保存,回到 Unity 查看效果,以下是不同 _ReflectAmount 的反射效果

很抱歉的是 git 图录制的清晰度不够好,以下两图是 _ReflectAmount 为 1 时的效果

完整代码:

 1 Shader "Unity/01-Reflection" {
2 Properties {
3 _Color ("Color Tint", Color) = (1,1,1,1)
4 _ReflectColor("Reflection Color",Color) = (1,1,1,1)
5 _ReflectAmount("Reflect Amount",Range(0,1)) = 1
6 _Cubemap("Reflection Cubemap",Cube) = "_Skybox"{}
7 }
8 SubShader
9 {
10
11 Pass
12 {
13 Tags { "LightMode"="ForwardBase" }
14
15 CGPROGRAM
16 #pragma multi_compile_fwdbase
17 #pragma vertex vert
18 #pragma fragment frag
19 #include "Lighting.cginc"
20 #include "AutoLight.cginc"
21
22 fixed4 _Color;
23 fixed4 _ReflectColor;
24 float _ReflectAmount;
25 samplerCUBE _Cubemap;
26
27 struct a2v
28 {
29 float4 vertex : POSITION;
30 float3 normal : NORMAL;
31 };
32
33 struct v2f
34 {
35 float4 pos : SV_POSITION;
36 float3 worldnormal : TEXCOORD0;
37 float3 worldpos : TEXCOORD1;
38 float3 worldViewDir : TEXCOORD2;
39 float3 worldReflect : TEXCOORD3;
40 SHADOW_COORDS(4)
41 };
42
43 v2f vert(a2v v)
44 {
45 v2f o;
46 o.pos = UnityWorldToClipPos(v.vertex);
47 o.worldnormal = UnityObjectToWorldNormal(v.normal);
48 o.worldpos = mul(unity_ObjectToWorld,v.vertex).xyz;
49 o.worldViewDir = UnityWorldSpaceViewDir(o.worldpos);
50 o.worldReflect = reflect(-o.worldViewDir,o.worldnormal);
51 TRANSFER_SHADOW(o);
52 return o;
53 }
54
55 fixed4 frag(v2f i) : SV_Target
56 {
57 fixed3 worldnormal = normalize(i.worldnormal);
58 fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldpos));
59 fixed3 worldViewDir = normalize(i.worldViewDir);
60
61 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
62
63 fixed3 diffuse = _LightColor0.rgb * _Color.rgb * max(0,dot(worldnormal,worldLightDir));
64
65 fixed3 reflection = texCUBE(_Cubemap,i.worldReflect).rgb * _ReflectColor.rgb;
66 UNITY_LIGHT_ATTENUATION(atten,i,i.worldpos);
67 fixed3 color = ambient + lerp(diffuse ,reflection,_ReflectAmount) * atten;
68 return fixed4(color,1.0);
69
70 }
71 ENDCG
72 }
73
74
75 }
76 FallBack "Reflective/VertexLit"
77 }

至此,我们介绍完了反射的效果,接下来,我们来讨论光现象中的另一种常见的折射效果

三. 光线折射

3.1 何为光线折射

光从一种介质进入另一种具有不同折射率的介质,或者在同一种介质中折射率不同的部分运行时,由于波速的差异,使光的运行方向改变的现象就称为光的折射。而光在发生折射时入射角与折射角符合斯涅耳定律:

常见的折射率有

  • 真空:1
  • 水:1.3330
  • 玻璃:一般约为 1.5

如果读者遇到其它物质折射的情况,可自行查阅该物质的折射率。

当得到了折射方向之后,我们就可以使用它来对立方体纹理采样”,相信读者头脑中可能会浮现出这个想法,但这个想法事实上是不够严谨的。对于透明的物体,应该模拟两次折射才会更为准确,光线射入物体内部,光线从内部射出。然而要在实时渲染中模拟出第二种折射是很复杂且耗费资源的,并且模拟第一次折射得到效果在大多数情况下也是良好的,所以,通常来说,我们的确会执行这种不太严谨的想法,即只模拟第一次折射

3.2 实践

其实折射的 shader 代码和 反射的代码相差不大,所以我们进行和反射一样的操作,然后进行几处修改。下面列出这些值得注意的修改之处。

I. 在 Properties 块中添加一个属性 _RefractRatio,代表不同介质的透射比。比如光从空气射到水体,透射比约为 1 / 1.3;同理光从空气射到玻璃,透射比约为 1 / 1.5;

II. 定义与 Properties 块匹配的属性

III. 在顶点着色器中计算折射方向

我们使用的是 CG 函数 refract,找到它的定义如下

这里需要注意的是,根据定义我们可以得知,参数是 入射光线的方向向量,表面法线的方向向量,透射比,与 reflect 函数不同,这里明确指出需要方向向量,所以我们需要对这两个向量归一化

IV. 其它的代码基本只需要替换相应的变量名字就可以了,这里直接给出完整代码

 1 Shader "Unity/02-Refraction" {
2 Properties {
3 _Color ("Color Tint", Color) = (1,1,1,1)
4 _RefractColor("Refraction Color",Color) = (1,1,1,1)
5 _RefractAmount("Refract Amount",Range(0,1)) = 1
6 _RefractRatio("Refract Ratio",Range(0,1)) = 1
7 _Cubemap("Refraction Cubemap",Cube) = "_Skybox"{}
8 }
9 SubShader
10 {
11
12 Pass
13 {
14 Tags { "LightMode"="ForwardBase" }
15
16 CGPROGRAM
17 #pragma multi_compile_fwdbase
18 #pragma vertex vert
19 #pragma fragment frag
20 #include "Lighting.cginc"
21 #include "AutoLight.cginc"
22
23 fixed4 _Color;
24 fixed4 _RefractColor;
25 float _RefractAmount;
26 float _RefractRatio;
27 samplerCUBE _Cubemap;
28
29 struct a2v
30 {
31 float4 vertex : POSITION;
32 float3 normal : NORMAL;
33 };
34
35 struct v2f
36 {
37 float4 pos : SV_POSITION;
38 float3 worldnormal : TEXCOORD0;
39 float3 worldpos : TEXCOORD1;
40 float3 worldViewDir : TEXCOORD2;
41 float3 worldRefract : TEXCOORD3;
42 SHADOW_COORDS(4)
43 };
44
45 v2f vert(a2v v)
46 {
47 v2f o;
48 o.pos = UnityWorldToClipPos(v.vertex);
49 o.worldnormal = UnityObjectToWorldNormal(v.normal);
50 o.worldpos = mul(unity_ObjectToWorld,v.vertex).xyz;
51 o.worldViewDir = UnityWorldSpaceViewDir(o.worldpos);
52 o.worldRefract = refract(normalize(o.worldViewDir),normalize(o.worldnormal),_RefractRatio);
53 TRANSFER_SHADOW(o);
54 return o;
55 }
56
57 fixed4 frag(v2f i) : SV_Target
58 {
59 fixed3 worldnormal = normalize(i.worldnormal);
60 fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldpos));
61 fixed3 worldViewDir = normalize(i.worldViewDir);
62
63 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
64
65 fixed3 diffuse = _LightColor0.rgb * _Color.rgb * max(0,dot(worldnormal,worldLightDir));
66
67 fixed3 Refraction = texCUBE(_Cubemap,normalize(i.worldRefract)).rgb * _RefractColor.rgb;
68 UNITY_LIGHT_ATTENUATION(atten,i,i.worldpos);
69 fixed3 color = ambient + lerp(diffuse ,Refraction,_RefractAmount) * atten;
70 return fixed4(color,1.0);
71
72 }
73 ENDCG
74 }
75
76
77 }
78 FallBack "Reflective/VertexLit"
79 }

V.保存,回到 Unity 查看效果

不同透射比的折射效果:

由于 gif 图清晰度有限,所以这里做反射和折射的对比,更能看出效果

反射:

折射:

通过对比,我们可以看到图二中的光线似乎是被 “扭曲了” ,这正是光线的角度改变了,也正是我们要实现的折射效果

四. 菲涅耳反射

相信读者并不会对这个名字感到陌生,没错,在我们生活中,最最最为常见的菲涅耳反射现象无疑是水边。当你站在湖边或河边时,你能清晰地看到脚边的水边一切景象,而当你抬头看向远处水面时,却只能看到一片白光。

当光射到物体表面时,一部分发生反射,一部分进入物体内部,然后发生折射或反射。反射光和入射光存在一定的比例关系,而这个关系可以由菲涅耳等式计算。 而菲涅耳等式有两条应用广泛的近似等式:

Schlick 菲涅耳近似等式 :

                             

v 是视角方向,n 是表面法线,F0 是反射系数

Empricial 菲涅耳近似等式 :

bias,scale,power 是控制项

使用菲涅耳近似等式,我们可以模拟边界处的反射、折射/漫反射光强间的变化。特别是油漆,水面这种材质。本文只是介绍其原理及简单实现,在以后的学习中,我们将会利用它来制作一条有趣的河流或水面。

4.2 简单菲涅耳反射的实现

此处我们使用 Schlick 菲涅耳近似等式 来实现一个菲涅耳反射现象。与实现折射时相同,大部分的计算都是一样的,所以这里同样只提出值得注意的地方。

I. 定义 Properties 块

II. 定义相匹配变量

III. 计算反射方向

IV. 在片元着色器中计算菲涅耳反射,然后混合得到最终颜色

V. 完整代码:

 1 Shader "Unity/03-Fresne" {
2 Properties {
3 _Color ("Color Tint", Color) = (1,1,1,1)
4 _FresnelScale ("Fresnel Scale",Range(0,1)) = 0.5
5 _Cubemap("Refraction Cubemap",Cube) = "_Skybox"{}
6 }
7 SubShader
8 {
9
10 Pass
11 {
12 Tags { "LightMode"="ForwardBase" }
13
14 CGPROGRAM
15 #pragma multi_compile_fwdbase
16 #pragma vertex vert
17 #pragma fragment frag
18 #include "Lighting.cginc"
19 #include "AutoLight.cginc"
20
21 fixed4 _Color;
22 float _FresnelScale;
23 samplerCUBE _Cubemap;
24
25 struct a2v
26 {
27 float4 vertex : POSITION;
28 float3 normal : NORMAL;
29 };
30
31 struct v2f
32 {
33 float4 pos : SV_POSITION;
34 float3 worldnormal : TEXCOORD0;
35 float3 worldpos : TEXCOORD1;
36 float3 worldViewDir : TEXCOORD2;
37 float3 worldReflect : TEXCOORD3;
38 SHADOW_COORDS(4)
39 };
40
41 v2f vert(a2v v)
42 {
43 v2f o;
44 o.pos = UnityWorldToClipPos(v.vertex);
45 o.worldnormal = UnityObjectToWorldNormal(v.normal);
46 o.worldpos = mul(unity_ObjectToWorld,v.vertex).xyz;
47 o.worldViewDir = UnityWorldSpaceViewDir(o.worldpos);
48 o.worldReflect = reflect(-o.worldViewDir,o.worldnormal);
49 TRANSFER_SHADOW(o);
50 return o;
51 }
52
53 fixed4 frag(v2f i) : SV_Target
54 {
55 fixed3 worldnormal = normalize(i.worldnormal);
56 fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldpos));
57 fixed3 worldViewDir = normalize(i.worldViewDir);
58
59 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
60
61 fixed3 diffuse = _LightColor0.rgb * _Color.rgb * max(0,dot(worldnormal,worldLightDir));
62
63 fixed3 reflection = texCUBE(_Cubemap,i.worldReflect).rgb;
64
65 fixed3 fresnel = _FresnelScale + (1 - _FresnelScale) * pow(1 - dot(worldViewDir,worldnormal),5);
66
67 UNITY_LIGHT_ATTENUATION(atten,i,i.worldpos);
68
69 fixed3 color = ambient + lerp(diffuse ,reflection,saturate(fresnel)) * atten;
70
71 return fixed4(color,1.0);
72
73 }
74 ENDCG
75 }
76
77
78 }
79 FallBack "Reflective/VertexLit"
80 }

VI.查看效果

当 _FresnelScale 为 0 时,这时该物体就是一个具有边缘光照效果的漫反射物体

如果觉得图片效果不太明显,读者可以自行实现,感受一下。

五. 总结

对于立方体纹理,读者可能不一定会熟悉,但你一定熟悉天空盒,而立方体纹理正是天空盒和环境映射的实现的常用方法。同时,在场景中存在天空盒的情况下,物体对环境的采光正是本文所探讨的问题。无论是反射或是折射都是再通常不过的现象,所以我们也应该熟悉其实现。希望本文能对您有所帮助。

【Unity Shader】(八) ------ 高级纹理之立方体纹理及光线反射、折射的实现的更多相关文章

  1. Unity Shader入门精要学习笔记 - 第10章 高级纹理

    转载自 冯乐乐的 <Unity Shader入门精要> 立方体纹理 在图形学中,立方体纹理是环境映射的一种实现方法.环境映射可以模拟物体周围的环境,而使用了环境映射的物体可以看起来像镀了层 ...

  2. 【Unity Shader】(九) ------ 高级纹理之渲染纹理及镜子与玻璃效果的实现

    笔者使用的是 Unity 2018.2.0f2 + VS2017,建议读者使用与 Unity 2018 相近的版本,避免一些因为版本不一致而出现的问题. [Unity Shader](三) ----- ...

  3. 【Unity Shader】(十) ------ UV动画原理及简易实现

    笔者使用的是 Unity 2018.2.0f2 + VS2017,建议读者使用与 Unity 2018 相近的版本,避免一些因为版本不一致而出现的问题. [Unity Shader](三) ----- ...

  4. Unity Shader入门精要读书笔记(一)序章

    本系列的博文是笔者读<Unity Shader入门精要>的读书笔记,这本书的章节框架是: 第一章:着手准备. 第二章:GPU流水线. 第三章:Shader基本语法. 第四章:Shader数 ...

  5. Unity Shader入门教程(一)

    参考文献:http://www.360doc.com/content/13/0923/15/12282510_316492286.shtml Unity Shader是着色器,将纹理.网格信息输入,得 ...

  6. Unity Shader入门精要学习笔记 - 第13章 使用深度和法线纹理

    线纹理的代码非常简单,但是我们有必要在这之前首先了解它们背后的实现原理. 深度纹理实际上就是一张渲染纹理,只不过它里面存储的像素值不是颜色值而是一个高精度的深度值.由于被存储在一张纹理中,深度纹理里的 ...

  7. Unity Shader入门精要学习笔记 - 第7章 基础纹理

    转自 冯乐乐的 <Unity Shader 入门精要> 纹理最初的目的就是使用一张图片来控制模型的外观.使用纹理映射技术,我们可以把一张图“黏”在模型表面,逐纹素地控制模型的颜色. 在美术 ...

  8. Unity Shader 基础(4) 由深度纹理重建坐标

    在PostImage中经常会用到物体本身的位置信息,但是Image Effect自身是不包含这些信息的,因为屏幕后处其实是使用特定的材质渲染一个刚好填满屏幕的四边形面片(四个角对应近剪裁面的四个角). ...

  9. Unity Shader 基础(3) 获取深度纹理

    Unity提供了很多Image Effect效果,包含Global Fog.DOF.Boom.Blur.Edge Detection等等,这些效果里面都会使用到摄像机深度或者根据深度还原世界坐标实现各 ...

随机推荐

  1. 用windows自带的fsutil修改稀疏文件大小成功,但文件内容似乎丢失

    fsutil sparse setflag. fsutil sparse setrange 10M对应字节,1G对应字节.. 看文件属性,实际尺寸是小了,但内容似乎也丢了..因为自己把该文件做成虚拟盘 ...

  2. 多个Firefox共存&&彻底关闭自动更新

    安装 0x001 下载好要安装Firefox的版本 可到Firefox官方仓库下载 https://ftp.mozilla.org/pub/firefox/releases/ 我下载的是42和56版 ...

  3. Maven实战(八)pom.xml简介

    目录 pom作为项目对象模型.通过xml表示maven项目,使用pom.xml来实现.主要描述了项目:包括配置文件.开发者需要遵循的规则.缺陷管理系统.组织和licenses.项目的url.项目的依赖 ...

  4. jstorm知识整理

    最近在做一个jstorm的程序.我的jstorm程序消费一个kafka主题,根据数据逻辑判断需要往下游哪几个kafka主题的生产者发送. 1.bolt的execute(Tuple input)方法每次 ...

  5. [SHOI2008]小约翰的游戏

    题目 不会,抄论文 这是一个非常牛逼的东西,叫做\(anti\)博弈,就是进行最后一次操作的人输 我们考虑一下这道题 显然如果石子个数都是\(1\),那么有奇数堆石子先手必败,有偶数堆石子先手必胜 如 ...

  6. PHP常用功能块_错误和异常处理 — php(32)

    一.错误和异常处理 1.1 错误类型和基本的调试方法PHP程序的错误发生一般归属于下列三个领域: 语法错误:语法错误最常见,并且也容易修复.如:代码中遗漏一个分号.这类错误会阻止脚本的执行. 运行时错 ...

  7. 10、Android--技巧

    10.1.全局获取Context的技巧 在实践中有很多的地方都可以使用到Context 弹出Toast的时候需要,启动活动的时候需要.发送广播的时候需要. 操作数据库的时候需要.使用通知的时候需要.. ...

  8. PAT02-线性结构3 Reversing Linked List

    题目:https://pintia.cn/problem-sets/1010070491934568448/problems/1037889290772254722 先是看了牛客(https://ww ...

  9. c模拟 页式管理页面置换算法之FIFO

    写的操作系统作业.... 放上来给需要的小伙伴 需要注意的地方: 1.该算法只涉及单进程 2.只是用c模拟FIFO的思想 FIFO思想:选择在内存中存活时间最久的页面淘汰 关于该算法我的理解: 一个进 ...

  10. CentOS 安装第三方yum源

    yum install wget #安装下载工具 wget http://www.atomicorp.com/installers/atomic #下载 sh ./atomic #安装 yum che ...