webGL學習隨筆

 這是對threejs初步的一個理解

 

 

 

EleVR  elevr是基於webGL的原生API來實現的一個全景播放平臺

首先elevr是根據繪製適口來進行雙屏VR渲染的web

 

if (eye === 0) { // left eye
    webGL.gl.viewport(0, 0, canvas.width / 2, canvas.height);
} else { // right eye
    webGL.gl.viewport(canvas.width / 2, 0, canvas.width / 2, canvas.height);
}編程

 

由於自己對webGLAPI不熟悉,因此改寫是存在很大難度的canvas

經過層層樣式的修改,經過用localstorage本地存儲的方式寫入一個變量值,每次點擊去修改其存儲的值,而後根據存入值的一個狀態來決定走哪一個繪製vierport,最後reload頁面,基本實現單雙屏切換的狀態,跨域

可是用戶體驗確定不是很樂觀,稍後會對webGL進入深層次的一個學習,暫時用此方法替代單雙屏切換的一個狀態瀏覽器

具體實現代碼cookie

var btn = document.getElementById("btn");//獲取點擊按鈕的dom元素
btn.onclick = function(){//註冊一個點擊事件
    if (window.localStorage) {//判斷瀏覽器是否支持localstorage
        if(localStorage.VR && localStorage.VR == "on"){dom

//判斷當前存入的VR是否有值或者值是什麼
            localStorage.VR = "off";
        }else{
            localStorage.VR = "on";
        }
    } else {//若是瀏覽器不支持localstorage,不支持當前存入的一個切換
        alert("sorry,換個瀏覽器試試")
       //setcookie
    }

    location.reload();//reload頁面
};編程語言

 

繪製vierport的代碼ide

  if (window.localStorage) {//判斷瀏覽器是否支持localstorage
      if (localStorage && localStorage.VR == "on") {
          if (eye === 0) { // left eye
              webGL.gl.viewport(0, 0, canvas.width / 2, canvas.height);
          } else { // right eye
              webGL.gl.viewport(canvas.width / 2, 0, canvas.width / 2, canvas.height);
          }
      }
      else {
          if (eye === 0) { // left eye
              webGL.gl.viewport(0, 0, canvas.width, canvas.height);
          } else { // right eye
              webGL.gl.viewport(0, 0, canvas.width, canvas.height);
          }
      }
  }else{
      if (eye === 0) { // left eye
          webGL.gl.viewport(0, 0, canvas.width / 2, canvas.height);
      } else { // right eye
          webGL.gl.viewport(canvas.width / 2, 0, canvas.width / 2, canvas.height);
      }
  }
    // Draw
    webGL.gl.bindBuffer(webGL.gl.ELEMENT_ARRAY_BUFFER, verticesIndexBuffer);
    webGL.gl.drawElements(webGL.gl.TRIANGLES, 6, webGL.gl.UNSIGNED_SHORT, 0);
},函數

 

 

Threejs

Threejs的具體切換原理是基於camare來切換繪製渲染,

 

 

 

 

webGL

webGL的紋理對象

紋理映射的四個步驟:

 1.準備好映射的圖像   能夠是任意圖片png  jpg

 2.爲幾何圖形配置紋理映射方式

   1》紋理座標

     

紋理座標值與圖像尺寸無關,其座標值是通用的

 

 

 

 

 3.加載紋理圖像,對其進行一些配置,方便在webGL中使用它

 4.在片元着色器中將相應的紋素從紋理中抽取出來,並將紋素的顏色賦給片元

 

var VSHADER_SOURCE =
  'attribute vec4 a_Position;\n' +
  'attribute vec2 a_TexCoord;\n' +
  'varying vec2 v_TexCoord;\n' +
  'void main() {\n' +
  '  gl_Position = a_Position;\n' +
  '  v_TexCoord = a_TexCoord;\n' +
  '}\n';

// Fragment shader program
var FSHADER_SOURCE =
  '#ifdef GL_ES\n' +
  'precision mediump float;\n' +
  '#endif\n' +
  'uniform sampler2D u_Sampler;\n' +
  'varying vec2 v_TexCoord;\n' +
  'void main() {\n' +
  '  gl_FragColor = texture2D(u_Sampler, v_TexCoord);\n' +
  '}\n';

function main() {   //主入口函數
  // Retrieve <canvas> element
  var canvas = document.getElementById('webgl');

  // Get the rendering context for WebGL
  var gl = getWebGLContext(canvas);
  if (!gl) {
    console.log('Failed to get the rendering context for WebGL');
    return;
  }

  // Initialize shaders
  if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
    console.log('Failed to intialize shaders.');
    return;
  }

  // S設置頂點信息
  var n = initVertexBuffers(gl);
  if (n < 0) {
    console.log('Failed to set the vertex information');
    return;
  }

  // Specify the color for clearing <canvas>
  gl.clearColor(0.0, 0.0, 0.0, 1.0);

  // 配置紋理
  if (!initTextures(gl, n)) {
    console.log('Failed to intialize the texture.');
    return;
  }
}

