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'