原文地址:http://www.adriancourreges.com/blog/2015/11/02/gta-v-graphics-study/
 

原文的简介:

GTA(侠盗猎车)系列自从1997年首部发售以来有了很大的进步,两年前,Rockstar发布的GTAV获得了成功,首日1100万套的销量打破了7项吉尼斯世界记录。

在PS3上游玩时,游戏的完成水准和技术质量给我留下了深刻印象。加载屏幕是最影响体验的:而在GTA中你可以游戏几个小时,在一个巨大的开放世界中驾车数百公里,而没有任何的中断。考虑到大量资源的Streaming和PS3的硬件规格(256M内存和256显存),很惊讶20分钟都不会崩溃,这样真正的技术实力。    
 
这里要讨论的是Directx 11的PC版,使用了几个G的内存和GPU显存,尽管这里讨论的是PC的规格,但大部分应该也是适用于PS4和PS3的。

Frame分析

这是我们要分析的帧,有主角麦克和他的Rapid GT,以漂亮的洛杉矶为背景。
    
 
GTA V使用的是延迟渲染管线( Deferred Rendering Pipeline),使用多张HDR(高动态范围) Buffer来工作。但HDR不能直接正确的显示在显示器上,所以通过后处理用简单的Reinhard 操作(一种Tone mapping算法,可以把高动态范围映射到的动态范围)把他们转回到8位每个通道。

Environment Cubemap 环境立方图

第一步,是在游戏里渲染Cumbemap,    这张Cumbemap是每帧上实时生成的,用来渲染后面真实的反射效果。这部分是前渲染的(forward-rendered)。Cumbemap是如何被渲染的?对于不熟悉这技术的人来说,这个就像是现实世界的拍摄全景图片,把相机放在三脚架上,想象你正好站在一个大的立方体中心,并拍摄这个立方体的六个面,每拍摄1次旋转90度。
 
这正是游戏所做的:每个面被渲染到一张128x128的 HDR Texture上,第一个面的渲染就像这样:
 
 
把剩下的5个面用相同的处理重复进行,最后获得Cubemap
 
 
 从外面看的立方体
 
渲染每个面大约有30个Draw Call,渲染的网格多边形数非常少,只有“风景”被绘制,(地形,天空,某些建筑),这就是为什么游戏里车辆的环境反射做的相当好,但其他的车辆和角色并不能被反射到。

Cubemap生成Spheremap

接下来,我们把获得的Cumbemap转换成一张Spheremap
 
 
                                        
 
Spheremap
 
为什么要这么转换,我想通常这是在做优化:一个Cubemap在Fragment Shader里,潜在的是访问6个面的128x128 texel,这里用Spheremap降低为两个“半球”的128x128 texel,更好的是,因为相机通常是在车顶,大多只访问顶部的半球就可以。
 
球面投影在顶部和底部保留了反射的细节,而牺牲了侧面。这对GTA V来说很有用:车顶和车罩通常是面朝上的,它们主要的是要来自顶部的反射获得更好的表现。

Culling和LOD(Level of Detail)

这一步由Compute Shader来处理的,无法用图片来解释。
基于到相机的距离,决定物体对像是用低模还是高模绘制,或者不绘制。
例如,超出一定距离的花草不再绘制,所以这步要计算每一个设置了LOD的物体对象。
这个计算实际在管线的位置在PS3与PC和PS4是不同的,在PS3上,所有这些计算都是运行在Cell的SPU上的。

G-Buffer 生成

渲染“主要”发生在这里,所有可见的Mesh一个个的绘制,但不会立刻进行着色计算,这些Draw Call只需要输出一些简单的着色用信息到叫做G-Buffer的不同缓冲中,GTA V里使用MRT,这样每个Draw Call可以一次输出到5个Render Target里。
 
然后,所有的这些缓冲用来合并计算每个Pixel的最终着色。因此,和“Deferred”相对的“Forward”。 这一步只有不透明物体被绘制,例如玻璃的透明Mesh需要在延迟管线中特别的延后处理。
 
 
所有的这些Render Target都是LDR buffers (RGBA, 8 bits per channel) 保存了各种信息,参与最后着色值的计算。
这些缓冲有:    
 
Diffuse map:它保存的是Mesh的“内在颜色”(Albedo),代表了材质的一个属性,在理论上是没有受光照影响的。但你有注意到车辆上的白色高光么。有趣的是,GTA V 中是在输出到Diffuse map之前,先计算从太阳方向光的着色结果。
Alpha通道包含了一些“Blend”用的特殊信息(后面解释)。
 