function initVertexBuffers(gl) {
  var verticesTexCoords = new Float32Array([
    // 頂點座標  紋理座標
    -0.5,  0.5,   0.0, 1.0,
    -0.5, -0.5,   0.0, 0.0,
     0.5,  0.5,   1.0, 1.0,
     0.5, -0.5,   1.0, 0.0,
  ]);
  var n = 4; // 頂點的數量
  // 建立緩衝區對象
  var vertexTexCoordBuffer = gl.createBuffer();
  if (!vertexTexCoordBuffer) {
    console.log('Failed to create the buffer object');
    return -1;
  }

  // 將頂點座標和紋理座標寫入緩衝區對象
  gl.bindBuffer(gl.ARRAY_BUFFER, vertexTexCoordBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, verticesTexCoords, gl.STATIC_DRAW);

  var FSIZE = verticesTexCoords.BYTES_PER_ELEMENT;
  //Get the storage location of a_Position, assign and enable buffer
  var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
  if (a_Position < 0) {
    console.log('Failed to get the storage location of a_Position');
    return -1;
  }
  gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE * 4, 0);
  gl.enableVertexAttribArray(a_Position);  // Enable the assignment of the buffer object

  // 將紋理座標分配給a_TexCoord 而且開啓它
  var a_TexCoord = gl.getAttribLocation(gl.program, 'a_TexCoord');
  if (a_TexCoord < 0) {
    console.log('Failed to get the storage location of a_TexCoord');
    return -1;
  }
  // Assign the buffer object to a_TexCoord variable
  gl.vertexAttribPointer(a_TexCoord, 2, gl.FLOAT, false, FSIZE * 4, FSIZE * 2);
  gl.enableVertexAttribArray(a_TexCoord);  // Enable the assignment of the buffer object

  return n;
}

function initTextures(gl, n) {
  var texture = gl.createTexture();   // 建立紋理對象
  if (!texture) {
    console.log('Failed to create the texture object');
    return false;
  }

  // 獲取u_Sampler的存儲位置
  var u_Sampler = gl.getUniformLocation(gl.program, 'u_Sampler');
  if (!u_Sampler) {
    console.log('Failed to get the storage location of u_Sampler');
    return false;
  }
  var image = new Image();  // 建立一個image對象
  if (!image) {
    console.log('Failed to create the image object');
    return false;
  }
  // 註冊圖像加載事件的相應函數
  image.onload = function(){ loadTexture(gl, n, texture, u_Sampler, image); };
  // 把路徑添加到src讓瀏覽器加載
  image.src = '../resources/sky.jpg';

  return true;
}

function loadTexture(gl, n, texture, u_Sampler, image) {
  gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1); // 對紋理圖像進行Y軸反轉,是由於webGL的座標跟圖像的y軸正好是相反的,因此須要y軸反轉,或者在着色器中進行紋理的t軸反轉


  // 開啓0號紋理單元
  gl.activeTexture(gl.TEXTURE0);


  // 向target綁定紋理對象
  gl.bindTexture(gl.TEXTURE_2D, texture);

  // 配置紋理參數
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  // 配置紋理圖像
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image);
  
  // 將0號紋理傳遞給着色器
  gl.uniform1i(u_Sampler, 0);
  
  gl.clear(gl.COLOR_BUFFER_BIT);   // Clear <canvas>

  gl.drawArrays(gl.TRIANGLE_STRIP, 0, n); // D繪製矩形
}

 

 

1.頂點着色器中接收頂點的紋理座標,光柵化後傳遞給片元着色器

2.片元着色器根據片元的紋理座標,從紋理圖像中抽取紋素顏色,賦給當前片元

3.設置頂點的紋理座標initVertexBuffers()

4.準備待加載的紋理圖像,令瀏覽器讀取它initTextures()

5.監聽紋理圖像的加載事件,一旦加載完成,就在webGL系統中使用紋理loadTexture()

 

Gl_TEXTURE0-------GL_TEXTURE7八個紋理單元都與gl_TEXTURE_2D相關聯

 

Gl_deleteTexture  刪除一個紋理對象

LoadTexture(gl,n,texture,u_Sampler,image),loadtexture有五個參數,第一個參數爲繪製上下文,第二個爲繪製的頂點的個數,第三個爲以前建立的紋理對象,第四個是從uniform中取得的變量u_Sampler的存儲位置,第五個是咱們須要渲染的圖片

