這是對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);
}
因為本身對webGL的API不熟悉,所以改寫是存在很大難度的
通過層層樣式的修改,通過用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()轉換為布爾值,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);
getAttribLocation(program, name)
在js中,我們首先通過getAttribLocation()獲取到變量 a_Position 在渲染器中的地址。 該方法接收兩個變量
- program project對象
- name 變量名稱
接下來我們通過vertexAttribPointer()方法,指定了如何處理渲染器中的值。
vertexAttribPointer(index, size, type, normalized, stride, offset);
比較復雜的一個方法
- index 綁定在gl.ARRAY_BUFFER中的目標索引,比較難理解,但是通常情況下我們可以通過getAttribLocation來獲取這個值。
- size 每個屬性的長度 [1,2,3,4(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中,一個程序對象必須包含一個頂點着色器和一個片元着色器
程序對象一旦被創建,就需要附上兩個着色器對象