WebGL -- 仿射变换

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WebGL -- 仿射变换相关的知识,希望对你有一定的参考价值。

本文参考《WebGL编程指南》

 

  仿射变换:移动,旋转,缩放

  在做变换时,通常是使用矩阵。

 

首先画出一个初始的三角形作为对比:

技术分享

源码:

test.js

技术分享
function main() {
  var gl = Init();
  if(!gl) {
    console.log(‘Failed to init‘);
    return;
  }

  var n = InitVertices(gl);
  if(n < 0) {
    console.log(‘Failed to init vertices‘);
    return;
  }

  // draw triangle
  gl.drawArrays(gl.TRIANGLES, 0, n);
  // draw coordinate system
  gl.drawArrays(gl.LINES, n, 4);

}

//@Func: init the WebGL
//@Return: gl(the WebGL context)
function Init() {
  var canvas = document.getElementById(‘webgl‘);

  var gl = getWebGLContext(canvas);
  if(!gl) {
    console.log(‘Failed to get the rendering context for WebGL‘);
    return null;
  }

  if(!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
    console.log(‘Failed to init shader‘);
    return null;
  }

  gl.clearColor(0.3, 1.0, 0.3, 1.0);

  gl.clear(gl.COLOR_BUFFER_BIT);

  return gl;
}

//@Func: init vertices
//@Return: n(the number of vertex)
function InitVertices(gl) {
  var vertexBuffer = gl.createBuffer();
  if(!vertexBuffer) {
    console.log(‘Failed to create vertex buffer‘);
    return -1;
  }

  gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);

  var n = 3;
  var vertices = new Float32Array([
      -0.3,0.0, 0.0,0.5, 0.3,0.0,
      -1.0,0.0, 1.0,0.0, 0.0,-1.0,
      0.0,1.0
    ]);

  gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

  var aPos = gl.getAttribLocation(gl.program, ‘aPos‘);
  if(aPos < 0) {
    console.log(‘Failed to get aPos‘);
    return -1;
  }

  gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);

  gl.enableVertexAttribArray(aPos);

  return n;
}
View Code

shader.js

技术分享
// vertical shader
var VSHADER_SOURCE = 
`
  attribute vec4 aPos;
  void main() {
    gl_Position = aPos; 
    gl_PointSize = 30.0;
  }
`

// fragment shader
var FSHADER_SOURCE = 
`
  precision mediump float;
  //uniform vec4 uColor;
  void main() {
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
  }
`
View Code

 

  移动

平移矩阵如下:

技术分享

(1)在着色器中做矩阵运算

// vertical shader
var VSHADER_SOURCE = 
`
  attribute vec4 aPos;
  uniform mat4 uTransform;
  void main() {
    gl_Position = uTransform * aPos; 
    gl_PointSize = 30.0;
  }
`

 

(2)赋值给矩阵

var transformMatrix = 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,
    0.3, 0.0, 0.0, 1.0
    ]);

  var uTransform = gl.getUniformLocation(gl.program, ‘uTransform‘);

  gl.uniformMatrix4fv(uTransform, false, transformMatrix);

 

注意:矩阵是列主元的,即上面定义的矩阵实际是如下:

技术分享

效果:

技术分享

源码:

test.js

技术分享
function main() {
  var gl = Init();
  if(!gl) {
    console.log(‘Failed to init‘);
    return;
  }

  var n = InitVertices(gl);
  if(n < 0) {
    console.log(‘Failed to init vertices‘);
    return;
  }

  var transformMatrix = 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,
    0.3, 0.0, 0.0, 1.0
    ]);

  var uAffineMat = gl.getUniformLocation(gl.program, ‘uAffineMat‘);

  gl.uniformMatrix4fv(uAffineMat, false, transformMatrix);

  // draw triangle
  gl.drawArrays(gl.TRIANGLES, 0, n);

  var normalMatrix = 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,
    0.0, 0.0, 0.0, 1.0
    ]);

  gl.uniformMatrix4fv(uAffineMat, false, normalMatrix);

  // draw coordinate system
  gl.drawArrays(gl.LINES, n, 4);

}

