重庆幸运农场中奖金额|重庆幸运农场官网
MyException - 我的異常網
當前位置:我的異常網» 編程 » 第9章 點染管道,著色器,效果

第9章 點染管道,著色器,效果

www.h0f1.com  網友分享于:2013-12-20  瀏覽:28次
第9章 渲染管道,著色器,效果
<<Beginning.XNA.3.0.Game.Programming.From.Novice.to.Professional>>第9章,圖片未貼出,原譯文在附近中

渲染管道,著色器,效果

本章你將學到一些與渲染管道,著色器,效果相關的概念.渲染管道作用是將3d場景繪制到2d圖形,這樣就可以在屏幕上顯示了.渲染管道的一些階段可以使用著色器,并使用效果來描述著色器和渲染管道階段配置的組合.這個特性可以讓你創建自定義的效果,提高最終圖形的效果.
渲染管道
為了讓3d場景在2d屏幕上可見,場景必須被轉換到2d圖形.將3d繪制進一個2d圖形稱為渲染.圖9-1顯示了xna使用的渲染管道的抽象.

圖 9-1 xna的渲染管道
3d場景中的物體是用網格(mesh)來描述,網格是頂點(還可能有索引)的集合.網格中的頂點有很多不同的屬性,如位置,顏色,紋理坐標,如8章所述.
如圖9-1所示,在渲染進程的開始,物體網格的頂點集合被發送到渲染管道,頂點集合將經過頂點處理階段,光柵,像素處理.流程的最后,就產生很多準備儲存進場景最終圖形的像素.物體三角形為屏幕上的同一個像素進行排序,渲染管道的最后一個階段-輸出合并-用來決定哪個像是離攝影機最近.并將這些像素儲存進最后的圖形丟棄不可見的像素.判斷是否可見的規則是攝影機與物體之間的距離,因此最近的物體可見,同時判斷會被透明度信息所影響.
在老版本的Directx和Opengl中,所有的渲染管道階段都是固定的(預先定義好).這意味著效果的集合都是固定的,強制所有的游戲使用相同的渲染管道,只允許修改一些預定義的參數.導致大部分游戲風格都一樣.
從directx8.1之后,通過創建一個被稱為著色器的小程序使渲染管道編程變為可能.著色器允許你定義gpu編程階段輸入哪些數據及輸出哪些數據,更重要的時每個階段都有此過程.使用著色器你可以創建很多固定管道不能實現的游戲效果.
Xna中,你使用著色器來渲染任何物體.為了簡化游戲開發xna提供了一些包含進程的著色器和效果的助手類.如,你可以使用SpriteBatch來繪制2d圖元,BasicEffect來繪制3d模型.這2個類都可以使用透明度.如他們的名字一樣這些類只提供了基礎的渲染.SpriteBatch來將渲染儲存在硬盤上的圖形,并不會應用聚光燈,反射及圖形漣漪效果.BasicEffect類可以使用基礎光渲染3d世界.如果你想得的更好的效果你需要寫自己的著色器.
著色器
著色器是跑在gpu中的小程序,用來定義可編程內容管道如何接收xna程序的數據.著色器通常用HLSL來寫.
有2個著色器:頂點著色器和像素著色器.光柵階段在頂點和像素間被執行.
頂點著色器
用于頂點處理階段,圖9-1被頂點著色器調用.頂點著色器的最基本的任務是從xna程序中讀取頂點的原始坐標,將其轉換為2d屏幕坐標,準備進行下一階段.另外,操作坐標的同時,你還可以處理各個頂點別的屬性,如顏色,法線等.
頂點著色器可以執行很多任務,如單純的形變,骨骼動畫,和粒子運動等.
光柵
在此階段,你的gpu來檢測每個三角形占據了屏幕的那些像素.所有的這些像素都將被發送到像素著色器,用于完成最后的處理.
圖9-2顯示了一個光柵的三角,占據了很多像素.特別注意:頂點的屬性是在所有生成的像素中使用線性插值.

