首先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中,一个程序对象必须包含一个顶点着色器和一个片元着色器
程序对象一旦被建立,就须要附上两个着色器对象