一 平移
(1)平移直接体现在代码当中
在二维当中,平移相当于就是改变x,y的位置。
function setRectangle(gl, x, y, width, height) {
var x1 = x;
var x2 = x + width;
var y1 = y;
var y2 = y + height;
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
x1, y1,
x2, y1,
x1, y2,
x1, y2,
x2, y1,
x2, y2
]), gl.STATIC_DRAW);
}
在这段代码当中,要实现矩形的移动,就改变x,y的值即可。x,y的值通过外界可变的方式传入,每改变一次x,y的值就要进行一次重绘矩形,refreshDraw()是对渲染代码进行封装,滑块引入webgl-lessons-ui.js库进行操作。
var translation = [10, 10];
var width = 100;
var height = 30;
var color = [Math.random(), Math.random(), Math.random(), 1];
refreshDraw();
webglLessonsUI.setupSlider("#x", { slide: updatePosition(0), max: webgl.canvas.width });
webglLessonsUI.setupSlider("#y", { slide: updatePosition(1), max: webgl.canvas.height });
function updatePosition(index) {
return function (event, ui) {
translation[index] = ui.value;
refreshDraw();
}
}
结果如下:
(2)平移体现在着色器当中
如果对一个复杂图形进行平移的话,像上述那种代码就比较复杂与繁琐。将平移项加入到着色器当中能够简化代码。比如F的绘制,只需要知道"F"形状的长宽即可,偏移量可不体现在setGeometry()这个函数当中:
function setRectangle(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);
}
偏移量(u_translation)体现在着色器中:
<script id="vertex-shader" type="nojs">
attribute vec2 a_position;
uniform vec2 u_resolution;
uniform vec2 u_translation;
void main(){
vec2 position = a_position + u_translation;
vec2 zeroToOne = position / u_resolution;
vec2 zeroToTwo = zeroToOne * 2.0;
vec2 clipSpace = zeroToTwo - 1.0;
gl_Position = vec4(clipSpace * vec2(1,-1),0,1);
}
</script>
之后的代码都差不多,需要注意的是参数单个分别传入与一起以数组的形式传入的区别:
webgl.uniform2f(resolutionUniformLocation, webgl.canvas.width, webgl.canvas.height);
webgl.uniform2fv(translationUniformLocation, translation);
webgl.uniform4fv(colorUniformLocation, color);
还要注意最后绘制的个数为18个,因为有6个三角形构成了”F“,而每个三角形有3个顶点。
webgl.drawArrays(webgl.TRIANGLES, 0, 18);
以及还要注意一下,加入这行代码与不加的区别:
webglUtils.resizeCanvasToDisplaySize(webgl.canvas);
不加上述那行代码的结果如下:
加了的结果:
二 旋转
有两种理解方式,一是将原来的坐标点乘以单位圆中的某一点来获得旋转后的坐标点,二是根据正余弦来求解旋转后的坐标点。其实二者算是同一种方式,只不过单位圆算是正余弦之后得到的结果了。
利用单位圆(其中中间的加减符号与旋转方向有关,该公式一般作顺时针旋转):
rotatedX = a_position.x * u_rotation.y + a_position.y * u_rotation.x;
rotatedY = a_position.y * u_rotation.y - a_position.x * u_rotation.x;
利用正余弦(其中中间的加减符号与旋转方向有关,也在一定程度上与传入的角度有关,该公式一般作逆时针旋转):
rotatedX = a_position.x * u_cosB - a_position.y * u_sinB;
rotatedY = a_position.y * u_cosB + a_position.x * u_sinB;
旋转量(u_rotation)也体现在着色器当中:
<script id="vertex-shader" type="nojs">
attribute vec2 a_position;
uniform vec2 u_resolution;
uniform vec2 u_translation;
uniform vec2 u_rotation;
void main(){
vec2 rotatedPosition = vec2(
a_position.x * u_rotation.y + a_position.y * u_rotation.x,
a_position.y * u_rotation.y - a_position.x * u_rotation.x);
vec2 position = rotatedPosition + u_translation;
vec2 zeroToOne = position / u_resolution;
vec2 zeroToTwo = zeroToOne * 2.0;
vec2 clipSpace = zeroToTwo - 1.0;
gl_Position = vec4(clipSpace * vec2(1,-1),0,1);
}
</script>
获得属性位置、传参以及加入旋转角度的滑块(代码借助正余弦方式进行实现):
var rotationUniformLocation = webgl.getUniformLocation(program, "u_rotation");
var rotation = [0, 1];
webglLessonsUI.setupSlider("#rotation", { slide: updateAngle, max: 360 });
function updateAngle(event, ui) {
var angleInDegrees = 360 - ui.value;
var angleInRadians = angleInDegrees * Math.PI / 180;
rotation[0] = Math.sin(angleInRadians);
rotation[1] = Math.cos(angleInRadians);
refreshDraw();
}
//不要忘记设置旋转参数
webgl.uniform2fv(rotationUniformLocation, rotation);
结果如下:
三 缩放
缩放跟平移的原理差不多。
缩放大小(u_scale)体现在顶点着色器当中:
<script id="vertex-shader" type="x-shader/x-vertex">
attribute vec2 a_position;
uniform vec2 u_resolution;
uniform vec2 u_translation;
uniform vec2 u_rotation;
uniform vec2 u_scale;
void main(){
vec2 scaledPosition = a_position * u_scale;
vec2 rotatedPosition = vec2(
scaledPosition.x * u_rotation.y + scaledPosition.y * u_rotation.x,
scaledPosition.y * u_rotation.y - scaledPosition.x * u_rotation.x);
vec2 position = rotatedPosition + u_translation;
vec2 zeroToOne = position / u_resolution;
vec2 zeroToTwo = zeroToOne * 2.0;
vec2 clipSpace = zeroToTwo - 1.0;
gl_Position = vec4(clipSpace * vec2(1,-1),0,1);
}
</script>
获得属性位置、传参以及加入缩放大小的滑块:
var scaleUniformLocation = webgl.getUniformLocation(program, "u_scale")
webglLessonsUI.setupSlider("#scalex", { value: scale[0], slide: updateScale(0), min: -5, max: 5, step: 0.01, precision: 2 });
webglLessonsUI.setupSlider("#scaley", { value: scale[1], slide: updateScale(1), min: -5, max: 5, step: 0.01, precision: 2 });
webgl.uniform2fv(scaleUniformLocation, scale);
function updateScale(index) {
return function (event, ui) {
scale[index] = ui.value;
refreshDraw();
}
}
//不要忘记设置缩放参数
webgl.uniform2fv(scaleUniformLocation, scale);
结果如下(x为负值向左缩放,y为负值向上缩放):