不告而取的东西――作者:装机工
本来早就发给GOUKI了,不过被其以看不懂为由而下岗,放在这里是想看看大家的意见,也许可能是有点深奥了,总之我会再改的!!(再强调一下,请不要转载,谢谢!!!)随着游戏机硬件以及软件技术的不断发展,游戏机上使用的图像渲染技术也越来越先进。现在的即时验算画面有时可以达到以往某些“低水平CG”的程度甚至过之而无不及!但是大多数的优秀游戏画面都是靠3D技术来实现的,有时候太多的多边形可能也会让人反胃。虽然2D游戏已经不是发展的主流,但是很长一段时间内有关2D影像技术和表现2D画面的发展似乎停滞了,不过,现在有一种能让画面看起来和迪斯尼动画大片一样感觉的新的渲染技术越来越流行,那就是今天要讨论的Cel-shading技术。
Cel-shading技术到目前为止并没有一个很精确严格的定义,如果非要对它作个解释,这样说可能稍微贴切一点:Cel-Shading,立体卡通着色。立体卡通着色技术通过将颜色和阴影融合在一起,使3D模型看上去不那么生硬,并产生类似卡通影视片的彩墨绘制的画面效果。立体卡通着色被Namco公司称为“Toon Shading”。它会像动画片或卡通那样以Non Photo-realistic style(非现实风格)来渲染物体模型。你可以简单地把它理解为使用单调的色彩、巨大的活动块以及在边缘有轮廓线的渲染。使用它,各种各样的卡通效果都能通过对源代码的细微修改达到。你可以得到动画效果,就是类似于龙珠或者高达那样的效果,当然你如果想获得像其他卡通片一般的经典动画效果也都是可以的。Cel-Shading是一种非常强大的渲染方法,使用它几乎能完全改变一个游戏的“感觉”。比如说,SEGA的《街头喷射小子未来版》在图像方面就相当令人兴奋,它看起来实在是太爽快了!但是,大家最好也不要以为Cel-Shading是万金油,只要游戏使用Cel-Shading技术画面就一定会很好看,错!这种技术还是有一些局限性的,特别那些有很大的平面的物体或者一些故意有“小平面”的物体最后经过渲染但看起来不怎么令人信服。有机会玩玩《Loony Toons Space Race》就知道了。
现在对Cel-shading技术似乎特别情有独衷的是任天堂公司,他们的看家大作《塞尔达传说》的图像制作就从传统3D渲染的写实风格改为了使用Cel-shading技术纯卡通风格,而且他们对自己的新主机NGC在Cel-shading技术方面的支持感到很满意甚至是很骄傲!对于Cel-shading/toon-shading来说,任天堂从NGC第一次在SPACE WORLD 2000展上公开之后很长一段时间内都渴望暗示这是NGC所独有的一种效果。当时公开的演示是用一个在飞行中的使用传统3D技术渲染的马里奥最终变为靠Cel-shading渲染,其展示了NGC主机如何有效地控制各种细节,尽管和其他令人激动的演示相比(比如《Rebirth》或《Metroid》),这段动画只不过像是一段比较漂亮的2D影像处理罢了。但是,综观全局,最终有足够的迹象表明如Cel-shading这类的处理事实上要比我们开始所想象的要复杂得多,或者说NGC对这样的渲染技术已经掌握得很好了!指出NGC拥有独特的cel-shading处理能力的不是别人正是Greg Buchner,他是直接参予NGC绘图处理器“Flipper”开发的ATI的资深工程师,他确定他们(ATI等公司)拥有一些在进行Cel-shading/toon-shading处理时的专利技术!(另外还拥有很多纹理设计和管理方面的专利技术)“我们有一些额外的因素来确保‘塞尔达’的视觉质量,在这个领域我们有一些专利技术。”不过装机工这里要提醒大家一点的是,此人的话不能不信但最好不要全信,在NGC发售之前,正是此人在接受媒体采访的时候大肆鼓吹NGC上的Flipper性能强大!而且现在除了在NGC上,我们同样能在XBOX、PS2上看到使用Cel-shading技术的游戏,对于XBOX、PS2我们不会感到太意外,不过这个出现在微软最新的DirectX 8.0中的技术也可以用以前老的指令来模拟,前不久,ST(意法半导体)就发布两个最新KYRO专用演示程序,其中一个叫做KYROTOON的程序就是专门用来展示例如Cel-Shading这样的Non Photo-realistic Rendering(非现实渲染)的演示程序,以此来证明DX8的shader(渲染)技术可以利用dx7来实现(!!!请放图tb1~3!!!)。所以我们甚至在‘久已淘汰’的DC上仍能看到采用这种技术制作的《Jet Set and Grind Radio on》,而且效果很好(以上程序只能在Kyro即PowerVR系列芯片上才能执行,而DC恰好正是使用的PowerVR系列芯片!)。
按照Greg Buchner的说法――“要完成‘cel-shading’处理并不是一件很轻松的事情,从头到尾都是。运用2D表面来代替3D图像应该很简单,实际上并非如此。要找到物体轮廓,找到物体边缘的运动轨迹其实是一件非常困难的事情。”――其实在使用Cel-shading技术的时候,游戏开发人员往往要在两个方面把握好:
1.在渲染物体模型时要达到一种我们常见的卡通风格,这需要使用很极端的色块。(讽刺的是,往往色块是很令我们讨厌的,不过在这里我们却很乐意把它们搞得很夸张!)
2.要像真正的动画片那样在物体的边缘做出那种动画师们辛苦画出的动画片特有的轮廓线。
另外,在我们开始深入讨论Cel-Shading技术的时候,如果大家对以下几个方面有一定的了解的话,相对来说就要容易得多:1D texture mapping、Texture co-ordinates、Software lighting、Vector math。当然,如果你对这几个方面是一窍不通甚至是闻所未闻也不用着急,我保证你一样能充满乐趣地愉快地阅读这篇文章,当然也许我不能保证你不会在当文章中出现一些比较专业的词汇、源程序、代码――可能会在用来表现Cel-Shading DEMO时犯糊涂。 不过,在每个部分的结尾我都会给出一个总结来说明怎么样才能得到你想要得到的效果,所以大家基本上可以放心了,呵呵^_^
基本篇:
基本渲染
我们从最简单最基本的地方开始,没有光照、没有轮廓线(outlines,就是平时我们看动画片上面的物体周围的一条黑线)、只有平面的卡通模型。对于这种简单的情况,我们在处理时只需要存储两组数据――每个顶点的位置和颜色。这只是最基本的情况,我们不需要处理任何的光照和抖动混合(blending),有够简单。
如果我们打开光照,我们处理的物体将会变得普通(相对于采用传统3D渲染技术光照处理后的视觉效果,请记住我们不是不需要光照,我们要的是平面、动画片式而不是像CG一般的光照!),而且我们无法达到我们想要得到的“平面”卡通的效果。另外,我们也要关闭抖动混合,以此来确保顶点之间相对位置不会错乱。
总结:1.关闭光照 2.禁止抖动混合 3.描绘着色顶点
基本Directional光照(定向)
这里就会用到刚刚我说的几个希望大家有所了解部分的知识。每个顶点都需要存储一点额外的数据――标准的顶点数据以及一个光照的强度值(一个专门的浮点变量值),靠这两个数据我们就能渲染出带基本光照效果的物体。
Lighting Maps
这里会出现一个名为Lighting Maps的概念,我可不想让大家理解错误,这里的这个Lighting Maps并不是像《Quake 1》或《Quake 2》中用来模拟在物体上的光照的那个东西(建议大家有机会的话仔细看看上面两个游戏中墙壁的光影变化),也不是指什么由于光照/背光而造成的明亮/黑暗的效果,这里是一个完全不同的概念,你猜是什么?1D texture是也!
大家可以去找一些动画片来看看它们在物体上施加的光照效果(这里推荐电视台经常播放的“Cartoon Network”,以前装机工就常常看得忘了吃饭,嘿嘿),请注意它们和真实世界之间的区别,光照被分为了一些与众不同的“块”(blocks)。我还不知道权威的术语管这个叫什么,所以我把它姑且叫做“Sharp Lighting”好了。为了实现Sharp Lighting,我们必须制作一张1D texture图来存储所需的值,就像下面这样:!!!放图texmap!!!
这是一个1*16像素的greyscale纹理图(灰度表,现在已经放大的很多),那些方型的盒子代表单独的像素。我们使用greyscale(灰度)值的原因是它们接下来将要和顶点的颜色结合,你可以发现在这里只有3种色彩上的变化,它们和在动画片中用来表现亮度颜色十分相似。另外,我们使用16像素宽的原因是这样的话我们就能轻松的修改数值来创建不同的效果、许多不同的颜色等等。如果愿意你还可以简单地在这儿只使用黑白两色,不过一般不建议这样做(最后的结果可能会缺乏过渡)。千万不要在纹理上使用100%的黑色,因为如果就这样添加后,最终会使高光和轮廓线等变得十分难看(想象一下大片大片黑糊糊的样子吧)。
一旦你做出了你所期望的纹理,赶紧把它存好并调用进你所使用的任何API中(应用程序接口,DirectX、OpenGL还是软件模拟都可以),我们要等一会才能用上。
光照算法
现在,你的软件光照知识就变得相当的重要了。当然你不知道也没有任何关系,我会给大家说清楚的,哈哈!其实,定向的光照是十分简单的,你只需要确定光照的方向向量就差不多了。
所有你所需要做的事情就是计算光照向量和普通顶点之间的点积(dot product),为什么会这么“简单”呢?这就要涉及到一点数学的理论知识了。
点积是用来计算两个向量之间的角度然后得到一个最大为1的值,简单地说,这个得到的数字实际上就是这个夹角的余弦值。然后剩下的事情只是顺水推舟,根据得到的这个余弦值再利用反余弦的计算就能得出这个角了。反正不管怎么说,这不过是个简单的数学问题,最终纹理坐标值都被存储为一个0到1之间的值(0 <= X <= 1,其中如果结果为负的话都统一设置为0),我们就是靠这样计算光照向量和普通顶点之间的点积来确定纹理坐标的!
渲染物体
现在,你得到了每个顶点的纹理坐标,是时候来描绘物体了。再一次的,我们禁用光照和抖动混合,但是开启了纹理(无论如何请记住这是一个1D texture,它总还是纹理呀!)。就像以前一样的描绘物体模型,但这次我们要在确定顶点位置以前放置纹理坐标。成功以后,我们就会得到一个拥有卡通光照效果的使用cel-shaded技术渲染的物体了!
总结:可能对大多数读者来说,上面说得还是相对复杂了一点,那么下面的总结大家看起来就应该轻松许多了。
1.创建一个“Sharp Lighting map”表
2.计算光照向量和顶点之间的点积
3.关闭光照和混合
4.打开纹理
5.设置最新的纹理
6.生成多边形,不过只需要指定纹理坐标、颜色和顶点位置。
下面是为大家作参考用的源程序,在这个示范中我们加入了一个普通的散射光源的计算,这是一个简单的单一Directional光照。另外请大家注意,这是个以DirectX为API的程序,原因是因为我觉得DirectX相对OpenGL来说更普遍一点,而且我们在计算机上找到并使用DirectX的SDK(软件开发工具包)要容易得多。当然,这得感谢比尔了,呵呵^_^
; Inputs: v0 = Position
; v1 = Normal
; c0 = (0,0.5,xxx,xxx) useful constants
; c1-4 = WorldView matrix
; c5-9 = WorldViewProjection matrix
; c9 = Light/material color
; c10 = Light direction (in view space)
vs.1.0 ; Shader version 1.0
m4x4 oPos , v0 , c5 ; Compute projected position
m3x3 r1 , v1 , c1 ; r1 = View space normal
dp3 r2 ,-r1 , c10 ; r2 = Diffuse lighting calc
max r2 , r2 , c0.x ; Clamp r2 to 0
mov oT0.x, r2 ; Tex coord 0 is (r2,0.5)
mov oT0.y, c0.y
mov oD0 , c9 ; Diffuse color = c9
Positional光照
这里使用的方法只需要根据上面表述的方法作稍稍作一点改变就可以了。Positional光照相对上面的光照技术来说能提供更大的弹性,因为它可以在画面内到处移动,动态的对所有多边型实现(光照)效果。虽然它看起来更好,不过相比上面的光照技术其所要求的数学计算要长得多――不过不要害怕,并不是复杂得多,只是长得多而已!^_^
Sharp Lighting坐标算法
在开始介绍的基本光照中,我们只是简单的需要得到光照向量和普通顶点之间的点积。现在,因为Positional光照没有方向性(它的光线射向四面八方),每个顶点都有照向自己的光线。很简单?至少在我们明白要用怎样的代码实现它以前情况还不算是太坏。
首先,我们得创建一个从光源位置到某一顶点位置的向量。然后对其规格化从而得到一个单位长度,并且赋值。这就给我们光源到那个具体顶点的方向,现在,我们再计算这条方向向量和顶点的点积,然后在这个画面中的所有顶点上重复这一计算,这就是方法。听起来很简单,不过这样做的话会导致一个严重的问题。在复杂的画面中,顶点的数量一般都是巨大的,要一一这样做的话肯定会导致帧速度大幅度降低,所以我们通常需要着眼于一些更快速的方法。
Positional光照半径校验
为了减少计算的工作量,我们首先赋予每个光源自己的半径。在计算光照值之前,我们会作某个顶点是否在光源的半径以内的判断,如果判断结果为Y(Yes,即顶点处于光照范围内),我们就按照正常的光照算法处理。如果不在,那我们就用不着太费心(简直是废话)。这只是一个很简单的确定某个点是否在球体内的判断,简单的数学问题(高中数学程度对付它可能都足够了,嘿嘿),一般把它称为point-in-sphere测试。
渲染
这当然还是必不可少的一步,只要指出颜色、纹理坐标和位置就OK了。
总结:
1.创建一个“Sharp Lighting”表
2.如果使用了光照半径,就执行point-in-sphere测试
3.得到从光源位置到顶点的向量并对其规格化
4.计算新的向量和普通顶点之间的点积
5.对画面内每个顶点重复第二到第四个步骤
6.正常进行渲染
大家可以看到,这其中不过是多了几个步骤而已,其中最重要的方法几乎没有任何改变。
轮廓线和加亮(Outlines and Highlighting)
这是指在动画片中动画师们用铅笔勾画的形状线条。可能大家会觉得用计算机和多边形来实现可能会很困难和复杂,不过事实上这要比你所想象的要简单得多。为了很好的做出动画片一样的轮廓线,我们首先得找到物体轮廓的边缘。这里的边缘可以理解为两个相邻的朝向不同的部分(也就是说一个朝前一个往后)。
算法
这两个东西可以简单的归纳到使用“加亮(highlighting)”的算法,因为都靠同一种技术(而且在同一个时间进行计算)完成。算法很简单:缘着边缘在朝前和朝后的多边型上
描绘一条线,我们在边缘部分勾线来表示那里真的是边缘所在,而且看起来可能会更像动画片。
请注意这里会特别的涉及到多边型,为什么在前面都没有专门的细讲多边形呢?因为这些生成多边形工作我们其实是交给API来完成的。
渲染
首先,我们需要设置线的宽度,一般来说的话用2到3个像素的话就会得到比较好的效果,另外你还可以在上面开启anti-aliasing(反混淆)功能,来降低干扰。我们得改变剪辑模式,这里需要切换到wireframe(线框)模式,以方便我们更好的画线。现在,除了不要指定色彩和纹理坐标外,我们像往常一样描绘多边形。虽然靠后的多边形上也会画上线,但是由于depth buffer(深度缓冲)的关系,只有前面的多边会被画上线。(需要注意的是,线的宽度如果我们设置为1的话用这个方法就会失效) !!!请放蝙蝴侠的两张图!!!
总结:
1.像平常一样描绘物体
2.改变朝向
3.将颜色设置为100%的黑色
4.切换到wireframe mode模式
5.渲染,但是只需要指出顶点位置
6.恢复到原始状态
源程序(请注意,这也是基于DirectX的):
; Inputs: v0 = Position
; v1 = Normal
; c0 = Useful constants (0,xxx,xxx,xxx)
; c1-4 = WorldView matrix
; c5-9 = WorldViewProjection matrix
vs.1.0 ; Shader version 1.0
m4x4 r0 , v0 , c1 ; r0 = View space position
m3x3 r1 , v1 , c1 ; r1 = View space normal
m4x4 oPos , v0 , c5 ; Spit out projected position
dp3 r2.x , r0 , r0 ; Normalize r0 (position)
rsq r2.x , r2.x
mul r0 , r0 , r2.x
dp3 r3.x , r0 , -r1 ; Compute dot product
mad oD0.w, r3.x , c0.y , c0.y ; Scale to and make alpha
mov oD0.xyz , c0.x ; Diffuse RGB is 0
下面是像素引擎中的代码:
m_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE , TRUE );
m_pd3dDevice->SetRenderState( D3DRS_ALPHAFUNC , D3DCMP_LESS );
m_pd3dDevice->SetRenderState( D3DRS_ALPHAREF , m_dwSilhouetteAmount );
在上面我们可以通过更改alpha测试的参考值(m_dwSilhouetteAmount)来改变轮廓线的粗细。
高级篇:
现在就要变得困难一点了,因为我们就要开始使用cel-shade来处理纹理了,不然画面也不会看起来像动画片啊。(否则也对不起高级两个字啊,是吧?哈哈)
Cel-Shading Textures(卡通化纹理)
现在,有两个办法来完成这项任务:采用多重纹理(很常用的一个3D技术)或者采用……
首先我们必须重新回到一开始介绍的Sharp Lighting map中。在这个方法中,我们实际上要切换纹理和顶点颜色双方的角色,不在是用纹理来表现色彩而是用色彩来渲染纹理。(应该和动画片很接近了,画画大家都画过吧,我们不是用常涂上天蓝色来表示天空,涂上深蓝色来代表大海嘛,这里的方法大慨的意思就和这个差不多。)
创建Sharp Lighting map
不知道大家对这样的一张图还有没印象? !!!放图texmap!!!
在前面我们可以在任何API中使用这个纹理,而现在则要我们自己来保存它的值。一旦我们调用这个纹理,就必须创建相应的以浮点数值组成的数组(如果
你使以字节byte为单位在存储的话就需要把每个像素分为255份),然后记录好这些数值。对物体模型来说,我们需要改变我们存储的数据,下面就是需要存储的数据的内容:顶点位置、顶点标准信息、纹理信息(注:并非1D Sharp Lighting map)、每个顶点的Sharp Map值(这部分可以使用整数来存储)。唯一要改变的是顶点的颜色,我们要用上面列出的纹理信息来替换。现在我们就拥有了本地存储有Sharp Lighting map的物体模型数据,接下来需要做的就是进行软件光照了。
纹理的光照
这部分和以前所讨论的光照算法没有太大的改变。Directional光照和Positional光照仍然采用相同的方法实现,不过唯一不同的是当计算方向向量和顶点间的标量积的时候,我们要注意Sharp Lighting map的取址,可取的范围为0到15,而这里为16(简单点说,大家可以数数上面的图中一共有16个格子),所以要减掉1,最后还要转换为一个整数。这个整数用来作为我们的光照表中的索引信息,在渲染的时候它就会相应的被转化为某种颜色。
渲染卡通化纹理
在DirectX和OpenGL这两个强大和最常用的API中,如果你同顶点颜色和纹理色彩一同指定的话,纹理的色彩会作相应的改变来适应顶点的颜色。现在既然我们使用了灰度值,指定纹理的色彩就会使顶点变得明亮或暗淡,但是一旦结合Sharp Lighting,最后看起来就是cel-shaded,呵呵,搞定!
所以我们要指定顶点的颜色,通过在顶点结构中获得Sharp Lighting值来确定,然后好在索引信息表中查询,这会给我们一个精确的数值。而现在由于我们使用RGB,所以只不过靠这个数据来得到所有的RGB的三元组合(也就是颜色了)。举例来说,如果我们得到的数值为0.4,那么我们就会据此作出红色值为0.4,绿色值也为0.4,蓝色值同样也为0.4的决定,很容易理解。然后我们为顶点设定适当的纹理,最后是指定顶点的位置。记住关闭混合和光照,开启纹理,在屏幕上你就可以看到使用cel-shaded卡通化的纹理了。
总结:
1.从文件中调用Sharp Lighting map,存储为一个数组(不过请记住取值范围在0到1之间)
2.使用正常的方式计算光照,但是在计算点积的时候请注意其取值范围(0到15),最后还要不要忘了转换为一个整数
3.在描绘的时候,使用Sharp Lighting map的数值,在索引信息中找
4.以这个数值作为RGB色的取值(确定颜色)
5.像往常一样渲染,不过仍要记住关闭一些东西
6.描绘轮廓线
后记
到这里,一些有关cel-shading技术的东西基本上我们都大概作了介绍,可能大家还会有很多疑问,当然我自己也是。^)^所以如果有错漏之处在所难免,希望广大读者交流。不过最后我不想再提及技术上的事情,而是其他的东西。写这篇文章,是受杂志编辑之约,而他是在某BBS上看到的题目,自然我也会去看。不过上面的人似乎在借技术来攻击其他的主机,这是很令人遗憾和很让人费解的。因为每个主机都有自己的特长,要想单凭某一点来说明主机的强大似乎有点说不过去。而且对游戏机来说即使是性能占上风也不一定能保证它会获胜,游戏的有趣和卖坐是最重要的,这一点我想大家都有很深的认识。另外,就算是同一个效果,就实现它的途径来讲,也许不止一条,条条大道通罗马!上面所说的ST的用DirectX 7.0的技术来代替DirectX 8.0的技术就是一个很好的例子,所以说借助Cel-Shading来做文章不算很明智。游戏主机的硬件机能不是不能比,而是要看你怎么比!
最后,愿大家都能在使用cel-shading技术的游戏中找到当年看卡通片时的兴奋,在充满想象的画面中获得乐趣,无论如何请记住,游戏是用来带给我们快乐的
活活 。。。
我可以证明装机工先生的清白,两者资料应该都来自于国外网站。不过是偶然巧合罢了...
欢迎你常来玩。 在没有考虑加入PS3开发员之前,没有兴趣看。 好多话怎么都在哪看过啊
就和那个他写的关于NGC硬件的文章(电软上那个)一样 当然就是这么点东西
但是至少要用自己的语言从新组织下吧
特别是某人的关于NGC的那篇
某大段落彻底抄袭
(特别是那个关于第五元素对星球大战的那个谬误的多边形分析,基本上没差多少字) 大哥
我说的并不是自己人抄袭自己人
我说的就是抄袭国外的那篇
而且那不是什么官方资料
而是某网站(商业)还不是杂志上的愿文
这个是第一
就算是E文翻译的话
两人翻译的也太……
不是什么说你装机兄的坏话的事情
其实我等早认识以前也老争吵过一些问题
但是也不是做那种事情的意思
只是……自己版权意识过浓(源自当年中国电视游戏的一些问题上) 最初由 nikewnx 发布
我还是扁爱2D游戏,虽然3D以成主流,2D还是有它独到之处,
也可能是\"先入为主\"
引用RAY的一句话:玩MGS就是要RAIDER OFF才有感觉,不然在雷达上能看见敌人的那和2D有什么区别 百分之80……看不懂 这样的文章最好看了:) 长见识。
真够专业啊。 还好高等数学没有全部还给导师……不过除了基础篇还能看懂之外,后面的怎么看怎么眼生。
基本篇说的就是用单色纹理填充某几个顶点之间的部分,而不是像\"真\"3D纹理那样用向量值阴影覆盖原来的纹理。 NGC新的那个太空堡垒的射击游戏也是用了这个技术……
对了,Konami好像还说过心跳3用的是原创技术……
真在《游戏机》上发表的话……
一定会被选为“本期最不喜欢的文章”的。 这个看得懂真还得有点水平。 最初由 ST.KuCSe 发布好多话怎么都在哪看过啊
就和那个他写的关于NGC硬件的文章(电软上那个)一样
这种文章你看过一遍还能记得真是强,不过这种文章写来写去也就这点东西了。 电软里介绍过一些,没有这里齐全,新的塞尔达真得很可爱,非常喜欢这种画面。 我还是扁爱2D游戏,虽然3D以成主流,2D还是有它独到之处,
也可能是\"先入为主\" 现在这种技术很流行啊!capcom的那款赛车游戏好像也是用的这种技术,难道想以此超越GT? 我就是为了这种文章才来这里的,不过我水平太差,怎么也看不懂.看来还要非常努力才行.各位专家们,可不可以多登些这类的文章,特别是基础篇,配以详细的解释,让我们这些硬件盲能学到些东西呀?拜托了.
回星骑士!!!
有关我NGC(电软上)的文章很多人都给我说过和小熊的有雷同的地方,我不认为我是抄的。对于你所说的那部分,如果我能给你E文原版资料你就不会认为我是抄别人的了!!(有关NGC星球大战的硬件资料,FROM FACTOR 5)
而且我从来就没有抄袭过任何人的作品!在这里说明一下!!!
DB同志!!!
我的QQ是57000126,快点加我啊!!!以前的号码被偷了!
页:
[1]