前腐后继 发表于 2007-3-21 23:05:00

Shaderey――非真实渲染

<p>本文版权归原作者所有,仅供个人学习使用,请勿转载,勿用于任何商业用途。<br/>由于本人水平有限,难免出错,不清楚的地方请大家以原著为准。欢迎大家和我多多交流。<br/>作者:Aras&nbsp;Pranckevicius<br/>翻译:clayman<br/>Blog:<a href="http://blog.csdn.net/soilwork" target="_blank"><font color="#9c0000">http://blog.csdn.net/soilwork</font></a><br/>clayman_joe@yahoo.com.cn&nbsp;&nbsp;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;本文描述了以非真实渲染(none-photorealistic&nbsp;rendering)风格,对户外场景进行着色的技术。在2003年秋天的Beyond3D/ATI&nbsp;shader&nbsp;compititon中,Shaderey程序最先使用了这些技术来进行渲染。在Shaderey的户外场景中,包含了地形,云,树木,房屋,天空顶,以及湖水,如图所示:<br/><img src="UploadFile/2007-3/200732123451734.jpg?v=0" border="0" alt=""/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;确切的说,这里使用的NPR技术都是在图片空间(image&nbsp;space)进行的操作,它依赖于场景中两张重要的图片:一张包含了颜色信息,一张包含法线和深度信息。处理过程分为两部分:<br/>渲染:&nbsp;把场景渲染到颜色和法线/深度目标中。<br/>后期处理:&nbsp;在图片空间进行一系列过滤操作,获得最终的非真实效果。</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;后期处理包括:HSV空间下的颜色扭曲,屏幕空间中简单“阴影线(hatching)”的渲染,以及在法线/深度不连续处的轮廓线绘制。我们将在后面详细讨论这些过滤操作。首先,先来看看Shaderey的场景渲染方式。</p><p>场景渲染</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;场景中所有的树木和房屋都经过了可视体裁剪(frustum-culled)。地形是一张512&nbsp;x&nbsp;512的高度图,但分为若干尺寸固定的(32&nbsp;x&nbsp;32)小块(chunk)。所有通过视见体裁剪的地形小块都没有进行任何形式的LOD。整个场景使用了一张1024&nbsp;x&nbsp;1024的阴影帖图。房屋和树木都将产生阴影,并且投影到地面上。场景中的树木和木屋投射阴影,而地形接收这些影子。我们使用pick-nearest采样器,对阴影贴图进行四次有偏移的采样,然后再shader中对这些值进行均值采样,以提高影子边界上的质量。阴影贴图并不需要覆盖整个地形的大小,在我们的实现中,它将随观察者的位置移动,以保证观察者前方总是有正确的阴影。</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;为了模拟湖面的简单反射效果,可以把摄像机反转到水面之下,把场景渲染为一张较小的平面反射贴图。我们把这张阴影贴图投影到水面上,另外使用两张卷动的EMBM风格的凹凸贴图来模拟波纹。为了减少几何数据,渲染到反射贴图中的地形将使用较低的LOD层次。对所有物体来说,大气光照散射效果都是在顶点级别计算的。</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;除了把颜色渲染到后备缓冲之外,还需要把场景中物体的法线和深度渲染到一张和屏幕大小相同的A8R8B8G8纹理中。世界坐标下的法线信息保存在RGB通道中,深度值的导数保存在alpha通道中。</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;下面是在vertex&nbsp;shader中,使用HLSL正确计算法线和深度值倒数的代码:</p><p><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//output&nbsp;normal&nbsp;in&nbsp;RGB,&nbsp;sort-of-depth&nbsp;in&nbsp;A,&nbsp;p&nbsp;–&nbsp;final&nbsp;(&nbsp;clip&nbsp;space)&nbsp;position,&nbsp;&nbsp;n—world&nbsp;space&nbsp;normal</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;static&nbsp;inline&nbsp;float4&nbsp;gNormalZ(&nbsp;float4&nbsp;p,&nbsp;float3&nbsp;n)</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;float4&nbsp;o;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;o.xyz&nbsp;=&nbsp;n&nbsp;*&nbsp;0.5&nbsp;+&nbsp;0.5;&nbsp;&nbsp;//&nbsp;in&nbsp;to&nbsp;0….1&nbsp;range<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;o.w&nbsp;=&nbsp;100.0&nbsp;/&nbsp;(&nbsp;p.w&nbsp;+&nbsp;100&nbsp;);&nbsp;&nbsp;//&nbsp;kind-of-depth</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果支持DirectX&nbsp;9中的Multiple&nbsp;Render&nbsp;Target(MRT),可以在渲染场景颜色的同时,渲染法线和深度。如果不支持MRT,则需要分两次渲染(译注:从demo来看,使用MRT将会严重影响渲染质量,应该是由于MRT不支持多重采样造成的)。当把地形渲染到法线/深度纹理中时,需要使用&lt;&lt;&nbsp;Non-Photorealistic&nbsp;Rendering&nbsp;with&nbsp;Pixel&nbsp;and&nbsp;Vertex&nbsp;Shader&gt;&gt;中所描述的方法,在pixel&nbsp;shader中对阴影贴图进行采样,对阴影中的像素来说,需要对插值之后深度值取反(译注:在Non-Photo原文中是对法线值取反)。这样做的原因在后面描述后期处理的部分会讲解。</p><p>图片后期处理</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;目前已经把场景渲染为颜色和法线/深度图片了,接下来就可以对这些图片进行一系列处理了,包括把颜色转到HSV颜色空间下进行风格化处理,绘制边缘轮廓线,实现阴影线。</p><p>颜色失真</p><p>图片处理的第一步是进行颜色失真,获得风格化的样式。<br/>1.降低采样率,把图片缩为一张521x512的纹理。<br/>2.把颜色从RGB空间转换到HSV空间,并且量化(quantize)颜色值。颜色空间的转换将通过对一张体积材质的查找来实现。把原像素的RGB值作为立方纹理坐标。立方纹理中的像素为HSV颜色空间。这里我们将使用一张32x32x32的纹理,并且不进行任何过滤,所以颜色转换的同时将会量化颜色值。<br/>3.使用2D偏移纹理,对同一纹理中当前像素的两个偏移位置进行采样。用来访问偏移纹理的纹理坐标由程序控制,它们将和观察者的位置有关(观察点的yaw值将在水平方向影响偏移,pitch值在垂直方向影响)。这些额外的采样颜色也必须转换到HSV空间。<br/>4.替换图片中的颜色。目前我们有2个额外的偏移采样。首先,我们检察两个偏移值之间差分的差值,如果小于某个限制,就什么也不做。如果它们之间的差别足够大,则输出S和V通道的均值,保留中心原像素的H值。这个方法能高效的在颜色区域边缘替换原像素的饱和度。<br/>5.再使用一张立方纹理把颜色转换回HSV空间。<br/>&nbsp;&nbsp;&nbsp;&nbsp;第2~5步的pixel&nbsp;shader代码如下,需要pixel&nbsp;shader&nbsp;2.0的支持。</p><p>struct&nbsp;PS_INPUT<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;float2&nbsp;uv&nbsp;:&nbsp;TEXCOORD0;&nbsp;//base&nbsp;uv,displace&nbsp;uv<br/>};</p><p>&nbsp;</p><p>float4&nbsp;psMain(&nbsp;PS_INTPUT&nbsp;i)&nbsp;:&nbsp;COLOR<br/>{</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//sample&nbsp;rgb,convert&nbsp;into&nbsp;hsv<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;half&nbsp;base&nbsp;=&nbsp;tex2D(&nbsp;smpBase,&nbsp;i.uv&nbsp;).rgb;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;base&nbsp;=&nbsp;tex3D(&nbsp;smpRGB2HSV,&nbsp;base&nbsp;).rgb;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//get&nbsp;2&nbsp;displaced&nbsp;sample&nbsp;locations<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;half2&nbsp;bleedB&nbsp;=&nbsp;tex2D&nbsp;(&nbsp;smpBleedB,&nbsp;i.uv&nbsp;).rg&nbsp;*&nbsp;2&nbsp;-1;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;half2&nbsp;bleedC&nbsp;=&nbsp;tex2D&nbsp;(&nbsp;smpBleedC,&nbsp;i.uv&nbsp;).rg&nbsp;*&nbsp;2&nbsp;-1;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;float2&nbsp;uvB&nbsp;=&nbsp;i.uv&nbsp;+&nbsp;bleedB&nbsp;*&nbsp;(8.0/512);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;float2&nbsp;uvC&nbsp;=&nbsp;i.uv&nbsp;+&nbsp;bleedC&nbsp;*&nbsp;(-7.0/512);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//sample&nbsp;base&nbsp;at&nbsp;displaced&nbsp;locations&nbsp;,convert&nbsp;to&nbsp;hsv<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;half3&nbsp;baseB&nbsp;=&nbsp;tex2D(&nbsp;smpBase,uvB).rgb;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;baseB&nbsp;=&nbsp;tex3D(&nbsp;smpRGB2HSV,baseB);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;half3&nbsp;baseC&nbsp;=&nbsp;tex2D(&nbsp;smpBase,&nbsp;uvC).rgb;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;baseC&nbsp;=&nbsp;tex3D(&nbsp;smpRGB2HSV,baseC);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;half3&nbsp;bleed&nbsp;=&nbsp;baseB&nbsp;*&nbsp;0.5&nbsp;+&nbsp;baseC&nbsp;*&nbsp;0.5;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//final&nbsp;color&nbsp;is&nbsp;base&nbsp;if&nbsp;differences&nbsp;in&nbsp;hsv&nbsp;values&nbsp;are&nbsp;smller&nbsp;than&nbsp;tresholds<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//else&nbsp;average&nbsp;of&nbsp;displace&nbsp;values<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;half3&nbsp;diff&nbsp;=&nbsp;abs(base&nbsp;-&nbsp;baseC)&nbsp;-&nbsp;half(&nbsp;1/8.0,1/3.0,1/3.0)<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;half3&nbsp;final&nbsp;=&nbsp;all(&nbsp;diff&nbsp;&lt;&nbsp;float3&nbsp;(&nbsp;0,0,0)&nbsp;?&nbsp;base&nbsp;:&nbsp;bleed;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//leave&nbsp;original&nbsp;hue&nbsp;channel<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;final.r&nbsp;=&nbsp;base.r;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//convert&nbsp;back&nbsp;to&nbsp;rgb<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;tex3D&nbsp;(&nbsp;smpHSV2RGB),final);</p><p>}</p><p>边缘检测和轮廓线<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;为了获得NPR风格的样式,必须在图片上渲染出深色的轮廓线和阴影线,表现出场景的着色效果。在Shaderey中,我们将同时绘制边缘轮廓线和阴影线。这里需要使用之前计算的法线/深度图来计算边缘,用光线和法线的点积来计算那些区域需要绘制阴影线。阴影线是一张简单的纹理。在这一步处理中,边缘和轮廓线都是白色。最终合成时,进行反色处理,轮廓线变为纯黑色,轮廓线颜色根据场景的着色进行衰减。<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;以下是绘制轮廓线和阴影线的pixel&nbsp;shader代码:</p><p>half4&nbsp;psMain&nbsp;(&nbsp;float2&nbsp;uv:TEXCOORD):&nbsp;COLOR<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//sample&nbsp;center&nbsp;and&nbsp;2&nbsp;neightbours<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;half4&nbsp;cbase&nbsp;=&nbsp;tex2D(&nbsp;smpBase,&nbsp;i.uv);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;half4&nbsp;cb1&nbsp;=&nbsp;tex2D(smpBase,&nbsp;i.uv);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;half4&nbsp;cb3&nbsp;=&nbsp;tex2D(smpBase,&nbsp;i.uv);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//normal&nbsp;into&nbsp;-1..1&nbsp;range<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;half3&nbsp;nbase&nbsp;=&nbsp;cbase.xyz&nbsp;*&nbsp;2&nbsp;-1;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;half3&nbsp;nb1&nbsp;=&nbsp;cb1.xyz&nbsp;*&nbsp;2&nbsp;-&nbsp;1;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;half3&nbsp;nb3&nbsp;=&nbsp;cb3.xyz&nbsp;*&nbsp;2&nbsp;-&nbsp;1;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//edges&nbsp;from&nbsp;normals<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;half2&nbsp;ndiff;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ndiff.x&nbsp;=&nbsp;dot(&nbsp;nbase,nb1);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ndiff.y&nbsp;=&nbsp;dot(&nbsp;nbase,nb3);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ndiff&nbsp;-=&nbsp;0.6;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ndiff&nbsp;=&nbsp;ndiff&nbsp;&gt;&nbsp;half2(0,0)&nbsp;?&nbsp;half2(0,0):half2(1,1);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;half&nbsp;ndiff1&nbsp;=&nbsp;ndiff.x&nbsp;+&nbsp;ndiff.y;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//edges&nbsp;from&nbsp;z<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;float2&nbsp;zdiff;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;zdiff.x&nbsp;=&nbsp;cbase.a&nbsp;-&nbsp;cd1.a;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;zdiff.y&nbsp;=&nbsp;cbase.a&nbsp;-&nbsp;cb3.a;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;adiff&nbsp;=&nbsp;abs(zdiff)&nbsp;-&nbsp;0.02;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;zdiff&nbsp;=&nbsp;zdiff&nbsp;&gt;&nbsp;half2(0,0)&nbsp;?&nbsp;half2(1,1)&nbsp;:&nbsp;half2(0,0);</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//sampler&nbsp;hatch<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;half4&nbsp;chatch&nbsp;=&nbsp;tex2D(&nbsp;smpHatch,&nbsp;i.uv);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//dot&nbsp;normal&nbsp;with&nbsp;light<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;half&nbsp;dotNL&nbsp;=&nbsp;dot(&nbsp;nbase,&nbsp;vLightDir);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//hatch&nbsp;blend&nbsp;factor<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;half&nbsp;factor&nbsp;=&nbsp;saturate(&nbsp;(1.0&nbsp;-&nbsp;0.9&nbsp;-&nbsp;dotNL)&nbsp;*&nbsp;2);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;chatch&nbsp;*=&nbsp;factor;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;chatch&nbsp;+&nbsp;ndiff1&nbsp;+&nbsp;dot(zdiff,half2(1,1));<br/>}</p><p>最终合成<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在处理完了两张图片之后,把失真之后的颜色与反转之后的边缘/轮廓线进行调制,合成出最终图像。</p><p>&nbsp;点击<a href="http://www.nesnausk.org/nearaz/files/shaderey.zip" target="_blank"><font color="#9c0000">这里</font></a>下载完成程序和代码。<br/><img src="UploadFile/2007-3/200732123454580.jpg?v=0" border="0" alt=""/><br/><img src="UploadFile/2007-3/200732123456621.jpg?v=0" border="0" alt=""/><br/></p>

hellowing 发表于 2007-3-24 20:17:00

在ShaderX3一書看過了, 還是要頂下

zhigu 发表于 2007-4-3 23:54:00

页: [1]
查看完整版本: Shaderey――非真实渲染