Normal map :在每个Pixel(RGB)里保存法线向量信息(世界空间)。Alpha通道也被使用到,但不确定是用的什么方法,看起来像是一些植物接近相机的二进制Mask。
 
Specular map:包含了关于 specular/reflectance的信息。
    Red: specular intensity 
    Green: glossiness (smoothness)
    Blue: fresnel intensity (通常属于相同材质的所有Pixel都是常量)
 
Irradiance map:Red通道看起来是包含的每个Pixel接受太阳光的irradiance(通过Pixel的法线和位置,以及太阳照射方向),这里不能100%确定通道的作用,看起来像是受第二光源产生的irradiance 。Blue是Pixel的emissive(自发光)信息(霓虹灯和电灯泡使用)。Alpha通道除了标记对应的角色皮肤或植物外,大部分不会被使用。
 
那么,前面我们提到输出了5个render target,但这里只展示了其中的4个。最后一个RT,是特殊的depth-stencil buffer。下面是在Pass最后看到的结果。
 
 
Depth map : 它保存了每个Pixel到相机的距离。
直观的看,你会认为远处的Pixel是白色(深度为1)而越近处的Pixel越黑。这里的情况有所不同,: GTA V看起来使用的是logarithmic  Z-buffer,并使用了reversed-Z(Z的倒数)。这么做是因为深度被encode了,这样浮点数越接近0,精度越高。Reversed-Z可以在排序深度非常接近的物体时有更高的精度,大大降低了 Z-fighting。这种方法在很长绘制距离的游戏里是必须的。也不是什么新技术,例如Just Cause 2 中也使用了类似的技术。
 
 
Stencil: 用来识别不同类型的Mesh绘制,同一种类的Mesh的所有Pixel赋予相同的ID。例如一些stencil 值就是:
 
0x89: 玩家控制的角色
0x82: 玩家驾驶的车辆
0x01: NPCs
0x02: 类似汽车,自行车的交通工具
0x03: 植被和树叶
0x07: 天空
 
生成所有的这些Buffer大约要1900的Draw Call
要注意的是,场景的渲染是“从前向后”这种方法的优化是得益于“early Z rejection”,当场景被绘制时,很多的Fragment因为被更近处绘制的Pixel遮挡,没有通过深度测试。如果Pixel没有通过深度测试,那么GPU会把自动丢弃它,并且也会执行Pixel Shader。当你有大量的Pixel Shader时,“从后向前”渲染(画家算法)是一种性能方面最差的选择,而“从前向后”则是最优的。
 
顺便说一下,为了解释alpha通道在Diffuse Map中起的作用,来看下下面的截图:
 
 
这里可以注意到一些Pixel的缺失,特别是树木上看的更明显,就好像他们的Sprite上缺失了Texel。
 
我在PS3上也几次注意到这些缺陷(artifacts ),那时让我很不解。当Texture Sprite变得很小时,它会走样么? 现在我可以看到他们所以的Mipmap都是正确的,并不会产生走样问题。这个pattern很特殊,就好像是棋盘格那样,游戏渲染会跳过渲染的两个Pixel中的一个。为了确认这一点,我查看了D3D的字节码,果然:
 
dp2 r1.y, v0.xyxx, l(0.5, 0.5, 0.0, 0.0)  // Dot product of the pixel's (x,y) with (0.5, 0.5)
frc r1.y, r1.y                                        // Keeps only the fractional part: always 0.0 or 0.5
lt r1.y, r1.y, l(0.5)                                 // Test if the fractional part is smaller than 0.5
 
这些指令都很简单,相当于测试 (x + y) % 2 == 0 ,2个Pixel中的1个会被pass掉(x和y是Pixel坐标),这只是其中的几个丢弃像素的条件之一(另一个是 当alpha < 0.75 ),但足够解释这个ditehr pattern了。
 
为了记住那些Mesh要用“dithered mode”绘制,这个信息就要保存在diffuse map的alpha通道中,就像下图所看到的那样。我认为这个模式是用在很远的距离或者是在LOD层次间过渡的,通过抛弃一些Pixel,节省了填充率和着色计算。
 

Shadows 阴影