圖9-2 三角行光柵化,灰色的網格表示產生的像素.
像素著色器
此著色器的主要任務是接收輸入的像素,計算每個像素的最終顏色并將它們傳遞到輸出合并.每個像素都可以為著色器提供多種數據,此數據由頂點著色器和光柵階段線性插值所產生.這可以允許你根據光照條件來調整像素的顏色.如增加反射,執行凹凸貼圖等.你也可以用像素著色器對一個完整的渲染過的場景進行后期處理.如,明亮度,對比度及顏色增強,飽和,模糊.
另外,像素著色器可以改變像素的深度.此深度用于輸出合并時決定哪些像素需要繪制.默認深度指示源三角離攝影機多遠.但是,如果你想影響輸出合并,你可以指定自己的值.
高級著色語言
Xna使用微軟的hlsl來原始支持著色.hlsl有一些內置的函數,包含數學操作,紋理訪問及流程控制.hlsl支持的數據類型很像c,除了向量(vector),矩陣(matrix),采樣器(sampler).
Hlsl數據類型
Hlsl支持多種不同的數據類型,包括,標量,向量,矩陣.表9-1顯示hlsl標量數據類型.注意用現有的標量類型來創建向量和矩陣是可能的,如float2,float4,bool3x3,double2x2等.
表 9-1. Hlsl標量類型
類型 說明
bool true或false
int 32位有符合整數
half 16位浮點
float 32位浮點
double 64位浮點

