20 WebGL使用纹理贴图
来源:互联网 发布:php微信三级分销 编辑:程序博客网 时间:2024/06/13 23:12
WebGL中纹理的限制
WebGL中的纹理需要注意一点,所使用的图片数据的大小必须是2的阶乘,横竖的像素长度大小必须是32x32,128x128等2的阶乘的形式。当然,做一些处理的话,不是2的阶乘的图片数据也是可以用的,但是基本上作为纹理使用的图像数据的大小必须是2的阶乘。
另外,看一下普通的网页就能感觉到,网页上的图片数据的读取是要花一点时间的,在进行纹理转换的话,必须是在图片读取完之后才行,这里需要做一些特殊的处理,如果对JavaScript不太熟悉的话可能会无从下手,这个后面会说。
为什么需要纹理?
因为不可能所有的图像都靠代码生成,那是在浪费生命。
这一部分由于WebGL的安全机制,必须开启服务获取,或者允许浏览器访问本地文件,要不然WebGL无法获取文件。
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Title</title> <style> body { margin: 0; text-align: center; } #canvas { margin: 0; } </style></head><body onload="main()"> <canvas id="canvas" height="800" width="800"></canvas></body><script src="lib/webgl-utils.js"></script><script src="lib/webgl-debug.js"></script><script src="lib/cuon-utils.js"></script><script src="lib/cuon-matrix.js"></script><script> /*第一部分顶点着色器接收顶点的纹理坐标,传递给片元着色器*/ 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"; var FSHADER_SOURCE = "" + "precision mediump float;\n" +// "uniform sampler2D u_Sampler;\n" +// "varying vec2 v_TexCoord;\n" +// "void main(){\n" + " gl_FragColor = texture2D(u_Sampler,v_TexCoord);\n" +// "}\n"; /*第二部分 main()方法 初始化着色器,设置顶点信息,调用配置纹理方法*/ function main() { var canvas = document.getElementById("canvas"); var gl = getWebGLContext(canvas); if(!gl){ console.log("你的电脑不支持WebGL!"); return; } if(!initShaders(gl,VSHADER_SOURCE,FSHADER_SOURCE)){ console.log("初始化着色器失败!"); return; } //设置顶点的相关信息 var n = initVertexBuffers(gl); if(n < 0){ console.log("无法获取到点的数据"); return; } //配置纹理 if(!initTextures(gl,n)){ console.log("无法配置纹理"); return; } } /*第三部分 initVertexBuffers() 设置顶点坐标和纹理坐标 调用initTextures()进行下一步处理*/ function initVertexBuffers(gl) { var verticesSizes = 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 vertexSizeBuffer = gl.createBuffer(); if(!vertexSizeBuffer){ console.log("无法创建缓冲区"); return -1; } gl.bindBuffer(gl.ARRAY_BUFFER,vertexSizeBuffer); gl.bufferData(gl.ARRAY_BUFFER,verticesSizes,gl.STATIC_DRAW); var a_Position = gl.getAttribLocation(gl.program,"a_Position"); if(a_Position < 0){ console.log("无法获取到存储位置"); return; } //获取数组一个值所占的字节数 var fsize = verticesSizes.BYTES_PER_ELEMENT; //将顶点坐标的位置赋值 gl.vertexAttribPointer(a_Position,2,gl.FLOAT,false,fsize*4,0); gl.enableVertexAttribArray(a_Position); //将顶点的纹理坐标分配给a_TexCoord并开启它 var a_TexCoord = gl.getAttribLocation(gl.program,"a_TexCoord"); if(a_TexCoord < 0){ console.log("无法获取到存储位置"); return; } //将纹理坐标赋值 gl.vertexAttribPointer(a_TexCoord,2,gl.FLOAT,false,fsize*4,fsize*2); gl.enableVertexAttribArray(a_TexCoord); return n; } /*第四部分 initTextures() 创建纹理对象 并调用纹理绘制方法*/ function initTextures(gl,n) { var texture = gl.createTexture();//创建纹理对象 if(!texture){ console.log("无法创建纹理对象"); return; } //获取u_Sampler的存储位置 var u_Sampler = gl.getUniformLocation(gl.program,"u_Sampler"); if(u_Sampler < 0){ console.log("无法获取变量的存储位置"); return; } //创建Image对象,并绑定加载完成事件 var image = new Image(); image.onload = function () { loadTexture(gl,n,texture,u_Sampler,image); }; image.src = "./resources/sky.jpg"; return true; } /*第五部分 设置纹理相关信息供WebGL使用,并进行绘制*/ function loadTexture(gl,n,texture,u_Sampler,image) { //对纹理图像进行y轴反转 gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,1); //开启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.clearColor(0.0,0.0,0.0,1.0); gl.clear(gl.COLOR_BUFFER_BIT); gl.drawArrays(gl.TRIANGLE_STRIP,0,n); }</script></html>
这次代码共分成了五大部分:
第一部分增加上了varying变量。
第二部分初始化WebGL。
第三部分绘制顶点信息。
第四部分主要是创建了纹理对象,和通过浏览器加载图片并且触发设置纹理的相关信息的方法。
重要的就是第五部分,在之前没有接触过的纹理相关的信息设置api:
首先要明白纹理的坐标问题:
为了将纹理坐标和广泛的使用的xy坐标区分开来,WebGL使用s和t命名纹理坐标,如图。
我们的任务是什么呢?
就是将图片映射到WebGL上面
我们在initVertexBuffers()里面的数据内添加了纹理的坐标,来达到上图的匹配。
首先需要创建gl.createTexture()了纹理对象:
对应的还有gl.deleteTexture()来删除纹理对象
如果删除一个已经被删除的纹理对象时,不会报错也不会产生任何影响。
在等待图片被浏览器加载成功后,就会调用loadTexture()方法进行设置WebGL的相关纹理信息。
第一个方法gl.pixelStorei()是对图像进行Y轴反转,才能正确的将图像映射到图形上。
然后激活纹理单元gl.activeTexture(),每个纹理单元有一个单元编号来管理纹理图像。即使你的程序只需要一张纹理图像,也得为其指定一个纹理单元。
然后需要绑定纹理对象gl.bindTexture(),这一点与缓冲区很像,写入数据之前需要绑定。
WebGL支持两种类型的纹理:
案例使用的二维图像,所以传入了gl.TEXTURE_2D
纹理对象绑定成功后,就可以进行纹理对象的参数进行配置gl.texParameteri():
参数设置完成以后,就需要将纹理图像分配给纹理对象gl.texImage2D():
这里的L(流明)表示我们感知到的物体表面的亮度。通常使用物体表面红、绿、蓝颜色分量值得加权平均来计算流明。
一旦将纹理图像传入WebGL系统,就必须将其传入片元着色器并映射到图形的表面上去。
在39行,我们使用uniform声明了一个texture2D类型的u_Sampler变量来表示纹理,因为纹理图像不会随着片元变化。
而表示纹理对象的unifrom变量必须声明为一种特殊的、专用于纹理对象的数据类型。如图:
在代码的156行,我们使用了gl.uniform1i(),指定纹理单元编号将纹理对象传递给u_Sampler,由于案例的纹理对象被绑定到了gl.TEXTURE0上面,第二个参数为0。
由于我们是使用的varying变量从顶点着色器内将变量传到片元着色器里面,片元着色器和顶点着色器内的同名、同类型的varying变量可以用来在两者之间传输数据。顶点之间的片元的纹理坐标会在光栅化的过程中内插出来,所以在片元着色器中,我们使用的是内插后的纹理坐标。
在片元着色器中,第四十二行的代码使用了GLSL ES内置函数texture2D()来抽取纹素颜色,然后把从纹理上获取到的颜色,逐片元的赋值到图形上面。
这个函数时内置的,留意一下其参数和返回值
- 20 WebGL使用纹理贴图
- WebGL自学课程(5):使用一张贴图纹理绘制地球
- 八、WebGL入门,纹理贴图
- WEBGL学习【五】纹理贴图
- WebGL中纹理贴图过滤器(filter)参数设置详解
- 使用纹理贴图的步骤
- WebGL自学课程(14):WebGL使用Mipmap纹理
- 22 WebGL使用多幅纹理
- 纹理贴图
- 纹理贴图
- 纹理贴图
- 纹理贴图
- 纹理贴图
- 纹理贴图
- 纹理贴图
- 纹理贴图
- Qt中使用OpenGL的纹理贴图
- 57 WebGL纹理贴图报错texture bound to texture unit 0 is not renderable.
- oj 1956: C语言实验——求阶乘(循环结构)
- Redis 3.2.3 源码安装(centos6.8)
- 数据库 shell脚本笔记
- 2017中国SaaS产业大会 CSIC即将于7月在沪召开!
- UltraEdit正则表达式文本替换
- 20 WebGL使用纹理贴图
- C# 字符串常用的方法
- oracle 建立表空间
- 多个版本的Python同时连接Oracle和安装cx_Oracle问题解决
- Android解析XML之DOM
- oracle中extract()函数
- SP324099: 无法完成操作--VS2015社区版无法登陆
- Python的__init__.py 文件
- JSON处理Hibernate实体类net.sf.json.JSONException: There is a cycle in the hierarchy异常