游戏的阴影使用了CSM (cascaded shadow maps):把4张shadow map生成到1张1024x4096的texture里,每张shadow map是由不同的t camera frustum创建的,随着迭代的进行,frustum获取了更大并包含更多的场景部分,这就确保了接近玩家的阴影用更高的分辨率保存,阴影越远细节也更少。下面4幅图是深度信息的预览:
 
 
这样做可以会有很高的消耗,因为需要渲染场景4次,但frustum-culling避免了不必要的多边形渲染。这里的CSM大约产生了1000个draw calls
通过这些深度信息,我们可以计算每个Pixel的阴影投射。引擎把阴影信息保存在 render targe中:由太阳方向光投射的阴影在Red通道,大气中云投射的阴影同时保存在Red和Green通道
shadow maps通过 dithering pattern 来采样(如果你仔细看下面的Texture,Red通道显示就像棋盘格那样)这样做是为了让阴影的边缘更加平滑。
然后这些缺陷会被修正,太阳的阴影和云的阴影合并到一张Buffer里,进行一些深度上的模糊(Blur)再把结果保存到specular map的alpha通道中。
 
 
模糊操作的一个快速的说明:这个操作非常的昂贵,因为它需要从多张texture里获取数据。所以为了减低负荷,在执行模糊处理前,提前创建一个Texture:把Shadow Buffer降采样到1/8,再调用4次称作 Gather()的由Pixel Shader执行的轻量的模糊处理。这样可以给予一个轻量的估算,那些Pixel是被完全照明(没有阴影)的。然后在执行完整的深度感知的模糊时,第一步先读取这个提前创建的Buffer,如果这个像素是被完全照亮的,那么 pixel shader 立即输出为1并跳全部沉重的模糊计算。

Planar Reflection Map 平面反射贴图

这里不会涉及太多的细节,反射部分会在第2部分详细解释。在我们选取的这个场景中几乎看不到这个效果,但是这一部分是用来产生海水表面的reflection map。基本上是把场景再一次绘制到(650 draw Call)一张240x120的Texture上,只是颠倒了,这样看起来是反射在水面上。
 
 

Screen Space Ambient Occlusion 屏幕空间环境遮蔽

计算出一个线性版的depth-buffer ,然后使用它来创建SSAO。
先是创建一个噪声版(Noisy),然后连续使用两次深度感知的模糊(Blurred水平和垂直方向)来平滑结果。
所有的这些都是在一半的原始分辨率下进行的以提高性能。
 

G-Buffer Combination

最后,合并所有生成的buffer!
在 pixel shader 中从不同的buffer获取数据,并计算出在HDR中Pixel最后的着色值。在这次举例的夜景里,光源和他们的irradiance也一样会加入到上面的场景里。
 
                                                                                                                    
 
这就很有条理了,虽然我们仍然缺少海洋,天空还有透明的物体,但首先:麦克的表现还需要加强。

Subsurface Scattering 次级表面散射

 
麦克的皮肤着色稍微有些不同,脸上有很暗的地方,就像身体是用厚塑料做的。
 
这也就是为什么要执行SSS(Subsurface Scattering),来模拟光在皮肤里的传播。看看他的耳朵和嘴唇,在SSS pass后,光会使得他们有血色,给予了真实世界中应该产生的正确红色。
为什么SSS只对麦克起作用?首先只有他的轮廓被提取了出来。这可能要得益于之前生成的stencil buffer:所有麦克的Pixel都有一个 0x89的值,那么当我们获取到麦克的Pixel,我们需要让SSS只作用在皮肤上,而不是衣服。
实际当所有的 G-Buffer被合并后,除了着色数据保存为RGB,还有一些数据被写入到alpha通道。更精确来说, irradiance map 和  specular map 的alpha通道被用来创建二进制Mask:Pixel属于麦克和一些植物的在Alpha通道中设置为1。其他的Pixel像是服装,Alpha通道的值是0。
这样通过提供的输入到合并的G-Buffer的Target以及depth-stencil buffer,SSS得以被应用。
 
你可能认为这个只是一个巧妙和局部的改进。虽说如此,但不要忘记在游戏时,我们作为人类会本能的倾向看向角色的脸,脸部任何的渲染改进,对深入体验都是一个很大的成功。游戏中,SSS被应用到你的角色和NPC上。
 

Water 水

这个例子里没有太多的水,我们在后面会介绍海洋和各处的游泳池。
GTA V中水的渲染包括反射(reflection)和折射(refraction)。
 
