向量点积的几点应用 - WebGL

·  阅读 360

在数学中,点积(英语:Dot Product)又称数量积或标量积(英语:Scalar Product),是一种接受两个等长的数字序列(通常是坐标向量)、返回单个数字的代数运算。在欧几里得几何中,两个笛卡尔坐标向量的点积常称为内积(英语:Inner Product),见内积空间。

-- wikipedia

应用一:Shader 光晕

为了营造太空的沉浸感,对针对地球额外做了一部分发光效果:

1.gif

这里借助了 Three.js 中的 ShaderMaterial 编写 Shader 代码,利用菲涅耳 Fresnel + 普通光照 Light 以及 Bloom 后处理的方式来实现预期效果(Live Demo 可以点击这里体验,含源码):

2.gif

值得注意的是两个需要传输给 Shader 的变量:用户视角 viewVector(也可以理解为摄像头视角)和 光照角度 LightDir,前者用于构建任意视角下菲涅耳效果始终面向用户,后者用于创建光照效果,最后通过光照范围来决定菲涅耳效果的范围,从而制作出预期的这种效果:

// 顶点着色器
uniform vec3 viewVector;
varying vec3 vNormal;
varying float intensity;
uniform float uAperture;
uniform float uPower;

void main() {
  vNormal = normalize( normalMatrix * normal );
  vec3 viewNormal = normalize( normalMatrix * viewVector );
  intensity = pow(uAperture - dot(vNormal, viewNormal), uPower );
  gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}

// 片元着色器
uniform vec4 uColor;
varying vec3 vNormal;
varying float intensity;
uniform vec3 uLightDir;

void main() {
    vec4 lDirection = viewMatrix * vec4( uLightDir, 0.0 );
    vec3 dirVector = normalize( lDirection.xyz );
    float lightShine = max( 1.5 * dot( vNormal, dirVector ), 0.0 );
    gl_FragColor = intensity * vec4( vec3(lightShine)*uColor.xyz, 1.0 );
}
复制代码

向量点积在这里主要有两个应用点, 计算球体法线向量和摄像机视角向量的点积,当两个向量都是单位向量时,点积结果就是 cosθ,取值 0~1,0 代表方向完全相反,1表示同一方向,0.5 表示垂直:

3.png

第二个应用点是光照的计算,原理和上面一样,唯一不同的就是光照角度,通过光照信息还可以将白天和黑夜两张贴图进行过渡,实现真实的灯光效果:

4.jpeg

5.gif

下面的示意了最终效果以及向量点积计算逻辑(P1 光线向量,P2 摄像机视角向量):

6.gif

应用二:屏蔽视野遮挡

在旋转页面浏览星球时,当前星球容易被其他星球遮挡(特别是缩小当前视角时):

7.gif

同样的,这里通过计算摄像机视角到当前星球的向量 P1,以及摄像机视角到其他星球的向量 P2,判断是否有其他星球出现在视角正前方(Live Demo 可以点击这里体验):

8.gif

应用三:约束摄像机运动幅度

页面中有一个按钮可以允许自动探索其他星球,此时涉及到其他星球的选择以及摄像机的旋转和位移变化,若是随机选择星球,容易因为星球位置在完全相反的方向造成摄像机运动幅度很大,或者说很鬼畜(从水星到海王星会发现摄像机跳跃幅度很大):

9.gif

下 GIF 演示的是原来的方案:随机选择下一个星球,容易出现移动过快的问题(特别是最后从 P3->P5,再从 P7->P5 时的剧变),在真实的场景中体验不佳。

10.gif

经过优化后,会先计算摄像头到当前星球的向量 A,与摄像头到其他星球的向量 B/C/D/E/F/G/...,点积后寻找一个值最大,即变化角度最小的星球(Live Demo 可以点击这里体验):

11.gif

H5 体验二维码:

WeCom20210930-145236@2x.png

分类:
前端
标签: