Shader 3d RayMarching4 相机与鼠标控制

坐标系

首先理解一个图形学中常常听到的概念【视图变换(View Transformation)】, 这个变换是计算机图形学中将场景从世界坐标系转换到相机坐标系的过程。先回忆以下坐标系

  1. 世界坐标系 (World Coordinates): 这是物体在三维空间中的实际位置和方向。所有物体和相机的位置、方向都在这个坐标系中定义。
  2. 视图坐标系 (View Coordinates): 这是以相机的位置为原点,相机的视线方向为一个轴建立起来的坐标系。视图变换将世界坐标系中的物体转换到视图坐标系中。
  3. 投影坐标系 (Projection Coordinates): 将3D坐标映射到2D平面上的过程。常见的投影方式有透视投影和正交投影。
  4. 屏幕坐标系 (Screen Coordinates): 最终的2D图像在屏幕上的像素位置。

在rayMarch中, ray的方向函数已经表示了屏幕与透视投影。

glsl 复制代码
     vec3 rayDirection = normalize(vec3(uv.x, uv.y, 1.));

相机函数

视图变换通常通过一个视图矩阵(View Matrix)来实现。这个矩阵将世界坐标转换到以相机位置为中心的坐标系中。在shader中视图矩阵的一般构建过程如下:

  1. 相机的位置 (ro): 相机在世界坐标系中的位置。
  2. 相机的目标 (ta): 相机镜头指向的目标点。
  3. 相机的上方向 (up): 定义相机的"顶部"方向,通常为 (0, 1, 0),表示相机向上的方向。

通过三个参数可以确定以下是那个 矢量

  1. 前向矢量 zaxis: 从相机的位置指向目标点的归一化矢量。表示相机视线的方向。
  2. 右向矢量 xaxis: 上方向和前向矢量的叉积,并归一化。表示相机右手边的方向。
  3. 上向矢量 yaxis: 前向矢量和右向矢量的叉积。表示相机头顶方向。

以三个矢量对应的便是三个角度 Pictch Yaw Roll

  1. Pitch (俯仰角) 定义: pitch 是围绕物体的右向轴(一般为X轴)旋转的角度。这种旋转导致物体前后倾斜,比如从地平面上向上或向下看。 正值: 向上仰视(抬头)。 负值: 向下俯视(低头)。 想象一个飞机的话,当飞机的机头上仰或下俯时,这就是pitch的效果。
  2. Yaw(偏航角) 定义: yaw 是围绕物体的上向轴(一般为Y轴)旋转的角度。这种旋转改变了物体的朝向左右方向,不过不改变其高度。 正值: 向右旋转。 负值: 向左旋转。 像汽车转弯时的场景,当汽车向左或向右转时,这就是yaw的效果。
  3. Roll(滚转角) 定义: roll 是围绕物体前向轴(一般为Z轴)旋转的角度。这种旋转导致物体左右翻滚,如飞机翻滚。 正值: 顺时针旋转(从前向看)。 负值: 逆时针旋转。

一般调试的时候Roll不会使用到,因为人的观察可以左右和上下,但是很少有翻转观察的场景。另外鼠标的变化只有x,y 两个方向, x方向用来控制相机的位置,沿着x axis移动等于沿着目的地旋转。 我个人喜欢y Axis用作pitch, 所以最后我们可以确定生成相机Matrix函数签名为

java 复制代码
mat3 setCamera(vec3 ro, vec3 ta, float pitch)

相机实现

相机主线逻辑主要分为以下4步骤

  1. 计算初始前向(forward)和右向(right)矢量。
  2. 构建 pitch 和 yaw 变换矩阵,用来表示上下旋转和左右旋转。
  3. 应用这些变换矩阵,生成新的前向、上向和右向矢量。
  4. 返回新的相机方向矩阵。
