当前位置:  首页>> 技术小册>> 微信小程序全栈开发实战(上)

48 | WebGL介绍(十二):如何创建相机、场景及光源

在WebGL这一强大的图形API中,构建三维场景不仅仅是绘制几何体那么简单,它还需要一个完整的视觉系统来模拟现实世界中的观察方式。这一系统通常由相机(Camera)、场景(Scene)和光源(Light)三大核心组件构成。本章将深入探讨如何在WebGL环境中创建这些关键元素,以实现更加逼真和动态的三维视觉效果。

一、WebGL中的相机

在WebGL中,相机代表了观察者的视角,它决定了哪些三维对象会被渲染到屏幕上,以及这些对象如何被透视变形。WebGL本身并不直接提供相机对象,但我们可以通过设置视图矩阵(View Matrix)和投影矩阵(Projection Matrix)来模拟相机的行为。

1.1 视图矩阵

视图矩阵定义了如何将世界空间中的点转换到观察空间(也称为相机空间或眼空间)。简单来说,就是将整个场景根据相机的位置和朝向进行变换,使得相机位于原点,且面向Z轴负方向。

  • 位置(Position):相机的位置决定了从哪里观察场景。
  • 朝向(Orientation):相机的朝向包括其看向的方向(通常指向Z轴负方向)以及绕Y轴的旋转(即“左右看”)和绕X轴的旋转(即“上下看”)。

创建视图矩阵通常涉及计算相机的逆变换矩阵,这可以通过GLM(GLSL Mathematics)库等数学库轻松实现。

  1. // 假设cameraPosition为相机位置,cameraTarget为相机看向的点,cameraUp为相机向上的方向
  2. mat4 createViewMatrix(vec3 cameraPosition, vec3 cameraTarget, vec3 cameraUp) {
  3. vec3 forward = normalize(vec3(cameraPosition - cameraTarget));
  4. vec3 side = normalize(cross(cameraUp, forward));
  5. vec3 up = cross(forward, side);
  6. return mat4(
  7. vec4(side.x, up.x, -forward.x, 0.0),
  8. vec4(side.y, up.y, -forward.y, 0.0),
  9. vec4(side.z, up.z, -forward.z, 0.0),
  10. vec4(-dot(side, cameraPosition), -dot(up, cameraPosition), dot(forward, cameraPosition), 1.0)
  11. );
  12. }
1.2 投影矩阵

投影矩阵决定了如何将观察空间中的点转换到裁剪空间,并最终映射到屏幕上的二维坐标。WebGL中常用的投影方式有两种:正交投影(Orthographic Projection)和透视投影(Perspective Projection)。

  • 正交投影:保持物体大小不变,常用于绘制二维图像或精确比例的三维场景。
  • 透视投影:模拟人眼观察物体的近大远小效果,使场景更具立体感。

透视投影矩阵的创建相对复杂,需要指定视场角(Field of View, FOV)、纵横比(Aspect Ratio)、近裁剪面(Near Clipping Plane)和远裁剪面(Far Clipping Plane)等参数。

  1. // 假设fovY为视场角(Y轴),aspectRatio为纵横比,near和far为近远裁剪面
  2. mat4 createPerspectiveMatrix(float fovY, float aspectRatio, float near, float far) {
  3. float tanHalfFovY = tan(radians(fovY) / 2.0);
  4. mat4 matrix = mat4(0);
  5. matrix[0][0] = 1.0 / (aspectRatio * tanHalfFovY);
  6. matrix[1][1] = 1.0 / tanHalfFovY;
  7. matrix[2][2] = -(far + near) / (far - near);
  8. matrix[2][3] = -1.0;
  9. matrix[3][2] = -(2.0 * far * near) / (far - near);
  10. matrix[3][3] = 0.0;
  11. return matrix;
  12. }

二、WebGL中的场景

在WebGL中,场景通常指的是一组需要被渲染的三维对象和它们之间的空间关系。虽然WebGL本身不直接管理场景的概念,但开发者可以通过组织和管理这些对象及其属性(如位置、大小、材质等)来构建场景。

