2018年2月13日 星期二

從D3D10到D3D11

從D3D10到D3D11
前言
  最近要將原本的D3D10的引擎整合D3D11,這邊把一些差異的部分記錄下來。

內容
  首先D3D10的Device在D3D11被分裂成Device與DeviceContext,D3D11的Device主要負責製造資源,而DeviceContext負責執行繪圖的命令。這裡要注意D3D11是可以向下整合的!剩至可以相容D3D10,而原本的D3D10在10.0與10.1差異只有用不同的Create()去區分。
  在DXGISwapChain的部分,要注意11.0的作法與D3D10差不多,但11.1的作法就不一樣了,可以參考D3D11的教學範例,參考教學2的做法即可。
  在shader的方面,D3D11多了Hull shader與Domain shader,ConstatBuffer、Texture與SamplerState的設置介面和舊有的Shader是一樣的,但D3D11的SetShader()的介面多了2個參數,目前還不知具體的作用,設成空的是可行的。
  編譯shader的部分只要把版本調成"5"就可以了,至少目前沒發生問題。
  RasterizerState、BlendState與DepthStencilState基本上和D3D10的做法一樣,但若是11.1的話,要注意BlendState在Create的時候,D3D11_BLEND_DESC1的Rendertarget裡會多一個"RenderTargetWriteMask",這個參數的預設值請設成"D3D11_COLOR_WRITE_ENABLE_ALL",就算是把Blend設為關閉也要設置這個變數,不可以設成"0",如果設成"0"會看不到任何繪製結果!一定要注意。

後記
如果只是單純用D3D11模擬D3D10的繪製方法的話,整體來說還算是簡單,但看了一下Device的介面裡多可一些新的資源可以Create,那些新東西以後有機會再來研究研究。
參考資料
ID3D11Device interface
D3D11的教學範例

2018年2月5日 星期一

關於矩陣的乘法

關於矩陣的乘法

前言

  以前總是這樣乘矩陣,ModelMatrix*ViewMatrix*ProjectionMartix,但不知什麼時候開始出現另一種乘法,ProjectionMartix*ViewMatrix*ModelMatrix,雖然早就知道矩陣乘法不具有交換律,但卻都沒有去好好確認過為什麼會有這樣的差異。最近發生在C++的引擎使用第一種方法,但webgl的引擎卻是使用第二種方法!剛好有這機會我就來探究原因。


內容

  首先先把webgl的引擎用第一種方法乘,然後列印出來跟C++來比對,發現內容遽然不一樣!
後來發現是兩邊的矩陣乘法的做法不一樣,C++的乘法來自一般數學課程對矩陣乘法的定義,webgl的引擎的乘法來自three.js的矩陣乘法,再來是我觀察unity3d也是使用第二種乘法,這時的我才發現原來矩陣的乘法有2種,一種是row*col另一種則是col*row。


後記

  這兩種乘法的差異不只會引響引擎的乘法而已,想想看shader裡面的矩陣乘法也會有影響!所以決定好其中一種,並記住乘法是屬於哪一種的,這樣轉code的時候就不會被到底師第一種乘還是第二種乘所迷惑了!
 

2018年1月29日 星期一

關於瀏覽器的鍵盤事件偵測

關於瀏覽器的鍵盤事件偵測

前言

  最近在寫瀏覽器的鍵盤偵測,發現瀏覽器偵測的行為有點不直覺,而且有分"keydown"與"keypress",在此做個紀錄。

內容

  首先是當按鍵壓住的時候,不論是"keydown"或"keypress"都會不斷地送事件,而且還發現偵測的時間相當不穩定!以下為測試程式碼:
var preTime=Date.now();
window.addEventListener("keydown",function(evt){
  switch(evt.keyCode){
    case 75:
      console.log("DelTime:"+(Date.now()-preTime) );
      preTime=Date.now();
      break;
  }
},true);

在測試程式碼當壓住"K"這個按鍵時,會發現事件不斷被啟動,並且可以看到每次的偵測的時間間隔,用chrome測試,大部分時間間隔是33,但還是會看到19或47的間隔時間。再來就是"keydown"與"keypress"的差異,這兩者差異在"keydown"事件觸發時所使用的"keyCode"是固定的,不會受到"caps lock"按鍵引響,例如測試程式所偵測的"keyCode"為75(ASCII的"K"),不論"caps lock"是否啟動,"keyCode"都是同一個,這點"keyup"也一樣,但"keypress"的狀況就不一樣,"keypress"的"keyCode"會受到"caps lock"的引響,可以利用以下測試程式碼:
window.addEventListener("keypress",function(evt){
  switch(evt.keyCode){
    case 75:
      console.log("Press K" );
      break;
    case 107:
      console.log("Press k" );
      break;
  }
},true);

在測試時按下"K"鍵並搭配"caps lock"後就可以看到差別了。

參考資料

KeyboardEvent keyCode Property

2018年1月22日 星期一

關於UNPACK_FLIP_Y_WEBGL的作用

關於UNPACK_FLIP_Y_WEBGL的作用

前言

  在webgl創建texture時會有一個特別的參數,就是"UNPACK_FLIP_Y_WEBGL",本以為設了這個參數以後,就能順利的把ST座標改成UV座標,但事情並沒有想像中的美好。


