1542605579614-4723a488-9f04-4ab6-83da-c4b2cdc4a634.png

    此文上接一系列文章,先从基础概念开始,上一篇是物体平移。

    我承认我不知道怎么解释比较好,但是管它呢!先试试吧(这是作者原话,下面也是)。

    首先我想向你介绍一个叫做“单位圆”的东西。如果你还记得初中数学的话(别睡着了啊~喂!),一个圆有一个半径,圆的半径是圆心到圆边缘的距离。单位圆是半径为 1.0 的圆。

    这里有个单位圆。

    image.png

    如果你还记得三年级的数学知识,数字和 1 相乘结果不变。例如 123 * 1 = 123 。非常基础,对吧?那么,单位圆,半径为 1.0 的圆也是 1 的一种形式,它是旋转的 1 。所以你可以把一些东西和单位圆相乘,除了发生一些魔法和旋转之外,某种程度上和乘以 1 相似。

    我们将从单位元上任取一点,并将该点的 X 和 Y 与 之前例子中的几何体相乘。

    这是新的着色器。

    1. <script id="2d-vertex-shader" type="x-shader/x-vertex">
    2. attribute vec2 a_position;
    3. uniform vec2 u_resolution;
    4. uniform vec2 u_translation;
    5. uniform vec2 u_rotation;
    6. void main() {
    7. // 旋转位置
    8. vec2 rotatedPosition = vec2(
    9. a_position.x * u_rotation.y + a_position.y * u_rotation.x,
    10. a_position.y * u_rotation.y - a_position.x * u_rotation.x);
    11. // 加上平移
    12. vec2 position = rotatedPosition + u_translation;

    更新JavaScript,传递两个值进去。

    1. ...
    2. var rotationLocation = gl.getUniformLocation(program, "u_rotation");
    3. ...
    4. var rotation = [0, 1];
    5. ...
    6. // 绘制场景
    7. function drawScene() {
    8. ...
    9. // 设置平移
    10. gl.uniform2fv(translationLocation, translation);
    11. // 设置旋转
    12. gl.uniform2fv(rotationLocation, rotation);
    13. // 绘制几何体
    14. var primitiveType = gl.TRIANGLES;
    15. var offset = 0;
    16. var count = 18; // 6 个三角形组成 'F', 每个三角形 3 个点
    17. gl.drawArrays(primitiveType, offset, count);
    18. }

    这是结果,拖动圆形手柄来旋转或拖动滑块来平移。

    image.png

    CodePen地址

    为什么会这样?来看看数学公式。

    1. rotatedX = a_position.x * u_rotation.y + a_position.y * u_rotation.x;
    2. rotatedY = a_position.y * u_rotation.y - a_position.x * u_rotation.x;

    假如你想旋转一个矩形,在开始旋转之前矩形右上角坐标是 3.0, 9.0 ,让我们在单位圆上以十二点方向为起点顺时针旋转30度后取一个点。

    WebGL 理论基础 - 二维旋转 - 图4

    圆上该点的位置是 0.50 和 0.87

    1. 3.0 * 0.87 + 9.0 * 0.50 = 7.1
    2. 9.0 * 0.87 - 3.0 * 0.50 = 6.3

    这个结果正好是我们需要的结果

    WebGL 理论基础 - 二维旋转 - 图5

    你会发现在我们顺时针旋转到右边的过程中,X 变大 Y 变小。如果我们继续旋转超过90度后,X 变小 Y 变大,这种形式形成了旋转。

    单位圆上的点还有一个名字,叫做正弦和余弦。所以对于任意给定角,我们只需要求出正弦和余弦,像这样

    1. function printSineAndCosineForAnAngle(angleInDegrees) {
    2. var angleInRadians = angleInDegrees * Math.PI / 180;
    3. var s = Math.sin(angleInRadians);
    4. var c = Math.cos(angleInRadians);
    5. console.log("s = " + s + " c = " + c);
    6. }

    如果你吧代码复制到JavaScript控制台,然后输入 printSineAndCosignForAngle(30) ,会打印出 s = 0.49 c = 0.87 (注意:我对结果四舍五入了)。

    如果你把这些组合起来,就可以对几何体旋转任意角度,使用时只需要设置旋转的角度。

    1. ...
    2. var angleInRadians = angleInDegrees * Math.PI / 180;
    3. rotation[0] = Math.sin(angleInRadians);
    4. rotation[1] = Math.cos(angleInRadians);

    这里有一个设置角度的版本,拖动滑块来旋转或平移。

    image.png

    CodePen地址

    希望解释的还过得去,这并不是旋转常用的方式,请继续阅读,我们将会在2篇文章后讲旋转的通用方式。