另外的數據類型是采樣器,用來從紋理采樣.不同的采樣器類型,如sampler1D,sampler2D,sampler3D,被用來用1d,2d,3d中采樣.與采樣器類型一起的還有一些狀態,指明如何從紋理中采樣,過濾器的使用,及紋理如何尋址.
采樣器應該定義在hlsl程序的頂部,這里是2d紋理采樣器的一個例子:
// 聲明輸入的紋理
texture skyTexture;
// 聲明從skyTexture紋理中采樣的采樣器
sampler2D skySampler = sampler_state
{
    Texture = skyTexture;
   
    MinFilter = Linear;
    MagFilter = Linear;
MipFilter = Linear;
AddressU = Wrap;
    AddressV = Wrap;
    AddressW = Wrap;
}
texture表示從哪個紋理采樣(通過xna程序來傳遞紋理),紋理是只能通過使用采樣器來讀取.MinFilter,MagFilter,MipFilter是過濾器狀態,AddressU,AddressV,AddressW是尋址狀態.
注意:directsdk的文檔包含完整的hlsl說明.你可以訪問這個網站: http://msdn2.microsoft.com/en-us/library/bb509638.aspx.
固定與可變的輸入參數
Hlsl有2種輸入數據類型:
固定的輸入數據:表示在頂點/像素著色處理過程中都是不變的.如渲染一棵樹,它的紋理,世界矩陣和光照條件是不變的.固定輸入數據是從你的xna應用中傳遞進著色器.
可變的輸入數據:表示每個著色器執行時數據會發生變化.如樹的渲染過程中,頂點著色器需要處理樹所有的頂點.這表示頂點著色器的每個循環使用的頂點都不一樣.與固定輸入不同,定義可變輸入數據類型需要使用語義(semantic),下面討論.
語義(semantic)
語義是hlsl預定義的,用于將變量名和輸入輸出數據進行匹配(opengl是指定變量存放的寄存器).如,你的3d物體可能有一個float4儲存3d位置,另外的一個float4用來儲存2個紋理坐標.但你的頂點著色器如何明白哪一個是表示位置?
解決的方案是在頂點處理階段添加一個POSITION0語義,用來匹配一個可變數據的位置屬性,如:
float4 vertexPosition : POSITION0;
在所有的可變輸入數據(從應用中獲取的或渲染階段中所傳遞)中,語義是必須的.如,從頂點輸出的將在像素著色器中使用的數據必須定義語義.在"創建一個簡單的著色器"中將看到語義的定義.
語義不是大小寫敏感并且需要在變量后面使用":"來指定.表9-2和9-3顯示了一些語義.
表9-2.輸入的頂點著色語義
輸入 描述 類型
POSITION[N] 在物體坐標系的頂點位置 float4
COLOR[n] 反射及鏡面高光顏色 float4
NORMAL[n] 法線向量 float4
TEXCOORD[N] 紋理坐標 float4
TANGENT[n] 切線向量 float4
BINORAML[n] 次法線向量 float4
BLENDINDICES[N] 骨骼混合索引 int4
BLENDWEIGHT[n] 骨骼混合寬度 float4
表9-3 頂點輸出語義
輸出 說明 類型
POSITION[N] 同一坐標系頂點的位置 float4(x,y,z,w)
COLOR[N] 反射或鏡面高光顏色 float4
TEXCOORD[n] 紋理坐標 float4
FOG 頂點的霧 float
使用頂點著色的輸入語言來接收可變數據.一些通用的語義如POSITION,COLOR,NORMAL和TEXTURE.如果頂點有切線和次法線需要使用TANGENT和BINORMAL語義,當你需要在效果中完成凹凸貼圖時.當頂點連接到骨骼時需要使用BLENDINDICES和BLENDWEIGHT語義.骨骼用于網格頂點的變形(12章詳解).
頂點著色輸出必須的一個語義是POSITION.如果你需要傳遞其余數據到像素著色,應該使用TEXCOORD[N].
[n]是一個可選的數字,用來定義使用的資源序號.如,如果一個模型有3個紋理,TEXCOORD[n]的n可以是0,1,2;因此,TEXCOORD0,TEXCOORD1,TEXCOORD2都是有效的頂點著色語義.表9-4顯示一些像素著色語義.
表9-4 像素著色語義
輸入 說明 類型
COLOR[N] 反射或鏡面高光顏色 float4
TEXCOORD[N] 紋理坐標 float4
COLOR[N] 輸出的顏色 float4
DEPTH[N] 輸出的深度 float
因為頂點著色在光柵階段執行完成后,可用的輸入語義是像素的顏色和一些紋理坐標.紋理坐標地址,紋理的位置與當前的像素匹配,并且這些坐標從頂點著色傳遞到像素著色.
像素著色最終輸出的數據是像素顏色和深度,像素顏色是必須的,像素深度是可選的.
函數
Hlsl的語法像c,每個函數有一個聲明和主體.方法聲明包含方法名和返回值,及一些參數.返回值可能指定了語義.
下面是用于像素著色的入口方法:
float4 simplePS(float4 inputColor : COLOR0) : COLOR0
{
    return inputColor * 0.5f;
}
因為simplePS是像素著色器的入口,參數必須指定一個語義.本例中simpleDS方法將接收顏色參數減弱一半后作為最后的顏色.注意方法的參數可以有其他的修飾符,如in,out,inout.用來定義輸入,輸出,輸入/輸出參數.
在"技術technique,途徑pass,和效果effect"一節中我們將演示用于頂點和像素著色的入口方法.
Hlsl內置了一小組內置的方法.包含數學操作,紋理訪問,及流程控制.這些方法不需要與gpu指令匹配.實際上,表9-5列出常用的hlsl方法.
表 9-5.常用的hlsl方法
方法 說明
Dot 返回2個向量的點乘
Cross 返回2個float 3d向量的叉乘
Lerp 2個值間執行線性插值,算法:(1-s)*x+s*y
Mul 執行矩陣x乘以矩陣y
Normalize 歸一化指定的浮點向量
Pow 返回x的y次冪
Reflect 根據給定的入射射線方向和表面法線返回反射向量
Refract 根據給定的入射射線方向和表面法線返回折射向量
Saturate 將值固定在[0,1]之間
Tex2d 執行2d紋理尋址
Tex3d 執行3d紋理尋址
創建一個簡單的著色器
本節中你將使用hlsl創建第一個著色器.作為一個好習慣,你應該在開始部分定義固定和可變變量:
//從應用中接收的矩陣-固定
//(world * view * projection)
float4x4 matWVP : WorldViewProjection;
// 用于頂點輸入的結構 - 可變
struct vertexInput
{
    float4 position : POSITION0;
};
// 從頂點著色傳遞到像素著色的結果 - 可變
struct vertexOutput
{
    float4 hposition : POSITION;
    float3 color : COLOR0;
};
著色器使用的matWVP矩陣需要在xna應用中進行設置.這個世界-視野-投影矩陣由xna應用的攝影機創建.當頂點著色將3d位置轉換到2d屏幕上時需要用到.
定義的vertexInput結構用來定義頂點著色需要的信息.如你所見,頂點著色可以處理包含位置數據的頂點.
vertexOutput結構定義數據類型,從頂點著色傳遞到光柵進行線性插值,然后傳遞到像素著色.頂點著色將被強制生成位置和顏色.
很重要的一點是頂點著色輸出的頂點位置在像素著色中無法訪問.光柵階段時需要知道2d屏幕位置,可以這樣想:在光柵階段時頂點3d位置被消化了,所以在像素著色時就無法訪問了.如果你的像素著色需要2d屏幕坐標,你應該使用額外的TEXCOORD[n]語義來定義.
接著,聲明頂點著色:
//頂點著色代碼
pixelInput SimpleVS(vertexInput IN)
{
    pixelInput OUT;
   
    // 轉換頂點的位置
    OUT.hposition = mul(IN.position, matWVP);
    OUT.color = float3(1.0f, 1.0f, 0.0f);
    return OUT;
}
Xna應用渲染每個頂點時均會調用頂點著色.這個頂點被你的著色器當作一個vertexInput對象來接收并最后被處理進一個pixedlInput對象.在SimpleVS方法,需要通過乘以matWVP矩陣來計算輸出的2d屏幕位置.輸出的頂點顏色被設為黃色,rgb(1,1,0).
接著,定義像素著色:
// 像素著色代碼
float4 SimplePS(pixelInput IN) : COLOR0
{
    return float4(IN.color.rgb, 1.0f);
}
此像素著色只是簡單的將從頂點著色獲取到的顏色返回.這個顏色將被用于最終的像素顏色.
不錯,你現在定義了一個頂點著色和像素著色.但你還沒有分別指定那個頂點著色及像素著色在將三角形渲染到屏幕上時使用.為此你需要指定需要使用那個技術(technique).
技術technique,途徑pass,效果effect
在最基礎的形式中,技術只是負責組合頂點著色與像素著色.下面的技術組合上面寫過的頂點和像素著色:
technique basicTechnique
{
    pass p0
    {
        VertexShader = compile vs_2_0 SimpleVS();
        PixelShader = compile ps_2_0 SimplePS();
    }
}
技術也定義了哪個著色需要用那個著色版本來編譯.本例中都是使用2.0的著色模型.更高的版本有更多的指令和功能但需要gpu硬件來支持.
如你所見,2個著色都被封裝在稱為途徑(pass)中.一個途徑讀入所有應該在技術中繪制的頂點,處理它們,處理生成的像素,并將其儲存進背面緩沖,當所有的像素被處理完畢后它們會被顯示到屏幕上.一些技術中可能你需要重復此步驟2次.因此一些技術將有2個途徑,每一個途徑均有一個頂點著色和像素著色.
為了一些更高級的效果,你需要使用多個技術.使用第一個技術將場景轉換進一個圖形中,另一個技術來處理此圖形.
所有的著色和技術的組合稱為效果(effect).一個簡單的效果將包含一個頂點著色,一個像素著色和一個技術.高級效果(如陰影貼圖或延遲渲染)將包含多個.
效果和技術是不同的,并且著色器使著色程序更容易的在不同的技術中重用,也可以創建不同的技術來面向低端和高端的gpu.
你將經常把相同效果的著色和技術放到同一個文件中,xna將每一個hlsl代碼稱為一個效果(effect).這將允許xna將效果作為游戲素材來處理,就像模型和紋理.所有的效果通過xna的內容管道來處理,生成可操控對象在運行時由內容管理器載入.
Effect類
此時,你已經完成了第一個完整效果并儲存在.fx文件.這表示你可以關閉.fx文件并將其移動進你的xna工程.下一步在你的xna工程中載入用來渲染物體到屏幕上.在xna程序中,效果應該被載入進一個Effect類的實例中(正如一個圖形被載入為一個Texture2D類的實例一樣).這個Effect類允許你配置效果的固定參數,選擇當前效果技術,及用來渲染的效果.下面的代碼顯示了如何載入及配置一個效果:
//xna Effect 對象
Effect effect;
//載入效果
effect = content.load<Effect>("/effects/simpleEffect");
//設置 技術
effect.CurrentTechnique = effect.Technique["basicTechnique"];
//配置 固定效果參數
effect.Parameters["matWVP"].SetValue(worldViewProjectionMatrix);
這些代碼使用content.Load方法從hlsl代碼文件中載入simpleEffect效果.然后指定那個效果的技術將被使用;本例中使用的是之前定義的basicTechnique技術.最后,設定了唯一的固定參數:matWVP.
下面的代碼顯示了如何使用載入的效果畫出物體:
//首先 開始 效果
effect.Begin();
//記住 效果可以有多個pass
foreach(EffectPass pass in effect.CurrentTechnique.Passes){
pass.Begin();
//放入繪制代碼
pass.End();
}
//最后,結束效果
effect.End();
為了繪制一個3d對象,你首先需要開啟準備使用的效果,然后遍歷當前技術的所有途徑.每一個pass,都需要開啟pass,繪制物體,結束pass.最后,還需要結束效果.當通過CurrentTechnique來訪問技術時,效果途徑由類EffectPass來表示.如果你需要在pass開始之后改變效果參數,就需要調用Effect類的CommitChanges方法來更新變化.
前面的步驟顯示了繪制一個模型的必要代碼.當你從硬盤載入一個3d模型時,模型和它的效果都儲存在ModelMesh對象中.
Effect助手類
當一個效果通過內容管理器載入時,你不知道它有什么參數或技術.為了修改效果的參數,你必須先確定效果里有什么參數.可能你配置了一個像這樣的lightPosition參數:
effect.Paramters["lightPosition"].SetValue(new Vector3(0.0f,40.0f,0.0f));
在此代碼中,當你修改了lightPosition參數的值時,效果的內部將產生一個lightPosition參數的查詢.這會有2個問題:查詢此參數的計算需求及查詢一個無效參數的可能.使用助手類可以避免這些問題.
為了簡化自定義效果的操作,你可以為每個效果創建一個助手類.每個助手類將儲存一個所有效果參數的引用,避免查詢的代價.下面的代碼顯示了如何為效果參數儲存一個引用及改變值:
EffectParameter param1 = effect.Parameters["lightPosition"];
// 渲染循環
{
param1.SetValue(new Vector3(0.0f,40.0f,0.0f));
//繪制模型
... ...
}
材質Materials
材質是你應該創建并儲存用于配置效果參數的類.例如,你可以使用一個效果來渲染2個面,每個面應用一個紋理.本例中每個面的材質是它的紋理,可以通過效果參數的配置來渲染表面.如果2個表面共享了相同的材質,你可以設置想要的效果和材質,在一個序列中渲染2個面來避免效果或效果參數的變化.
下面是你需要創建的2個基礎的材質類:
1 LightMaterial : 將儲存用于光線計算(反射顏色,高光顏色,高光強度)的表面屬性.
2 TextureMaterial : 此類將儲存一個紋理貼圖或網格(tile)用于將紋理應用到表面上.
你可以使用這2個基礎的材質類來創建更復雜材質類型,如多紋理材質.
下面是LightMaterail完整代碼:
public class LightMaterial
{
    // 材質屬性 - 反射或 鏡面高光的顏色
    Vector3 diffuseColor;
    Vector3 specularColor;
    // 鏡面高光強度 (亮度)
    float specularPower;
    // 屬性
    public Vector3 DiffuseColor
    {
        get { return diffuseColor; }
        set { diffuseColor = value; }
    }
    public Vector3 SpecularColor
    {
        get { return specularColor; }
        set { specularColor = value; }
    }
    public float SpecularPower
    {
        get { return specularPower; }
        set { specularPower = value; }
}
public LightMaterial (Vector3 diffuseColor, Vector3 specularColor, float specularPower)
    {
        this.diffuseColor = diffuseColor;
        this.specularColor = specularColor;
        this.specularPower = specularPower;
    }
}
將光線的反射和高光顏色以xna的Vector3分別儲存在LightMaterail類的diffuseColor和specularColor屬性中.將光線強度(亮度)以float值儲存在specularPower中.注意(x,y,z)分量表示顏色的rgb格式.你還需要用屬性來存取光線的反射顏色,高光顏色及高光強度.
下面是TextureMaterial類的完整代碼:
public class TextureMaterial
{
    // 紋理
    Texture2D texture;
    // 紋理 UV 塊
    Vector2 uvTile;
    // 屬性
    public Texture2D Texture
    {
        get { return texture; }
        set { texture = value; }
    }
    public Vector2 UVTile
    {
        get { return uvTile; }
        set { uvTile = value; }
    }
    public TextureMaterial(Texture2D texture, Vector2 uvTile)
    {
        this.texture = texture;
        this.uvTile = uvTile;
    }
}
用xna的Texture2D類來將一個紋理儲存在TextureMaterial類的texture屬性.紋理的uv塊用于凹凸貼圖,以xna的Vector2儲存在uvTile屬性.像LightMaterial類一樣,你還需要創建屬性來存取材質和uv塊.
著色創作工具
在著色的開發中,通常需要修改你的著色,調整它的參數,使用不同的素材(模型,紋理等)來做測試.此過程可能會很慢并如果每次修改著色你都需要重編譯并執行你的游戲就會非常郁悶.為了幫助著色的開發你可以使用著色創作工具.
其中一個最好的可用工具是NVIDIA的FX Composer,網站(http://developer.nvidia.com).FX Composer是一個跨平臺的ide.支持一些著色語言包含hlsl,及多種類型素材格式,如COLLADA,FBX,X,3DS,OBJ.使用FX Composer可以在創作和修改實時查看著色的效果.FX Composer還包含場景管理和著色效率分析.
總結
本章,你學習了渲染管道各階段,及如何用它們將3d場景輸出到2d圖形.
你也學習了如何創建著色(gpu階段的編程)和著色,技術和效果之間的關系.
最后,你學習了xna中如何載入,配置,及使用效果.內容管道處理過的效果,你可以簡單載入并使用它們來渲染你的3d物體.
現在你需要復習一些基礎的3d著色和效果的概念,你可以開始繪制一些3d模型.下一章,將創建更復雜的效果來渲染3d模型.每一個效果,你將創建一個新的將用于創建材質庫效果助手類

文章評論

60個開發者不容錯過的免費資源庫
60個開發者不容錯過的免費資源庫
程序員應該關注的一些事兒
程序員應該關注的一些事兒
我是如何打敗拖延癥的
我是如何打敗拖延癥的
程序員都該閱讀的書
程序員都該閱讀的書
科技史上最臭名昭著的13大罪犯
科技史上最臭名昭著的13大罪犯
總結2014中國互聯網十大段子
總結2014中國互聯網十大段子
如何區分一個程序員是“老手“還是“新手“?
如何區分一個程序員是“老手“還是“新手“?
老程序員的下場
老程序員的下場
程序員的鄙視鏈
程序員的鄙視鏈
 程序員的樣子
程序員的樣子
寫給自己也寫給你 自己到底該何去何從
寫給自己也寫給你 自己到底該何去何從
要嫁就嫁程序猿—錢多話少死的早
要嫁就嫁程序猿—錢多話少死的早
中美印日四國程序員比較
中美印日四國程序員比較
如何成為一名黑客
如何成為一名黑客
為什么程序員都是夜貓子
為什么程序員都是夜貓子
程序員周末都喜歡做什么?
程序員周末都喜歡做什么?
“骯臟的”IT工作排行榜
“骯臟的”IT工作排行榜
鮮為人知的編程真相
鮮為人知的編程真相
程序猿的崛起——Growth Hacker
程序猿的崛起——Growth Hacker
編程語言是女人
編程語言是女人
我跳槽是因為他們的顯示器更大
我跳槽是因為他們的顯示器更大
那些爭議最大的編程觀點
那些爭議最大的編程觀點
“懶”出效率是程序員的美德
“懶”出效率是程序員的美德
5款最佳正則表達式編輯調試器
5款最佳正則表達式編輯調試器
Java程序員必看電影
Java程序員必看電影
做程序猿的老婆應該注意的一些事情
做程序猿的老婆應該注意的一些事情
每天工作4小時的程序員
每天工作4小時的程序員
親愛的項目經理,我恨你
親愛的項目經理,我恨你
一個程序員的時間管理
一個程序員的時間管理
初級 vs 高級開發者 哪個性價比更高?
初級 vs 高級開發者 哪個性價比更高?
Java 與 .NET 的平臺發展之爭
Java 與 .NET 的平臺發展之爭
程序員眼里IE瀏覽器是什么樣的
程序員眼里IE瀏覽器是什么樣的
看13位CEO、創始人和高管如何提高工作效率
看13位CEO、創始人和高管如何提高工作效率
Web開發人員為什么越來越懶了?
Web開發人員為什么越來越懶了?
為啥Android手機總會越用越慢?
為啥Android手機總會越用越慢?
代碼女神橫空出世
代碼女神橫空出世
10個調試和排錯的小建議
10個調試和排錯的小建議
Web開發者需具備的8個好習慣
Web開發者需具備的8個好習慣
漫畫:程序員的工作
漫畫:程序員的工作
程序員必看的十大電影
程序員必看的十大電影
聊聊HTTPS和SSL/TLS協議
聊聊HTTPS和SSL/TLS協議
老美怎么看待阿里赴美上市
老美怎么看待阿里赴美上市
當下全球最炙手可熱的八位少年創業者
當下全球最炙手可熱的八位少年創業者
程序員和編碼員之間的區別
程序員和編碼員之間的區別
什么才是優秀的用戶界面設計
什么才是優秀的用戶界面設計
軟件開發程序錯誤異常ExceptionCopyright © 2009-2015 MyException 版權所有
重庆幸运农场中奖金额 拿命赚钱的字句 修改捕鱼命中率修改器 幸运飞艇开奖结果 老虎机秘诀 海南夜场赚钱吗 重庆欢乐生肖彩票走势图 甘肃快3遗漏数据查询 ag金拉霸老虎机怎么样 qq分分彩计划玻色计划 快三二不同号稳赚技巧 延边中彩票 特马资料三肖三码 黑龙江快乐10分平台 金七乐 幸运飞艇计划全天 捕鱼达人3d新手必备