webGL不容許跨域的紋理圖像

從瀏覽器加載圖像到loadTexture函數調用圖像

 

 

Gl.pixelStorei()方法的規範

 

Gl.activeTexture(gl.texTure0)激活紋理單元,參數爲八個紋理單元

 

在對紋理對象進行操做以前,還須要綁定紋理單元,跟綁定緩衝區對象很相似

開啓紋理對象並綁定紋理到target

Gl.bindTexTure(gl.texTure2D,texTure);綁定二維紋理對象

Gl.bindTexTure(gl.texTure_CUBE_MAP,texTure);綁定立方體紋理對象

 

 

注意:在webGL中沒辦法直接操控紋理對象,只能把紋理對象綁定到紋理單元上,而後經過操控紋理單元來操控紋理對象;

配置紋理對象的參數gl.texParameteri()

 

經過paname能夠指定四個紋理參數

放大方法:gl.texTure_MAG_FILTER 當紋理的繪製自己比紋理更大時

縮小方法:gl.texTure_MIN_FILTER  當繪製的紋理比紋理更小時

水平填充方法:gl.texTure_wrap_s

垂直填充方法:gl.texTure_wrap_t

其圖示以下:

 

 

 

 

將紋理圖像分配給紋理對象gl.texImage2D()

 

 

若是爲png格式的圖片就用gl.rgba  jpg之類的就用gl.rgb

 

 

GLSL ES 編寫着色器的編程語言

必須有且僅有一個main函數作爲主函數

Void聲明一個函數沒有返回值

支持整型數和浮點數,支持布爾類型,不支持字符串

變量命名規範和js類似,如下是關鍵字

 

GLSL ES 是一種強類型語言,必須聲明數據類型

float()將整形轉換爲浮點數

Int()轉換爲整型數

Booln()轉換爲布爾值,0false

 

Mat4矩陣函數

Vec4

 

Attribute  頂點着色器裏聲明的全局變量,

Varying   從頂點着色器向片元着色器傳輸數據,也是一個全局變量

Uniform

Const  表示聲明一個變量且這個變量是不可改變的,而且不能從新賦值,不然會致使報錯

 

 

 

片元着色器中要對float類型的精度作限定,否則就會編譯報錯

 

指令必須在最頂部

 

SetlokAt

 

GLSL 變量的使用

var VSHADER_SOURCE =  'attribute vec4 a_Position;\n' +  'void main() {\n' +  '  gl_Position = a_Position;\n' +  '  gl_PointSize = 10.0;\n' +  '}\n';

首先看頂點着色器,咱們聲明瞭a_Position變量,接下來咱們經過下面的方法進行賦值。

var a_Position = gl.getAttribLocation(gl.program, 'a_Position');

gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, 0, 0);

gl.enableVertexAttribArray(a_Position);

getAttribLocationprogram, name

js中,咱們首先經過getAttribLocation()獲取到變量 a_Position 在渲染器中的地址。 該方法接收兩個變量

  • program project對象
  • name 變量名稱

接下來咱們經過vertexAttribPointer()方法,指定了如何處理渲染器中的值。

vertexAttribPointer(index, size, type, normalized, stride, offset);

比較複雜的一個方法

  • index 綁定在gl.ARRAY_BUFFER中的目標索引,比較難理解,可是一般狀況下咱們能夠經過getAttribLocation來獲取這個值。
  • size 每一個屬性的長度 [1234(default)]
  • type 類型 指定數據類型 咱們有兩個選擇,[gl.FLOAT (default)|gl.FIXED]
  • normalized 是否初始化傳入的數據 [gl.FALSE|gl.TRUE]
  • stride 每組數據的個數,[0-255]
  • offset 這一組中的數據起始位置(從0開始)

接下來啓用 enableVertexAttribArray()

enableVertexAttribArray(index);

  • index vertexAttribPointer中的index

開啓深度檢測肯定是否將其畫出來,就是所謂的物體遮擋面是否顯示 gl.enable(gl.DEPTH_TEST)開啓隱藏面消除功能,固然還有多邊形偏移的功能

在繪製以前,清除深度緩衝區gl.clear(gl_DEPTH_BUFFER_BIT);一般時繪製每一幀以前

深度緩衝區通常是用來存儲深度信息的,深度通常都是Z軸方向,因此又稱Z緩衝區

Gl.desable()關閉某種功能

 

A_Normal   

建立着色器對象

 

着色器對象管理一個頂點着色器或一個片元着色器,每個着色器都有一個着色器對象

程序對象是管理着色器對象的容器,webGL中,一個程序對象必須包含一個頂點着色器和一個片元着色器

 

 

程序對象一旦被建立,就須要附上兩個着色器對象

相關文章
相關標籤/搜索