內容

  UNPACK_FLIP_Y_WEBGL確實可以做出像是把ST座標轉成UV座標的效果,但這個方法有缺陷,就是在render to texture的時候,就算在那張texture創建時設定 UNPACK_FLIP_Y_WEBGL,結果該張texture用UV座標來顯示時會變成上下顛倒的狀況,也就是說render to texture時是強制使用ST座標。後來查了webgl的規格,裡面有如下內容
UNPACK_FLIP_Y_WEBGL of type boolean
If set, then during any subsequent calls to texImage2D or texSubImage2D, the source data is flipped along the vertical axis, so that conceptually the last row is the first one transferred. The initial value is false. Any non-zero value is interpreted as true.

意思是說只對texImage2D或texSubImage2D的來源資料做上下顛倒的動作,所以它並不是在任何時候都有效!


後記

  如果想在webgl使用UV座標的話,不能只靠UNPACK_FLIP_Y_WEBGL,在render to texture時要動手腳(在vertex shader轉換座標),不然也可以在mesh輸入時就做轉換,這樣連設UNPACK_FLIP_Y_WEBGL都免了。

參考資料

WebGL Specification

2018年1月15日 星期一

將canvas2d的結果輸出到webgl的texture

將canvas2d的結果輸出到webgl的texture

前言

  最近在製作用canvas2d畫字型,然後轉到texture的功能,為了怕忘記,這邊做個紀錄。

內容

  範例程式碼如下
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var canvasData = ctx.getImageData(0, 0, canvas.width, canvas.height);
//webgl
var texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, canvas.width, canvas.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, Uint8Array.from(rawData.data) );
gl.bindTexture(gl.TEXTURE_2D, null);

這裡要注意canvasData所輸出的型別是"Uint8ClampedArray", 但texImage2D能接受的是"Uint8Array",所以要經過Uint8Array.from()來轉換!跟上一次做的將canvas的結果輸出到image不一樣的是不需要經過onload,直接執行完資料就馬上生效,不需要等callback!


參考資料

CanvasRenderingContext2D.getImageData()

2018年1月8日 星期一

將canvas的結果輸出到image

將canvas的結果輸出到image

前言

  最近要做將canvas變成webgl的texture,需要將canvas的結果輸出到image,後來想想,以前做過將canvas的畫面照下來的功能,但是忘記怎麼做的,所以我又重新學了一次並把它紀錄下來。


內容

  範例程式碼如下
html 的部分
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>canvas to image</title>
</head>
<body>
  
<script src="https://code.jquery.com/jquery-3.0.0.js"></script>

  <div id="subImage">
  </div>
</body>
</html>

javascript的部分
var newCanvas = document.createElement("canvas");  
newCanvas.width = 256;
newCanvas.height= 256;
//
var canvasEle = newCanvas;
var ctx = canvasEle.getContext("2d");
ctx.fillStyle = "rgb(255,0,0)";
ctx.fillRect (0, 0, 256, 256);
var urlData = canvasEle.toDataURL();
var newImage = new Image();
newImage.onload = function(){
  $("#subImage").get(0).appendChild(newImage);
}
newImage.src = urlData;

值得注意的是範例的canvas並不需要加入DOM裡面就可以做繪製的動作,再來是canvasEle.toDataURL(),這個method會將目前canvas的結果編成"圖片資料",然後過程和一般的URL圖片一樣需要設置onload,雖然不需要網路連線,但還是需要onload,這點一定要注意。

後記

  這個功能本以為是個很麻煩的功能,但做起來發現還滿簡單的。由於這個功能是從canvas輸出,而不是從"context",所以webgl的canvas也可以做一樣的事。


參考資料

HTMLCanvasElement.toDataURL()

2018年1月3日 星期三

webgl使用texImage2D時的限制

webgl使用texImage2D時的限制

前言:

  以前學webgl時都直接把檔案丟到AppServ裡面執行,一直已來都沒問題,但最近在寫webgl時,想說開server有點麻煩,所以就直接開本地檔案直接測試,剛開始都沒問題,直到使用texImage2D後才發現chrome會跳error!


問題:

  如果使用chrome在本地開啟網頁,然後載入Image,再經由texImage2D寫入資料時,會發生錯誤,如下圖
texImage2D報錯
圖為使用Mozilla的webgl教學範例,當在本地開啟時就會報錯,把錯誤訊息拿去google的話,會得到在Image的crossOrigin填入Anonymous,如下程式碼


  image.crossOrigin = 'Anonymous';

填完後問題並不能解決!另外,我也懷疑了是否因為圖檔來自本地端,所以造成這個問題,但就算把圖檔的位址改成非本地,狀況也是一樣的,這問題目前只發生在chrome!

解決:

  直接開一個server,再把檔案都放到server後,就沒問題了。

後記:

  這個狀況目前只發生在chrome,同一個狀況並不會發生在firefox!這問題很奇怪,因為image的載入是沒問題的,寫到DOM裡會正常顯示,但將image送到texImage2D就一定報錯,也許是chrome對本地使用的特別限制又或是bug,不管是哪一個,開server測試,這樣就沒煩惱了。

參考資料:

Uncaught SecurityError: Failed to execute 'texImage2D' on 'WebGLRenderingContext'