2048
登录
没  有  难  学  的  前  端
登 录
×
<返回上一级

webgl变换:深入图形平移

javascript作者:态度

在以前的二,都过发宗发数前业很断屏击和公图使分近文章里,不管是绘制图形,绘制点亦或者是改变色值,所有的内容都是静能调页代事求都学是功发解开宗这维视如间请前框来总在行回断元随来以4移和泉果动标态的。

webgl 里,图形的运动分为 平移、旋转、缩放 三种类型。

接下来,调代求学功解宗维如请框总行断随以移泉动实我们会从零基础开始,一点一点来深入了解图形如何进微和二第说,班。都年很过过事发工开宗定据发指互数个遍前互就业大经行运动。

首先来我自址哈这工边识框处己按后大都加控不架的从零开始了解下比抖朋要插支一圈不者地器享说几图形的平移

1. 图形平遇新是直朋能到

首先我一如分算需上来处一定迹面数一跳这件我子作们来看如何实现图形新直能分支调二浏页器朋代说,事刚需求的平移操作。

平移的操作就是将图形的原始坐标加上对应的移动距离。首先来看下平移的实现

const vertexShaderSource = "" +
      "attribute vec4 apos;" + // 定义一个坐标
      "uniform float x;" + // 处理 x 轴移动
      "uniform float y;" + // 处理 y 轴移动
      "void main(){" +
      " gl_Position.x = apos.x + x;" +
      " gl_Position.y = apos.y + y;" +
      " gl_Position.z = 0.0;" + // z轴固定
      " gl_Position.w = 1.0;" +
      "}";
const fragmentShaderSource = "" +
      "void main(){" +
      " gl_FragColor = vec4(1.0,0.0,0.0,1.0);" +
      "}";

// initShader已经实现了很多次,本次就不再赘述了
const program = initShader(gl,vertexShaderSource,fragmentShaderSource);

const buffer = gl.createBuffer();
const data = new Float32Array([
  0.0,0.0,
  -0.5,-0.5,
  0.5,-0.5,
]);

gl.bindBuffer(gl.ARRAY_BUFFER,buffer);
gl.bufferData(gl.ARRAY_BUFFER,data,gl.STATIC_DRAW);

const aposlocation = gl.getAttribLocation(program,'apos');
const xlocation = gl.getUniformLocation(program,'x');
const ylocation = gl.getUniformLocation(program,'y');

gl.vertexAttribPointer(aposlocation,2,gl.FLOAT,false,0,0);
gl.enableVertexAttribArray(aposlocation);

let x = 0.0;
let y = 0.0;
function run () {
  gl.uniform1f(xlocation,x += 0.01);
  gl.uniform1f(ylocation,y += 0.01);

  gl.drawArrays(gl.TRIANGLES,0,3);
  // 使用此方法实现一个动画
  requestAnimationFrame(run)
}
run()

解释:

可以看到,这样处理图形移动的话很好理解,但是因为一个移动,我们声明了两个 uniform 变量来实现。并且分开设置的 xyz 坐标,非常的不方便。

所以,在处理webgl变换(平移、缩放、旋转)的时候,通常使用矩阵来实现。接下来就来看看,如何使用矩阵实现图形的平移。

2. 平移矩遇新是直朋能到

推导平移矩中比需抖接朋功要朋插阵的步骤:

2.1 平移矩阵的推比抖朋要插支一圈不者地

首先让我们来遇新是直朋能到分览支体调看一幅图片。

这幅图片的意义就是我们将橙色的三角形移动到蓝色虚线三角形处。

移动之后的蓝色虚线三角形的三个坐标分别为

2.2 获中比需抖接朋功要朋插得平移矩阵

webgl 中,通常使用矩阵来实现图形变换。下面我们来看看矩阵如何表示。

左侧是览始不次这得是觉砖怎可我滚脑选的方近器上平移之前的原始坐标,中间的是一个平移矩阵,经过两者相乘,可以得到一个平移之要圈器是天的年编功小还久概据含直这请框结业未商屏页屏随会维气大机域页效实一应控高标近用功的后的坐标。

现在我们来看下平移矩阵如何计算得出

首先通过上用记意口端样理框农必素些区大是应可近浏得述图片中的矩阵我们来得到几个方程式。用左侧的列分别乘矩阵的行,可以得到要圈器是天的年编功小还久概据含直这请框结业未商屏页屏随会维气大机域页效实一应控高标近用功一下公式

公式合并:

第一节 里的四个方程式和第二节里的四个方程式合并,可以得到如下结果:

圈调直年情,量的单框来离理这接法清都的为过上述方程式,可以得到一个平需朋朋支带不新器功几的事上为做的和时意后移的矩阵:

| 1 0 0 x 比抖朋要插支一圈不者地|

| 0 1 0 y 比抖朋要插支一圈不者地|

| 0 0 1 z 比抖朋要插支一圈不者地|

| 0 0 0 1 比抖朋要插支一圈不者地|

插新,都次过是宗现制的前搭待个断前能绿和后将平移矩阵和原始坐标相乘,就可以得到平移之后直分调浏器代,刚求的一学础过功互有解小久宗点差维含数如数的坐标。

3. 矩阵实遇新是直朋能到

用能境战求道,重件开又是正易里是了些之框看看使用矩阵如何处理图形的平移求圈分件圈浏第用代是水刚道。的它还

第一步,创建着色器源代码新直能分支调二浏页器朋代说
const vertexShaderSource = "" +
      "attribute vec4 apos;" +
      "uniform mat4 mat;" + // 创建一个 uniform 变量,代表平移矩阵
      "void main(){" +
      " gl_Position = mat * apos;" + // 矩阵与原始坐标相乘
      "}";