//@Func: init the WebGL
//@Return: gl(the WebGL context)
function Init() {
  var canvas = document.getElementById(‘webgl‘);

  var gl = getWebGLContext(canvas);
  if(!gl) {
    console.log(‘Failed to get the rendering context for WebGL‘);
    return null;
  }

  if(!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
    console.log(‘Failed to init shader‘);
    return null;
  }

  gl.clearColor(0.3, 1.0, 0.3, 1.0);

  gl.clear(gl.COLOR_BUFFER_BIT);

  return gl;
}

//@Func: init vertices
//@Return: n(the number of vertex)
function InitVertices(gl) {
  var vertexBuffer = gl.createBuffer();
  if(!vertexBuffer) {
    console.log(‘Failed to create vertex buffer‘);
    return -1;
  }

  gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);

  var n = 3;
  var vertices = new Float32Array([
      -0.3,0.0, 0.0,0.5, 0.3,0.0,
      -1.0,0.0, 1.0,0.0, 0.0,-1.0,
      0.0,1.0
    ]);

  gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

  var aPos = gl.getAttribLocation(gl.program, ‘aPos‘);
  if(aPos < 0) {
    console.log(‘Failed to get aPos‘);
    return -1;
  }

  gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);

  gl.enableVertexAttribArray(aPos);

  return n;
}
View Code

 

shader.js

技术分享
// vertical shader
var VSHADER_SOURCE = 
`
  attribute vec4 aPos;
  uniform mat4 uAffineMat;
  void main() {
    gl_Position = uAffineMat * aPos; 
    gl_PointSize = 30.0;
  }
`

// fragment shader
var FSHADER_SOURCE = 
`
  precision mediump float;
  //uniform vec4 uColor;
  void main() {
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
  }
`
View Code

 

 

   旋转

旋转矩阵如下:

技术分享

效果:

技术分享

源码:

test.js

技术分享
function main() {
  var gl = Init();
  if(!gl) {
    console.log(‘Failed to init‘);
    return;
  }

  var n = InitVertices(gl);
  if(n < 0) {
    console.log(‘Failed to init vertices‘);
    return;
  }

  var angle = 3.14 / 4;

  var transformMatrix = new Float32Array([
    Math.cos(angle), Math.sin(angle), 0.0, 0.0,
    -Math.sin(angle), Math.cos(angle), 0.0, 0.0,
    0.0, 0.0, 1.0, 0.0,
    0.0, 0.0, 0.0, 1.0
    ]);

  var uAffineMat = gl.getUniformLocation(gl.program, ‘uAffineMat‘);

  gl.uniformMatrix4fv(uAffineMat, false, transformMatrix);

  // draw triangle
  gl.drawArrays(gl.TRIANGLES, 0, n);

  var normalMatrix = 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,
    0.0, 0.0, 0.0, 1.0
    ]);

  gl.uniformMatrix4fv(uAffineMat, false, normalMatrix);

  // draw coordinate system
  gl.drawArrays(gl.LINES, n, 4);

}

//@Func: init the WebGL
//@Return: gl(the WebGL context)
function Init() {
  var canvas = document.getElementById(‘webgl‘);

  var gl = getWebGLContext(canvas);
  if(!gl) {
    console.log(‘Failed to get the rendering context for WebGL‘);
    return null;
  }

  if(!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
    console.log(‘Failed to init shader‘);
    return null;
  }

  gl.clearColor(0.3, 1.0, 0.3, 1.0);

  gl.clear(gl.COLOR_BUFFER_BIT);

  return gl;
}

//@Func: init vertices
//@Return: n(the number of vertex)
function InitVertices(gl) {
  var vertexBuffer = gl.createBuffer();
  if(!vertexBuffer) {
    console.log(‘Failed to create vertex buffer‘);
    return -1;
  }

  gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);

  var n = 3;
  var vertices = new Float32Array([
      -0.3,0.0, 0.0,0.5, 0.3,0.0,
      -1.0,0.0, 1.0,0.0, 0.0,-1.0,
      0.0,1.0
    ]);

  gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

  var aPos = gl.getAttribLocation(gl.program, ‘aPos‘);
  if(aPos < 0) {
    console.log(‘Failed to get aPos‘);
    return -1;
  }

  gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);

  gl.enableVertexAttribArray(aPos);

  return n;
}
View Code

shader.js

技术分享
// vertical shader
var VSHADER_SOURCE = 
`
  attribute vec4 aPos;
  uniform mat4 uAffineMat;
  void main() {
    gl_Position = uAffineMat * aPos; 
    gl_PointSize = 30.0;
  }
`

// fragment shader
var FSHADER_SOURCE = 
`
  precision mediump float;
  //uniform vec4 uColor;
  void main() {
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
  }
`
View Code

 

  缩放

缩放矩阵如下:

技术分享

效果:

技术分享

源码:

test.js

技术分享
function main() {
  var gl = Init();
  if(!gl) {
    console.log(‘Failed to init‘);
    return;
  }

  var n = InitVertices(gl);
  if(n < 0) {
    console.log(‘Failed to init vertices‘);
    return;
  }

  var angle = 3.14 / 4;

  var transformMatrix = new Float32Array([
    2, 0, 0.0, 0.0,
    0, 0.5, 0.0, 0.0,
    0.0, 0.0, 1.0, 0.0,
    0.0, 0.0, 0.0, 1.0
    ]);

  var uAffineMat = gl.getUniformLocation(gl.program, ‘uAffineMat‘);

  gl.uniformMatrix4fv(uAffineMat, false, transformMatrix);

  // draw triangle
  gl.drawArrays(gl.TRIANGLES, 0, n);

  var normalMatrix = 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,
    0.0, 0.0, 0.0, 1.0
    ]);

  gl.uniformMatrix4fv(uAffineMat, false, normalMatrix);

  // draw coordinate system
  gl.drawArrays(gl.LINES, n, 4);

}

//@Func: init the WebGL
//@Return: gl(the WebGL context)
function Init() {
  var canvas = document.getElementById(‘webgl‘);

  var gl = getWebGLContext(canvas);
  if(!gl) {
    console.log(‘Failed to get the rendering context for WebGL‘);
    return null;
  }

  if(!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
    console.log(‘Failed to init shader‘);
    return null;
  }

  gl.clearColor(0.3, 1.0, 0.3, 1.0);

  gl.clear(gl.COLOR_BUFFER_BIT);

  return gl;
}

//@Func: init vertices
//@Return: n(the number of vertex)
function InitVertices(gl) {
  var vertexBuffer = gl.createBuffer();
  if(!vertexBuffer) {
    console.log(‘Failed to create vertex buffer‘);
    return -1;
  }

  gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);

  var n = 3;
  var vertices = new Float32Array([
      -0.3,0.0, 0.0,0.5, 0.3,0.0,
      -1.0,0.0, 1.0,0.0, 0.0,-1.0,
      0.0,1.0
    ]);

  gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

  var aPos = gl.getAttribLocation(gl.program, ‘aPos‘);
  if(aPos < 0) {
    console.log(‘Failed to get aPos‘);
    return -1;
  }

  gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);

  gl.enableVertexAttribArray(aPos);

  return n;
}
View Code

 

shader.js

技术分享
// vertical shader
var VSHADER_SOURCE = 
`
  attribute vec4 aPos;
  uniform mat4 uAffineMat;
  void main() {
    gl_Position = uAffineMat * aPos; 
    gl_PointSize = 30.0;
  }
`

// fragment shader
var FSHADER_SOURCE = 
`
  precision mediump float;
  //uniform vec4 uColor;
  void main() {
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
  }
`
View Code

 

 

  多个变换组合在一起

要将多个仿射变换组合在一起,只需要将对应的变换矩阵相乘。

利用cuon-matrix.js,其中定义了有用的矩阵运算:

var affineMat = new Matrix4();
  affineMat.setTranslate(0.3, 0.0, 0.0);
  affineMat.scale(2, 0.5, 1);
  
  var uAffineMat = gl.getUniformLocation(gl.program, ‘uAffineMat‘);

  gl.uniformMatrix4fv(uAffineMat, false, affineMat.elements);

 

效果:

技术分享

源码:

test.js

技术分享
function main() {
  var gl = Init();
  if(!gl) {
    console.log(‘Failed to init‘);
    return;
  }

  var n = InitVertices(gl);
  if(n < 0) {
    console.log(‘Failed to init vertices‘);
    return;
  }

  var affineMat = new Matrix4();
  affineMat.setTranslate(0.3, 0.0, 0.0);
  affineMat.scale(2, 0.5, 1);
  
  var uAffineMat = gl.getUniformLocation(gl.program, ‘uAffineMat‘);

  gl.uniformMatrix4fv(uAffineMat, false, affineMat.elements);

  // draw triangle
  gl.drawArrays(gl.TRIANGLES, 0, n);

  var normalMatrix = 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,
    0.0, 0.0, 0.0, 1.0
    ]);

  gl.uniformMatrix4fv(uAffineMat, false, normalMatrix);

  // draw coordinate system
  gl.drawArrays(gl.LINES, n, 4);

}

//@Func: init the WebGL
//@Return: gl(the WebGL context)
function Init() {
  var canvas = document.getElementById(‘webgl‘);

  var gl = getWebGLContext(canvas);
  if(!gl) {
    console.log(‘Failed to get the rendering context for WebGL‘);
    return null;
  }

  if(!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
    console.log(‘Failed to init shader‘);
    return null;
  }

  gl.clearColor(0.3, 1.0, 0.3, 1.0);

  gl.clear(gl.COLOR_BUFFER_BIT);

  return gl;
}

//@Func: init vertices
//@Return: n(the number of vertex)
function InitVertices(gl) {
  var vertexBuffer = gl.createBuffer();
  if(!vertexBuffer) {
    console.log(‘Failed to create vertex buffer‘);
    return -1;
  }

  gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);

  var n = 3;
  var vertices = new Float32Array([
      -0.3,0.0, 0.0,0.5, 0.3,0.0,
      -1.0,0.0, 1.0,0.0, 0.0,-1.0,
      0.0,1.0
    ]);

  gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

  var aPos = gl.getAttribLocation(gl.program, ‘aPos‘);
  if(aPos < 0) {
    console.log(‘Failed to get aPos‘);
    return -1;
  }

  gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);

  gl.enableVertexAttribArray(aPos);

  return n;
}
View Code

 

shader.js

技术分享
// vertical shader
var VSHADER_SOURCE = 
`
  attribute vec4 aPos;
  uniform mat4 uAffineMat;
  void main() {
    gl_Position = uAffineMat * aPos; 
    gl_PointSize = 30.0;
  }
`

// fragment shader
var FSHADER_SOURCE = 
`
  precision mediump float;
  //uniform vec4 uColor;
  void main() {
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
  }
`
View Code

 

以上是关于WebGL -- 仿射变换的主要内容,如果未能解决你的问题,请参考以下文章

仿射变换(CGAffineTransform)使用小结

OpenGL基础仿射变换原理解析

【转】仿射变换及其变换矩阵的理解

Python-移位密码仿射变换解密

使用内在函数提高数组仿射变换的速度

图像处理之_仿射变换与透视变换