使用WebGL讲解3D坐标系下的点的转换矩阵

admin使用WebGL讲解3D坐标系下的点的转换矩阵已关闭评论条评论 159 次浏览

1. 平移 (Translation)

在3D空间中,假设我们需要将一个点平移到另一个位置。假设空间中的一点P,其用坐标表示为(x,y,z);将其向 x方向平移 tx,向y方向平移ty, 向z方向平移tz, 设平移后点的坐标为(x’,y’,z’),则上述点的平移操作可以归纳为如下公式:

2. 缩放 (Scaling)

在3D空间中,对点(x,y,z)常用的另一种操作为相对于另一点(px,py,pz)进行缩放操作,我们不妨x方向的缩放因子为sx,y方向的缩放因子为sy,z方向的缩放因子为sz, 则上述点(x,y,z)相对于点(px,py,pz)的缩放操作可以归纳为如下公式:

3. 旋转(Rotation)

在3D空间中,对点(x,y,z)常用的另一种操作为相对于另一点(px,py,pz)进行旋转操作,我们依旧采用右手坐标系,即旋转角的正方向为逆时针方向。旋转我们可分为绕x轴、y轴、z轴旋转。假设绕x轴旋转角度为alpha,绕y轴旋转角度为beta,绕z轴旋转的角度为gamma。则相应的变换如下:

绕Z轴旋转γ角度,z的坐标不变不变,x、y的坐标发生变化,如果你有兴趣,可以用你高中的三角函数知识推理,可以知道旋转后的坐标:

X=xcosγ-ysinγ,Y=xsinγ+ycosγ

绕X轴旋转α角度

x的坐标不变,y、z的坐标发生变化,Y=ycosα-zsinα,Z=ysinα+zcos

绕Y轴旋转β角度

y的坐标不变,z、x的坐标发生变化,Z=zsinβ+xcosβ,X=zcosβ-xsinβ

使用webGL代码表示

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>作者个人博客 liubf.com</title>
  </head>
  <body>
    <canvas
      id="webgl"
      width="500"
      height="500"
      style="background-color: #0d72da"
    ></canvas>
    <!-- 顶点着色器源码 -->
    <script id="vertexShader" type="x-shader/x-vertex">
        //attribute声明vec4类型变量apos
        attribute vec4 apos;
        void main() {


          // 创建平移矩阵
          //1   0   0  -0.4  // tx
          //0   1   0  -0.4  // ty
          //0   0   1  -0.4  // tz
          //0   0   0    1
          mat4 translation = mat4(1,0,0,0,  0,1,0,0,  0,0,1,0,  -0.4,-0.4,-0.4,1);

          // 缩放矩阵
          // 0.5   0     0    0     // sx
          // 0     0.5   0    0     // sy
          // 0     0     0.5  0     // sz
          // 0     0     0    1
          mat4 scale = mat4(0.5,0,0,0,  0,0.5,0,0,  0,0,0.5,0,  0,0,0,1);


          //设置几何体轴旋转角度为30度,并把角度值转化为弧度值
          float radian = radians(30.0);
          //求解旋转角度余弦值
          float cos = cos(radian);
          //求解旋转角度正弦值
          float sin = sin(radian);
          //引用上面的计算数据,创建绕x轴旋转矩阵
          // 1      0       0    0
          // 0   cosα   sinα   0
          // 0  -sinα   cosα   0
          // 0      0        0   1
          mat4 mx = mat4(1,0,0,0,  0,cos,-sin,0,  0,sin,cos,0,  0,0,0,1);
          //引用上面的计算数据,创建绕y轴旋转矩阵
          // cosβ   0   sinβ    0
          //     0   1   0        0
          //-sinβ   0   cosβ    0
          //     0   0   0        1
          mat4 my = mat4(cos,0,-sin,0,  0,1,0,0,  sin,0,cos,0,  0,0,0,1);
          //创建绕z轴旋转矩阵
          // cosα   sinα    0    0
          //-sinα   cosα    0    0
          //    0      0    1    0
          //    0      0    0    1
          mat4 mz = mat4(cos,-sin,0,0,  sin,cos,0,0,  0,0,1,0,  0,0,0,1);

          //多个旋转矩阵、顶点齐次坐标连乘 运算从右到左 依次变换
          gl_Position = translation*scale*mz*mx*my*apos;




        }
    </script>
    <!-- 片元着色器源码 -->
    <script id="fragmentShader" type="x-shader/x-fragment">

      void main() {
        // 逐片元处理数据,所有片元(像素)设置为红色
        gl_FragColor = vec4(1.0,0.0,0.0,1.0);
      }
    </script>

    <script>
      //通过getElementById()方法获取canvas画布
      var canvas = document.getElementById("webgl");
      //通过方法getContext()获取WebGL上下文
      var gl = canvas.getContext("webgl");

      //顶点着色器源码
      var vertexShaderSource =
        document.getElementById("vertexShader").innerText;

      //片元着色器源码
      var fragShaderSource =
        document.getElementById("fragmentShader").innerText;
      //初始化着色器
      var program = initShader(gl, vertexShaderSource, fragShaderSource);
      //获取顶点着色器的位置变量apos
      var aposLocation = gl.getAttribLocation(program, "apos");

      //创建立方体的顶点坐标数据
      var data = new Float32Array([
        //z为0.5时,xOy平面上的四个点坐标
        0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5,
        //z为-0.5时,xOy平面上的四个点坐标
        0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, 0.5, -0.5, -0.5,
        //上面两组坐标分别对应起来组成一一对
        0.5, 0.5, 0.5, 0.5, 0.5, -0.5,

        -0.5, 0.5, 0.5, -0.5, 0.5, -0.5,

        -0.5, -0.5, 0.5, -0.5, -0.5, -0.5,

        0.5, -0.5, 0.5, 0.5, -0.5, -0.5,
      ]);

      //创建缓冲区对象
      var buffer = gl.createBuffer();
      //绑定缓冲区对象
      gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
      //顶点数组data数据传入缓冲区
      gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
      //缓冲区中的数据按照一定的规律传递给位置变量apos
      gl.vertexAttribPointer(aposLocation, 3, gl.FLOAT, false, 0, 0);
      //允许数据传递
      gl.enableVertexAttribArray(aposLocation);

      //LINE_LOOP模式绘制前四个点
      gl.drawArrays(gl.LINE_LOOP, 0, 4);
      //LINE_LOOP模式从第五个点开始绘制四个点
      gl.drawArrays(gl.LINE_LOOP, 4, 4);
      //LINES模式绘制后8个点
      gl.drawArrays(gl.LINES, 8, 8);

      //声明初始化着色器函数
      function initShader(gl, vertexShaderSource, fragmentShaderSource) {
        var vertexShader = gl.createShader(gl.VERTEX_SHADER);
        var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
        gl.shaderSource(vertexShader, vertexShaderSource);
        gl.shaderSource(fragmentShader, fragmentShaderSource);
        gl.compileShader(vertexShader);
        gl.compileShader(fragmentShader);
        var program = gl.createProgram();
        gl.attachShader(program, vertexShader);
        gl.attachShader(program, fragmentShader);
        gl.linkProgram(program);
        gl.useProgram(program);
        return program;
      }
    </script>
  </body>
