• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            永遠也不完美的程序

            不斷學習,不斷實踐,不斷的重構……

            常用鏈接

            統計

            積分與排名

            好友鏈接

            最新評論

            Shaderey――非真實渲染

            Shaderey――非真實渲染

             

            本文版權歸原作者所有,僅供個人學習使用,請勿轉載,勿用于任何商業用途。
            由于本人水平有限,難免出錯,不清楚的地方請大家以原著為準。歡迎大家和我多多交流。
            作者:Aras Pranckevicius
            翻譯:clayman
            Blog:http://blog.csdn.net/soilwork
            clayman_joe@yahoo.com.cn  

                 本文描述了以非真實渲染(none-photorealistic rendering)風格,對戶外場景進行著色的技術。在2003年秋天的Beyond3D/ATI shader compititon中,Shaderey程序最先使用了這些技術來進行渲染。在Shaderey的戶外場景中,包含了地形,云,樹木,房屋,天空頂,以及湖水,如圖所示:

                     確切的說,這里使用的NPR技術都是在圖片空間(image space)進行的操作,它依賴于場景中兩張重要的圖片:一張包含了顏色信息,一張包含法線和深度信息。處理過程分為兩部分:
            渲染: 把場景渲染到顏色和法線/深度目標中。
            后期處理: 在圖片空間進行一系列過濾操作,獲得最終的非真實效果。

                     后期處理包括:HSV空間下的顏色扭曲,屏幕空間中簡單“陰影線(hatching)”的渲染,以及在法線/深度不連續處的輪廓線繪制。我們將在后面詳細討論這些過濾操作。首先,先來看看Shaderey的場景渲染方式。

            場景渲染

                     場景中所有的樹木和房屋都經過了可視體裁剪(frustum-culled)。地形是一張512 x 512的高度圖,但分為若干尺寸固定的(32 x 32)小塊(chunk)。所有通過視見體裁剪的地形小塊都沒有進行任何形式的LOD。整個場景使用了一張1024 x 1024的陰影帖圖。房屋和樹木都將產生陰影,并且投影到地面上。場景中的樹木和木屋投射陰影,而地形接收這些影子。我們使用pick-nearest采樣器,對陰影貼圖進行四次有偏移的采樣,然后再shader中對這些值進行均值采樣,以提高影子邊界上的質量。陰影貼圖并不需要覆蓋整個地形的大小,在我們的實現中,它將隨觀察者的位置移動,以保證觀察者前方總是有正確的陰影。

                     為了模擬湖面的簡單反射效果,可以把攝像機反轉到水面之下,把場景渲染為一張較小的平面反射貼圖。我們把這張陰影貼圖投影到水面上,另外使用兩張卷動的EMBM風格的凹凸貼圖來模擬波紋。為了減少幾何數據,渲染到反射貼圖中的地形將使用較低的LOD層次。對所有物體來說,大氣光照散射效果都是在頂點級別計算的。

                     除了把顏色渲染到后備緩沖之外,還需要把場景中物體的法線和深度渲染到一張和屏幕大小相同的A8R8B8G8紋理中。世界坐標下的法線信息保存在RGB通道中,深度值的導數保存在alpha通道中。

                     下面是在vertex shader中,使用HLSL正確計算法線和深度值倒數的代碼:


                     //output normal in RGB, sort-of-depth in A, p – final ( clip space) position,  n—world space normal

                     static inline float4 gNormalZ( float4 p, float3 n)

                     {
                               float4 o;
                               o.xyz = n * 0.5 + 0.5;  // in to 0….1 range
                              o.w = 100.0 / ( p.w + 100 );  // kind-of-depth

                     }

                     如果支持DirectX 9中的Multiple Render Target(MRT),可以在渲染場景顏色的同時,渲染法線和深度。如果不支持MRT,則需要分兩次渲染(譯注:從demo來看,使用MRT將會嚴重影響渲染質量,應該是由于MRT不支持多重采樣造成的)。當把地形渲染到法線/深度紋理中時,需要使用<< Non-Photorealistic Rendering with Pixel and Vertex Shader>>中所描述的方法,在pixel shader中對陰影貼圖進行采樣,對陰影中的像素來說,需要對插值之后深度值取反(譯注:在Non-Photo原文中是對法線值取反)。這樣做的原因在后面描述后期處理的部分會講解。

            圖片后期處理

                     目前已經把場景渲染為顏色和法線/深度圖片了,接下來就可以對這些圖片進行一系列處理了,包括把顏色轉到HSV顏色空間下進行風格化處理,繪制邊緣輪廓線,實現陰影線。

            顏色失真

            圖片處理的第一步是進行顏色失真,獲得風格化的樣式。
            1.降低采樣率,把圖片縮為一張521x512的紋理。
            2.把顏色從RGB空間轉換到HSV空間,并且量化(quantize)顏色值。顏色空間的轉換將通過對一張體積材質的查找來實現。把原像素的RGB值作為立方紋理坐標。立方紋理中的像素為HSV顏色空間。這里我們將使用一張32x32x32的紋理,并且不進行任何過濾,所以顏色轉換的同時將會量化顏色值。
            3.使用2D偏移紋理,對同一紋理中當前像素的兩個偏移位置進行采樣。用來訪問偏移紋理的紋理坐標由程序控制,它們將和觀察者的位置有關(觀察點的yaw值將在水平方向影響偏移,pitch值在垂直方向影響)。這些額外的采樣顏色也必須轉換到HSV空間。
            4.替換圖片中的顏色。目前我們有2個額外的偏移采樣。首先,我們檢察兩個偏移值之間差分的差值,如果小于某個限制,就什么也不做。如果它們之間的差別足夠大,則輸出S和V通道的均值,保留中心原像素的H值。這個方法能高效的在顏色區域邊緣替換原像素的飽和度。
            5.再使用一張立方紋理把顏色轉換回HSV空間。
                第2~5步的pixel shader代碼如下,需要pixel shader 2.0的支持。

            struct PS_INPUT
            {
                     float2 uv[2] : TEXCOORD0; //base uv,displace uv
            };

             

            float4 psMain( PS_INTPUT i) : COLOR
            {

                     //sample rgb,convert into hsv
                     half base = tex2D( smpBase, i.uv[0] ).rgb;
                     base = tex3D( smpRGB2HSV, base ).rgb;

                     //get 2 displaced sample locations
                     half2 bleedB = tex2D ( smpBleedB, i.uv[1] ).rg * 2 -1;
                     half2 bleedC = tex2D ( smpBleedC, i.uv[1] ).rg * 2 -1;
                     float2 uvB = i.uv[0] + bleedB * (8.0/512);
                     float2 uvC = i.uv[0] + bleedC * (-7.0/512);

                     //sample base at displaced locations ,convert to hsv
                     half3 baseB = tex2D( smpBase,uvB).rgb;
                     baseB = tex3D( smpRGB2HSV,baseB);
                     half3 baseC = tex2D( smpBase, uvC).rgb;
                     baseC = tex3D( smpRGB2HSV,baseC);
                     half3 bleed = baseB * 0.5 + baseC * 0.5;
                  
                     //final color is base if differences in hsv values are smller than tresholds
                     //else average of displace values
                     half3 diff = abs(base - baseC) - half( 1/8.0,1/3.0,1/3.0)
                     half3 final = all( diff < float3 ( 0,0,0) ? base : bleed;

                     //leave original hue channel
                     final.r = base.r;
                     //convert back to rgb
                     return tex3D ( smpHSV2RGB),final);

            }

            邊緣檢測和輪廓線
                     為了獲得NPR風格的樣式,必須在圖片上渲染出深色的輪廓線和陰影線,表現出場景的著色效果。在Shaderey中,我們將同時繪制邊緣輪廓線和陰影線。這里需要使用之前計算的法線/深度圖來計算邊緣,用光線和法線的點積來計算那些區域需要繪制陰影線。陰影線是一張簡單的紋理。在這一步處理中,邊緣和輪廓線都是白色。最終合成時,進行反色處理,輪廓線變為純黑色,輪廓線顏色根據場景的著色進行衰減。
                     以下是繪制輪廓線和陰影線的pixel shader代碼:

            half4 psMain ( float2 uv[3]:TEXCOORD): COLOR
            {
                     //sample center and 2 neightbours
                     half4 cbase = tex2D( smpBase, i.uv[0]);
                     half4 cb1 = tex2D(smpBase, i.uv[1]);
                     half4 cb3 = tex2D(smpBase, i.uv[2]);

                     //normal into -1..1 range
                     half3 nbase = cbase.xyz * 2 -1;
                     half3 nb1 = cb1.xyz * 2 - 1;
                     half3 nb3 = cb3.xyz * 2 - 1;

                     //edges from normals
                     half2 ndiff;
                     ndiff.x = dot( nbase,nb1);
                     ndiff.y = dot( nbase,nb3);
                     ndiff -= 0.6;
                     ndiff = ndiff > half2(0,0) ? half2(0,0):half2(1,1);
                     half ndiff1 = ndiff.x + ndiff.y;
                   
                     //edges from z
                     float2 zdiff;
                     zdiff.x = cbase.a - cd1.a;
                     zdiff.y = cbase.a - cb3.a;
                     adiff = abs(zdiff) - 0.02;
                     zdiff = zdiff > half2(0,0) ? half2(1,1) : half2(0,0);

                     //sampler hatch
                     half4 chatch = tex2D( smpHatch, i.uv[0]);
                     //dot normal with light
                     half dotNL = dot( nbase, vLightDir);
                     //hatch blend factor
                     half factor = saturate( (1.0 - 0.9 - dotNL) * 2);
                     chatch *= factor;
                     return chatch + ndiff1 + dot(zdiff,half2(1,1));
            }

            最終合成
                     在處理完了兩張圖片之后,把失真之后的顏色與反轉之后的邊緣/輪廓線進行調制,合成出最終圖像。

             點擊這里下載完成程序和代碼。

            posted on 2008-08-26 17:47 狂爛球 閱讀(862) 評論(0)  編輯 收藏 引用 所屬分類: 圖形編程

            久久精品国产99久久香蕉| 久久久一本精品99久久精品88| 精品一久久香蕉国产线看播放 | 国产精品内射久久久久欢欢| 亚洲国产综合久久天堂| 久久久久久夜精品精品免费啦| 爱做久久久久久| 亚洲国产精品一区二区久久hs| 久久这里只有精品久久| 欧美黑人激情性久久| 国内精品久久久久久中文字幕| 99久久国产精品免费一区二区 | 成人久久免费网站| 久久99久久无码毛片一区二区| 久久久精品国产免大香伊| 久久久无码精品亚洲日韩软件| 国产精品无码久久综合| 囯产极品美女高潮无套久久久 | 精品国产青草久久久久福利 | 久久九九亚洲精品| 色综合久久无码中文字幕| 日韩欧美亚洲综合久久影院Ds| 精品久久久久久久无码 | 99久久久精品| 亚洲AV无码久久精品蜜桃| 偷窥少妇久久久久久久久| 久久国产精品视频| 久久综合丝袜日本网| 久久综合久久综合久久| 久久国产精品无码HDAV| 91精品国产9l久久久久| 国产精品99久久99久久久| 成人国内精品久久久久一区| 狼狼综合久久久久综合网| 麻豆AV一区二区三区久久| 久久九九精品99国产精品| 久久综合给合久久国产免费| 久久国产乱子伦免费精品| 国产亚洲欧美成人久久片| 香蕉久久夜色精品国产小说| 国产69精品久久久久99|