经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 软件/图像 » WebGL » 查看文章
WebGL简易教程(十一):纹理
来源:cnblogs  作者:charlee44  时间:2019/10/16 12:49:47  对本文有异议

1. 概述

在之前的之前的教程《WebGL简易教程(九):综合实例:地形的绘制》中,绘制了一个带颜色的地形场景。地形的颜色是根据高程赋予的RGB值,通过不同的颜色来表示地形的起伏,这是表达地形渲染的一种方式。除此之外,还可以将拍摄得到的数字影像,贴到地形上面,得到更逼真的地形效果。这就要用到我们这一章的新知识——纹理了。

这里用到的纹理图像,是一张从GoogleEarth上下载的卫星影像DOM.tif,其范围正好覆盖地形数据。为了方便使用,特意将其转换为JPG格式的影像:tex.jpg。并放到与HTML和JS同目录下。用图像查看软件打开图像的显示效果为:
image

注意,在大部分浏览器(如chrome)中,基于安全策略是不允许访问本地文件的。WebGL的纹理需要用到本地的图像,所以需要将浏览器设置成支持跨域访问或者建立服务器在域内使用。

2. 实例

基于《WebGL简易教程(九):综合实例:地形的绘制》中的JS代码进行改进:

  1. // 顶点着色器程序
  2. var VSHADER_SOURCE =
  3. 'attribute vec4 a_Position;\n' + //位置
  4. 'attribute vec4 a_Color;\n' + //颜色
  5. 'uniform mat4 u_MvpMatrix;\n' +
  6. 'varying vec4 v_Color;\n' +
  7. 'varying vec4 v_position;\n' +
  8. 'void main() {\n' +
  9. ' v_position = a_Position;\n' +
  10. ' gl_Position = u_MvpMatrix * a_Position;\n' + // 设置顶点坐标
  11. ' v_Color = a_Color;\n' +
  12. '}\n';
  13. // 片元着色器程序
  14. var FSHADER_SOURCE =
  15. 'precision mediump float;\n' +
  16. 'uniform vec2 u_RangeX;\n' + //X方向范围
  17. 'uniform vec2 u_RangeY;\n' + //Y方向范围
  18. 'uniform sampler2D u_Sampler;\n' +
  19. 'varying vec4 v_Color;\n' +
  20. 'varying vec4 v_position;\n' +
  21. 'void main() {\n' +
  22. ' vec2 v_TexCoord = vec2((v_position.x-u_RangeX[0]) / (u_RangeX[1]-u_RangeX[0]), 1.0-(v_position.y-u_RangeY[0]) / (u_RangeY[1]-u_RangeY[0]));\n' +
  23. ' gl_FragColor = texture2D(u_Sampler, v_TexCoord);\n' +
  24. '}\n';
  25. //定义一个矩形体:混合构造函数原型模式
  26. function Cuboid(minX, maxX, minY, maxY, minZ, maxZ) {
  27. this.minX = minX;
  28. this.maxX = maxX;
  29. this.minY = minY;
  30. this.maxY = maxY;
  31. this.minZ = minZ;
  32. this.maxZ = maxZ;
  33. }
  34. Cuboid.prototype = {
  35. constructor: Cuboid,
  36. CenterX: function () {
  37. return (this.minX + this.maxX) / 2.0;
  38. },
  39. CenterY: function () {
  40. return (this.minY + this.maxY) / 2.0;
  41. },
  42. CenterZ: function () {
  43. return (this.minZ + this.maxZ) / 2.0;
  44. },
  45. LengthX: function () {
  46. return (this.maxX - this.minX);
  47. },
  48. LengthY: function () {
  49. return (this.maxY - this.minY);
  50. }
  51. }
  52. //定义DEM
  53. function Terrain() { }
  54. Terrain.prototype = {
  55. constructor: Terrain,
  56. setWH: function (col, row) {
  57. this.col = col;
  58. this.row = row;
  59. }
  60. }
  61. var currentAngle = [0.0, 0.0]; // 绕X轴Y轴的旋转角度 ([x-axis, y-axis])
  62. var curScale = 1.0; //当前的缩放比例
  63. var initTexSuccess = false; //纹理图像是否加载完成
  64. function main() {
  65. var demFile = document.getElementById('demFile');
  66. if (!demFile) {
  67. console.log("Failed to get demFile element!");
  68. return;
  69. }
  70. //加载文件后的事件
  71. demFile.addEventListener("change", function (event) {
  72. //判断浏览器是否支持FileReader接口
  73. if (typeof FileReader == 'undefined') {
  74. console.log("你的浏览器不支持FileReader接口!");
  75. return;
  76. }
  77. //读取文件后的事件
  78. var reader = new FileReader();
  79. reader.onload = function () {
  80. if (reader.result) {
  81. var terrain = new Terrain();
  82. if (!readDEMFile(reader.result, terrain)) {
  83. console.log("文件格式有误,不能读取该文件!");
  84. }
  85. //绘制函数
  86. onDraw(gl, canvas, terrain);
  87. }
  88. }
  89. var input = event.target;
  90. reader.readAsText(input.files[0]);
  91. });
  92. // 获取 <canvas> 元素
  93. var canvas = document.getElementById('webgl');
  94. // 获取WebGL渲染上下文
  95. var gl = getWebGLContext(canvas);
  96. if (!gl) {
  97. console.log('Failed to get the rendering context for WebGL');
  98. return;
  99. }
  100. // 初始化着色器
  101. if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
  102. console.log('Failed to intialize shaders.');
  103. return;
  104. }
  105. // 指定清空<canvas>的颜色
  106. gl.clearColor(0.0, 0.0, 0.0, 1.0);
  107. // 开启深度测试
  108. gl.enable(gl.DEPTH_TEST);
  109. //清空颜色和深度缓冲区
  110. gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  111. }
  112. //绘制函数
  113. function onDraw(gl, canvas, terrain) {
  114. // 设置顶点位置
  115. //var cuboid = new Cuboid(399589.072, 400469.072, 3995118.062, 3997558.062, 732, 1268);
  116. var n = initVertexBuffers(gl, terrain);
  117. if (n < 0) {
  118. console.log('Failed to set the positions of the vertices');
  119. return;
  120. }
  121. //设置纹理
  122. if (!initTextures(gl, terrain)) {
  123. console.log('Failed to intialize the texture.');
  124. return;
  125. }
  126. //注册鼠标事件
  127. initEventHandlers(canvas);
  128. //绘制函数
  129. var tick = function () {
  130. if (initTexSuccess) {
  131. //设置MVP矩阵
  132. setMVPMatrix(gl, canvas, terrain.cuboid);
  133. //清空颜色和深度缓冲区
  134. gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  135. //绘制矩形体
  136. gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_SHORT, 0);
  137. //gl.drawArrays(gl.Points, 0, n);
  138. }
  139. //请求浏览器调用tick
  140. requestAnimationFrame(tick);
  141. };
  142. //开始绘制
  143. tick();
  144. }
  145. function initTextures(gl, terrain) {
  146. // 传递X方向和Y方向上的范围到着色器
  147. var u_RangeX = gl.getUniformLocation(gl.program, 'u_RangeX');
  148. var u_RangeY = gl.getUniformLocation(gl.program, 'u_RangeY');
  149. if (!u_RangeX || !u_RangeY) {
  150. console.log('Failed to get the storage location of u_RangeX or u_RangeY');
  151. return;
  152. }
  153. gl.uniform2f(u_RangeX, terrain.cuboid.minX, terrain.cuboid.maxX);
  154. gl.uniform2f(u_RangeY, terrain.cuboid.minY, terrain.cuboid.maxY);
  155. //创建一个image对象
  156. var image = new Image();
  157. if (!image) {
  158. console.log('Failed to create the image object');
  159. return false;
  160. }
  161. //图像加载的响应函数
  162. image.onload = function () {
  163. if (loadTexture(gl, image)) {
  164. initTexSuccess = true;
  165. }
  166. };
  167. //浏览器开始加载图像
  168. image.src = 'tex.jpg';
  169. return true;
  170. }
  171. function loadTexture(gl, image) {
  172. // 创建纹理对象
  173. var texture = gl.createTexture();
  174. if (!texture) {
  175. console.log('Failed to create the texture object');
  176. return false;
  177. }
  178. // 开启0号纹理单元
  179. gl.activeTexture(gl.TEXTURE0);
  180. // 绑定纹理对象
  181. gl.bindTexture(gl.TEXTURE_2D, texture);
  182. // 设置纹理参数
  183. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  184. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
  185. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  186. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  187. // 配置纹理图像
  188. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image);
  189. // 将0号单元纹理传递给着色器中的取样器变量
  190. var u_Sampler = gl.getUniformLocation(gl.program, 'u_Sampler');
  191. if (!u_Sampler) {
  192. console.log('Failed to get the storage location of u_Sampler');
  193. return false;
  194. }
  195. gl.uniform1i(u_Sampler, 0);
  196. return true;
  197. }
  198. //读取DEM函数
  199. function readDEMFile(result, terrain) {
  200. var stringlines = result.split("\n");
  201. if (!stringlines || stringlines.length <= 0) {
  202. return false;
  203. }
  204. //读取头信息
  205. var subline = stringlines[0].split("\t");
  206. if (subline.length != 6) {
  207. return false;
  208. }
  209. var col = parseInt(subline[4]); //DEM宽
  210. var row = parseInt(subline[5]); //DEM高
  211. var verticeNum = col * row;
  212. if (verticeNum + 1 > stringlines.length) {
  213. return false;
  214. }
  215. terrain.setWH(col, row);
  216. //读取点信息
  217. var ci = 0;
  218. terrain.verticesColors = new Float32Array(verticeNum * 6);
  219. for (var i = 1; i < stringlines.length; i++) {
  220. if (!stringlines[i]) {
  221. continue;
  222. }
  223. var subline = stringlines[i].split(',');
  224. if (subline.length != 9) {
  225. continue;
  226. }
  227. for (var j = 0; j < 6; j++) {
  228. terrain.verticesColors[ci] = parseFloat(subline[j]);
  229. ci++;
  230. }
  231. }
  232. if (ci !== verticeNum * 6) {
  233. return false;
  234. }
  235. //包围盒
  236. var minX = terrain.verticesColors[0];
  237. var maxX = terrain.verticesColors[0];
  238. var minY = terrain.verticesColors[1];
  239. var maxY = terrain.verticesColors[1];
  240. var minZ = terrain.verticesColors[2];
  241. var maxZ = terrain.verticesColors[2];
  242. for (var i = 0; i < verticeNum; i++) {
  243. minX = Math.min(minX, terrain.verticesColors[i * 6]);
  244. maxX = Math.max(maxX, terrain.verticesColors[i * 6]);
  245. minY = Math.min(minY, terrain.verticesColors[i * 6 + 1]);
  246. maxY = Math.max(maxY, terrain.verticesColors[i * 6 + 1]);
  247. minZ = Math.min(minZ, terrain.verticesColors[i * 6 + 2]);
  248. maxZ = Math.max(maxZ, terrain.verticesColors[i * 6 + 2]);
  249. }
  250. terrain.cuboid = new Cuboid(minX, maxX, minY, maxY, minZ, maxZ);
  251. return true;
  252. }
  253. //注册鼠标事件
  254. function initEventHandlers(canvas) {
  255. var dragging = false; // Dragging or not
  256. var lastX = -1,
  257. lastY = -1; // Last position of the mouse
  258. //鼠标按下
  259. canvas.onmousedown = function (ev) {
  260. var x = ev.clientX;
  261. var y = ev.clientY;
  262. // Start dragging if a moue is in <canvas>
  263. var rect = ev.target.getBoundingClientRect();
  264. if (rect.left <= x && x < rect.right && rect.top <= y && y < rect.bottom) {
  265. lastX = x;
  266. lastY = y;
  267. dragging = true;
  268. }
  269. };
  270. //鼠标离开时
  271. canvas.onmouseleave = function (ev) {
  272. dragging = false;
  273. };
  274. //鼠标释放
  275. canvas.onmouseup = function (ev) {
  276. dragging = false;
  277. };
  278. //鼠标移动
  279. canvas.onmousemove = function (ev) {
  280. var x = ev.clientX;
  281. var y = ev.clientY;
  282. if (dragging) {
  283. var factor = 100 / canvas.height; // The rotation ratio
  284. var dx = factor * (x - lastX);
  285. var dy = factor * (y - lastY);
  286. currentAngle[0] = currentAngle[0] + dy;
  287. currentAngle[1] = currentAngle[1] + dx;
  288. }
  289. lastX = x, lastY = y;
  290. };
  291. //鼠标缩放
  292. canvas.onmousewheel = function (event) {
  293. if (event.wheelDelta > 0) {
  294. curScale = curScale * 1.1;
  295. } else {
  296. curScale = curScale * 0.9;
  297. }
  298. };
  299. }
  300. //设置MVP矩阵
  301. function setMVPMatrix(gl, canvas, cuboid) {
  302. // Get the storage location of u_MvpMatrix
  303. var u_MvpMatrix = gl.getUniformLocation(gl.program, 'u_MvpMatrix');
  304. if (!u_MvpMatrix) {
  305. console.log('Failed to get the storage location of u_MvpMatrix');
  306. return;
  307. }
  308. //模型矩阵
  309. var modelMatrix = new Matrix4();
  310. modelMatrix.scale(curScale, curScale, curScale);
  311. modelMatrix.rotate(currentAngle[0], 1.0, 0.0, 0.0); // Rotation around x-axis
  312. modelMatrix.rotate(currentAngle[1], 0.0, 1.0, 0.0); // Rotation around y-axis
  313. modelMatrix.translate(-cuboid.CenterX(), -cuboid.CenterY(), -cuboid.CenterZ());
  314. //投影矩阵
  315. var fovy = 60;
  316. var near = 1;
  317. var projMatrix = new Matrix4();
  318. projMatrix.setPerspective(fovy, canvas.width / canvas.height, 1, 10000);
  319. //计算lookAt()函数初始视点的高度
  320. var angle = fovy / 2 * Math.PI / 180.0;
  321. var eyeHight = (cuboid.LengthY() * 1.2) / 2.0 / angle;
  322. //视图矩阵
  323. var viewMatrix = new Matrix4(); // View matrix
  324. viewMatrix.lookAt(0, 0, eyeHight, 0, 0, 0, 0, 1, 0);
  325. //MVP矩阵
  326. var mvpMatrix = new Matrix4();
  327. mvpMatrix.set(projMatrix).multiply(viewMatrix).multiply(modelMatrix);
  328. //将MVP矩阵传输到着色器的uniform变量u_MvpMatrix
  329. gl.uniformMatrix4fv(u_MvpMatrix, false, mvpMatrix.elements);
  330. }
  331. //
  332. function initVertexBuffers(gl, terrain) {
  333. //DEM的一个网格是由两个三角形组成的
  334. // 0------1 1
  335. // | |
  336. // | |
  337. // col col------col+1
  338. var col = terrain.col;
  339. var row = terrain.row;
  340. var indices = new Uint16Array((row - 1) * (col - 1) * 6);
  341. var ci = 0;
  342. for (var yi = 0; yi < row - 1; yi++) {
  343. //for (var yi = 0; yi < 10; yi++) {
  344. for (var xi = 0; xi < col - 1; xi++) {
  345. indices[ci * 6] = yi * col + xi;
  346. indices[ci * 6 + 1] = (yi + 1) * col + xi;
  347. indices[ci * 6 + 2] = yi * col + xi + 1;
  348. indices[ci * 6 + 3] = (yi + 1) * col + xi;
  349. indices[ci * 6 + 4] = (yi + 1) * col + xi + 1;
  350. indices[ci * 6 + 5] = yi * col + xi + 1;
  351. ci++;
  352. }
  353. }
  354. //
  355. var verticesColors = terrain.verticesColors;
  356. var FSIZE = verticesColors.BYTES_PER_ELEMENT; //数组中每个元素的字节数
  357. // 创建缓冲区对象
  358. var vertexColorBuffer = gl.createBuffer();
  359. var indexBuffer = gl.createBuffer();
  360. if (!vertexColorBuffer || !indexBuffer) {
  361. console.log('Failed to create the buffer object');
  362. return -1;
  363. }
  364. // 将缓冲区对象绑定到目标
  365. gl.bindBuffer(gl.ARRAY_BUFFER, vertexColorBuffer);
  366. // 向缓冲区对象写入数据
  367. gl.bufferData(gl.ARRAY_BUFFER, verticesColors, gl.STATIC_DRAW);
  368. //获取着色器中attribute变量a_Position的地址
  369. var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
  370. if (a_Position < 0) {
  371. console.log('Failed to get the storage location of a_Position');
  372. return -1;
  373. }
  374. // 将缓冲区对象分配给a_Position变量
  375. gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, FSIZE * 6, 0);
  376. // 连接a_Position变量与分配给它的缓冲区对象
  377. gl.enableVertexAttribArray(a_Position);
  378. //获取着色器中attribute变量a_Color的地址
  379. var a_Color = gl.getAttribLocation(gl.program, 'a_Color');
  380. if (a_Color < 0) {
  381. console.log('Failed to get the storage location of a_Color');
  382. return -1;
  383. }
  384. // 将缓冲区对象分配给a_Color变量
  385. gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, FSIZE * 6, FSIZE * 3);
  386. // 连接a_Color变量与分配给它的缓冲区对象
  387. gl.enableVertexAttribArray(a_Color);
  388. // 将顶点索引写入到缓冲区对象
  389. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
  390. gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
  391. return indices.length;
  392. }

