webGL學習隨筆


 這是對threejs初步的一個理解

 

 

 

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

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

 

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不熟悉,所以改寫是存在很大難度的

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

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

具體實現代碼

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

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

    location.reload();//reload頁面
};

 

繪制vierport的代碼

  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中,一個程序對象必須包含一個頂點着色器和一個片元着色器

 

 

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM