当前位置:首页 »“秋了秋”个人博客 » 前端编程 » WebGPU教程(说人话)空间裁剪和变换矩阵(四)

WebGPU教程(说人话)空间裁剪和变换矩阵(四)

作者:秋了秋 发表时间:2024年03月22日

    上一章节学习了使用WebGPU绘制3D动态图形,也看到了效果,确实有点3D的效果了

blog_webgpu 3D动画.gif

    但仔细看总觉得哪里不对劲,旋转的时候似乎在变形,每一帧截图来看,发现有些旋转角度下渲染不全,部分内容被裁切了才导致看起来变形了。

webGPU绘图扭曲.jpg

    WebGPU渲染是有空间的,超出空间会被裁剪,xy很好理解,就是超出画布宽高范围被裁切不渲染,同样Z也有,超出Z范围0~1也会被裁切。我们定义的顶点数据是-0.3~0.3,其实一开始就有一半没有显示出来,看看我们定义的顶点x范围是[-0.2, 0.2],z的范围是[-0.3,0.3],x有0.4个单位宽度,z有0.6个单位厚度,但视觉上厚度反而没有宽度感官上大。如果旋转一定角度,角也会跑到z方向的0~1之外被切割。WebGPU的剪辑空间可以看成是一个盒子,超出盒子范围就会被裁剪。

webGPU剪辑空间.jpg

    明白原理之后,要想看到立方体全面目的话,我们可以把立方体整个往屏幕后面(Z)正方向移动即可。上一章节我们用了一个简易的4x4矩阵来实现绕不同轴旋转。除此之外形变矩阵还有平移矩阵缩放矩阵透视投影矩阵,幸运的是他们都可以通过乘积归到一个矩阵来实现所有的各种变换。更幸运的是可以借助gl-matrix矩阵库很轻松地帮我们实现了这些矩阵,我们只需要引入这个矩阵变换库来生成我们想要的矩阵即可,下载地址为https://github.com/toji/gl-matrix/blob/master/dist/gl-matrix.js


下载后我们引入它:

<script src="./gl-matrix.js"></script>

使用矩阵库进行一系列形变操作:

let rotation = 0;
const mat4 = glMatrix.mat4; 
function render() {
    rotation += 0.01;
    const modeMatrix = mat4.create(); // 创建一个4维矩阵
    mat4.translate(modeMatrix, modeMatrix, [0,0,0.5]); // 平移
    mat4.rotate(modeMatrix, modeMatrix, rotation, [1,1,0]); // 旋转
    device.queue.writeBuffer(matrixBuffer,0,modeMatrix.buffer,0,modeMatrix.byteLength);
    ...
}
requestAnimationFrame(render);

    以上代码只是演示矩阵库怎么使用,具体效果请自行调节。


    形变矩阵很好理解,着重看一下透视矩阵,mat4.perspective方法,此矩阵实现一个投影,让物体看上去近大远小,某些场景需要这种效果,也能更大的模拟人眼效果。它有几个参数:

const outMatrix = mat4.create();
mat4.perspective(outMatrix, fovy, aspect, zNear, zFar);

    outMatrix: 需要输出的矩阵;

    fovy: 视椎体的视角,单位是弧度。表示从相机(人眼)出发的光线的角度小,此时同等距离下,可观察到的视野范围较小,反之则大。从物体显示在画板的大小来反映,如果fovy值较大,则物体在画板中所占比例就较少,看起来比较小,反之则显示比较大。符合人眼的条件一般设置为40°~70°之间,注意要转换成弧度。

    aspect: 一般指画布canvas宽高比。定义物体显示在画板上的x和y方向上的比例。aspect小于1,则物体显示出来比实际更高,大于1,显示出来比实际看起来更宽,设为1,会按实际反应长宽比。

    zNear: 近裁切面,单位为像素。定义距离相机(人眼)最近处物体截面相距的距离。这个值越大,表示观测点距离物体距离越远,看起来物体就比较小,反之则比较大。如果物体运动到距离观测点的距离小于了设定的zNear,则物体不会被绘制在画板上。

    zFar: 远裁切面,单位为像素。定义可观测到的物体的最远处截面相距相机的距离。如果物体运动到距离观测点的距离大于了设定的zFar,则物体不会被绘制的画板上。


这看起来还是很难理解,通过图片来理解就会容易得多

视椎体.png

perspective2.png

可以理解为,在near处放一块立着的无限大的不透明挡板,让后挖一个aspect宽高比例的洞口,这个洞口大小根据fov视线角度和near大小决定,眼睛以fov的角度透过洞口观察near和far之间的视椎体内的物体,凡是在视椎体外的物体都被裁切,说人话就是看不见。


如果不用perspective,默认就是正交投影,物体不会有近大远小的效果,适合需要测量的3D预览。


还要注意一点的是zNear和zFar都是从观察者或者相机的视点出发计算的,而不是从世界坐标系的原点出发的。


perspective往往要配合lookAt函数使用,表示眼睛(视点)在三维空间中的位置:

mat4.lookAt(outMatrix, eye, center, up);

    eye: 眼睛的位置,三维向量【x,y,z】;

    center: 眼睛注释的方向,三维向量【x,y,z】;

    up: 头部朝向(说人话:天灵盖方向),跟视线垂直的,三维向量【x,y,z】。[0,1,0]表示头顶朝上,就是正常头人的方向,[0,-1,0]表示倒立看物体。


注意:如果没有调用lookAt设置视图矩阵,默认情况下,相机会被设置为位置在世界坐标系原点,指向z轴负方向,朝上向量为[0,1,0]。

0
文章作者: “秋了秋”个人博客,本站鼓励原创。
转载请注明本文地址:http://netblog.cn/blog/511.html
目录: 前端编程标签: WebGPU,矩阵库 664次阅读

请求播放音乐,请点击播放

登 录
点击获取验证码
还没账号?点击这里