主要作了以下三点的改动以使用纹理。

2.1. 准备纹理

在WebGL中,由于JS的异步特性,需要在JS加载图片完成之后,再把图片当做纹理传入着色器进行绘制,所以首先这里定义了一个boolean全局变量initTexSuccess来标识纹理图像是否加载完成。在绘制函数onDraw()中,增加了一个设置纹理函数initTextures()。最后,在重绘刷新函数tick()中检测initTexSuccess变量,如果完成,就进行绘制。

  1. var initTexSuccess = false; //纹理图像是否加载完成
  2. //...
  3. //绘制函数
  4. function onDraw(gl, canvas, terrain) {
  5. //...
  6. //设置纹理
  7. if (!initTextures(gl)) {
  8. console.log('Failed to intialize the texture.');
  9. return;
  10. }
  11. //...
  12. //绘制函数
  13. var tick = function () {
  14. if (initTexSuccess) {
  15. //...
  16. }
  17. //请求浏览器调用tick
  18. requestAnimationFrame(tick);
  19. };
  20. //开始绘制
  21. tick();
  22. }

在初始化纹理函数initTextures()中,首先给着色器传入了X方向和Y方向上的实际坐标(局部坐标系坐标)范围,这个范围是用来计算纹理坐标的。接着创建了一个Image对象,通过这个对象来加载图像。最后给图像加载编写响应函数,一旦纹理配置函数loadTexture()成功,就设置initTexSuccess为true。

  1. function initTextures(gl, terrain) {
  2. // 传递X方向和Y方向上的范围到着色器
  3. var u_RangeX = gl.getUniformLocation(gl.program, 'u_RangeX');
  4. var u_RangeY = gl.getUniformLocation(gl.program, 'u_RangeY');
  5. if (!u_RangeX || !u_RangeY) {
  6. console.log('Failed to get the storage location of u_RangeX or u_RangeY');
  7. return;
  8. }
  9. gl.uniform2f(u_RangeX, terrain.cuboid.minX, terrain.cuboid.maxX);
  10. gl.uniform2f(u_RangeY, terrain.cuboid.minY, terrain.cuboid.maxY);
  11. //创建一个image对象
  12. var image = new Image();
  13. if (!image) {
  14. console.log('Failed to create the image object');
  15. return false;
  16. }
  17. //图像加载的响应函数
  18. image.onload = function () {
  19. if (loadTexture(gl, image)) {
  20. initTexSuccess = true;
  21. }
  22. };
  23. //浏览器开始加载图像
  24. image.src = 'tex.jpg';
  25. return true;
  26. }

