<?xml version="1.0" encoding="UTF-8"?>
  <feed xmlns="http://www.w3.org/2005/Atom">
  <title type="html"><![CDATA[H31Home家园]]></title>
  <subtitle type="html"><![CDATA[In 2008,H31Home Will Do The Best!   创造机会的人是勇者；等待机会的人是愚者]]></subtitle>
  <id>http://h31home.com/</id> 
  <link rel="alternate" type="text/html" href="http://h31home.com/" /> 
  <link rel="self" type="application/atom+xml" href="http://h31home.com/atom.asp" /> 
  <generator uri="http://h31home.com/" version="2.0">H31Home</generator> 
  <updated>2008-7-6 8:36:26</updated> 

  <entry>

	  <title type="html"><![CDATA[.NET软件保护与破解浅析[转]]]></title>
	  <author>
		 <name>admin</name>
		 <uri>http://h31home.com/h312005/blogview.asp?ID=980</uri>
		 <email></email>
	  </author>
	  <category term="" scheme="http://h31home.com/h312005/blogview.asp?ID=980" label="VS and C#" /> 
	  <updated>2008-6-21 10:53:07</updated>

	  <published>2008-6-21 10:53:07</published>
		  <summary type="html"><![CDATA[&lt;P&gt;.NET软件保护与破解浅析&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;网上很少看到有关.NET软件保护与破解的文章，刚好分析了几款有一定代表性的.NET软件，于是便将他们的保护措施和如何破解方法记录下来，以便和大家交流。在开始之前，首先申明：本文中反编译和破解的软件只是为学习和研究的目的，请勿非法使用。&nbsp;&lt;/P&gt;&lt;P&gt;&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;.NET平台下的软件(exe,dll文件)叫做程序集。它使用一种扩展的PE格式文件来保存。.NET程序集与以往的应用程序不同，它保存的是Microsoft中间语言指令(MSIL)和元数据(Metadata)，而不是机器指令和数据。.NET程序集在运行的时候才会动态将Microsoft中间语言编译成机器指令执行。所以我们不能简单的使用反汇编来解读程序逻辑。初学者明白这点很重要。不过幸运的是，.NET程序集是一种自描述的组件，可以用它自描述的特性反编译出高级程序代码(如c#,vb.net)，这比汇编代码更容易读懂得多。即使不反编译成高级程序代码，Microsoft中间语言本身也是一种抽象、基于堆栈的面向对象伪汇编语言。它本身也比汇编代码更容易读懂。在代码易阅读这点上，.NET程序更容易遭到破解。不过，有矛必有盾，现在有很多产品都可以混淆.NET代码，使得反编译出来后的结果也同样没有可读性。&lt;/P&gt;&lt;P&gt;&nbsp;&nbsp;&nbsp;&nbsp;.NET程序集与以往的应用程序另一个不同点在于它可以使用强名称签名来防止自身被篡改。使用强名称签名的程序集包含公钥和数字签名信息。.NET在执行具有强名称的程序集前会对它进行安全检查，以防止它被非法篡改。这一点很厉害，它限制了我们通过修改程序代码（爆破）来破解程序的方法。&lt;/P&gt;&lt;P&gt;&nbsp;&nbsp;&nbsp;&nbsp;.NET平台还提供了很多安全相关的类库，利用这些类库可以写成很强壮的注册算法（如使用RSA对注册文件签名，只有使用私钥才能产生正确的注册码）。这些算法破解者很难破解。&lt;/P&gt;&lt;P&gt;&nbsp;&nbsp;&nbsp;&nbsp;另外，现在还出现了很多其他的保护措施，如流程混淆，元数据加密，加密壳，虚拟机技术，编译为本地代码等保护手段。综合使用这些保护手段，会使破解难道大幅度提高。&lt;/P&gt;&lt;P&gt;&nbsp;&nbsp;&nbsp;&nbsp;软件破解一般有两种方式。一种方式为不对软件做出修改，只是分析软件注册算法，根据注册算法写出生成正确注册码的注册机程序完成注册过程。第二种方式需要对软件逻辑作出修改，使软件正常判断注册逻辑失效，总是认为软件已经注册成功。这种方式就是通常说的“爆破”。由于第二种方法需要修改软件逻辑，不能保证软件修改后的行为和原来一样，故一般只有在第一种方式尝试失败后才使用第二种方式。&lt;/P&gt;&lt;P&gt;&nbsp;&nbsp;&nbsp;&nbsp;下面，我将通过对两款软件的分析来讲解.NET平台下软件的保护措施和破解方法。&lt;/P&gt;&lt;P&gt;准备的工具：&nbsp;&lt;BR&gt;1，Reflector&nbsp;&lt;A&nbsp;href=&quot;http://www.aisto.com/roeder/dotnet/&quot;&gt;http://www.aisto.com/roeder/dotnet/&lt;/A&gt;&nbsp;&lt;BR&gt;.NET平台下极好的反编译工具。&nbsp;&lt;BR&gt;2，ManagedSpy&nbsp;&lt;BR&gt;可以查看.NET代码写的程序窗口。&nbsp;&nbsp;&lt;/P&gt;&lt;P&gt;实例一，GatherBird&nbsp;Copy&nbsp;Large&nbsp;Files&nbsp;2.4&lt;/P&gt;&lt;P&gt;&nbsp;&nbsp;&nbsp;&nbsp;这是个拷贝大文件的工具，它的注册算法不强，可以很容易写出注册机。我们可以通过破解这个软件来了解破解.NET软件的一般流程。&lt;/P&gt;&lt;P&gt;&nbsp;&nbsp;&nbsp;&nbsp;首先运行Copy&nbsp;Large&nbsp;Files&nbsp;2.4&nbsp;(Windows&nbsp;.Net&nbsp;2.0&nbsp;version)&nbsp;。发现界面有个“Register”的按钮。查看功能说明书，知道这是没有注册的标志，注册了界面上就不会多这个按钮。点击这个按钮，就弹出注册框，窗口标题为“Register”。然后运行ManagedSpy，可以看出DotNetCopyLargeFiles程序有两个窗体，一个“Form1_class”，另一个“RFLib_Forms_Registration_class”。很显然，第二个就是我们弹出的注册框。&lt;/P&gt;&lt;P&gt;&nbsp;&nbsp;&nbsp;&nbsp;运行Reflactor，将DotNetCopyLargeFiles.exe拖进Reflactor，查找“RFLib_Forms_Registration_class”就是反编译好的注册框C#或VB源代码。读懂代码。发现在点击“Register”按钮后会触发“button3_Click”函数，在这个函数中将文本框中输入的注册码保存到了registerstring属性中。使用Reflactor查找哪些地方在调用registerstring属性。发现在Form1_class中点击“Register”按钮后将这个registerstring属性保持在Form1_class中的RegistryString字段中。用Reflactor查找谁在使用RegistryString，发现在Form1_class的OnTimerTick方法中将RegistryString传给RSF1_class.SF40Helper方法检查。&lt;/P&gt;&lt;P&gt;&nbsp;&nbsp;&nbsp;&nbsp;读懂RSF1_class，这就注册算法所在的类。读代码的时候，可以借助Reflactor反编译成源文件，然后使用VS2005或VS2008编译后动态调试。这样，可以分析SF4就是注册码产出的方法，根据这个方法，我们不难写出注册机算法。下面就是我写的一个注册机算法。当然，你也可以自己写，方法中用到的其他方法和类都可以从Reflector反编译的源代码中得到。&lt;/P&gt;&lt;P&gt;GenerateKey&nbsp;&lt;BR&gt;1public&nbsp;static&nbsp;string&nbsp;GenerateKey(byte[]&nbsp;exename)&nbsp;&nbsp;&lt;BR&gt;2{&nbsp;&nbsp;&lt;BR&gt;3&nbsp;&nbsp;&nbsp;&nbsp;byte[]&nbsp;buffer&nbsp;=&nbsp;new&nbsp;byte[0x5f];&nbsp;&nbsp;&lt;BR&gt;4&nbsp;&nbsp;&nbsp;&nbsp;byte[]&nbsp;row&nbsp;=&nbsp;new&nbsp;byte[0x800];&nbsp;&nbsp;&lt;BR&gt;5&nbsp;&nbsp;&nbsp;&nbsp;DotNetRandom_class&nbsp;random&nbsp;=&nbsp;new&nbsp;DotNetRandom_class();&nbsp;&nbsp;&lt;BR&gt;6&nbsp;&nbsp;&nbsp;&nbsp;StringBuilder&nbsp;key&nbsp;=&nbsp;new&nbsp;StringBuilder();&nbsp;&nbsp;&lt;BR&gt;7&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(!SF20())&nbsp;&nbsp;&lt;BR&gt;8&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&lt;BR&gt;9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;random.RRandomSeed2(exename);&nbsp;&nbsp;&lt;BR&gt;10&nbsp;&lt;BR&gt;11&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;0x5f;&nbsp;i++)&nbsp;&nbsp;&lt;BR&gt;12&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&lt;BR&gt;13&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buffer[i]&nbsp;=&nbsp;(byte)(i&nbsp;+&nbsp;0x20);&nbsp;&nbsp;&lt;BR&gt;14&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;BR&gt;15&nbsp;&lt;BR&gt;16&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SF2(row,&nbsp;ref&nbsp;random);&nbsp;&nbsp;&lt;BR&gt;17&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Random&nbsp;r&nbsp;=&nbsp;new&nbsp;Random();&nbsp;&nbsp;&lt;BR&gt;18&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;numberIndex&nbsp;=&nbsp;GetNumberIndex(buffer,(byte)r.Next(50,57));&nbsp;&nbsp;&lt;BR&gt;19&nbsp;&lt;BR&gt;20&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;6;&nbsp;i&nbsp;++)&nbsp;&nbsp;&lt;BR&gt;21&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&lt;BR&gt;22&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;key.Append(&nbsp;Convert.ToChar(row[numberIndex&nbsp;*&nbsp;2]));&nbsp;&nbsp;&lt;BR&gt;23&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;key.Append(Convert.ToChar(&nbsp;row[numberIndex&nbsp;*&nbsp;2+1]));&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;BR&gt;24&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(int&nbsp;j&nbsp;=&nbsp;0;&nbsp;j&nbsp;&lt;&nbsp;buffer[numberIndex];&nbsp;j++)&nbsp;&nbsp;&lt;BR&gt;25&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&lt;BR&gt;26&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;random.RRandomUnsignedLong();&nbsp;&nbsp;&lt;BR&gt;27&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&lt;BR&gt;28&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SF2b(row,&nbsp;ref&nbsp;random);&nbsp;&nbsp;&lt;BR&gt;29&nbsp;&lt;BR&gt;30&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;numberIndex&nbsp;=&nbsp;GetNumberIndex(buffer,&nbsp;(byte)r.Next(48,&nbsp;57));&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;BR&gt;31&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&lt;BR&gt;32&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&lt;BR&gt;33&nbsp;&lt;BR&gt;34&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;key.ToString();&nbsp;&nbsp;&lt;BR&gt;35}&nbsp;&nbsp;&lt;BR&gt;36&nbsp;&lt;BR&gt;37public&nbsp;static&nbsp;int&nbsp;GetNumberIndex(byte[]&nbsp;buffer,&nbsp;byte&nbsp;number)&nbsp;&nbsp;&lt;BR&gt;38{&nbsp;&nbsp;&lt;BR&gt;39&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;buffer.Length;&nbsp;i++)&nbsp;&nbsp;&lt;BR&gt;40&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&lt;BR&gt;41&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(buffer[i]&nbsp;==&nbsp;number)&nbsp;&nbsp;&lt;BR&gt;42&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&lt;BR&gt;43&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;i;&nbsp;&nbsp;&lt;BR&gt;44&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&lt;BR&gt;45&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&lt;BR&gt;46&nbsp;&lt;BR&gt;47&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;20;&nbsp;&nbsp;&lt;BR&gt;48}&lt;BR&gt;&nbsp;&lt;/P&gt;&lt;P&gt;实例二，ANTS&nbsp;Profiler&lt;/P&gt;&lt;P&gt;&nbsp;&nbsp;&nbsp;&nbsp;ANTS&nbsp;Profiler是一个检测基于.Net&nbsp;Framework的任何语言开发出的应用程序的代码性能的工具。它使用激活码和网络激活的方式进行双重验证。代码经过了混淆器混淆，程序集也经过强名称签名，注册算法也用的是成熟的RSA算法。所以整体安全性不错，是.NET平台下比较成熟的做法，很有借鉴意义。&lt;/P&gt;&lt;P&gt;&nbsp;&nbsp;&nbsp;&nbsp;在安装完ANTS&nbsp;Profiler后，运行ANTS&nbsp;Profiler&nbsp;，会弹出Trial界面，提示还有14天试用期。另外，有一个激活按钮。点击激活按钮，第一步会弹出提示输入激活码的窗口。这里需要先得到正确的激活码，才能进行下面的验证步骤。那么怎么才能得到正确的激活码呢？像分析第一款软件一样，我们先打开ManagedSpy。在ManagedSpy中我们发现Trial界面的窗体类叫_53，输入激活码的窗体类叫_3。很显然，都是经过代码混淆的，这是ANTS&nbsp;Profiler安全保护的第一关-“代码混淆关”。这一关只是增加过其他关的难度，不需要特别处理。&lt;/P&gt;&lt;P&gt;&nbsp;&nbsp;&nbsp;&nbsp;在找到注册信息相关的类名_53后，打开Reflactor，搜索_53类，顺藤摸瓜，再找到_3类，这个类在RedGate.Licensing.Client.dll中(RedGate.Licensing.Client.dll是注册相关的程序集，需要重点关注)。读_3类的代码，发现输入的激活码被设置到_2类中SerialNumber属性中，_2类中_2(string&nbsp;text1)方法就是校验激活码的方法。代码如下：&nbsp;&lt;/P&gt;&lt;P&gt;&lt;BR&gt;Code&nbsp;&lt;BR&gt;1private&nbsp;static&nbsp;bool&nbsp;_2(string&nbsp;text1)&nbsp;&lt;BR&gt;2{&nbsp;&lt;BR&gt;3&nbsp;&nbsp;&nbsp;&nbsp;text1&nbsp;=&nbsp;text1.ToUpper().Trim();&nbsp;&lt;BR&gt;4&nbsp;&nbsp;&nbsp;&nbsp;Regex&nbsp;regex&nbsp;=&nbsp;new&nbsp;Regex(@&quot;[A-Z]{2}-[0-9A-Z]{1}-[0-9A-Z]{1}-\d{5}-[0-9A-F]{4}&quot;);&nbsp;&lt;BR&gt;5&nbsp;&nbsp;&nbsp;&nbsp;Regex&nbsp;regex2&nbsp;=&nbsp;new&nbsp;Regex(@&quot;\d{3}-\d{3}-\d{6}-[0-9A-F]{4}&quot;);&nbsp;&lt;BR&gt;6&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(regex.IsMatch(text1))&nbsp;&lt;BR&gt;7&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&lt;BR&gt;8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string&nbsp;str&nbsp;=&nbsp;text1.Substring(0,&nbsp;12);&nbsp;&lt;BR&gt;9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string&nbsp;str2&nbsp;=&nbsp;string.Format(&quot;{0:X4}&quot;,&nbsp;_7._1(str));&nbsp;&lt;BR&gt;10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(!text1.EndsWith(str2))&nbsp;&lt;BR&gt;11&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&lt;BR&gt;12&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;false;&nbsp;&lt;BR&gt;13&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&lt;BR&gt;14&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&lt;BR&gt;15&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if&nbsp;(regex2.IsMatch(text1))&nbsp;&lt;BR&gt;16&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&lt;BR&gt;17&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string&nbsp;str3&nbsp;=&nbsp;text1.Substring(0,&nbsp;14);&nbsp;&lt;BR&gt;18&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string&nbsp;str4&nbsp;=&nbsp;string.Format(&quot;{0:X4}&quot;,&nbsp;_7._1(str3));&nbsp;&lt;BR&gt;19&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(!text1.EndsWith(str4))&nbsp;&lt;BR&gt;20&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&lt;BR&gt;21&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;false;&nbsp;&lt;BR&gt;22&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&lt;BR&gt;23&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&lt;BR&gt;24&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;&lt;BR&gt;25&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&lt;BR&gt;26&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;false;&nbsp;&lt;BR&gt;27&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&lt;BR&gt;28&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;true;&nbsp;&lt;BR&gt;29}&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;这段代码表明，激活码是符合regex和regex2这两种正则表达式的形式。同时，满足激活码使用_7._1(string&nbsp;text1)方法返回值结尾。很显然，前12为是激活码信息，后四位是激活码校验位。_7._1(string&nbsp;text1)就是计算校验位的方法，代码如下：&nbsp;&lt;/P&gt;&lt;P&gt;&lt;BR&gt;Code&nbsp;&lt;BR&gt;1internal&nbsp;static&nbsp;uint&nbsp;_1(string&nbsp;text1)&nbsp;&lt;BR&gt;2{&nbsp;&lt;BR&gt;3&nbsp;&nbsp;&nbsp;&nbsp;long&nbsp;num&nbsp;=&nbsp;0L;&nbsp;&lt;BR&gt;4&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;text1.Length;&nbsp;i++)&nbsp;&lt;BR&gt;5&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&lt;BR&gt;6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;num4&nbsp;=&nbsp;text1[i];&nbsp;&lt;BR&gt;7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(int&nbsp;j&nbsp;=&nbsp;7;&nbsp;j&nbsp;&gt;=&nbsp;0;&nbsp;j--)&nbsp;&lt;BR&gt;8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&lt;BR&gt;9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bool&nbsp;flag&nbsp;=&nbsp;((num&nbsp;&amp;&nbsp;0x8000L)&nbsp;==&nbsp;0x8000L)&nbsp;^&nbsp;((num4&nbsp;&amp;&nbsp;(((int)&nbsp;1)&nbsp;&lt;&lt;&nbsp;j))&nbsp;!=&nbsp;0);&nbsp;&lt;BR&gt;10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;num&nbsp;=&nbsp;(num&nbsp;&amp;&nbsp;0x7fffL)&nbsp;&lt;&lt;&nbsp;1;&nbsp;&lt;BR&gt;11&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(flag)&nbsp;&lt;BR&gt;12&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&lt;BR&gt;13&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;num&nbsp;^=&nbsp;0x1021L;&nbsp;&lt;BR&gt;14&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&lt;BR&gt;15&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&lt;BR&gt;16&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&lt;BR&gt;17&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(uint)&nbsp;num;&nbsp;&lt;BR&gt;18}&nbsp;&lt;BR&gt;19&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;知道了激活码的合法形式和校验位的计算方法，我们就可以构建一个合法的激活码。以regex表示的合法激活码形式为例，选择前12位为最小值“AA-0-0-00000”的一个合法激活码，然后使用_7._1(string&nbsp;text1)方法计算校验码为：“DE33”。那么一个合法的激活码就这样得到了“AA-0-0-00000-DE33”。复制激活码到激活窗口，成功通过验证。至此，ANTS&nbsp;Profiler安全保护的第二关-“激活码验证关”通过了。在激活码验证通过后，点击下一步会进入到网络激活或Email激活界面。选择Email激活，我们可以看见ANTS&nbsp;Profiler收集了版本信息，激活码，session，和机器硬件等信息。这可以保障一个注册码只能用在一台电脑上，值得学习。激活请求信息如下：&lt;/P&gt;&lt;P&gt;activationrequest&nbsp;&lt;BR&gt;1&lt;activationrequest&gt;&nbsp;&nbsp;&lt;BR&gt;2&lt;version&gt;2&lt;/version&gt;&nbsp;&nbsp;&lt;BR&gt;3&lt;machinehash&gt;F6FB-285E-CD12-667D&lt;/machinehash&gt;&nbsp;&nbsp;&lt;BR&gt;4&lt;productcode&gt;5&lt;/productcode&gt;&nbsp;&nbsp;&lt;BR&gt;5&lt;majorversion&gt;3&lt;/majorversion&gt;&nbsp;&nbsp;&lt;BR&gt;6&lt;minorversion&gt;0&lt;/minorversion&gt;&nbsp;&nbsp;&lt;BR&gt;7&lt;serialnumber&gt;AA-0-0-00000-DE33&lt;/serialnumber&gt;&nbsp;&nbsp;&lt;BR&gt;8&lt;session&gt;689fae08-2fdb-485e-9df7-28e2888cfbff&lt;/session&gt;&nbsp;&nbsp;&lt;BR&gt;9&lt;locale&gt;zh-CN&lt;/locale&gt;&nbsp;&nbsp;&lt;BR&gt;10&lt;/activationrequest&gt;&nbsp;&lt;BR&gt;11&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;接下来，就是输入激活响应信息，验证激活响应信息的界面了。这是激活界面的第四步，同样代码在_3类中。跟踪代码，发现验证逻辑在RedGate.Licensing.Client.Licence类中的_2(XmlDocument&nbsp;document1,&nbsp;ref&nbsp;_2&nbsp;_Ref1)方法中，代码如下：&nbsp;&lt;/P&gt;&lt;P&gt;&lt;BR&gt;Code&nbsp;&lt;BR&gt;&nbsp;&nbsp;1private&nbsp;bool&nbsp;_2(XmlDocument&nbsp;document1,&nbsp;ref&nbsp;_2&nbsp;_Ref1)&nbsp;&lt;BR&gt;&nbsp;&nbsp;2{&nbsp;&lt;BR&gt;&nbsp;&nbsp;3&nbsp;&nbsp;&nbsp;&nbsp;XmlNodeList&nbsp;elementsByTagName&nbsp;=&nbsp;document1.GetElementsByTagName(&quot;data&quot;);&nbsp;&lt;BR&gt;&nbsp;&nbsp;4&nbsp;&nbsp;&nbsp;&nbsp;XmlNodeList&nbsp;list2&nbsp;=&nbsp;document1.GetElementsByTagName(&quot;signature&quot;);&nbsp;&lt;BR&gt;&nbsp;&nbsp;5&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;((elementsByTagName.Count&nbsp;!=&nbsp;1)&nbsp;||&nbsp;(list2.Count&nbsp;!=&nbsp;1))&nbsp;&lt;BR&gt;&nbsp;&nbsp;6&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&lt;BR&gt;&nbsp;&nbsp;7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_Ref1._3&nbsp;=&nbsp;_6._1(_6._16);&nbsp;&lt;BR&gt;&nbsp;&nbsp;8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;false;&nbsp;&lt;BR&gt;&nbsp;&nbsp;9&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&lt;BR&gt;10&nbsp;&nbsp;&nbsp;&nbsp;string&nbsp;outerXml&nbsp;=&nbsp;elementsByTagName[0].OuterXml;&nbsp;&lt;BR&gt;11&nbsp;&nbsp;&nbsp;&nbsp;string&nbsp;innerXml&nbsp;=&nbsp;list2[0].InnerXml;&nbsp;&lt;BR&gt;12&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(innerXml.Length&nbsp;==&nbsp;0)&nbsp;&lt;BR&gt;13&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&lt;BR&gt;14&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_Ref1._3&nbsp;=&nbsp;_6._1(_6._17);&nbsp;&lt;BR&gt;15&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;false;&nbsp;&lt;BR&gt;16&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&lt;BR&gt;17&nbsp;&nbsp;&nbsp;&nbsp;RSACryptoServiceProvider&nbsp;provider&nbsp;=&nbsp;new&nbsp;RSACryptoServiceProvider();&nbsp;&lt;BR&gt;18&nbsp;&nbsp;&nbsp;&nbsp;string&nbsp;xmlString&nbsp;=&nbsp;&quot;&lt;RSAKeyvalue&gt;&lt;Modulus&gt;zLizNmLUd4VlIWee1GXgn/KxEwcghPASQ+NUzZhbY2fTGzpW64T6yEOdHlIbhX1DX6yAz2gMZKfnpQL2aFqxh5ACFV9dONSTzuQzkqeXwFEARsMxGP3eTQSWMpwVhEcraSn1zOqMb3CRDeQpgasq0lv4HRFhbwalOifKarjEL/8=&lt;/Modulus&gt;&lt;Exponent&gt;AQAB&lt;/Exponent&gt;&lt;/RSAKeyvalue&gt;&quot;;&nbsp;&lt;BR&gt;19&nbsp;&nbsp;&nbsp;&nbsp;provider.FromXmlString(xmlString);&nbsp;&lt;BR&gt;20&nbsp;&nbsp;&nbsp;&nbsp;byte[]&nbsp;signature&nbsp;=&nbsp;Convert.FromBase64String(innerXml);&nbsp;&lt;BR&gt;21&nbsp;&nbsp;&nbsp;&nbsp;byte[]&nbsp;bytes&nbsp;=&nbsp;Encoding.UTF8.GetBytes(outerXml);&nbsp;&lt;BR&gt;22&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(!provider.VerifyData(bytes,&nbsp;new&nbsp;SHA1Managed(),&nbsp;signature))&nbsp;&lt;BR&gt;23&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&lt;BR&gt;24&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_Ref1._3&nbsp;=&nbsp;_6._1(_6._18);&nbsp;&lt;BR&gt;25&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;false;&nbsp;&lt;BR&gt;26&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&lt;BR&gt;27&nbsp;&nbsp;&nbsp;&nbsp;_Ref1._1&nbsp;=&nbsp;false;&nbsp;&lt;BR&gt;28&nbsp;&nbsp;&nbsp;&nbsp;foreach&nbsp;(XmlNode&nbsp;node&nbsp;in&nbsp;elementsByTagName[0].ChildNodes)&nbsp;&lt;BR&gt;29&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&lt;BR&gt;30&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string&nbsp;name&nbsp;=&nbsp;node.Name;&nbsp;&lt;BR&gt;31&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(name&nbsp;==&nbsp;null)&nbsp;&lt;BR&gt;32&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&lt;BR&gt;33&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;continue;&nbsp;&lt;BR&gt;34&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&lt;BR&gt;35&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name&nbsp;=&nbsp;string.IsInterned(name);&nbsp;&lt;BR&gt;36&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(name&nbsp;!=&nbsp;&quot;productcodes&quot;)&nbsp;&lt;BR&gt;37&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&lt;BR&gt;38&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(name&nbsp;==&nbsp;&quot;serialnumber&quot;)&nbsp;&lt;BR&gt;39&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&lt;BR&gt;40&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;goto&nbsp;Label_0294;&nbsp;&lt;BR&gt;41&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&lt;BR&gt;42&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(name&nbsp;==&nbsp;&quot;productcode&quot;)&nbsp;&lt;BR&gt;43&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&lt;BR&gt;44&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;goto&nbsp;Label_02A7;&nbsp;&lt;BR&gt;45&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&lt;BR&gt;46&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(name&nbsp;==&nbsp;&quot;majorversion&quot;)&nbsp;&lt;BR&gt;47&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&lt;BR&gt;48&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;goto&nbsp;Label_02BF;&nbsp;&lt;BR&gt;49&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&lt;BR&gt;50&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(name&nbsp;==&nbsp;&quot;minorversion&quot;)&nbsp;&lt;BR&gt;51&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&lt;BR&gt;52&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;goto&nbsp;Label_02D7;&nbsp;&lt;BR&gt;53&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&lt;BR&gt;54&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(name&nbsp;==&nbsp;&quot;edition&quot;)&nbsp;&lt;BR&gt;55&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&lt;BR&gt;56&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;goto&nbsp;Label_02EF;&nbsp;&lt;BR&gt;57&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&lt;BR&gt;58&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(name&nbsp;==&nbsp;&quot;machinehash&quot;)&nbsp;&lt;BR&gt;59&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&lt;BR&gt;60&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;goto&nbsp;Label_02FF;&nbsp;&lt;BR&gt;61&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&lt;BR&gt;62&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(name&nbsp;==&nbsp;&quot;extension&quot;)&nbsp;&lt;BR&gt;63&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&lt;BR&gt;64&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;goto&nbsp;Label_030F;&nbsp;&lt;BR&gt;65&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&lt;BR&gt;66&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(name&nbsp;==&nbsp;&quot;session&quot;)&nbsp;&lt;BR&gt;67&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&lt;BR&gt;68&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;goto&nbsp;Label_0319;&nbsp;&lt;BR&gt;69&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&lt;BR&gt;70&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;continue;&nbsp;&lt;BR&gt;71&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&lt;BR&gt;72&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach&nbsp;(XmlNode&nbsp;node2&nbsp;in&nbsp;node.ＳelectNodes(&quot;product&quot;))&nbsp;&lt;BR&gt;73&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&lt;BR&gt;74&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_1&nbsp;_&nbsp;=&nbsp;new&nbsp;_1();&nbsp;&lt;BR&gt;75&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;&lt;BR&gt;76&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&lt;BR&gt;77&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_._1&nbsp;=&nbsp;node2.ＳelectSingleNode(&quot;productname&quot;).InnerText;&nbsp;&lt;BR&gt;78&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_._1&nbsp;=&nbsp;Convert.ToInt32(node2.ＳelectSingleNode(&quot;productcode&quot;).InnerText);&nbsp;&lt;BR&gt;79&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_._2&nbsp;=&nbsp;Convert.ToInt32(node2.ＳelectSingleNode(&quot;majorversion&quot;).InnerText);&nbsp;&lt;BR&gt;80&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_._3&nbsp;=&nbsp;Convert.ToInt32(node2.ＳelectSingleNode(&quot;minorversion&quot;).InnerText);&nbsp;&lt;BR&gt;81&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_._2&nbsp;=&nbsp;node2.ＳelectSingleNode(&quot;edition&quot;).InnerText;&nbsp;&lt;BR&gt;82&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_Ref1._1.Add(_);&nbsp;&lt;BR&gt;83&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;continue;&nbsp;&lt;BR&gt;84&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&lt;BR&gt;85&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;catch&nbsp;(Exception)&nbsp;&lt;BR&gt;86&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&lt;BR&gt;87&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;continue;&nbsp;&lt;BR&gt;88&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&lt;BR&gt;89&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&lt;BR&gt;90&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;continue;&nbsp;&lt;BR&gt;91&nbsp;&nbsp;&nbsp;&nbsp;Label_0294:&nbsp;&lt;BR&gt;92&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_Ref1._2&nbsp;=&nbsp;node.InnerText;&nbsp;&lt;BR&gt;93&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;continue;&nbsp;&lt;BR&gt;94&nbsp;&nbsp;&nbsp;&nbsp;Label_02A7:&nbsp;&lt;BR&gt;95&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;&lt;BR&gt;96&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&lt;BR&gt;97&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_Ref1._1&nbsp;=&nbsp;Convert.ToInt32(node.InnerText);&nbsp;&lt;BR&gt;98&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&lt;BR&gt;99&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;catch&nbsp;&lt;BR&gt;100&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&lt;BR&gt;101&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&lt;BR&gt;102&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;continue;&nbsp;&lt;BR&gt;103&nbsp;&nbsp;&nbsp;&nbsp;Label_02BF:&nbsp;&lt;BR&gt;104&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;&lt;BR&gt;105&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&lt;BR&gt;106&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_Ref1._2&nbsp;=&nbsp;Convert.ToInt32(node.InnerText);&nbsp;&lt;BR&gt;107&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&lt;BR&gt;108&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;catch&nbsp;&lt;BR&gt;109&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&lt;BR&gt;110&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&lt;BR&gt;111&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;continue;&nbsp;&lt;BR&gt;112&nbsp;&nbsp;&nbsp;&nbsp;Label_02D7:&nbsp;&lt;BR&gt;113&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;&lt;BR&gt;114&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&lt;BR&gt;115&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_Ref1._3&nbsp;=&nbsp;Convert.ToInt32(node.InnerText);&nbsp;&lt;BR&gt;116&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&lt;BR&gt;117&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;catch&nbsp;&lt;BR&gt;118&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&lt;BR&gt;119&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&lt;BR&gt;120&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;continue;&nbsp;&lt;BR&gt;121&nbsp;&nbsp;&nbsp;&nbsp;Label_02EF:&nbsp;&lt;BR&gt;122&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_Ref1._5&nbsp;=&nbsp;node.InnerText;&nbsp;&lt;BR&gt;123&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;continue;&nbsp;&lt;BR&gt;124&nbsp;&nbsp;&nbsp;&nbsp;Label_02FF:&nbsp;&lt;BR&gt;125&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_Ref1._1&nbsp;=&nbsp;node.InnerText;&nbsp;&lt;BR&gt;126&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;continue;&nbsp;&lt;BR&gt;127&nbsp;&nbsp;&nbsp;&nbsp;Label_030F:&nbsp;&lt;BR&gt;128&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_Ref1._1&nbsp;=&nbsp;true;&nbsp;&lt;BR&gt;129&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;continue;&nbsp;&lt;BR&gt;130&nbsp;&nbsp;&nbsp;&nbsp;Label_0319:&nbsp;&lt;BR&gt;131&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_Ref1._4&nbsp;=&nbsp;node.InnerText;&nbsp;&lt;BR&gt;132&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&lt;BR&gt;133&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;true;&nbsp;&lt;BR&gt;134}&nbsp;&lt;BR&gt;135&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;细读这段代码可以发现，激活响应信息已经使用RSA算法进行过数字签名，这样可以防止激活响应信息被篡改。要篡改或伪造激活响应信息，必需破解RSA私钥公钥对。公钥已经在方法体中给出，所以需要破解私钥。从公钥可以看出，它使用的1024位密钥长度，理论攻破时间1011MIPS年。虽然破解的可能性存在，但破解几率很小。这就是ANTS&nbsp;Profiler安全保护的第三关-“RSA数字签名关”。这使得我们不得不放弃伪造激活响应信息的办法。通常碰到RSA等成熟算法，我们只能选择“爆破”这款软件了。&lt;/P&gt;&lt;P&gt;通过前面的分析，我们发现程序中判断软件是否注册的逻辑放在RedGate.Licensing.Client.dll程序集中的Licence类里面。我们需要做的就是打开Reflactor软件，加载RedGate.Licensing.Client.dll文件，将RedGate.Licensing.Client.dll文件Export成C#工程源文件。然后将源文件中Licence类中所有公共方法都返回注册成功的信息，再重新编译生成新的修改后的RedGate.Licensing.Client.dll文件，用新生成的文件替换原RedGate.Licensing.Client.dll文件。这样，注册判断逻辑就被非法篡改了，使软件误认为已经注册。修改后的Licence类就像下面这样：&nbsp;&lt;/P&gt;&lt;P&gt;&lt;BR&gt;Code&nbsp;&lt;BR&gt;1namespace&nbsp;RedGate.Licensing.Client&nbsp;&nbsp;&lt;BR&gt;2{&nbsp;&nbsp;&lt;BR&gt;3&nbsp;&nbsp;&nbsp;&nbsp;using&nbsp;System;&nbsp;&nbsp;&lt;BR&gt;4&nbsp;&lt;BR&gt;5&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;class&nbsp;Licence&nbsp;&nbsp;&lt;BR&gt;6&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&lt;BR&gt;7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;bool&nbsp;DisplayUI()&nbsp;&nbsp;&lt;BR&gt;8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&lt;BR&gt;9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;true;&nbsp;&nbsp;&lt;BR&gt;10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&lt;BR&gt;11&nbsp;&lt;BR&gt;12&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;Licence&nbsp;GetLicence(int&nbsp;productCode,&nbsp;string&nbsp;productName,&nbsp;int&nbsp;majorVersion,&nbsp;int&nbsp;minorVersion)&nbsp;&nbsp;&lt;BR&gt;13&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&lt;BR&gt;14&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;new&nbsp;Licence();&nbsp;&nbsp;&lt;BR&gt;15&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&lt;BR&gt;16&nbsp;&lt;BR&gt;17&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;Licence&nbsp;GetLicence(int&nbsp;productCode,&nbsp;string&nbsp;productName,&nbsp;int&nbsp;majorVersion,&nbsp;int&nbsp;minorVersion,&nbsp;string&nbsp;path)&nbsp;&nbsp;&lt;BR&gt;18&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&lt;BR&gt;19&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;new&nbsp;Licence();&nbsp;&nbsp;&lt;BR&gt;20&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&lt;BR&gt;21&nbsp;&lt;BR&gt;22&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;InitializeAtInstall(string&nbsp;productName,&nbsp;int&nbsp;productCode,&nbsp;int&nbsp;majorVersion,&nbsp;int&nbsp;minorVersion,&nbsp;string&nbsp;guid)&nbsp;&nbsp;&lt;BR&gt;23&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&lt;BR&gt;24&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&lt;BR&gt;25&nbsp;&lt;BR&gt;26&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;bool&nbsp;Activated&nbsp;&nbsp;&lt;BR&gt;27&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&lt;BR&gt;28&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;get&nbsp;&nbsp;&lt;BR&gt;29&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&lt;BR&gt;30&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;true;&nbsp;&nbsp;&lt;BR&gt;31&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&lt;BR&gt;32&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&lt;BR&gt;33&nbsp;&lt;BR&gt;34&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;int&nbsp;DaysLeftInTrial&nbsp;&nbsp;&lt;BR&gt;35&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&lt;BR&gt;36&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;get&nbsp;&nbsp;&lt;BR&gt;37&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&lt;BR&gt;38&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0x7fffffff;&nbsp;&nbsp;&lt;BR&gt;39&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&lt;BR&gt;40&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&lt;BR&gt;41&nbsp;&lt;BR&gt;42&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;string&nbsp;Edition&nbsp;&nbsp;&lt;BR&gt;43&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&lt;BR&gt;44&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;get&nbsp;&nbsp;&lt;BR&gt;45&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&lt;BR&gt;46&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;&quot;professional&quot;;&nbsp;&nbsp;&lt;BR&gt;47&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&lt;BR&gt;48&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&lt;BR&gt;49&nbsp;&lt;BR&gt;50&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;string&nbsp;LicenceFilePath&nbsp;&nbsp;&lt;BR&gt;51&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&lt;BR&gt;52&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;get&nbsp;&nbsp;&lt;BR&gt;53&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&lt;BR&gt;54&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;string.Empty;&nbsp;&nbsp;&lt;BR&gt;55&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&lt;BR&gt;56&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&lt;BR&gt;57&nbsp;&lt;BR&gt;58&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;string&nbsp;SerialNumber&nbsp;&nbsp;&lt;BR&gt;59&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&lt;BR&gt;60&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;get&nbsp;&nbsp;&lt;BR&gt;61&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&lt;BR&gt;62&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;&quot;AA-0-0-00000-DE33&quot;;&nbsp;&nbsp;&lt;BR&gt;63&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&lt;BR&gt;64&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set&nbsp;&nbsp;&lt;BR&gt;65&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&lt;BR&gt;66&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&lt;BR&gt;67&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&lt;BR&gt;68&nbsp;&lt;BR&gt;69&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;RedGate.Licensing.Client.TrialStatus&nbsp;TrialStatus&nbsp;&nbsp;&lt;BR&gt;70&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&lt;BR&gt;71&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;get&nbsp;&nbsp;&lt;BR&gt;72&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&lt;BR&gt;73&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;RedGate.Licensing.Client.TrialStatus.InTrial;&nbsp;&nbsp;&lt;BR&gt;74&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&lt;BR&gt;75&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&lt;BR&gt;76&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&lt;BR&gt;77}&nbsp;&nbsp;&lt;BR&gt;78&lt;/P&gt;&lt;P&gt;&nbsp;&nbsp;&nbsp;&nbsp;爆破虽然是一种好方法，不过.NET中有专门对付这种方法的杀手锏-“强名称签名”。不幸的是，ANTS&nbsp;Profiler使用了强名称签名机制，是我们在爆破软件这条路上受阻。这就是ANTS&nbsp;Profiler软件保护的第四关-“强名称签名”。强名称签名会在软件被加入GAC时验证。如果软件没在GAC中，那么运行软件的时候也会验证。如果软件被篡改，在运行软件的时候软件会直接抛出异常，使得软件无法正常运行。&lt;/P&gt;&lt;P&gt;&nbsp;&nbsp;&nbsp;&nbsp;那么如何破解这种强名称签名验证机制呢？&lt;/P&gt;&lt;P&gt;&nbsp;&nbsp;&nbsp;&nbsp;有几种办法可以解除强名称的验证机制。第一种方法适合单个文件的软件，对单个文件的软件我们可以移除强名称签名信息，使软件变成弱名称的程序，这样在软件运行的时候就不会验证是否被篡改了。对于引用关系复杂的多文件软件，我们可以采取第二种方法。这种方法需要理由.NET平台上设计的“后门”才能完成。这个“后门”是什么呢？原来，为了使软件开发后能够使用混淆工具混淆，微软允许延迟签名程序集，被延迟签名的程序集可以在混淆之后再重新签名。而为了测试方便，只需要在注册表中加入一条记录就可以使混淆修改后的程序在没有被重新签名前也能运行，即不进行强名称验证。&lt;/P&gt;&lt;P&gt;&nbsp;&nbsp;&nbsp;&nbsp;利用这个“后门”，我们只需要将修改后的修改完Licence类编译成新的RedGate.Licensing.Client.dll文件，编译选项中使用任意一对公钥私钥对强名称签名，并选择延迟签名，然后篡改编译后的public&nbsp;key为原始RedGate.Licensing.Client.dll文件的public&nbsp;key。再在注册表中加入一条记录就可以是强名称签名验证机制失效，达到破解的目的。具体做法如下：&lt;/P&gt;&lt;P&gt;1，我们用sn命令生成一个新的公钥私钥对，用于签名&lt;/P&gt;&lt;P&gt;sn&nbsp;-k&nbsp;my.key&lt;/P&gt;&lt;P&gt;2，将反编译的RedGate.Licensing.Client.dll工程文件中Licence类修改成上面的代码，并在编译选项中使用第一步得到的my.key签名程序集。注意，一定要选择延迟签名选项。编译生成新的RedGate.Licensing.Client.dll文件。&lt;/P&gt;&lt;P&gt;3，使用sn命令得到原始RedGate.Licensing.Client.dll文件的public&nbsp;key和新RedGate.Licensing.Client.dll文件的public&nbsp;key。&lt;/P&gt;&lt;P&gt;sn&nbsp;-Tp&nbsp;RedGate.Licensing.Client.dll&lt;/P&gt;&lt;P&gt;4，使用二进制编辑软件，如WinHex打开新的RedGate.Licensing.Client.dll文件，替换掉它的public&nbsp;key为老文件中的public&nbsp;key。&lt;/P&gt;&lt;P&gt;5，在注册表“Software\Microsoft\StrongName\Verification\”下加一条子健“RedGate.Licensing.Client,7F465A1C156D4D57”即可完成破解。这步也可以使用sn命令代替。&lt;/P&gt;&lt;P&gt;sn&nbsp;-Vr&nbsp;RedGate.Licensing.Client.dll&lt;/P&gt;&lt;P&gt;&nbsp;&nbsp;&nbsp;&nbsp;当然，你可以将修改后的RedGate.Licensing.Client.dll文件打包到一个Patch文件中，并在Patch文件中自动完成替换文件和修改注册表的操作。至此，ANTS&nbsp;Profiler就被破解了。&nbsp;&lt;/P&gt;&lt;P&gt;&nbsp;&nbsp;&nbsp;&nbsp;通过对以上两款软件的分析，我们可以看出，ANTS&nbsp;Profiler的保护手段还是比较成熟的，值得借鉴。它使用了名称混淆，激活码+网络验证，RSA数字签名，强名称签名等保护手段，整体安全系数较高。而GatherBird&nbsp;Copy&nbsp;Large&nbsp;Files则没有充分运用上.NET平台提供的保护措施，还处于比较低的保护级别。如果我们综合运用流程混淆，元数据加密，加密壳，虚拟机技术，编译为本地代码等保护手段，软件保护强度将更高。&lt;/P&gt;&lt;P&gt;&nbsp;&lt;/P&gt;]]></summary>
	  <link rel="alternate" type="text/html" href="http://h31home.com/h312005/blogview.asp?ID=980" /> 
	  <id>http://h31home.com/h312005/blogview.asp?ID=980</id> 
  </entry>	

  <entry>

	  <title type="html"><![CDATA[关于CAB在ASP内的调用与使用[转]]]></title>
	  <author>
		 <name>admin</name>
		 <uri>http://h31home.com/h312005/blogview.asp?ID=979</uri>
		 <email></email>
	  </author>
	  <category term="" scheme="http://h31home.com/h312005/blogview.asp?ID=979" label="ASP学习" /> 
	  <updated>2008-6-21 10:19:09</updated>

	  <published>2008-6-21 10:19:09</published>
		  <summary type="html"><![CDATA[具体代码如下:&nbsp;&lt;BR&gt;&lt;FONT&nbsp;face=Verdana&gt;&lt;FONT&nbsp;face=Verdana&gt;&lt;%@LANGUAGE=&quot;VBSCRIPT&quot;&nbsp;CODEPAGE=&quot;936&quot;%&gt;&lt;BR&gt;&lt;%&nbsp;on&nbsp;error&nbsp;resume&nbsp;next%&gt;&lt;BR&gt;&lt;!--#include&nbsp;file=&quot;../Connections/ds.asp&quot;&nbsp;--&gt;&lt;BR&gt;&lt;!--#include&nbsp;file=&quot;../Connections/informix.asp&quot;&nbsp;--&gt;&lt;/FONT&gt;&lt;BR&gt;&lt;html&gt;&lt;BR&gt;&lt;head&gt;&lt;BR&gt;&lt;title&gt;*********title&gt;&lt;BR&gt;&lt;meta&nbsp;http-equiv=&quot;Content-Type&quot;&nbsp;content=&quot;text/html;&nbsp;charset=gb2312&quot;&gt;&lt;BR&gt;&lt;link&nbsp;rel=&quot;stylesheet&quot;&nbsp;href=&quot;../css/css1.css&quot;&nbsp;type=&quot;text/css&quot;&gt;&lt;BR&gt;&lt;/head&gt;&lt;BR&gt;&lt;body&gt;&lt;BR&gt;&lt;SPAN&nbsp;style=&quot;COLOR:&nbsp;red&quot;&gt;&lt;OBJECT&nbsp;id=htactx&nbsp;name=htactx&nbsp;&lt;BR&gt;classid=clsid:FB4EE423-43A4-4AA9-BDE9-4335A6D3C74E&nbsp;codebase=&quot;../js/HTActX.cab#version=1,0,0,1&quot;&nbsp;style=&quot;HEIGHT:&nbsp;0px;&nbsp;WIDTH:&nbsp;0px&quot;&gt;&lt;/OBJECT&gt;&lt;BR&gt;&lt;SPAN&nbsp;style=&quot;COLOR:&nbsp;#000000&quot;&gt;&lt;SPAN&nbsp;style=&quot;COLOR:&nbsp;#008000&quot;&gt;&#39;在此对CAB包进行应用以后,在下面的代码中进行调用,但总是有问题出现,错误代号为:424(缺少对象)&lt;BR&gt;&lt;/SPAN&gt;&lt;%&lt;BR&gt;&lt;P&gt;&lt;FONT&nbsp;face=Verdana&gt;&#39;启用USBkey进行验证&lt;/FONT&gt;&lt;/P&gt;&lt;P&gt;&lt;FONT&nbsp;face=Verdana&gt;dim&nbsp;SubmitTm&lt;BR&gt;dim&nbsp;ReceiveTm&lt;BR&gt;dim&nbsp;y&lt;BR&gt;dim&nbsp;m&lt;BR&gt;dim&nbsp;d&lt;BR&gt;dim&nbsp;h&lt;BR&gt;dim&nbsp;n&lt;BR&gt;dim&nbsp;se&lt;BR&gt;Dim&nbsp;FirstDigest&lt;BR&gt;Dim&nbsp;Digest&lt;BR&gt;dim&nbsp;EnData&lt;BR&gt;Digest=&nbsp;&quot;01234567890123456&quot;&lt;BR&gt;&#39;dim&nbsp;htactx&lt;BR&gt;&#39;set&nbsp;htactx&nbsp;=&nbsp;CreateObject(&quot;HTSrvActX.HTSrvActXCtrl&quot;)&lt;BR&gt;dim&nbsp;LibVer&lt;BR&gt;&nbsp;LibVer&nbsp;=&nbsp;htactx.GetLibVersion&lt;BR&gt;&nbsp;If&nbsp;Err.number&nbsp;&lt;&gt;&nbsp;0&nbsp;Then&lt;BR&gt;&nbsp;&nbsp;&nbsp;&#39;&nbsp;response.Write(err.number)&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;response.write&nbsp;&quot;&lt;script&nbsp;language=javascript&gt;&nbsp;alert(&#39;加载客户端控件失败！&#39;);history.go(-1);&lt;/script&gt;&quot;&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;response.end&lt;BR&gt;&nbsp;else&lt;BR&gt;&nbsp;dim&nbsp;hCard&lt;BR&gt;&nbsp;&nbsp;hCard&nbsp;=&nbsp;0&nbsp;&lt;BR&gt;&nbsp;&nbsp;hCard&nbsp;=&nbsp;htactx.OpenDevice(1)&#39;打开设备&lt;BR&gt;&nbsp;&nbsp;If&nbsp;Err.number&lt;&gt;0&nbsp;or&nbsp;hCard&nbsp;=&nbsp;0&nbsp;then&lt;BR&gt;&nbsp;&nbsp;&nbsp;response.Write(err.number)&lt;BR&gt;&nbsp;&nbsp;response.write&nbsp;&quot;&lt;script&nbsp;language=javascript&gt;&nbsp;alert(&#39;打开硬件锁失败！&#39;);history.go(-1);&lt;/script&gt;&quot;&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;response.end&lt;BR&gt;&nbsp;&nbsp;end&nbsp;if&lt;BR&gt;&nbsp;&nbsp;dim&nbsp;UserName&lt;BR&gt;&nbsp;&nbsp;UserName&nbsp;=&nbsp;htactx.GetUserName(hCard)&#39;获取用户名&lt;BR&gt;&nbsp;&nbsp;if&nbsp;id&lt;&gt;UserName&nbsp;then&lt;BR&gt;&nbsp;&nbsp;response.write&nbsp;&quot;&lt;script&nbsp;language=javascript&gt;&nbsp;alert(&#39;您输入的登录编号与锁不一致,请核查！&#39;);history.go(-1);&lt;/script&gt;&quot;&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;response.end&lt;BR&gt;&nbsp;&nbsp;end&nbsp;if&lt;BR&gt;&nbsp;&nbsp;Digest&nbsp;=&nbsp;htactx.HTSHA1(Rnddata,lRndLen)&#39;SHA1数据&lt;BR&gt;&nbsp;&nbsp;if&nbsp;Err.number&lt;&gt;0&nbsp;then&lt;BR&gt;&nbsp;&nbsp;response.write&nbsp;&quot;&lt;script&nbsp;language=javascript&gt;&nbsp;alert(&#39;USB安全锁数据加密失败！&#39;);history.go(-1);&lt;/script&gt;&quot;&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;response.end&lt;BR&gt;&nbsp;&nbsp;htactx.CloseDevice&nbsp;hCard&lt;BR&gt;&nbsp;&nbsp;end&nbsp;if&lt;BR&gt;&nbsp;&nbsp;Digest&nbsp;=&nbsp;Digest&amp;&quot;04040404&quot;&#39;对SHA1数据进行补码&lt;BR&gt;&nbsp;&nbsp;EnData&nbsp;=&nbsp;htactx.HTCrypt(hCard,0&nbsp;,0,Digest,&nbsp;len(Digest))&#39;DES3加密SHA1后的数据&lt;BR&gt;&nbsp;&nbsp;If&nbsp;Err.number&lt;&gt;0&nbsp;Then&nbsp;&lt;BR&gt;&nbsp;&nbsp;response.write&nbsp;&quot;&lt;script&nbsp;language=javascript&gt;&nbsp;alert(&#39;HashToken&nbsp;compute！&#39;);history.go(-1);&lt;/script&gt;&quot;&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;response.end&lt;BR&gt;&nbsp;&nbsp;htactx.CloseDevice&nbsp;hCard&lt;BR&gt;&nbsp;&nbsp;end&nbsp;if&lt;BR&gt;&nbsp;&nbsp;htactx.CloseDevice&nbsp;hCard&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;end&nbsp;if&lt;BR&gt;&nbsp;dim&nbsp;obj&lt;BR&gt;&nbsp;dim&nbsp;PasswordInFile,UserNameInFile&lt;BR&gt;&nbsp;PasswordInFile=rs1(&quot;usbkey&quot;)&lt;BR&gt;&nbsp;UserNameInFile=rs1(&quot;gys&quot;)&lt;BR&gt;&nbsp;&nbsp;&nbsp;set&nbsp;obj&nbsp;=&nbsp;CreateObject(&quot;HTSrvActX.HTSrvActXCtrl&quot;)&lt;BR&gt;&nbsp;&nbsp;&nbsp;Digest&nbsp;=&nbsp;obj.HTSrvSHA1(Rnddata,&nbsp;len(Rnddata))&lt;BR&gt;&nbsp;&nbsp;&nbsp;Digest&nbsp;=&nbsp;Digest&amp;&quot;04040404&quot;&lt;BR&gt;&nbsp;&nbsp;&nbsp;ServerEncData&nbsp;=&nbsp;obj.HTSrvCrypt(0,&nbsp;PasswordInFile,len(PasswordInFile),0,&nbsp;Digest,&nbsp;len(Digest))&lt;BR&gt;&nbsp;&nbsp;&nbsp;if&nbsp;UCase(ServerEncData)=&nbsp;UCase(EndData)&nbsp;and&nbsp;UCase(UserNameInFile)&nbsp;=&nbsp;UCase(UserName)&nbsp;Then&nbsp;&lt;BR&gt;&nbsp;&nbsp;&nbsp;session(&quot;userID&quot;)=rssql2(&quot;gys&quot;)&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;session(&quot;name&quot;)=rssql2(&quot;gysname&quot;)&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;session(&quot;userclass&quot;)=1&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;response.redirect&nbsp;&quot;../default.asp&quot;&lt;BR&gt;&nbsp;&nbsp;&nbsp;else&lt;BR&gt;&nbsp;&nbsp;&nbsp;response.write&nbsp;&quot;&lt;script&nbsp;language=javascript&gt;&nbsp;alert(&#39;Anknow&nbsp;Error&nbsp;Happend！&#39;);history.go(-1);&lt;/script&gt;&quot;&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;response.end&lt;BR&gt;&nbsp;&nbsp;&nbsp;end&nbsp;if&lt;BR&gt;&lt;/FONT&gt;&lt;/P&gt;&nbsp;&nbsp;end&nbsp;if&lt;BR&gt;%&gt;&lt;BR&gt;&lt;FONT&nbsp;face=Verdana&gt;&lt;/body&gt;&lt;BR&gt;&lt;/html&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/FONT&gt;]]></summary>
	  <link rel="alternate" type="text/html" href="http://h31home.com/h312005/blogview.asp?ID=979" /> 
	  <id>http://h31home.com/h312005/blogview.asp?ID=979</id> 
  </entry>	

  <entry>

	  <title type="html"><![CDATA[SQLServer2000的“数据库维护计划”[转]]]></title>
	  <author>
		 <name>admin</name>
		 <uri>http://h31home.com/h312005/blogview.asp?ID=978</uri>
		 <email></email>
	  </author>
	  <category term="" scheme="http://h31home.com/h312005/blogview.asp?ID=978" label="Oralce" /> 
	  <updated>2008-6-21 10:07:18</updated>

	  <published>2008-6-21 10:07:18</published>
		  <summary type="html"><![CDATA[&lt;FONT&nbsp;color=#5b5b5b&gt;具体实现步骤&lt;BR&gt;　　&lt;STRONG&gt;目录&nbsp;&lt;/STRONG&gt;&lt;BR&gt;　　&lt;STRONG&gt;第一步：打开SQL&nbsp;Server“企业管理器”窗体&lt;/STRONG&gt;&lt;BR&gt;　　&lt;STRONG&gt;第二步：找到“数据库维护计划”功能&lt;/STRONG&gt;&lt;BR&gt;　　&lt;STRONG&gt;第三步：创建“数据库维护计划”&lt;/STRONG&gt;&lt;BR&gt;　　&lt;STRONG&gt;第四步：维护和管理“数据库维护计划”&lt;/STRONG&gt;&lt;BR&gt;　　&lt;STRONG&gt;第五步：启动SQL&nbsp;Server&nbsp;2000代理以便执行“作业”&lt;/STRONG&gt;&lt;BR&gt;　　&lt;STRONG&gt;第六步：检查结果&nbsp;&lt;/STRONG&gt;&lt;BR&gt;　　“数据库维护计划”功能在SQL&nbsp;Server&nbsp;2000的“企业管理器”中可以找到。&lt;BR&gt;　　&lt;STRONG&gt;说明：&nbsp;&lt;/STRONG&gt;&lt;BR&gt;　　1.以下操作是在服务器的Windows&nbsp;2000&nbsp;Server上进行操作的。&lt;BR&gt;　　2.由于SQL&nbsp;Server&nbsp;2000执行备份时将产生许多文件(特别是在进行事务日志备份时)，所以建议按数据库名称分别建立独立的备份目录进行存储。&lt;BR&gt;　　3.以下所有操作过程当中一般不会对数据库的使用产生影响。&lt;BR&gt;　　&lt;STRONG&gt;第一步：打开SQL&nbsp;Server“企业管理器”窗体&nbsp;&lt;/STRONG&gt;&lt;BR&gt;　　用鼠标单击任务栏上的“开始”按钮中的“程序(P)”菜单下的“Microsoft&nbsp;SQL&nbsp;Server”子菜单中的“企业管理器”菜单项，即可打开SQL&nbsp;Server&nbsp;2000的“企业管理器”窗体。&lt;BR&gt;　　&lt;STRONG&gt;第二步：找到“数据库维护计划”功能&nbsp;&lt;/STRONG&gt;&lt;BR&gt;　　在“企业管理器”窗体中左侧的树型选项卡中，用鼠标单击“+”图标扩展开“控制台根目录”下的“Microsoft&nbsp;SQL&nbsp;Servers”，可以看到其下有一个“SQL&nbsp;Server组”；接着继续扩展开“SQL&nbsp;Server组”，此时可以看到其下出现了服务器的名称(图1中的“JXNC-SERVER”就是我的服务器的名称)；再继续扩展开此服务器，可以看到其下列出了诸如“数据库”、“数据转换服务”等项目；最后单击“管理”项目，可以看到其下存在一个“数据库维护计划”(如图1)。&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/FONT&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;9pt;&nbsp;COLOR:&nbsp;#5b5b5b;&nbsp;LINE-HEIGHT:&nbsp;150%;&nbsp;FONT-FAMILY:&nbsp;微软雅黑&quot;&gt;单击“数据库维护计划”项目，在“企业管理器”窗口右侧将会显示出已经存在的维护计划项目。每个维护计划均包括以下项目：&lt;BR&gt;　　1.名称：就是维护计划的名称。此名称可以自定义，中英文皆可。&lt;BR&gt;　　2.数据库：就是维护计划所进行维护的数据库的名称。&lt;BR&gt;　　因为一个维护计划允许同时维护多个数据库，所以此处可以显示出多个数据库的名称(在图1中可以看到名为“系统数据库备份”的数据库维护计划中的“数据库”就包括三个数据库：master、model和msdb)。&lt;BR&gt;　　3.服务器：也就是维护计划所维护的数据库所处的服务器的名称。“(local)”表示是本地服务器。&lt;BR&gt;　　4.对策：是指维护计划所需要进行的具体维护工作的内容。&lt;BR&gt;　　图1中有3个“数据库维护计划”均为“数据库备份，事务日志备份”，它的含义就是这些维护计划中同时对所指定的数据库进行“数据库”和“事务日志”的备份。&lt;BR&gt;　　&lt;STRONG&gt;第三步：创建“数据库维护计划”&nbsp;&lt;/STRONG&gt;&lt;BR&gt;　　鼠标右击“数据库维护计划”项目，选择“新建维护计划(P)”功能，将打开“数据库维护计划向导”窗体，依照此向导能够创建一个新的“数据库维护计划”。&lt;BR&gt;　　步骤1：单击&nbsp;“下一步(N)”按钮，打开“选择数据库”窗体(如图2)。在此窗体中可以选定一个或多个的数据库作为操作对象。为了叙述方便，我在此只选择了一个数据库“regie”。&lt;/SPAN&gt;&lt;FONT&nbsp;color=#3366ff&gt;&nbsp;&lt;/FONT&gt;&lt;P&nbsp;style=&quot;LINE-HEIGHT:&nbsp;150%;&nbsp;TEXT-ALIGN:&nbsp;center&quot;&nbsp;align=center&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;9pt;&nbsp;COLOR:&nbsp;#5b5b5b;&nbsp;LINE-HEIGHT:&nbsp;150%;&nbsp;FONT-FAMILY:&nbsp;微软雅黑&quot;&gt;&lt;FONT&nbsp;color=#3366ff&gt;&lt;IMG&nbsp;height=383&nbsp;alt=&quot;&quot;&nbsp;src=&quot;http://www.cnblogs.com/images/cnblogs_com/zhaoqing/bf1.JPG&quot;&nbsp;width=497&nbsp;border=0&gt;&lt;/FONT&gt;　&nbsp;&lt;BR&gt;　　步骤2：单击图2中的“下一步(N)”按钮，打开“更新数据优化信息”窗体(如图3)。&lt;BR&gt;　　&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;LINE-HEIGHT:&nbsp;150%;&nbsp;TEXT-ALIGN:&nbsp;center&quot;&nbsp;align=center&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;9pt;&nbsp;COLOR:&nbsp;#5b5b5b;&nbsp;LINE-HEIGHT:&nbsp;150%;&nbsp;FONT-FAMILY:&nbsp;微软雅黑&quot;&gt;&lt;IMG&nbsp;height=383&nbsp;alt=&quot;&quot;&nbsp;src=&quot;http://www.cnblogs.com/images/cnblogs_com/zhaoqing/bf2.JPG&quot;&nbsp;width=498&nbsp;border=0&gt;　&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;LINE-HEIGHT:&nbsp;150%&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;9pt;&nbsp;COLOR:&nbsp;#5b5b5b;&nbsp;LINE-HEIGHT:&nbsp;150%;&nbsp;FONT-FAMILY:&nbsp;微软雅黑&quot;&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;9pt;&nbsp;COLOR:&nbsp;#5b5b5b;&nbsp;LINE-HEIGHT:&nbsp;150%;&nbsp;FONT-FAMILY:&nbsp;微软雅黑&quot;&gt;　　在此窗体中可以对数据库中的数据和索引重新进行组织，以及能够设定在满足一定条件的情况下，维护计划自动删除数据库中的未使用的空间，以便提高性能。&lt;BR&gt;　　但要注意的是，在此窗体中，只要选定了“重新组织数据和索引页[R]”复选框，“更新查询优化器所使用的统计。示例[D]”复选框将失效(变成灰色，不能选择)。而且“重新组织数据和索引页[R]”复选框和“从数据库文件中删除未使用的空间[M]”复选框二者只要有一个被选中，其下的“调度[S]”功能才有效。单击“更改[C]”按钮可以对“调度”进行自定义。&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;LINE-HEIGHT:&nbsp;150%;&nbsp;TEXT-ALIGN:&nbsp;left&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;9pt;&nbsp;COLOR:&nbsp;#5b5b5b;&nbsp;LINE-HEIGHT:&nbsp;150%;&nbsp;FONT-FAMILY:&nbsp;微软雅黑&quot;&gt;各位读者可以根据自身情况决定是否选用其中的功能。当然也可以通过单击“帮助”按钮来查看各功能的具体含义。&lt;BR&gt;　　在此窗体中能够便捷地设定每项作业的持续运行时间和运行的频率。完成自己的设置后，一定要选定右上角的“启用调度[B]”复选框，这样一个作业调度才算真正完成了。&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/SPAN&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;9pt;&nbsp;COLOR:&nbsp;#5b5b5b;&nbsp;LINE-HEIGHT:&nbsp;150%;&nbsp;FONT-FAMILY:&nbsp;微软雅黑&quot;&gt;步骤3：单击图3中的“下一步(N)”按钮，打开“检查数据库完整性”窗体。&lt;BR&gt;　　在此窗体中可以设定维护计划在备份数据库前自动检查数据库的完整性，以便检测由于硬件或软件错误而导致数据的不一致。在此窗体中只有先选定了“检查数据库完整性[H]”复选框即可。&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;剩下的操作就不提了，只要根据自己的需要进行相应的配置即可，最后不要忘了数据库内的作业任务检查一下，看有没有启用。&lt;BR&gt;&lt;/SPAN&gt;&lt;/P&gt;]]></summary>
	  <link rel="alternate" type="text/html" href="http://h31home.com/h312005/blogview.asp?ID=978" /> 
	  <id>http://h31home.com/h312005/blogview.asp?ID=978</id> 
  </entry>	

  <entry>

	  <title type="html"><![CDATA[重装grub的方法及grub相关配置]]></title>
	  <author>
		 <name>admin</name>
		 <uri>http://h31home.com/h312005/blogview.asp?ID=977</uri>
		 <email></email>
	  </author>
	  <category term="" scheme="http://h31home.com/h312005/blogview.asp?ID=977" label="Linux学习" /> 
	  <updated>2008-6-6 16:24:38</updated>

	  <published>2008-6-6 16:24:38</published>
		  <summary type="html"><![CDATA[&lt;P&gt;&nbsp;&nbsp;重装系统的时候,MBR都会被重写,这样原来的GRUB或LILO&nbsp;就会不见了,或者由于某些原因使原来的GRUB不见了,就得重装GRUB.&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;重装GRUB的方法,任选一种试试:&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1.用安装光盘启动,选择升级安装,再只选安装GRUB.&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2.用安装光盘启动,到BOOT&nbsp;那里输入&nbsp;linux&nbsp;rescue&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;进入救援模式,到出现#命令提示符时输入&nbsp;chroot&nbsp;&nbsp;&nbsp;/mnt/sysimage&nbsp;&nbsp;&nbsp;之后再输入&nbsp;grub-install&nbsp;&nbsp;&nbsp;/dev/hda&nbsp;&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3.没有软驱如何修复grub/lilo&nbsp;引导菜单?&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a.把第一张linux安装盘里的dosutils&nbsp;目录复制到windows盘中.&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b.进入纯DOS,进入dosutils目录,执行loadlin&nbsp;&nbsp;autoboot/vmlinuz&nbsp;&nbsp;&nbsp;root=/dev/hdx&nbsp;-&gt;hdx&nbsp;是linux的根分区号,这样就能进入linux.&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c.执行grub-install&nbsp;&nbsp;&nbsp;/dev/hdx&nbsp;&nbsp;(x=a,b,c,d)即可重写引导.&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4.如果用grub来引导linux&nbsp;和windows,当windows出毛病重装安装后会破坏MBR中的GRUB,这时需要恢复GRUB&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a.把linux&nbsp;安装光盘的第一张放到光驱,重启到BIOS中,把第一引导设为光驱引导.&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b.安装界面出来后,按F4&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c.一系列简单的点鼠标后会出现提示符&nbsp;sh#,这样我们就可以操作GRUB了,sh#&nbsp;&nbsp;grub&nbsp;&nbsp;会出现这样的提示符:&nbsp;grub&gt;root&nbsp;&nbsp;(hdx,y)&nbsp;&nbsp;&nbsp;&nbsp;x为0是第一个盘,为1是第二个盘;y为linux系统所在的根分区.grub&gt;setup&nbsp;&nbsp;(hd0)&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5.如何删除GRUB或LILO&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在DOS下执行fdisk&nbsp;&nbsp;&nbsp;/mbr&nbsp;&nbsp;就OK了.&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;6.如何配置grub?&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;修改&nbsp;/boot/grub/grub.conf&nbsp;文件,其中default=n&nbsp;n是数字,是grub引导菜单默认被选中的项,n从0开始,0表示第一项,1表示第二项依次类推.&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;timeout=x&nbsp;&nbsp;&nbsp;&nbsp;是时间,单位为秒,也就是引导菜单显示后,如果x秒内不进行选择,那么grub将启动默认项.&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;splashimage=******x&nbsp;&nbsp;&nbsp;这是引导菜单的背景图.&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;title&nbsp;Red&nbsp;Hat&nbsp;8.0&nbsp;&nbsp;&nbsp;是启动菜单列表里显示的名字.&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;root&nbsp;&nbsp;&nbsp;(hd1,6)&nbsp;&nbsp;&nbsp;用来指定你的boot分区位置,hdx是所在的第几块硬盘,hd1是第二块;y的分区位置,从0开始&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;kernel&nbsp;&nbsp;&nbsp;/boot/vmlinuz-2.4.18-14&nbsp;&nbsp;&nbsp;&nbsp;是要用的内核路径,如果你编译了新的内核,把它改成新内核的路径.&lt;/P&gt;&lt;P&gt;&nbsp;&lt;/P&gt;]]></summary>
	  <link rel="alternate" type="text/html" href="http://h31home.com/h312005/blogview.asp?ID=977" /> 
	  <id>http://h31home.com/h312005/blogview.asp?ID=977</id> 
  </entry>	

  <entry>

	  <title type="html"><![CDATA[于梯度方向图的汽车牌照定位[收集]]]></title>
	  <author>
		 <name>admin</name>
		 <uri>http://h31home.com/h312005/blogview.asp?ID=976</uri>
		 <email></email>
	  </author>
	  <category term="" scheme="http://h31home.com/h312005/blogview.asp?ID=976" label="VC学习" /> 
	  <updated>2008-6-6 16:20:59</updated>

	  <published>2008-6-6 16:20:59</published>
		  <summary type="html"><![CDATA[&lt;P&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;由梯度公式获取梯度纹理方向图&lt;BR&gt;用Sobel算子分别求取水平方向、垂直方向、倾斜方向(包括45度和135度)的梯度分量，分别用Gx、Gy、Gxy、Gyx表示。&lt;BR&gt;将车牌灰度图分成若干块WxW(5x5)进行分块处理，其计算量减少为对整幅图象的25倍，速度快、计算少能满足系统的实时性要求。&lt;BR&gt;再分别对分块的灰度图利用已求取的Gx、Gy、Gxy、Gyx求取每块的局部方向vx、vy。&lt;/P&gt;&lt;P&gt;?根据反正切函数求取车牌图象的方向角度值。&lt;BR&gt;a=atan(Vx(i,j)/&nbsp;Vy(i,j))/2&lt;BR&gt;以上步骤已经求取了图象的纹理梯度方向，主要代码如下：&lt;BR&gt;CClientDC&nbsp;dc(this);&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;CPlateDoc&nbsp;*pDoc=GetDocument();&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;CPen&nbsp;mypen(PS_SOLID,0,RGB(0,100,126));&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;dc.ＳelectObject(&amp;mypen);&lt;BR&gt;&nbsp;&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;Image&nbsp;*im;&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;im=pDoc-&gt;m_dib.DibToImage();&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&lt;BR&gt;//---------------------------------------------&lt;BR&gt;Field&nbsp;&nbsp;*im_x,*im_y,*im_jd,*im_vx,*im_vy；&lt;BR&gt;Field&nbsp;&nbsp;*im_wenli;&lt;BR&gt;Field&nbsp;&nbsp;*im_xy,*im_yx;&lt;/P&gt;&lt;P&gt;&nbsp;&nbsp;&nbsp;im_x=new&nbsp;&nbsp;Field(im-&gt;width,im-&gt;height);&lt;BR&gt;&nbsp;&nbsp;&nbsp;im_y=new&nbsp;&nbsp;Field(im-&gt;width,im-&gt;height);&lt;BR&gt;&nbsp;&nbsp;&nbsp;im_xy=new&nbsp;&nbsp;Field(im-&gt;width,im-&gt;height);&lt;BR&gt;&nbsp;&nbsp;&nbsp;im_yx=new&nbsp;&nbsp;Field(im-&gt;width,im-&gt;height);&lt;BR&gt;&nbsp;&nbsp;&nbsp;&lt;BR&gt;&nbsp;&nbsp;&nbsp;im_vx=new&nbsp;Field(im-&gt;width,im-&gt;height);&lt;BR&gt;&nbsp;&nbsp;&nbsp;im_vy=new&nbsp;Field(im-&gt;width,im-&gt;height);&lt;/P&gt;&lt;P&gt;&nbsp;&nbsp;&nbsp;im_jd=new&nbsp;Field(im-&gt;width/W,im-&gt;height/W);&lt;BR&gt;&nbsp;&nbsp;&nbsp;im_wenli=new&nbsp;Field(im-&gt;width/W,im-&gt;height/W);&lt;BR&gt;&nbsp;&nbsp;&nbsp;&lt;/P&gt;&lt;P&gt;&nbsp;//-----------------------------求取方向图------&lt;BR&gt;&nbsp;&nbsp;&nbsp;int&nbsp;i,j,u,v,k,l;&lt;BR&gt;&nbsp;&nbsp;for(j=0,l=1;j&lt;im-&gt;height-W;j+=W,l++)&lt;BR&gt;&nbsp;&nbsp;&nbsp;{&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(i=0,k=1;i&lt;im-&gt;width-W;i+=W,k++)&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;im_x-&gt;field[k][l]=(im-&gt;ng[k-1][l+1]+2*im-&gt;ng[k][l+1]+im-&gt;ng[k+1][l+1])-&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(im-&gt;ng[k-1][l-1]+2*im-&gt;ng[k][l-1]+im-&gt;ng[k+1][l-1]);//水平方向的梯度&lt;/P&gt;&lt;P&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;im_y-&gt;field[k][l]=(im-&gt;ng[k-1][l-1]+2*im-&gt;ng[k-1][l]+im-&gt;ng[k-1][l+1])-&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(im-&gt;ng[k+1][l-1]+2*im-&gt;ng[k+1][l]+im-&gt;ng[k+1][l+1]);//垂直方向的梯度&lt;/P&gt;&lt;P&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;im_xy-&gt;field[k][l]=(im-&gt;ng[k+2][l]+2*im-&gt;ng[k+1][l+1]+im-&gt;ng[k][l+2])-&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(im-&gt;ng[k-1][l+1]+2*im-&gt;ng[k][l]+im-&gt;ng[k+1][l-1]);//45方向的梯度&lt;/P&gt;&lt;P&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;im_yx-&gt;field[k][l]=(im-&gt;ng[k][l-1]+2*im-&gt;ng[k+1][l]+im-&gt;ng[k+2][l+1])-&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(im-&gt;ng[k-1][l]+2*im-&gt;ng[k][l+1]+im-&gt;ng[k+1][l+2]);//135方向的梯度&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&lt;BR&gt;&nbsp;&nbsp;&nbsp;}&lt;BR&gt;//---------------------------------------------&lt;BR&gt;&nbsp;&nbsp;&nbsp;for(j=0,l=0;j&lt;im-&gt;height-W;j+=W,l++)&lt;BR&gt;&nbsp;&nbsp;&nbsp;{&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(i=0,k=0;i&lt;im-&gt;width-W;i+=W,k++)&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(v=j;v&lt;j+W;v++)&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(u=i;u&lt;i+W;u++)&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;im_vx-&gt;field[u][v]=(2*im_x-&gt;field[u][v]*im_y-&gt;field[u][v])/(fabs(im_x-&gt;field[u][v])+fabs(im_y-&gt;field[u][v]))+(im_xy-&gt;field[u][v]*&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;im_xy-&gt;field[u][v]-im_yx-&gt;field[u][v]*im_yx-&gt;field[u][v])/(fabs(im_xy-&gt;field[u][v])+fabs(im_yx-&gt;field[u][v]));&lt;BR&gt;&nbsp;&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;im_vy-&gt;field[u][v]=(im_x-&gt;field[u][v]*im_x-&gt;field[u][v]-im_y-&gt;field[u][v]*im_y-&gt;field[u][v])/(fabs(im_x-&gt;field[u][v])+&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fabs(im_y-&gt;field[u][v]))&nbsp;-(2*im_xy-&gt;field[u][v]*im_yx-&gt;field[u][v])/(fabs(im_xy-&gt;field[u][v])+fabs(im_yx-&gt;field[u][v]));&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&lt;/P&gt;&lt;P&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;im_jd-&gt;field[k][l]=(atan2(-im_vx-&gt;field[k][l],-im_vy-&gt;field[k][l]))/2;&lt;/P&gt;&lt;P&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(im_jd-&gt;field[k][l]&lt;0)&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;im_wenli-&gt;field[k][l]=(im_jd-&gt;field[k][l]+2*PI)/2;&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;im_wenli-&gt;field[k][l]=im_jd-&gt;field[k][l]/2;&nbsp;&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(fabs(im_x-&gt;field[k][l]-im_y-&gt;field[k][l])&lt;16&nbsp;&amp;&amp;&nbsp;fabs(im_xy-&gt;field[k][l]-im_yx-&gt;field[k][l])&lt;21)&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;im_wenli-&gt;field[k][l]=0;&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&lt;BR&gt;&nbsp;&nbsp;&nbsp;}&lt;/P&gt;]]></summary>
	  <link rel="alternate" type="text/html" href="http://h31home.com/h312005/blogview.asp?ID=976" /> 
	  <id>http://h31home.com/h312005/blogview.asp?ID=976</id> 
  </entry>	

  <entry>

	  <title type="html"><![CDATA[基于四叉树空间划分的地形实时渲染方法[收集]]]></title>
	  <author>
		 <name>admin</name>
		 <uri>http://h31home.com/h312005/blogview.asp?ID=975</uri>
		 <email></email>
	  </author>
	  <category term="" scheme="http://h31home.com/h312005/blogview.asp?ID=975" label="VC学习" /> 
	  <updated>2008-6-6 15:57:09</updated>

	  <published>2008-6-6 15:57:09</published>
		  <summary type="html"><![CDATA[&lt;P&gt;地形是计算机图形的一个重要组成部分，而它又具有特殊的形态。地形往往覆盖面积极广，且精度要求很高，使得我们必须用许多多边形来描述。这样的特点使得我们不能像对待其他普通模型那样对待地形。要想实时地渲染地形，我们需要一些特殊的方法。&nbsp;&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;地形渲染一直以来都是计算机图形学中一个重要的研究领域。并且在这一方面已经诞生了许多优秀的算法。其中包括基于体素的渲染方法，也有基于多边形的渲染方法。早期的游戏，如三角洲特种部队就是采用体素渲染法的成功例子。体素法类似光线追踪渲染，它从屏幕空间出发，找到地形与屏幕像素发出的射线交点，然后确定该像素的颜色。这种方法不依赖具体的图形硬件，整个渲染过程完全使用CPU处理，因此它不能使用现代硬件来加速，并且对于一个场景来说，往往不只是地形，还有其他使用多边形描述的物体，体素法渲染的图像很难与硬件渲染的多边形进行混合，因此这种方法现在用得极少。而多边形渲染方法则成为一种主流。选择多边形来描述和渲染地形有很多的理由和优点。最重要的是它能够很好地使用硬件加速，并且能够和其他多边形对象一起统一管理。&lt;/P&gt;&lt;P&gt;&nbsp;&nbsp;&nbsp;&nbsp;已有大量优秀的基于多边形的地形渲染算法。比较经典的算法有M.&nbsp;Duchaineau等人提出ROAM算法。这个算法采用一棵三角二*树来描述整个地形。一个地形在最初的层次上由两个较大的等腰直角三角形组成，这两个等腰直角三角形可以被不断地细分来展现地形的更多细节。每一次细分过程都向直角三角形的斜边的中点处增加一个由高程数据所描述的顶点，该点将所在的直角三角形一分为二，同时该算法也定义了一些规则来保证地形中不会因相邻两个三角形细节层次的不同而出现裂缝。这个算法已被许多游戏所采用。还有一类算法，通过将地形在X-Z投影面上不断地规则细分来得到不同的细节，这就是本文要介绍的四*树空间划分算法。另外，最新提出的一个地形算法也不得不提，Hugues&nbsp;Hoppe在2004年提出的几何裁剪图方法(Geometry&nbsp;Clipmaps)，算法使用了最新硬件所支持的顶点纹理来定义地形的外观，并且对于距离摄影机不同远近的地方采用不同的纹理层，最大限度地使用硬件加速了地形渲染的过程。这个方法听起来非常美妙，但它目前只被较少的硬件支持。因为顶点纹理是Shader&nbsp;Model&nbsp;3.0才支持的功能，也就是说只有DirectX&nbsp;9.0c级别的显卡才能支持这种算法。这对于某些有普及性要求的图形应用程序，尤其是对游戏来讲不是一件好的事情。因此大多数人现在还在使用经典的地形渲染方法。&lt;/P&gt;&lt;P&gt;&nbsp;&nbsp;&nbsp;&nbsp;首先，基于四*树的地形渲染方法使用高程数据作为数据源。且算法要求高程数据的大小必须为2n+1的正方形。所谓高程数据，即色彩范围在0-255的灰度图片，不同的灰度代表了不同的高度值。如果某高程数据指出这个高程数据最高处的Y坐标值是4000，那么在高程数据中一个值为255的像素点就表示这个点所代表的地形区域的高度是4000，同理如果该像素值是127那么就表示这个点所代表的地形区域的高度是4000×(127/255)=2000。高程数据的每个像素都对应所渲染网格中的一个顶点。另外还有一个参数描述顶点与顶点之间的水平距离，以及一个描述最大高度的参数。因此地形的基本数据结构如下：&lt;/P&gt;&lt;P&gt;&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;Terrain&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;{&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;**DEM;&nbsp;//一个描述高程数据的二维数组&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;float&nbsp;CellSpace;&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;float&nbsp;HeightScale;&nbsp;&nbsp;&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;}&lt;/P&gt;&lt;P&gt;&nbsp;&nbsp;&nbsp;&nbsp;其中，各变量的具体意义如下图所示：&lt;BR&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=center&gt;&lt;CITE&nbsp;style=&quot;FONT-STYLE:&nbsp;normal&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&lt;IMG&nbsp;src=&quot;http://www.graphixer.com.cn/ArtImages/TerrainQuad/Terrai1.jpg&quot;&nbsp;border=0&gt;&nbsp;有了这些参数，我们可以很容易地由高程数据的参数值得到它所表述的多边形网格。得到这个网格之后，可以简单地把它放入顶点数组，并为之建立一个顶点索引，就可以传入硬件进行渲染了。然而，事情并不是这么简单。对于较小尺寸的高程数据(如129×129)，这样做确实可行，但随着高程数据规模的增大，所需的顶点数和描述网格的三角形数会急剧膨胀。这个数值很快就会大到最新的显卡也无法接受。比如一个1025×1025的高程数据，我们需要1025×1025=1050625个顶点，以及1050625×2=2101250个三角形。就算你的显卡每秒能够渲染1000万个三角形，你也只能得到不到5fps的渲染速度，况且你的场景可能还不只包括地形。因此我们必须想办法在不影响视觉效果的情况下缩减所渲染的三角形数量，另外还应该注意一次性将最多的数据预先传给硬件以节约带宽。&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;CITE&nbsp;style=&quot;FONT-STYLE:&nbsp;normal&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;这里要讲解的算法，目的就是在不影响或在视觉可以接受的范围内缩减所渲染三角形的数量，以达到实时渲染的要求。根据测试，本算法在漫游大小为1025*1025的地形时速度稳定在150fps以上(在nVidia&nbsp;Geforce&nbsp;6200&nbsp;+&nbsp;P4&nbsp;1.6GHz的硬件上得到)。&lt;/SPAN&gt;&lt;/CITE&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;CITE&nbsp;style=&quot;FONT-STYLE:&nbsp;normal&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;由于地形覆盖范围广，但它的投影在XZ平面上均匀分布(以下采用OpenGL中的右手坐标系，Y轴为竖直向上的坐标轴)，因此我们有必要考虑对地形进行空间划分。正是由于这样的均匀分布，给我们的划分过程带来了便利。我们不需要具体地去分割某个三角形，只要选择那些过顶点且和X或Z轴垂直的平面作为划分面即可。例如对于一个高程数据，我们可以以坐标原点作为地形的中心点，然后沿着X轴和Z轴依次展开来分布各个顶点。如下如所示。&lt;/SPAN&gt;&lt;/CITE&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=center&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&lt;IMG&nbsp;src=&quot;http://www.graphixer.com.cn/ArtImages/TerrainQuad/Terrai2.gif&quot;&nbsp;border=0&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;首先，我们可以选择X=0和Z=0这两个平面，将地形划分为等大的四个区域，然后对划分出来的四个子区域进行递归划分，每次划分都选择交于区域中心点并且互相垂直的两个平面作为划分面，直到每个子区域都只包含一个地形单元块（即两个三角形）而不能再划分为止。例如对于上图所示9*9大小的地形块，经过划分之后如下图所示：&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=center&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&lt;IMG&nbsp;src=&quot;http://www.graphixer.com.cn/ArtImages/TerrainQuad/Terrai3.gif&quot;&nbsp;border=0&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;由图可知，只有高程数据满足&lt;CITE&nbsp;style=&quot;FONT-STYLE:&nbsp;normal&quot;&gt;大小2&lt;SUP&gt;n&lt;/SUP&gt;+1的正方形这个条件，我们才可能对地形进行均匀划分。&lt;/CITE&gt;我们可以把划分结果用一棵树来表述，由于每次划分之后产生四个子节点，因此这棵树叫四*树。那么，这棵树中应该存储那些信息呢？首先对于每个节点，应该指定这个节点所代表的地形的区域范围。并不是把地形网格中实际的顶点放入树中，而是要在树中说明这个节点覆盖了地形的那些区域。比如一个子节点应该有一个Center(X,Y)变量，指定这个节点的中心点所对应的顶点索引，或编号。为了方便起见，可以把地形中心点编号为(0,0)然后沿着坐标轴递增。此外还要有个变量指定这个节点到底覆盖了地形的多少个顶点。如下图所示。&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=center&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&lt;IMG&nbsp;src=&quot;http://www.graphixer.com.cn/ArtImages/TerrainQuad/Terrai4.gif&quot;&nbsp;border=0&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;我们目前的四*树的数据结构如下：&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&lt;STRONG&gt;struct&lt;/STRONG&gt;&nbsp;QuadTreeNode&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;{&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;STRONG&gt;QuadTreeNode&lt;/STRONG&gt;&nbsp;*Children[4];&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;STRONG&gt;int&lt;/STRONG&gt;&nbsp;CenterX,CenterY;&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;STRONG&gt;int&lt;/STRONG&gt;&nbsp;HalfRange;&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;}&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;有了四*树之后，如何利用它的优势呢？首先我们考虑简单的视见体裁剪(View&nbsp;Frustum&nbsp;Culling，以下简称VFC)。相信很多接触过基本图形优化的人都应该熟悉VFC，VFC的作用既是对那些明显位于可见平截头体之外的多边形在把它们传给显卡之前剔除掉。这个过程由CPU来完成。虽然简单，但它却非常有效。VFC过程如下：&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;1.为每个节点计算包围球。包围球可以简单的以中心顶点为球心，最大坐标值点(节点所覆盖的所有顶点的最大X、Y、Z值作为此点的坐标值)到球心的距离为半径。&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;2.根据当前的投影和变换矩阵计算此时可视平截头体的六个平面方程。这一步可以参考Azure的Blog上的一篇文章，这篇文章给出了VFC的具体代码。&lt;A&nbsp;href=&quot;http://www.azure.com.cn/article.asp?id=155&quot;&nbsp;target=_blank&gt;&lt;FONT&nbsp;color=#0022cc&gt;单击这里&lt;/FONT&gt;&lt;/A&gt;。&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;3.从树的根结点以深度优先的顺序遍历树。每次访问节点时，测试该节点包围球与视见体的相交情况。在下面的情况下，包围球与视见体相交：&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1)&nbsp;球心在六个平面所包围的凸状区域内部。&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2)&nbsp;球心在六个平面所包围的凸状区域外部，但球心到某个平面的距离小于半径。&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;4.如果相交测试显示包围球和视见体存在交集，继续递归遍历此节点的4个子节点，如果此节点已经是叶节点，则这个节点应被绘制。如果不存在交集，放弃这个节点，对于这个节点的所有子节点不再递归检查。因为如果一个节点不可见，那么其子节点一定不可见。&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;这样，我们剔除了那些不在视见体内的地形区域，节约了一些资源。但这还不够。在某些情况下，VFC可能还会指出整个地形都可见，在这种情况下，将这么多三角形都画出显然是不可取的。&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;因此还要考虑地形的细节层次(LOD)。我们应该考虑到，地形不可能所有部分都一样平坦或陡峭。对于平坦的部分，我们用过多的三角形去描述是没有意义的。而对于起伏程度较大的区域，只有较多的三角形数量才不让人感到尖锐的棱角。再者，无论地形起伏程度如何，那些距离视点很远的区域，也没有必要花费太多的资源去渲染，毕竟它们投影到屏幕上的面积很小，对其进行简化也是必要的。&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;既然我们要对起伏程度不同的区域采用不同的细节级别，我们首先必须找到一种描述地形起伏程度的量。与其说起伏程度，不如说是地形的某个顶点因为被简化后而产生的误差。要计算这个误差，我们先要了解地形是如何被简化的。&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;考虑下图所示的地形块，它的渲染结果如下图右图所示。&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=center&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&lt;IMG&nbsp;src=&quot;http://www.graphixer.com.cn/ArtImages/TerrainQuad/Terrai6.gif&quot;&nbsp;border=0&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;现在如果要对所需渲染的三角形进行简化，我们可以考虑这个地形块每条边中间的顶点(下图左侧红色点)：&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=center&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&lt;IMG&nbsp;src=&quot;http://www.graphixer.com.cn/ArtImages/TerrainQuad/Terrai7.gif&quot;&nbsp;border=0&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;如果将这些红色的顶点剔除，我们可以得到上图右边所示的简化后的网格。误差就在这一步产生。由于红色的顶点被剔除后，原本由红色顶点所表示的地形高度现在变成了两侧黑色顶点插值后的高度。这个高度就是误差。如下图。&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=center&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&lt;IMG&nbsp;src=&quot;http://www.graphixer.com.cn/ArtImages/TerrainQuad/Terrai8.gif&quot;&nbsp;border=0&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;因此，对于每个节点，我们先计算这个节点所有边中点被删除后所造成的误差，分别记为ΔH1,&nbsp;ΔH2,&nbsp;ΔH3,&nbsp;ΔH4。如果这个节点包含子节点，递归计算子节点的误差，并把四个子节点的误差记为ΔHs1,&nbsp;ΔHs2,&nbsp;ΔHs3,&nbsp;ΔHs4。这个节点的误差就是这八个误差值中的最大值。由于这是一个递归的过程，因此应该把这个过程加到四*树的生成过程中，并向四*树的数据结构中加入一个误差变量。如下。&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;QuadTreeNode&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;{&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;QuadTreeNode&nbsp;*Children;&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;CenterX,CenterY;&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;HalfRange;&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;float&nbsp;DeltaH;&nbsp;&nbsp;//节点误差值&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;}&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;下面来看一下地形的具体渲染过程。&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;首先，我们位于四*树的根结点。我们此时考虑根结点的误差，如果这个误差小于一个阈值，直接使用根结点的中心点以及此节点的四个边角点作为顶点渲染一个三角扇形，这个三角扇形就是渲染出来的地形。但是更经常的情况下，根结点的误差值是很大的，因此算法认为要对根结点进行细分，以展现更多细节。于是对于根结点的每个子节点，重复这个步骤，即检查它的误差值是否大于阈值，如果大于，直接渲染这个节点，如果小于，递归细分节点。目前我们的算法伪代码如下。&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;procedure&nbsp;DrawTerrain(QuadTreeNode&nbsp;*node)&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;{&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(node-&gt;DeltaH&nbsp;&gt;&nbsp;k)&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(i=0;i&lt;4;i++)&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DrawTerrain(node-&gt;Children[i]);//递归划分&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GraphicsAPI-&gt;DrawPrimitive(node);//以节点的中心点和四个边角点绘制三角扇形&nbsp;&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;}&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;这个伪代码在一个较高的层次上表述了算法的基本思想。然而我们还有许多问题要考虑。其一是目前我们仅仅考虑了地形的细节层次和地形表面起伏程度的关系，但还应该考虑地形块距离视点远近跟地形细节层次的关系。解决这个问题很简单，我们只需在伪代码的条件中加入距离这一因素即可。即把&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(node-&gt;DeltaH&nbsp;&gt;&nbsp;k)&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;...&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;改为：&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(node-&gt;DeltaH&nbsp;/&nbsp;d&nbsp;&gt;&nbsp;k)&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;...&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;其中d为节点中心点与视点之间的距离。而事实上，当细节程度与距离的平方成反比时，能够减少更多的三角形，而且视觉效果更好，只要阈值k设置得当，根本感觉不出地形因为视点的移动而发生几何形变。因此，我们最终的条件式为：&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;node-&gt;DeltaH&nbsp;/&nbsp;d&lt;SUP&gt;2&lt;/SUP&gt;&nbsp;&gt;&nbsp;k&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;还有一个很重要的问题，就是这个算法所产生的地形会因为节点之间细节层次的不同而产生裂缝。下图说明了裂缝的产生原因。&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=center&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&lt;IMG&nbsp;src=&quot;http://www.graphixer.com.cn/ArtImages/TerrainQuad/Terrai9.gif&quot;&nbsp;border=0&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;有两个方法可以解决这个问题，一个方法是删除左侧节点中产生裂缝的顶点，使两条边能够重合。另一种方法是人为地在右侧地形块中插入一条边，这条边连接中心点和造成裂缝的顶点，从而消除裂缝。在渲染地形时，可以采取下面的办法避免裂缝的产生：&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;1.在预处理阶段，为所有顶点创建一个标记数组，标记以该顶点为中心点的节点在某一帧是否被细分。如果被细分则标记为1，否则标记0。&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;2.从根节点开始，以广度优先的顺序遍历四*树，使用之前提出的条件式判断节点是否需要分割。如果公式表明需要分割，并且与节点相邻的四个节点的中心点都被标记为1，那么把这个节点及其四个子节点的标记设为1，并递归细分这个节点。否则，将这个节点的标记设为1，把这个节点的四个子节点的标记设为0，然后采用下面的方法绘制这个地形块：&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1)将节点的中心顶点和四个边角点添加到即将绘制的三角扇形列表中。&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2)依次检查与四条边相邻的节点的标记数组，如果相应的标记为1，那么将该点添加到三角扇形的顶点列表中，否则跳过该点。&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3)绘制三角扇形。&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;我们最终的伪代码如下。&lt;/SPAN&gt;&lt;/P&gt;&lt;DIV&nbsp;align=center&gt;&lt;TABLE&nbsp;id=table1&nbsp;width=&quot;72%&quot;&nbsp;border=1&gt;&lt;TBODY&gt;&lt;TR&gt;&lt;TD&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;STRONG&gt;&lt;/STRONG&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&lt;STRONG&gt;bool&lt;/STRONG&gt;&nbsp;IsNodeInFrustum(QuadTreeNode&nbsp;*node)&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;{&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&lt;STRONG&gt;return&lt;/STRONG&gt;&nbsp;(node-&gt;BoudingSphere&nbsp;in&nbsp;frustum);&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;}&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;STRONG&gt;&lt;/STRONG&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&lt;STRONG&gt;bool&lt;/STRONG&gt;&nbsp;NeighbourIsValid(QuadTreeNode&nbsp;*node)&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;{&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&lt;STRONG&gt;return&lt;/STRONG&gt;&nbsp;(all&nbsp;four&nbsp;neighbours&nbsp;of&nbsp;node&nbsp;are&nbsp;identified&nbsp;as&nbsp;1)&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;}&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&lt;STRONG&gt;void&lt;/STRONG&gt;&nbsp;RenderTerrain()&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;{&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;list&lt;QuadTreeNode&nbsp;*&gt;next,current,draw;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&lt;STRONG&gt;int&lt;/STRONG&gt;&nbsp;level&nbsp;=0;&lt;BR&gt;&nbsp;&nbsp;&nbsp;current.push_back(root);&lt;BR&gt;&nbsp;&nbsp;&nbsp;&lt;STRONG&gt;while&lt;/STRONG&gt;&nbsp;(current.size()!=0)&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;{&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;STRONG&gt;for&lt;/STRONG&gt;&nbsp;&lt;STRONG&gt;each&lt;/STRONG&gt;&nbsp;thisNode&nbsp;in&nbsp;current&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;STRONG&gt;if&lt;/STRONG&gt;&nbsp;(!IsNodeInFrustum(thisNode))&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;STRONG&gt;continue&lt;/STRONG&gt;;&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;STRONG&gt;if&lt;/STRONG&gt;&nbsp;(level&nbsp;==&nbsp;MaxResolution)&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;draw.push_back(thisNode);&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;STRONG&gt;else&lt;/STRONG&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;STRONG&gt;if&lt;/STRONG&gt;&nbsp;(thisNode-&gt;DeltaH/(distance*distance)&nbsp;&gt;&nbsp;k&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&amp;&amp;&nbsp;NeighbourIsValid(thisNode)&nbsp;)&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SetFlag(thisNode,1);&nbsp;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;STRONG&gt;for&lt;/STRONG&gt;&nbsp;j=&nbsp;1&nbsp;&lt;STRONG&gt;to&lt;/STRONG&gt;&nbsp;4&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;next.push_back(thisNode-&gt;Children[j]);&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SetFlag(thisNode-&gt;Children[j],1)&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;STRONG&gt;else&lt;/STRONG&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SetFlag(thisNode,1);&nbsp;&nbsp;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;STRONG&gt;for&lt;/STRONG&gt;&nbsp;j=&nbsp;1&nbsp;&lt;STRONG&gt;to&lt;/STRONG&gt;&nbsp;4&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;draw.push_back(thisNode-&gt;Children[j]);&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SetFlag(thisNode-&gt;Children[j],0);&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SwapList(current,next);&lt;BR&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;next.clear();&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;level++;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;}&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;GraphicsAPI-&gt;DrawPrimitives(draw);&nbsp;&nbsp;&nbsp;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;0px;&nbsp;MARGIN-BOTTOM:&nbsp;0px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;}&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/DIV&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;另外，一个重要的优化是利用硬件的缓冲区或顶点数组(对于不支持顶点缓冲的硬件而言)。因为地形无论怎样简化，顶点数据总是固定不变的。我们在每一帧动态产生的仅仅是顶点索引，因此我们有必要实现将地形的所有顶点数据输入到顶点缓冲中，然后在渲染时一次性将所有的索引传给显卡，以提高速度。实验表明，使用顶点缓冲比直接使用glBegin/glEnd绘制图形要快5倍以上。&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;以上讲述了如何做到实时地渲染大型地形。主要应用了LOD和VFC两种手段来精简三角形数量。然而VFC只能剔除不在视见体内的图形，而对于在视见体内但被其他更近的物体遮挡的情况却无能为力。如果要实现地形的自遮挡剔除，地平线算法是一个好的选择。然而当你的场景不仅仅是包含地形时，地平线算法也只能处理地形的自遮挡情况。因为地平线算法只对2.5D的地图(即在XZ平面上无重合投影的场景)有效。对于完全3D场景，地平线并不能很好的工作。所以当你在引擎中使用地形时，可以考虑将地形分块后放入场景的管理树中，如BSP或Octree等。然后根据引擎的性质使用入口(Portal)、PVS或者遮挡测试(Occlusion&nbsp;Culling)等方法进行遮挡剔除。值得强调的是，遮挡测试是一个非常灵活的实时的剔除算法，且无需任何预计算过程。但要想有效的实现它并不是一件容易的事。我曾将地形分块后使用遮挡剔除来完成地形的自遮挡，但是渲染速度不但没有提升，反而有轻微的下降。因此如果要使用遮挡剔除的话必须和引擎结合起来统一进行遮挡测试，才有可能提高效率。&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;现在你应该了解了基本的地形实时渲染方法。要想让地形的外观更加真实，我们还需要更多的工作。我们需要为地形加上纹理贴图和光照。首先考虑地形的光照。由于地形的多边形网格是实时产生的，它会随着视点的移动而变化，因此如果你直接使用OpenGL内置的顶点光照，你会得到极度不稳定的光照效果。你会看到地形表面会因为你的移动而不断跳动。因此我们必须使用其他的光照方法来避免这个问题。我们想到了光照贴图。光照贴图是一个游戏中常用的光照技术。它是一个覆盖了场景中所有多边形的贴图。通过给贴图赋值，我们可以得到多边形表面复杂的光照效果。使用好的算法计算出来的光照贴图可以模拟极度逼真的光影效果。它给我们带来的视觉享受远远地超过了OpenGL的内置光照。有关光照贴图的计算可以参考我翻译的一篇文章：&lt;/SPAN&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&lt;A&nbsp;href=&quot;http://program.stedu.net/showArticle.asp?index=68&quot;&gt;&lt;FONT&nbsp;color=#0022cc&gt;辐射度算法(Radiosity)&lt;/FONT&gt;&lt;/A&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=center&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;&lt;IMG&nbsp;src=&quot;http://www.graphixer.com.cn/ArtImages/TerrainQuad/Terrai11.jpg&quot;&nbsp;border=0&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=left&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;你可以简单地为地形覆盖上单一的纹理，这看起来些许增加了地形的真实性：&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&nbsp;align=center&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&lt;IMG&nbsp;src=&quot;http://www.graphixer.com.cn/ArtImages/TerrainQuad/Terrai12.jpg&quot;&nbsp;border=0&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;在上图中，我们创建了一个地形，并运用了一个重复的纹理。这个过程让地形的无论哪一个区域看起来都是一样的（例如都是草地）。这显然不太真实，也过于乏味。或许你会创建了一幅超大的图片，以拉伸覆盖的方式映射到地形表面。这样做的后果是内存开销过于庞大，这样做也很会受到硬件的限制。因此我们应该使用一种更好的纹理贴图方式，纹理索引贴图。&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;纹理索引贴图对三个可重复的纹理进行索引贴图。所谓索引贴图，就是对三个可重复纹理进行索引，以决定地形的哪些区域需要使用哪些纹理的混合来贴图。因为对于任意的贴图，都由一组包含3个颜色通道（即R、G、B）的像素组成。用于索引的贴图的像素并不表示地形的某个区域的具体颜色，而是表示地形的某个区域用何种具体的纹理贴图。因为具体的纹理细节存储在这三个可重复的纹理中，因此索引贴图的贴图方式也为拉伸到地形表面，但它的分辨率可以大大降低。&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;纹理索引贴图的工作方式如下：对于地形投影到屏幕上的像素，查找该像素所映射到索引贴图上的像素。然后根据这一像素R、G、B分量的不同，决定R、G、B分量所代表的具体纹理贴图的混合因子。根据这个混合因子混合三个可重复贴图后，将混合得到的最终颜色值输出到屏幕上。&lt;/SPAN&gt;&lt;/P&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;例如，令索引贴图的R分量代表沙滩的纹理，G分量代表草地，B分量代表岩石。如果索引贴图上一个像素的值是(0,255,0)，即绿色，则这个像素所对应的地形区域的具体纹理就为草地。如果该像素颜色值是(127,127,0)，即黄色，则该像素所对应的地形区域的纹理为草地和沙滩的混合，看起来既有草，又有沙。又如下图显示了一个样本索引贴图，以及使用该贴图索引纹理之后的渲染效果。&lt;/SPAN&gt;&lt;/P&gt;&lt;DIV&nbsp;align=center&gt;&lt;TABLE&nbsp;id=table2&nbsp;width=&quot;20%&quot;&nbsp;border=0&gt;&lt;TBODY&gt;&lt;TR&gt;&lt;TD&nbsp;align=middle&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&lt;IMG&nbsp;height=238&nbsp;src=&quot;http://www.graphixer.com.cn/ArtImages/TerrainQuad/Terrai13.jpg&quot;&nbsp;width=236&nbsp;border=0&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;/TD&gt;&lt;TD&nbsp;align=middle&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&lt;IMG&nbsp;height=242&nbsp;src=&quot;http://www.graphixer.com.cn/ArtImages/TerrainQuad/Terrai14.jpg&quot;&nbsp;width=327&nbsp;border=0&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&nbsp;align=middle&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;索引贴图（R=沙滩，G=草地,B=岩石）&lt;/SPAN&gt;&lt;/P&gt;&lt;/TD&gt;&lt;TD&nbsp;align=middle&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;渲染效果&lt;/SPAN&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/DIV&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;原理很简单，下面讲解一下具体的实现过程。首先，我们准备4个纹理，其中1个纹理索引贴图，它将被拉伸覆盖整个地形，然后3张细节贴图，并将它们绑定到相应的纹理通道上。然后使用Vertex&nbsp;Shader为每个顶点自动计算索引贴图的纹理坐标，在Fragment&nbsp;Shader里，对索引贴图进行纹理查找，使用查找得到的颜色值的RGB颜色信息混合3张细节贴图，得到当前像素的颜色。最后还应该把这个颜色和光照贴图中的值相乘，得到最终的结果。下面是相关的Shader代码，使用GLSL编写。&lt;/SPAN&gt;&lt;/P&gt;&lt;DIV&nbsp;align=center&gt;&lt;TABLE&nbsp;id=table3&nbsp;width=&quot;68%&quot;&nbsp;border=1&gt;&lt;TBODY&gt;&lt;TR&gt;&lt;TD&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;STRONG&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;Vertex&nbsp;Shader:&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;/FONT&gt;&nbsp;&lt;P&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;uniform&nbsp;float&nbsp;TexInc;&nbsp;&nbsp;&nbsp;//纹理缩放值,用于查找索引纹理&lt;BR&gt;void&nbsp;main()&lt;BR&gt;{&lt;BR&gt;&nbsp;&nbsp;gl_TexCoord[6]&nbsp;=&nbsp;gl_Vertex;&lt;BR&gt;&nbsp;&nbsp;gl_TexCoord[0]&nbsp;=&nbsp;gl_MultiTexCoord0;&lt;BR&gt;&nbsp;&nbsp;gl_TexCoord[2]&nbsp;=&nbsp;TexInc*vec4(gl_Vertex.xz,0.0,0.0);&lt;BR&gt;&nbsp;&nbsp;gl_Position&nbsp;=&nbsp;ftransform();&lt;BR&gt;}&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;TR&gt;&lt;TD&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;STRONG&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;Fragment&nbsp;Shader:&lt;/SPAN&gt;&lt;/STRONG&gt;&lt;/FONT&gt;&nbsp;&lt;P&gt;&lt;FONT&nbsp;face=&quot;Courier&nbsp;New&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;uniform&nbsp;sampler2D&nbsp;IndexMap;&lt;BR&gt;uniform&nbsp;sampler2D&nbsp;LightMap;&lt;BR&gt;uniform&nbsp;sampler2D&nbsp;texR,texG,texB,texA;&lt;BR&gt;void&nbsp;main()&lt;BR&gt;{&lt;BR&gt;&nbsp;&nbsp;vec4&nbsp;idx,lm,r,g,b,color;&lt;BR&gt;&nbsp;&nbsp;idx&nbsp;=&nbsp;texture2D(IndexMap,gl_TexCoord[0].xy);&nbsp;//索引值&lt;BR&gt;&nbsp;&nbsp;lm&nbsp;=&nbsp;texture2D(LightMap,gl_TexCoord[0].xy);&nbsp;&nbsp;//光照度&lt;BR&gt;&nbsp;&nbsp;r&nbsp;=&nbsp;texture2D(texR,gl_TexCoord[2].xy);&nbsp;&nbsp;&nbsp;//R通道纹理&lt;BR&gt;&nbsp;&nbsp;g&nbsp;=&nbsp;texture2D(texG,gl_TexCoord[2].xy);&nbsp;&nbsp;&nbsp;//G通道纹理&lt;BR&gt;&nbsp;&nbsp;b&nbsp;=&nbsp;texture2D(texB,gl_TexCoord[2].xy);&nbsp;&nbsp;&nbsp;//B通道纹理&nbsp;&lt;BR&gt;&nbsp;&nbsp;color&nbsp;=&nbsp;lm*(idx.x*r&nbsp;+&nbsp;idx.y*g+idx.z*b);&nbsp;&nbsp;//混合颜色&lt;BR&gt;&nbsp;&nbsp;gl_FragColor&nbsp;=&nbsp;color;&lt;BR&gt;}&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/DIV&gt;&lt;P&nbsp;style=&quot;MARGIN-TOP:&nbsp;9px;&nbsp;MARGIN-BOTTOM:&nbsp;9px;&nbsp;LINE-HEIGHT:&nbsp;18px&quot;&gt;&lt;SPAN&nbsp;style=&quot;FONT-SIZE:&nbsp;10.5pt&quot;&gt;&nbsp;&nbsp;&nbsp;&nbsp;最后，如果你对本文有不解之处，欢迎和我共同讨论。&lt;/SPAN&gt;&lt;/P&gt;&lt;/SPAN&gt;&lt;/CITE&gt;]]></summary>
	  <link rel="alternate" type="text/html" href="http://h31home.com/h312005/blogview.asp?ID=975" /> 
	  <id>http://h31home.com/h312005/blogview.asp?ID=975</id> 
  </entry>	

  <entry>

	  <title type="html"><![CDATA[Linux环境进程间通信-共享内存[收集]]]></title>
	  <author>
		 <name>admin</name>
		 <uri>http://h31home.com/h312005/blogview.asp?ID=974</uri>
		 <email></email>
	  </author>
	  <category term="" scheme="http://h31home.com/h312005/blogview.asp?ID=974" label="Linux学习" /> 
	  <updated>2008-6-6 15:54:59</updated>

	  <published>2008-6-6 15:54:59</published>
		  <summary type="html"><![CDATA[&lt;P&gt;共享内存可以说是最有用的进程间通信方式，也是最快的IPC形式。两个不同进程A、B共享内存的意思是，同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新，反之亦然。由于多个进程共享同一块内存区域，必然需要某种同步机制，互斥锁和信号量都可以。&lt;BR&gt;采用共享内存通信的一个显而易见的好处是效率高，因为进程可以直接读写内存，而不需要任何数据的拷贝。对于像管道和消息队列等通信方式，则需要在内核和用户空间进行四次的数据拷贝，而共享内存则只拷贝两次数据[1]：一次从输入文件到共享内存区，另一次从共享内存区到输出文件。实际上，进程之间在共享内存时，并不总是读写少量数据后就解除映射，有新的通信时，再重新建立共享内存区域。而是保持共享区域，直到通信完毕为止，这