glsl 复制代码
mat3 setCamera(vec3 ro, vec3 ta, float a) {
    vec3 forward = normalize(ta - ro);
    vec3 up = vec3(0., 1.,  0.);
    vec3 right = cross(forward, up);
    
    // pitch
    mat3 pitchMat = mat3(
      cos(a), sin(a), 0.0,
     -sin(a), cos(a), 0.0,
         0.0,    0.0, 1.0
    );
    
    // roll
    mat3 rollMat = mat3(
    1.0,    0.0,    0.0,
    0.0, cos(a), sin(a),
    0.0,-sin(a), cos(a)
    );
     
     
     // yaw
     mat3 yawMat = mat3(
     cos(a), 0.0, sin(a),
        0.0, 1.0, 0.0,
    -sin(a), 0.0, cos(a)
    );
     
     
    vec3 newForward = forward * pitchMat ;
    vec3 newUp = up * pitchMat;
    vec3 newRight = cross(newForward, newUp);
    

    return mat3(newRight, newUp, newForward);
}

鼠标控制

shadertoy里面有 imouse的 unifrom可以用, 用 屏幕坐标x表示旋转角度, y表示 pitch于是有

glsl 复制代码
float theta = 2.0 * PI * iMouse.x/ iResolution.x;
float pitch =  0.1 * PI * (iMouse.y - iResolution.y * .5)/ iResolution.y;
vec3 target = vec3(0.0);
vec3 rayOrigin  = vec3( 10.*cos(theta), 2.0, 10.*sin(theta) );

实现看像世界中心, 相机的位置随鼠标沿着屏幕坐标X的移动,绕世界坐标Y axis 环绕运动

ini 复制代码
vec3 target = vec3(0.0);
vec3 rayOrigin  = vec3( 10.*cos(theta), 2.0, 10.*sin(theta) );

随着camera的变化,我们的rayDirection需要去做 视图变换变换

ini 复制代码
mat3 camera = setCamera( rayOrigin, target, pitch );
vec3 rayDirection = normalize(camera * vec3(uv,1.8) );

最后得到镜头感十足的画面

相关推荐
总要学点什么17 小时前
第96篇:三维数据加载-城市建筑白模样式+着色器——让色带按体量上色,最白的那档却涂不上去
前端·gis·webgl·cesium·着色器·空间分析·白模
总要学点什么2 天前
第97篇:三维数据加载-城市建筑白模自定义着色器——让一条光带沿高度扫上去,快慢却由帧率说了算
前端·gis·webgl·cesium·着色器·空间分析·白模
总要学点什么3 天前
第98篇:三维特效-材质线效果——给一条线换十种材质,虚线的图案只填了一半
开发语言·前端·javascript·ecmascript·gis·webgl·材质
总要学点什么10 天前
第92篇:三维特效-圆(逐渐消逝)——从圆心开始,让一个洞把整片光啃到只剩外圈
gis·webgl·cesium·空间分析·1024程序员节
总要学点什么10 天前
第89篇:三维特效-螺旋圆效果——让螺旋臂卷起一圈圈外扩的涟漪
开发语言·javascript·ecmascript·webgl·cesium·空间分析·1024程序员节
GoldenSpider.AI11 天前
一张户型图做成浏览器 3D 漫游:house.json 统一模型、1.2 m 剖切图纸与分阶段验收
ai编程·webgl·three.js·3d漫游·claude code
Jmyd012313 天前
WebGL 三维党史馆怎么扛住 720 度全景与移动端弱网?
webgl·三维数字化
♡すぎ♡14 天前
SWE 的原理解析
算法·计算机图形学·swe
limit007516 天前
三维 WebGIS 工具选型:加载、样式、分析、交付,一套界面能做完什么
android·前端·web3·安卓·webgl
总要学点什么17 天前
第79篇:数据可视化-模拟迁徙效果——把三十条航线画成会飞的弧
3d·信息可视化·数据挖掘·数据分析·gis·webgl·cesium