2.2. 配置纹理

在配置纹理函数loadTexture()中,首先创建了一个纹理对象,并将其绑定到0号纹理单元。WebGL至少支持8个纹理单元,内置的变量名形如gl.TEXTURE0、gl.TEXTURE1......gl.TEXTURE7。

  1. function loadTexture(gl, image) {
  2. // 创建纹理对象
  3. var texture = gl.createTexture();
  4. if (!texture) {
  5. console.log('Failed to create the texture object');
  6. return false;
  7. }
  8. // 开启0号纹理单元
  9. gl.activeTexture(gl.TEXTURE0);
  10. // 绑定纹理对象
  11. gl.bindTexture(gl.TEXTURE_2D, texture);
  12. //...
  13. return true;
  14. }

接着通过gl.texParameteri()函数配置纹理的参数,这个函数规定了纹理在缩放时的插值方法,以及纹理填充时采用何种方式铺填。这里表示纹理缩放时采用线性插值,填充范围不够时采用纹理图像边缘值进行填充:

  1. function loadTexture(gl, image) {
  2. //...
  3. // 设置纹理参数
  4. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  5. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
  6. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  7. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  8. //...
  9. return true;
  10. }

最后通过gl.texImage2D()函数将纹理对象分配给纹理对象。而该纹理对象已经与0号纹理单元绑定,因此直接将0号纹理单元作为Uniform变量传递给着色器:

  1. function loadTexture(gl, image) {
  2. //...
  3. // 配置纹理图像
  4. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image);
  5. // 将0号单元纹理传递给着色器中的取样器变量
  6. var u_Sampler = gl.getUniformLocation(gl.program, 'u_Sampler');
  7. if (!u_Sampler) {
  8. console.log('Failed to get the storage location of u_Sampler');
  9. return false;
  10. }
  11. gl.uniform1i(u_Sampler, 0);
  12. return true;
  13. }