</html>

默认效果

应用平移矩阵 x y z 分别平移-0.4

mat4 translation = mat4(1,0,0,0,  0,1,0,0,  0,0,1,0,  -0.4,0,0,1);  
gl_Position = translation*apos; 

平移后的效果

应用缩放矩阵 x y z分别缩放0.5

mat4 scale = mat4(0.5,0,0,0,  0,0.5,0,0,  0,0,0.5,0,  0,0,0,1); 
gl_Position = scale*apos;

缩放后的效果

多重矩阵运算 先缩放后平移

 gl_Position = translation*scale*apos; 

应用旋转矩阵 y->x->z 依次分别旋转30度

/设置几何体轴旋转角度为30度,并把角度值转化为弧度值
          float radian = radians(30.0);
          //求解旋转角度余弦值
          float cos = cos(radian);
          //求解旋转角度正弦值
          float sin = sin(radian);
          //引用上面的计算数据,创建绕x轴旋转矩阵
          // 1      0       0    0
          // 0   cosα   sinα   0
          // 0  -sinα   cosα   0
          // 0      0        0   1
          mat4 mx = mat4(1,0,0,0,  0,cos,-sin,0,  0,sin,cos,0,  0,0,0,1);
          //引用上面的计算数据,创建绕y轴旋转矩阵
          // cosβ   0   sinβ    0
          //     0   1   0        0
          //-sinβ   0   cosβ    0
          //     0   0   0        1
          mat4 my = mat4(cos,0,-sin,0,  0,1,0,0,  sin,0,cos,0,  0,0,0,1);
          //创建绕z轴旋转矩阵
          // cosα   sinα    0    0
          //-sinα   cosα    0    0
          //    0      0    1    0
          //    0      0    0    1
          mat4 mz = mat4(cos,-sin,0,0,  sin,cos,0,0,  0,0,1,0,  0,0,0,1);

          //多个旋转矩阵、顶点齐次坐标连乘 运算从右到左 依次变换
          gl_Position = mz*mx*my*apos;

应用旋转矩阵后 再缩放在平移 多矩阵结合

多个旋转矩阵、顶点齐次坐标连乘 运算从右到左 依次变换

gl_Position = translation*scale*mz*mx*my*apos;

分类目录