Web编程技术营地
研究、演示、创新

视图变换

撰写时间:2023-08-18

修订时间:2026-04-17

视图变换主要解决相机的问题。即观察者站在什么地方,朝哪个方向拍照,以及相机的是否左右旋转的倾斜角度的问题。

本章中,我们准备渲染一前一后的两个三角形。

着色器

顶点着色器的语法与之前模型变换的语法完全一样,只不过变量名改为uViewMatrix

片断着色器无需修改。

JavaScript代码

主干流程

view-matrix.htmlJavaScript的主干代码如下:

import {WebGLUtils} from './js/esm/WebGLUtils-v8.js'; import { GLColors, WireframeMesh, FaceMesh, mat4 } from './js/esm/index-independent.js'; let glu, gl, program; let axisMesh; let mesh1, mesh2; let lookAtMatrix; init(); function init() { initContext(); initViewMatrix(); initMeshes(); render(); }

initContext

引用了顶点着色器中的uViewMatrix。并且,因为两个网格物体有前后遮挡关系,使用代码:

打开景深测试功能,这样,WebGL引擎将在后台自动帮我们计算所有渲染网格物体的前后遮挡关系,并在渲染时将被遮挡的物体消隐掉。可见,WebGL引擎又在后台帮我们干了多少脏活、累活!

initViewMatrix

应用程序中如果只有唯一的一个相机,当摆放好它后,所有的网格物体均应统一使用其视图矩阵。因此将设置视图变换的代码置于只运行一次的initViewMatrix函数中。

mat4lookAt方法用以设置视图变换矩阵

在其参数中,以最后3向量的方式,分别指定了相机位置、所拍摄物体的顶点位置,以及何为相机顶端的朝向。

这里,我们站在坐标值为(0.2, 0.3, 0.5)的位置,看向原点(0.0, 0.0, 0.0),且相机顶端朝上。

设置好视图变换矩阵后,将其向顶点着色器中的uViewMatrix赋值。

initMeshes

设置了分别代表坐标系、位于前方的蓝色三角形、位于后方的绿色三角形共3个网格对象。

render

因之前打开了景深测试,故glclear方法的参数中还需加入gl.DEPTH_BUFFER_BIT位域。

运行网页

发现问题

主要有3个问题。一是两个前后的三角形没有正确地处理景深,后面的三角形没有被遮挡。二是两个三角形均出现了缺失的部分。三是在调试lookAt方法时,很容易出现看似无规律可遁的缺失部分。

这些问题都是由于我们尚未应用投影变换的缘故。

视图变换只解决了相机朝向的问题,但只有投影变换才能根据相机朝向来解决景深视锥体的问题,因此,投影变换视图变换紧密联系。因为投影变换会最终影响视图变换,且这些变换在一个正常的三维应用程序都不可缺少,因此,我们将这些问题延至下一章中集中解决。

本章小结

本章中,我们只需学习掌握下面两点。

一是在顶点着色器中进行设置:

uniform mat4 uViewMatrix; ... void main() { gl_Position = uViewMatrix * aPosition; vColor = aColor; }

二是了解lookAt方法的使用:

function initViewMatrix() { lookAtMatrix = mat4.create(); mat4.lookAt( lookAtMatrix, [0.2, 0.3, 0.5], // eye position [0.0, 0.0, 0.0], // look-at target [0.0, 1.0, 0.0] // up direction ); gl.uniformMatrix4fv(program['uViewMatrix'], false, lookAtMatrix); }

而一旦设置好视图变换,整个场景中所有网格对象的所有顶点位置,立即统一地在后台进行了自动计算、更新后再渲染出来,而其渲染效果,就真的如同我们在拍摄现场,坐在升降机上朝左下角的前方取景一样。

lookAt方法不够直观,以后,我们将以更直观、更便利的方式来操作视图变换

从WebGL引擎看浏览器的开发

这是目前为止,我们的WebGL应用程序第一次渲染出3D效果图。尽管还不够真实。

想像一下,如果不使用矩阵,每当相机的朝向一改变,我们就得自己计算出整个场景中所有网格对象的所有顶点位置后再予以渲染,这得多耗时、耗力、耗资源?! 而这正是矩阵的威力所在,矩阵变换的威力所在,GPU算力的威力所在,着色器的威力所在,WebGL引擎的威力所在。

而在我们使用矩阵后,WebGL引擎只需我们提供一个代表视图变换矩阵,所有这些活都将由WebGL引擎代劳完成了。

是谁给我们带来了这么强大的引擎?

如果您在IE浏览器上运行WebGL应用程序,将会看到,浏览器中什么都不会出现。甚至,连相应的报错信息都没有。因此,不是所有的浏览器都一样,不是所有的浏览器都是名副其实的浏览器。浏览器的功能,不是仅阅读文本内容这么简单。

首先,得有一批资深专家先制订出WebGL标准规范。然后,各浏览器的开发与维护人员在各自浏览器中实现了符合规范的相应功能。再次,我们作为开发人员,遵循规范调用各类APIs开发各种WebGL应用程序。最后,在使用遵循Web标准的浏览器的最终用户的电脑上,才渲染出与规范预期完全一致的图像。

而各种Web标准始终处于不断完善与改进过程中,这也意味着各个浏览器的开发与维护者始终都得跟上,这也正是浏览器不断升级版本的意义所在。

并且由于各种Web标准的数量众多,开发与维护遵循Web标准的浏览器的工作量非常巨大,需要投入大量的人力与物力。在这一点上,开发与维护一个可让我们足以信赖的浏览器的工作量并不亚于开发与维护一个操作系统。

正是Web标准,正是遵循Web标准的浏览器,给我们带来了在网上冲浪时真正酣畅淋漓的快感。

参考资源

Specifications

  1. WebGL 2.0 Specification

glMatrix

  1. mat4.lookAt()