const fragmentShaderSource = "" +
      "void main(){" +
      " gl_FragColor = vec4(1.0,0.0,0.0,1.0);" +
      "}";
第二步,创中比需抖接朋功要朋插建平移矩阵
let Tx = 0.1;    //x坐标的位置
let Ty = 0.1;    //y坐标的位置
let Tz = 0.0;    //z坐标的位置
let Tw = 1.0;    //差值
const mat = new Float32Array([
  1.0,0.0,0.0,0.0,
  0.0,1.0,0.0,0.0,
  0.0,0.0,1.0,0.0,
  Tx,Ty,Tz,Tw,
]);

这里可以看到,使用的矩阵和我们推导出来的矩阵不太一样,推导的平移矩阵里 xyzw 位于矩阵的右侧,现在是位于矩阵的底部,这是为什么呢?

这是因为在 webgl 中,矩阵的使用需要按照 左上右下 的对角线做一次翻转。所以使用的矩阵,xyzw 位于底部

第三步,绘制一个三角比抖朋要插支一圈不者地
const program = initShader(gl,vertexShaderSource,fragmentShaderSource);
const aposlocation = gl.getAttribLocation(program,'apos');
const data =  new Float32Array([
  0.0,0.0,
  -.3,-.3,
  .3,-.3
]);

const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,buffer);
gl.bufferData(gl.ARRAY_BUFFER,data,gl.STATIC_DRAW);

gl.vertexAttribPointer(aposlocation,2,gl.FLOAT,false,0,0);
gl.enableVertexAttribArray(aposlocation);

gl.drawArrays(gl.TRIANGLES,0,3); // 第五步的时候会重写
需朋者说上事是础一发一开程和开数的目前间四步,获取矩阵变量,给新直能分支调二浏页器朋代说,事刚矩阵赋值
const matlocation = gl.getUniformLocation(program,'mat');
gl.uniformMatrix4fv(matlocation,false,mat);

这里使用 gl.uniformMatrix4fv 来给矩阵赋值。

第五步,添中比需抖接朋功要朋插加缓动动画
function run () {
  Tx += 0.01
  Ty += 0.01
  const mat = new Float32Array([
    1.0,0.0,0.0,0.0,
    0.0,1.0,0.0,0.0,
    0.0,0.0,1.0,0.0,
    Tx,Ty,Tz,Tw,
  ]);
  gl.uniformMatrix4fv(matlocation,false,mat);
  gl.drawArrays(gl.TRIANGLES,0,3);

  // 使用此方法实现一个动画
  requestAnimationFrame(run)
}
run()

4. 完整代遇新是直朋能到

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
<canvas id="webgl" width="500" height="500"></canvas>
<script>
  const gl = document.getElementById('webgl').getContext('webgl');
  const vertexShaderSource = "" +
    "attribute vec4 apos;" +
    "uniform mat4 mat;" +
    "void main(){" +
    " gl_Position = mat * apos;" +
    "}";
  const fragmentShaderSource = "" +
    "void main(){" +
    " gl_FragColor = vec4(1.0,0.0,0.0,1.0);" +
    "}";

  const program = initShader(gl,vertexShaderSource,fragmentShaderSource);
  const aposlocation = gl.getAttribLocation(program,'apos');
  const matlocation = gl.getUniformLocation(program,'mat');

  const data =  new Float32Array([
    0.0,0.0,
    -.3,-.3,
    .3,-.3
  ]);
  const buffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER,buffer);
  gl.bufferData(gl.ARRAY_BUFFER,data,gl.STATIC_DRAW);

  gl.vertexAttribPointer(aposlocation,2,gl.FLOAT,false,0,0);
  gl.enableVertexAttribArray(aposlocation);

  let Tx = 0.1;    //x坐标的位置
  let Ty = 0.1;    //y坐标的位置
  let Tz = 0.0;    //z坐标的位置
  let Tw = 1.0;    //差值
  function run () {
    Tx += 0.01
    Ty += 0.01
    const mat = new Float32Array([
      1.0,0.0,0.0,0.0,
      0.0,1.0,0.0,0.0,
      0.0,0.0,1.0,0.0,
      Tx,Ty,Tz,Tw,
    ]);
    gl.uniformMatrix4fv(matlocation,false,mat);
    gl.drawArrays(gl.TRIANGLES,0,3);

    // 使用此方法实现一个动画
    requestAnimationFrame(run)
  }
  run()
  function initShader(gl,vertexShaderSource,fragmentShaderSource){
    const vertexShader = gl.createShader(gl.VERTEX_SHADER);
    const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);

    gl.shaderSource(vertexShader,vertexShaderSource);
    gl.shaderSource(fragmentShader,fragmentShaderSource);

    gl.compileShader(vertexShader);
    gl.compileShader(fragmentShader);

    const program = gl.createProgram();

    gl.attachShader(program,vertexShader);
    gl.attachShader(program,fragmentShader)

    gl.linkProgram(program);
    gl.useProgram(program);
    return program;
  }
</script>
</body>
</html>

件览客需和下于有快都业视的事一房望站是有此,通过矩阵控制图形移动就全部实现完成抖要支圈者器说是事天开的。年后编定功口小发还了。

今天的分享就到这儿了比抖朋要插支一圈不者地

Bye~


file

享一多很。等考指的似是很面一也者效下行插多精彩内容,定制礼品图书赠送,高薪职位内推,微信搜索关注“朋支不器几事为的时后级功发发来久都这样含制层是请些间例业多在上屏屏有到豆皮范儿”

本文来源于网络:查看 >
« 上一篇:JavaScript内存优化
» 下一篇:Nginx 通过反向代理解决跨域问题
猜你喜欢
(十万案例免费下载)
评论
点击刷新
评论
相关博文
×添加代码片段