430 likes | 543 Views
2D / 3D 遊戲程式設計入門 使用 XNA 3.0 與 C#. 第六章 3D 繪出管道流程、著色器與特效檔. 本章目的. 介紹 3D 繪出的管道流程 (rendering pipeline) 、著色器 (shader) 、與特效檔 (effect) 。. 3D 繪出的管道流程. 是一系列的過程,描述如何將 3D 的模型經由頂點座標矩陣轉換、頂點顏色運算、像素顏色運算、像素貼圖運算等等一連串的處理,最後呈現成可繪出在螢幕的 2D 圖像. 著色器 (shader).
E N D
2D / 3D 遊戲程式設計入門 使用 XNA 3.0 與 C# 第六章 3D繪出管道流程、著色器與特效檔
本章目的 • 介紹3D繪出的管道流程 (rendering pipeline)、著色器(shader)、與特效檔(effect)。
3D繪出的管道流程 • 是一系列的過程,描述如何將3D的模型經由頂點座標矩陣轉換、頂點顏色運算、像素顏色運算、像素貼圖運算等等一連串的處理,最後呈現成可繪出在螢幕的2D圖像
著色器(shader) • 是將這個輸出過程的頂點運算與像素運算的部份以High-Level Shading Language (HLSL) 程式語法撰寫,在繪圖卡的GPU上執行的技術
特效檔(effect) • 是專案下的一個文字檔案,其內容包括頂點著色器程式、像素著色器程式以及相關設定的配對包裝檔案
世界座標轉換 • 世界座標轉換是要將3D模型搬到世界舞台某個方向、位置、以及調整縮放比例的必要運算。 Matrix M1 = Matrix.CreateTranslation(1.0f, 2.0f, 3.0f); // 位移 Matrix M2 = Matrix.CreateRotationX(MathHelper.PiOver2); // 旋轉 Matrix M3 = Matrix.CreateScale(1.5f, 2, 3); // 縮放 Matrix MT = M1 * M2 * M3;
視覺空間轉換 • 視覺空間轉換是當相機擺置好後,從相機看過去的景象。 Matrix ViewMatrix = Matrix.CreateLookAt( new Vector3(0.0f, 2.0f, 2.0f), // 相機觀測點 Vector3.Zero, // 相機目標點 Vector3.Up); // 相機的 上方向量
背面剪裁 • 背面剪裁是預先將特定方向描述的三角面作剔除的動作,其目的是節省CPU運算量。通常我們只會要求繪出時,三角面只呈現出正面,而不呈現背面,因為背面是包藏在3D模型物體的內部,正常的狀況下是看不到的 GraphicsDeviceManager graphics; … graphics.GraphicsDevice.RenderState.CullMode = CullMode.CullClockwiseFace; // 將 順時間方向 的三角面剔除 或 graphics.GraphicsDevice.RenderState.CullMode = CullMode.CullCounterClockwiseFace; // 將逆時間方向的三角面剔除(內定) 或 graphics.GraphicsDevice.RenderState.CullMode = CullMode.None; // 三角面的正反面 都不剔除
燈光值計算 • 燈光值計算是將頂點依照頂點預設顏色、頂點法向量、光源顏色、光源向量等等因素計算後得到的頂點顏色。 BasicEffect basicEffect = new BasicEffect(graphics.GraphicsDevice, null); basicEffect.DiffuseColor = new Vector3(1.0f, 0, 0); // 紅色 擴散光 basicEffect.AmbientLightColor = new Vector3(0.2f, 0.2f, 0.2f); // 環境光 basicEffect.EmissiveColor = new Vector3(0, 0, 1); // 自發光 basicEffect.SpecularColor = new Vector3(1, 1, 1); // 反射光 basicEffect.DirectionalLight0.Enabled = true; basicEffect.DirectionalLight0.DiffuseColor = new Vector3(1.0f, 1, 1); basicEffect.DirectionalLight0.Direction = new Vector3(1.0f, 0, 0); basicEffect.LightingEnabled = true;
剪輯 • 剪輯是將位於平頭角椎體之外的基本形狀剔除;位於平頭角椎體之內的基本形狀保留;部份位於平頭角椎體之內的基本形狀切割成保留與剔除兩部份。
投影空間轉換 • 投影空間轉換是將位於平頭角椎體之內的頂點,依照比例,壓縮成為 2 x 2 x 1 的立方體。所以離鏡頭比較遠的頂點的壓縮移動量就會比較大。 Matrix ProjectMatrix = Matrix.CreatePerspectiveFieldOfView( MathHelper.ToRadians(45.0f), // 視角 1.333f, // 寬高比 1.0f, // 近平面 10000.0f); // 遠平面
視口空間轉換 • 視口空間轉換是將2 x 2 x 1 的立方體3D投影到視窗2D矩形畫面上的轉換。
填點處理 • 填點處理的部分主要是處理兩件事情 • 第一是依照程式的設定產生基本形狀 • 第二是以補插方式產生許多像素來將基本形狀填滿。
頂點著色器以及像素著色器 • 早期遊戲3D皆使用固定的處理流程,程式終止要給予要設定的參數即可。 • 近年來由於繪圖卡功能的大幅提昇,繪圖卡已經取代CPU來作頂點處理以及像素處理。 • 我們要寫出頂點處理的小程式與像素處理的小程式來讓繪圖卡的GPU作運算。 • 這種可程式化,能讓GPU處理的小程式叫做頂點著色器(Vertex Shader)以及像素著色器(Pixel Shader)。 • 著色器特效程式目前常用的有微軟的High-Level Shading Language、OpenGL Shading Language和Nvidia公司的Cg語言。
HLSL的基本資料型態 • Bool 布林值 true、false • int 32 位元 整數 • half 16 位元 浮點數 • float 32 位元 浮點數 • double 64 位元 浮點數
HLSL的資料型態 • sampler取樣器 • struct結構 • texture紋理貼圖
取樣器 • 取樣器是用來描述如何從紋理貼圖讀出圖素的方式 texture2D diffuseTexture; sampler2D diffuseSampler = sampler_state { Texture = diffuseTexture; MinFilter = Linear; // 線性取樣 MagFilter = Linear; MipFilter = Linear; AddressU = Wrap; //環繞模式 AddressV = Wrap; AddressW = Wrap; }
頂點著色器的輸入語意 • POSITION頂點座標float4 • COLOR頂點顏色float4 • NORMAL頂點法向量float4 • TEXCOORD頂點的紋理圖UV座標float4 • TANGENT頂點的正切向量float4 • BINORMAL頂點的binormal向量float4 • BLENDINDICES頂點的骨骼混合索引值int4 • BLENDWEIGHT頂點的骨骼混合權重float4
頂點著色器的輸出語意 • POSITION頂點座標float4 • COLOR頂點顏色float4 • TEXCOORD頂點的紋理圖UV座標float4 • FOG頂點霧化值float
像素著色器的輸入語意 • COLOR像素顏色float4 • TEXCOORD像素的紋理圖UV座標float4
像素著色器的輸出語意 • COLOR像素顏色float4 • DEPTH像素的Z軸值(深度值)float
HLSL語言內建函數 • dot向量內積 • cross向量外積 • lerp線性內插 • mul矩陣相承 • normalize向量單位化 • pow指數 • eflect反射向量 • refract折射向量 • saturate將值限制在 0~1 之間 • tex2d2D紋理圖素採樣 • tex3d3D紋理圖素採樣
範例一:使用BasicEffect呈現一個3D模型 • 加入3D模型(宣告及上載) • 在LoadContent將模型內的骨架轉換矩陣拷貝出來 • 在Draw中一一畫出在模型中的每一個網格(mesh)
範例一:使用BasicEffect呈現一個3D模型 protected override void LoadContent() { // TODO: use this.Content to load your game content here myModel = this.Content.Load<Model>(“monster_01”); // 上載 // 3D 模型 // 將myModel模型內的骨轉換矩陣拷貝出來到一個矩陣 transforms = new Matrix[myModel.Bones.Count]; myModel.CopyAbsoluteBoneTransformsTo(transforms); }
範例一:使用BasicEffect呈現一個3D模型 protected override void Draw(GameTime gameTime) { …..foreach (ModelMesh mesh in myModel.Meshes) {// 設定網格的呈現效果 (世界、觀測、投影矩陣) foreach (BasicEffect effect in mesh.Effects) {effect.World = transforms[mesh.ParentBone.Index] * Matrix.CreateScale(0.01f); // 如果模型太大 就縮小一些 effect.World = effect.World* Matrix.CreateRotationY(modelRotation); effect.View = Matrix.CreateLookAt(new Vector3(0.0f, 1.2f, 1.2f), Vector3.Zero, Vector3.Up); effect.Projection = Matrix.CreatePerspectiveFieldOfView( MathHelper.ToRadians(45.0f), 1.333f, 1.0f, 10000.0f);} // 畫出在 模型 中的 某一個 網格 mesh.Draw();} base.Draw(gameTime);}} }
範例一:使用BasicEffect呈現一個3D模型 • /// • protected override void Update(GameTime gameTime) • { // Allows the game to exit • if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) • this.Exit(); • // 旋轉角度 • modelRotation += 0.01f; • base.Update(gameTime); • }
範例二:使用BasicEffect呈現一個3D模型 • /// • protected override void Update(GameTime gameTime) • { // Allows the game to exit • if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) • this.Exit(); • // 旋轉角度 • modelRotation += 0.01f; • base.Update(gameTime); • }