2.3. 使用纹理

在顶点着色器中,将顶点坐标值a_Position赋值为varying变量v_position,这个变量是用来传递给片元着色器的。

  1. // 顶点着色器程序
  2. var VSHADER_SOURCE =
  3. 'attribute vec4 a_Position;\n' + //位置
  4. 'attribute vec4 a_Color;\n' + //颜色
  5. 'uniform mat4 u_MvpMatrix;\n' +
  6. 'varying vec4 v_Color;\n' +
  7. 'varying vec4 v_position;\n' +
  8. 'void main() {\n' +
  9. ' v_position = a_Position;\n' +
  10. ' gl_Position = u_MvpMatrix * a_Position;\n' + // 设置顶点坐标
  11. ' v_Color = a_Color;\n' +
  12. '}\n';

经过内插,片元着色器接受到了每个片元对应的顶点坐标v_position。由于这个值是根据实际的顶点坐标(局部坐标系坐标)内插的,所以这个值也是实际坐标值。同时片元着色器也接收到了传递过来的纹理对象u_Sampler,可以通过texture2D()函数来获取对应坐标的像素,将其作为片元最终值:

  1. // 片元着色器程序
  2. var FSHADER_SOURCE =
  3. 'precision mediump float;\n' +
  4. 'uniform vec2 u_RangeX;\n' + //X方向范围
  5. 'uniform vec2 u_RangeY;\n' + //Y方向范围
  6. 'uniform sampler2D u_Sampler;\n' +
  7. 'varying vec4 v_Color;\n' +
  8. 'varying vec4 v_position;\n' +
  9. 'void main() {\n' +
  10. ' vec2 v_TexCoord = vec2((v_position.x-u_RangeX[0]) / (u_RangeX[1]-u_RangeX[0]), 1.0-(v_position.y-u_RangeY[0]) / (u_RangeY[1]-u_RangeY[0]));\n' +
  11. ' gl_FragColor = texture2D(u_Sampler, v_TexCoord);\n' +
  12. '}\n';

上述代码可以看到并没有直接用v_position来进行插值。这是因为纹理坐标范围是在0~1之间,需要经过一个纹理映射的换算。如图所示,这是一个简单的线性变换的过程:
image

3. 结果

用浏览器运行,最终的显示结果如下,可以清楚的看到山川河流等纹理:
image
image

再次说明下这个实例用到了本地图片,需要让浏览器设置跨域或者建立服务器在域内使用。

4. 参考

本来部分代码和插图来自《WebGL编程指南》,源代码链接:地址 。会在此共享目录中持续更新后续的内容。

原文链接:http://www.cnblogs.com/charlee44/p/11684805.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号