首先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);
}編程
由於自己對webGL的API不熟悉,因此改寫是存在很大難度的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的具體切換原理是基於camare來切換繪製渲染,
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中沒辦法直接操控紋理對象,只能把紋理對象綁定到紋理單元上,而後經過操控紋理單元來操控紋理對象;
經過paname能夠指定四個紋理參數
放大方法:gl.texTure_MAG_FILTER 當紋理的繪製自己比紋理更大時
縮小方法:gl.texTure_MIN_FILTER 當繪製的紋理比紋理更小時
水平填充方法:gl.texTure_wrap_s
垂直填充方法:gl.texTure_wrap_t
其圖示以下:
若是爲png格式的圖片就用gl.rgba jpg之類的就用gl.rgb
必須有且僅有一個main函數作爲主函數
Void聲明一個函數沒有返回值
支持整型數和浮點數,支持布爾類型,不支持字符串
變量命名規範和js類似,如下是關鍵字
GLSL ES 是一種強類型語言,必須聲明數據類型
float()將整形轉換爲浮點數
Int()轉換爲整型數
Booln()轉換爲布爾值,0爲false
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);
在js中,咱們首先經過getAttribLocation()獲取到變量 a_Position 在渲染器中的地址。 該方法接收兩個變量
接下來咱們經過vertexAttribPointer()方法,指定了如何處理渲染器中的值。
比較複雜的一個方法
接下來啓用 enableVertexAttribArray()
開啓深度檢測肯定是否將其畫出來,就是所謂的物體遮擋面是否顯示 gl.enable(gl.DEPTH_TEST)開啓隱藏面消除功能,固然還有多邊形偏移的功能
在繪製以前,清除深度緩衝區gl.clear(gl_DEPTH_BUFFER_BIT);一般時繪製每一幀以前
深度緩衝區通常是用來存儲深度信息的,深度通常都是Z軸方向,因此又稱Z緩衝區
Gl.desable()關閉某種功能
A_Normal
建立着色器對象
着色器對象管理一個頂點着色器或一個片元着色器,每個着色器都有一個着色器對象
程序對象是管理着色器對象的容器,webGL中,一個程序對象必須包含一個頂點着色器和一個片元着色器
程序對象一旦被建立,就須要附上兩個着色器對象