先前创建的对数Z-buffer 用来生成它第2个版本:一半分辨率的线性的Z-buffer。
海洋和水池被依次的绘制,以MRT模式一次输出到多个target上。
 
 
Water Diffuse map: 水的固有颜色
Water Opacity map: Red通道看起来保存的是一些水的不透明属性(opacity,例如海洋通常是0.102,水池是0.129)。Green通道保存的水面Pixel的深度(深的Pixel代表更加不透明的水,颜色受Diffuse map影响硬大,而浅水的Pixel几乎是透明的)。
要注意的是,所有的水池都是无条件的被渲染,即便是他们被场景中其他的Mesh所遮挡,也都会显示在Red通道里。而Green通道中,值有可见的Pixel会被计算,只有“水”的像素会计算到最终的图像里。
 
现在我们可以合并之前创建的buffer来生成refraction map:
 
 
在refraction map中,水池中注满了水(水越深越蓝),caustic效果也被加入了。
 
现在,进行水的最后渲染:再一次的顺序渲染海面和水池的网格,但这次把反射和折射合并,通过一些bump map来扰乱水面的法线。
 
                                                                                                                

Atmosphere 大气

 
light-shaft map,也被叫做“volumetric shadow”:它的作用是让大气或雾的那些不被太阳直接照射的部分变暗。
 
这个map以一半的分辨率生成,通过ray-marching 每个pixel,并与太阳的shadow map中值做对比。获得到有噪声的结果后,再对缓冲最模糊
 
接下来我们在场景里加入雾的效果:通过雾可以很方便的隐藏远处低多边形建筑细节上的缺陷。这个pass读取 light-shaft map和 depth-buffer来输出雾的信息。
 
然后是渲染天空和云彩:
 
 
天空实际是一个draw call渲染的:使用的mesh是一个巨大的圆顶覆盖了整个场景。
这个步骤中加入一些texture做成Perlin noise。
 
 
云的渲染也是相同的方法,一个巨大的mesh,这里是环的形状,在地平线上渲染。使用了一张normal map 和 density map来渲染云彩:这是一张巨大的2048x512的Texture的,而且是无缝的(左边和右边循环)、
 

Transparent Objects

这一步渲染场景中所有的透明物体对象,眼镜,挡风玻璃,飞散的灰尘颗粒等等。
 
 
全部透明物体的绘制只用了11个draw-call,粒子大量使用了instancing。

Dithering Smoothing

还记得前面我们顺便提到的在Diffuse map中的一些树木是dither的吧?
这次我们来修复这些缺陷:使用Pixel Shader执行的后处理效果,读取原始的颜色缓冲以及Diffuse map中的alpha通道的信息,就可以得知是那些pixel是dither的。每个pixel,可以对周围的两个pixel做采样,计算出最后“光滑”的颜色值。
 
 
这个巧妙的方法,有助于减少前面的计算量和填充率,现在只需要一个pass就可以“修复”图像:它的处理成本是恒定的,不收场景中几何体数量的影响。不过这个Filter并不完美,在PS3和PC上我还是注意到屏幕上有一些棋盘格的图案,有些情况Filter并不能处理。
 

Tone Mapping and Bloom

我们之前渲染的图像一直保存在HDR格式,每个RGB通道保存为1个16bit的浮点。这样就光照强度就可以有巨大的变化。但显示器并不能显示这种高范围的值,只能输出每个通道8bit的RGB颜色。
 
Tone Mapping用于把这些颜色值从HDR转换到LDR空间。这里有几种函数把一个范围映射到另一个范围。经典并广泛使用的方法就是Reinhard,实际上也是我前面用来生成所有截图的方法,它给出的结果很接近游戏最终的渲染。
 
但GTA V真的是使用Reinhard么?这里我们还是逆向分析一些shader的字节码:
 
// Suppose r0 is the HDR color, r1.xyzw is (A, B, C, D) and r2.yz is (E, F)
mul r3.xy, r1.wwww, r2.yzyy                // (DE, DF)
mul r0.w, r1.y, r1.z                                //  BC
[...]
div r1.w, r2.y, r2.z                                   // E/F
[...]
mad r2.xyz, r1.xxxx, r0.xyzx, r0.wwww  // Ax+BC
mad r2.xyz, r0.xyzx, r2.xyzx, r3.xxxx      // x(Ax+BC)+DE
mad r3.xzw, r1.xxxx, r0.xxyz, r1.yyyy      // Ax+B
mad r0.xyz, r0.xyzx, r3.xzwx, r3.yyyy      // x(Ax+B)+ DF
div r0.xyz, r2.xyzx, r0.xyzx                       // (x(Ax+BC)+DE) / (x(Ax+B)+DF)
add r0.xyz, -r1.wwww, r0.xyzx                  // (x(Ax+BC)+DE) / (x(Ax+B)+DF) - (E/F)
 
(x(Ax+BC)+DE) / (x(Ax+B)+DF) - (E/F) 是在 http://filmicgames.com/archives/75 中出现的典型的方程式,看来GTA V里使用的不是Reinhard,而是神秘海域2中的方法,这样不会让黑色区域失去饱和度。
 
 
float A = 0.15;
float B = 0.50;
float C = 0.10;
float D = 0.20;
float E = 0.02;
float F = 0.30;
float W = 11.2;
 
float3 Uncharted2Tonemap(float3 x)
{
   return ((x*(A*x+C*B)+D*E)/(x*(A*x+B)+D*F))-E/F;
}
 
float4 ps_main( float2 texCoord  : TEXCOORD0 ) : COLOR
{
   float3 texColor = tex2D(Texture0, texCoord );
   texColor *= 16;  // Hardcoded Exposure Adjustment
 
   float ExposureBias = 2.0f;
   float3 curr = Uncharted2Tonemap(ExposureBias*texColor);
 
   float3 whiteScale = 1.0f/Uncharted2Tonemap(W);
   float3 color = curr*whiteScale;
 
   float3 retColor = pow(color,1/2.2);
   return float4(retColor,1);
}
 
转换到LDR的处理流程:
    将HDR buffer降采样到1/4的分辨率
    使用compute shader计算buffer平均的亮度(luminance),把结果输出到一张1x1的texture。
    计算新的曝光,用来控制场景的明暗
    使用bright-pass filter,把亮度值高于一定阈值(由曝光值来决定)的pixel提取出来。
    场景中只有少数的pixel被filter保留了下来:比如车上有着强烈反射亮度的斑点。
    把这个brightness buffer反复的减少尺寸并按原尺寸的1/16来做模糊,然后再upscale几次直到原尺寸的一半为止。
    把这个bloom加入到原始的HDR pixel,再使用神秘海域2的tone-map操作,把颜色转化到LDR,同时运用伽马校正( gamma correction ),从线性空间转化到sRGB空间。
 
 
最终的结果很大程度上取决于曝光值,下面是说明这个参数的图例:
 
曝光实际是在帧与帧之间慢慢演变的,不会有突然的变化。
 
这是为了模拟人眼的行为:游戏中你是否注意到,当在黑暗的隧道中驾车,突然离开隧道照射在阳光下时,所有的环境在几帧里看起来会非常亮?然后再逐渐的从"耀眼"恢复到"正常",同时曝光也调整到一个新的值。GTA V甚至考虑到给予的“明亮”到“黑暗”的曝光适应,比“黑暗”到"明亮"更快,就像人眼的行为一样。

Anti-Aliasing and Lens Distortion

如果anti-aliased(反走样)的方法使用的是FXAA,它是用来平滑网格的锯齿边缘。然后,为了模拟真实相机,使用一个简单的pixel Shader在图像上执行 lens-distortion。它不光是扭曲图像,也在帧的边缘稍微加入了色差,通过Red通道的比Green和Blue更稍加扭曲来实现。
 
 

UI

最后提及的是:UI,这里只包含了屏幕左上角的小地图。地图实际上是划分为若干个正方形的Tile,引擎只绘制显示在屏幕中的Tile。每个Tile都是通过一个draw call来绘制的。我把这些Tile上色,以方便了解结构。
 
 
Scissor Test 允许只渲染左下角,并抛弃外面的内容。所有的道路实际上是矢量的(见上面截图的线框),可以作为mesh渲染并放大到任意的等级。
然后小地图绘制到主图像缓冲,把一些小的图标和部件添加在顶部。
 
所有这些使用了4155个draw calls,包含了1113张texture和88张ender target。
 
 
 
 
 

Grand Theft Auto V (侠盗列车手5)图形研究的更多相关文章

  1. Grand Theft Auto V 图形研究(3)

    原文链接 http://www.adriancourreges.com/blog/2015/11/02/gta-v-graphics-study-part-3/ Post Processing Eff ...

  2. Grand Theft Auto V 图形研究(2)

    原文链接 http://www.adriancourreges.com/blog/2015/11/02/gta-v-graphics-study-part-2/   Level of Detail 如 ...

  3. 怎样关闭WIN7系统的自动更新

    百度经验 > 游戏/数码 > 电脑 > 电脑软件 怎样关闭WIN7系统的自动更新 听语音 | 浏览:108460 | 更新:2012-07-24 18:03 | 标签:win7 1 ...

  4. (转)Multi-Object-Tracking-Paper-List

    Multi-Object-Tracking-Paper-List 2018-08-07 22:18:05 This blog is copied from: https://github.com/Sp ...

  5. Lessons Learned from Developing a Data Product

    Lessons Learned from Developing a Data Product For an assignment I was asked to develop a visual ‘da ...

  6. 剖析虚幻渲染体系(14)- 延展篇:现代渲染引擎演变史Part 1(萌芽期)

    目录 14.1 本篇概述 14.1.1 游戏引擎简介 14.1.2 游戏引擎模块 14.1.3 游戏引擎列表 14.1.3.1 Unreal Engine 14.1.3.2 Unity 14.1.3. ...

  7. 当今游戏大作share的特性大盘点

    极品游戏制作时的考虑要素大盘点 不知不觉入坑Steam已近4年,虽然说Steam的毒性让很多人走向一条不归路,但是想我这样即使"中毒"还是很快乐很感恩的.那么本期文章就谈谈我对其中 ...

  8. 深度学习与自动驾驶领域的数据集(KITTI,Oxford,Cityscape,Comma.ai,BDDV,TORCS,Udacity,GTA,CARLA,Carcraft)

    http://blog.csdn.net/solomon1558/article/details/70173223 Torontocity HCI middlebury caltech 行人检测数据集 ...

  9. AI佳作解读系列(三)——深度学习中的合成数据研究

    Below are some investigation resources for synthetic datasets: 1. Synthetic datasets vs. real images ...

随机推荐

  1. Cocos2dx实现象棋之布局

    开始界面 #ifndef SCENESTART_H #define SCENESTART_H #include "cocos2d.h" #include "SceneGa ...

  2. xampp 访问出现New XAMPP security concept

    在浏览器输入 http://60.10.140.22/xampp出现以下错误信息: Access forbidden! New XAMPP security concept: Access to th ...

  3. linux多种安装包格式的安装方法

    linux多种安装包格式的安装方法 一.rpm包安装方式步骤:1.找到相应的软件包,比如soft.version.rpm,下载到本机某个目录: 2.打开一个终端,su -成root用户: 3.cd s ...

  4. laravel框架中注册信息验证

    .路由配置 <?php Route::. 控制器分配页面及验证表单提交内容 <?php .form 表单验证 {{ Form::open(array().slideUp();   < ...

  5. poj 3264 RMQ 水题

    题意:找到一段数字里最大值和最小值的差 水题 #include<cstdio> #include<iostream> #include<algorithm> #in ...

  6. ML 04、模型评估与模型选择

    机器学习算法 原理.实现与实践——模型评估与模型选择 1. 训练误差与测试误差 机器学习的目的是使学习到的模型不仅对已知数据而且对未知数据都能有很好的预测能力. 假设学习到的模型是$Y = \hat{ ...

  7. PHP 5.4 中经 htmlspecialchars 转义后的中文字符串为空,DeDeCMS在PHP5.4下编辑器中文不显示问题

    在加入 发布招聘功能的时候,出现问题了,就是修改招聘信息的时候.编辑器内容不显示,只显示英文,中文不显示,以前记得开发此功能没这问题啊!然后各种原因找不出,没办法,从编辑器函数入手,一步一步查,查到 ...

  8. HTML-Geolocation API

    获取位置信息: 请求一个位置信息,如果用户同意,浏览器就会返回位置信息(由经纬度和其他元数据组成),该信息是通过支持html5地理定位功能的底层设备提供给浏览器的:该API不指定设备用哪种底层技术来定 ...

  9. spring实战一:装配bean之注入Bean属性

    内容参考自spring in action一书. 创建应用对象之间协作关系的行为通常称为装配,这也是依赖注入的本质. 1. 创建spring配置 spring是一个基于容器的框架.如果没有配置spri ...

  10. HDU3037 Saving Beans(Lucas定理+乘法逆元)

    题目大概问小于等于m个的物品放到n个地方有几种方法. 即解这个n元一次方程的非负整数解的个数$x_1+x_2+x_3+\dots+x_n=y$,其中0<=y<=m. 这个方程的非负整数解个 ...