ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

WebGL 理论基础 - 二维平移

2022-05-29 14:04:49  阅读:187  来源: 互联网

标签:平移 WebGL 30 thickness width 二维 var translation gl


在学习三维之前让我们先看一看二维,还请见谅。这个主题对有些人来说可能过于简单,但还是准备在几篇文章中加以阐述。

此文上接WebGL 基础概念,没读的建议先看那里。

平移就是普通意义的“移动”物体。用第一篇文章中的代码,你可以改变传递给 setRectangle() 的值,移动矩形的位置。这里有个例子基于前一个例子

首先我们来定义一些变量存储矩形的平移,宽,高和颜色。

var translation = [0, 0];
var width = 100;
var height = 30;
var color = [Math.random(), Math.random(), Math.random(), 1];

然后定义一个方法重绘所有东西,我们可以在更新变换之后调用这个方法。

// 绘制场景
  function drawScene() {
    webglUtils.resizeCanvasToDisplaySize(gl.canvas);
    // 告诉WebGL如何从裁剪空间对应到像素
    gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
    // 清空画布
    gl.clear(gl.COLOR_BUFFER_BIT);
    // 使用我们的程序
    gl.useProgram(program);
    // 启用属性
    gl.enableVertexAttribArray(positionLocation);
    // 绑定位置缓冲
    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
    // 设置矩形参数
    setRectangle(gl, translation[0], translation[1], width, height);
    // 告诉属性怎么从positionBuffer中读取数据 (ARRAY_BUFFER)
    var size = 2;          // 每次迭代运行提取两个单位数据
    var type = gl.FLOAT;   // 每个单位的数据类型是32位浮点型
    var normalize = false; // 不需要归一化数据
    var stride = 0;        // 0 = 移动单位数量 * 每个单位占用内存(sizeof(type))
    var offset = 0;        // 从缓冲起始位置开始读取
    gl.vertexAttribPointer(
        positionLocation, size, type, normalize, stride, offset)
    // 设置分辨率
    gl.uniform2f(resolutionLocation, gl.canvas.width, gl.canvas.height);
    // 设置颜色
    gl.uniform4fv(colorLocation, color);
    // 绘制矩形
    var primitiveType = gl.TRIANGLES;
    var offset = 0;
    var count = 6;
    gl.drawArrays(primitiveType, offset, count);
  }

在下方的例子中,我添加了一对滑块,当它们值改变时会更新translation[0]translation[1] 并且调用drawScene方法。拖动滑块来平移矩形。

CodePen 地址

到目前为止还不错!但是想象一下如果对一个更复杂的图形做类似操作怎么办。

假设我们想绘制一个由六个三角形组成的 ‘F’ ,像这样

![](data:image/svg+xml;utf8,)

接着当前的代码我们需要修改 setRectangle(),像这样

// 在缓冲存储构成 'F' 的值
function setGeometry(gl, x, y) {
  var width = 100;
  var height = 150;
  var thickness = 30;
  gl.bufferData(
      gl.ARRAY_BUFFER,
      new Float32Array([
          // 左竖
          x, y,
          x + thickness, y,
          x, y + height,
          x, y + height,
          x + thickness, y,
          x + thickness, y + height,
          // 上横
          x + thickness, y,
          x + width, y,
          x + thickness, y + thickness,
          x + thickness, y + thickness,
          x + width, y,
          x + width, y + thickness,
          // 中横
          x + thickness, y + thickness * 2,
          x + width * 2 / 3, y + thickness * 2,
          x + thickness, y + thickness * 3,
          x + thickness, y + thickness * 3,
          x + width * 2 / 3, y + thickness * 2,
          x + width * 2 / 3, y + thickness * 3,
      ]),
      gl.STATIC_DRAW);
}

你可能发现这样做可能并不好,如果我们想绘制一个含有成百上千个线条的几何图形,将会有很复杂的代码。最重要的是,每次绘制 JavaScript 都要更新所有点。

这里有个简单的方式,上传几何体然后在着色器中进行平移。

这是新的着色器

attribute vec2 a_position;
uniform vec2 u_resolution;
uniform vec2 u_translation;
void main() {
   // 加上平移量
   vec2 position = a_position + u_translation;
   // 从像素坐标转换到 0.0 到 1.0
   vec2 zeroToOne = position / u_resolution;
   ...
</code></pre><div>重构一下代码,首先我们只需要设置一次几何体。</div>
<pre data-syntax=""><code>// 在缓冲存储构成 'F' 的值
function setGeometry(gl) {
  gl.bufferData(
      gl.ARRAY_BUFFER,
      new Float32Array([
          // 左竖
          0, 0,
          30, 0,
          0, 150,
          0, 150,
          30, 0,
          30, 150,
          // 上横
          30, 0,
          100, 0,
          30, 30,
          30, 30,
          100, 0,
          100, 30,
          // 中横
          30, 60,
          67, 60,
          30, 90,
          30, 90,
          67, 60,
          67, 90,
      ]),
      gl.STATIC_DRAW);
}
</code></pre>

然后我们只需要在绘制前更新u_translation为期望的平移量。

...
  var translationLocation = gl.getUniformLocation(
             program, "u_translation");
  ...
  // 创建一个存放位置信息的缓冲
  var positionBuffer = gl.createBuffer();
  // 绑定到 ARRAY_BUFFER (简单的理解为 ARRAY_BUFFER = positionBuffer)
  gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
  // 将几何数据存到缓冲
  setGeometry(gl);
  ...
  // 绘制场景
  function drawScene() {
    ...
    // 设置平移
    gl.uniform2fv(translationLocation, translation);
    // 绘制矩形
    var primitiveType = gl.TRIANGLES;
    var offset = 0;
    var count = 18;
    gl.drawArrays(primitiveType, offset, count);
  }

注意到setGeometry只调用了一次,它不在drawScene内部了。

CodePen 地址

现在当我们绘制时,WebGL几乎做了所有事情,我们做的仅仅是设置平移然后让它绘制,即使我们的几何体有成千上万个点,主要的代码还是保持不变。你可以对比上方例子中使用 JavaScript 更新所有点的情况。

我希望这个例子不会过于简单,请继续阅读,我们会用更好的方式实现平移。下一篇将介绍二维旋转。

本文转自 https://zhuanlan.zhihu.com/p/54341191,如有侵权,请联系删除。

标签:平移,WebGL,30,thickness,width,二维,var,translation,gl
来源: https://www.cnblogs.com/hustshu/p/16323716.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有