2.1 对象管理

可以使用JavaScript对象或类来表示场景中的每一个三维对象,包括其几何体、材质和变换矩阵等信息。通过遍历这些对象,并应用相应的视图矩阵和投影矩阵,可以将它们渲染到屏幕上。

  1. class SceneObject {
  2. constructor(geometry, material, position, rotation, scale) {
  3. this.geometry = geometry;
  4. this.material = material;
  5. this.modelMatrix = mat4.create();
  6. mat4.translate(this.modelMatrix, this.modelMatrix, position);
  7. mat4.rotateX(this.modelMatrix, this.modelMatrix, rotation.x);
  8. mat4.rotateY(this.modelMatrix, this.modelMatrix, rotation.y);
  9. mat4.rotateZ(this.modelMatrix, this.modelMatrix, rotation.z);
  10. mat4.scale(this.modelMatrix, this.modelMatrix, scale);
  11. }
  12. // 渲染方法,需结合视图矩阵和投影矩阵
  13. render(viewMatrix, projectionMatrix) {
  14. // 计算最终变换矩阵
  15. let finalMatrix = mat4.create();
  16. mat4.multiply(finalMatrix, projectionMatrix, viewMatrix);
  17. mat4.multiply(finalMatrix, finalMatrix, this.modelMatrix);
  18. // 使用finalMatrix和geometry, material进行渲染...
  19. }
  20. }

三、WebGL中的光源

光源是影响场景视觉效果的关键因素,它决定了场景中物体的明暗、色彩和阴影等特性。WebGL通过光照模型来模拟光源对物体的影响,常见的光照模型包括环境光(Ambient Light)、漫反射光(Diffuse Light)和镜面反射光(Specular Light)等。

3.1 光源类型
  • 点光源(Point Light):从一个点向四周发射光线,如灯泡。
  • 平行光(Directional Light):从一个方向平行地照射所有物体,如太阳光。
  • 聚光灯(Spotlight):类似手电筒,从一个点发出,但光线被限制在一个锥形区域内。
3.2 光照计算

光照计算通常涉及计算光源对物体每个顶点的光照贡献,并将这些贡献合并到顶点颜色中。这可以通过在顶点着色器中实现光照方程来完成。

  1. // 假设ambientColor为环境光颜色,diffuseColor为漫反射光颜色,specularColor为镜面反射光颜色
  2. // lightPosition为世界空间中的光源位置,viewPosition为世界空间中的观察点位置
  3. // normal为顶点的法线向量,vertexPosition为顶点的世界空间位置
  4. vec3 calculateLight(vec3 ambientColor, vec3 diffuseColor, vec3 specularColor, vec3 lightPosition, vec3 viewPosition, vec3 normal, vec3 vertexPosition) {
  5. vec3 lightDir = normalize(lightPosition - vertexPosition);
  6. vec3 viewDir = normalize(viewPosition - vertexPosition);
  7. vec3 reflectDir = reflect(-lightDir, normal);
  8. float diffuseFactor = max(dot(normal, lightDir), 0.0);
  9. vec3 diffuse = diffuseColor * diffuseFactor;
  10. float specularFactor = 0.0;
  11. if (dot(normal, lightDir) > 0.0) {
  12. float specPower = 32.0; // 镜面高光强度
  13. specularFactor = pow(max(dot(viewDir, reflectDir), 0.0), specPower);
  14. }
  15. vec3 specular = specularColor * specularFactor;
  16. vec3 ambient = ambientColor;
  17. return ambient + diffuse + specular;
  18. }

结语

通过创建相机、场景和光源,WebGL能够模拟出复杂而逼真的三维世界。本章详细介绍了如何在WebGL中设置相机的位置和朝向、构建透视投影矩阵、管理场景中的对象,以及实现基本的光照计算。这些技术是构建任何三维图形应用的基础,掌握了它们,你将能够进一步探索WebGL的无限可能。


该分类下的相关小册推荐: