Chapter 15 · 渲染管线

相机系统:透视投影

学习 XGE 的透视投影相机,理解 FOV、近远裁剪面的含义,实现 2.5D 透视效果。

15

概念:透视投影

透视投影模拟人眼观察——远处的物体看起来更小。XGE 虽然是 2D 引擎,但通过透视相机 + xgeDrawQuad3D 可以实现 2.5D 效果(如倾斜的棋盘地面、卡片翻转动画)。

关键参数:
• fFovY:垂直视场角(度),越大视野越广、物体越小
• fNearZ:近裁剪面,比这更近的物体不渲染
• fFarZ:远裁剪面,比这更远的物体不渲染

API 速查

函数说明
xge_camera_t xgeCameraPerspective(float fWidth, float fHeight, float fFovY, float fNearZ, float fFarZ)创建透视投影相机
void xgeCameraSet(const xge_camera_t* pCamera)设置当前相机
xge_camera_t xgeCameraGet(void)获取当前相机

编译本章示例

gcc -O2 -I. -o ch15.exe ch15_main.c build\xge.lib -lm -lws2_32 -liphlpapi -lgdi32 -luser32 -lshell32 -lopengl32 -lole32 -lwinmm -lavrt
.\ch15.exe

透视相机字段说明

字段典型值说明
iProjectionModeXGE_CAMERA_PERSPECTIVE (1)标记为透视模式
fFovY45°–90°垂直视场角(度)
fNearZ0.1近裁剪面距离
fFarZ1000.0远裁剪面距离
fPerspectiveDistance自动计算相机到投影平面的距离

示例 1:基本透视相机

static int onFrame(void* pUser) {
    xgeClear(0x081114FF);

    // 创建透视相机
    xge_camera_t cam = xgeCameraPerspective(
        800.0f,    // 视口宽度
        600.0f,    // 视口高度
        60.0f,     // 垂直 FOV 60 度
        0.1f,      // 近裁剪面
        1000.0f    // 远裁剪面
    );
    xgeCameraSet(&cam);

    // 开启深度测试(透视场景推荐)
    xgeDepthTestSet(1);

    // 绘制 3D 四边形(透视效果)
    // xgeDrawQuad3D(...);

    xgeDepthTestSet(0);
    return XGE_OK;
}

示例 2:调整 FOV 对比效果

// 窄 FOV → 类似长焦镜头,透视变形小
xge_camera_t tele = xgeCameraPerspective(800, 600, 30.0f, 0.1f, 500.0f);

// 标准 FOV → 接近人眼
xge_camera_t normal = xgeCameraPerspective(800, 600, 60.0f, 0.1f, 500.0f);

// 广角 FOV → 夸张透视,边缘畸变
xge_camera_t wide = xgeCameraPerspective(800, 600, 110.0f, 0.1f, 500.0f);

// 按 1/2/3 键切换
if (xgeKeyPressed('1')) xgeCameraSet(&tele);
if (xgeKeyPressed('2')) xgeCameraSet(&normal);
if (xgeKeyPressed('3')) xgeCameraSet(&wide);

示例 3:动态 FOV 动画(呼吸效果)

static int onFrame(void* pUser) {
    double t = xgeTimer();

    // FOV 在 50°~70° 之间正弦呼吸
    float fov = 60.0f + 10.0f * (float)sin(t * 0.8);

    xge_camera_t cam = xgeCameraPerspective(800, 600, fov, 0.1f, 800.0f);
    xgeCameraSet(&cam);

    xgeClear(0x081114FF);
    // ... 绘制场景 ...
    return XGE_OK;
}

正交 vs 透视对比

特性正交 (ORTHO)透视 (PERSPECTIVE)
远处物体大小不变变小
平行线保持平行汇聚于灭点
典型用途2D 游戏、UI、CAD2.5D 效果、卡片动画
深度测试通常不需要推荐开启
创建函数xgeCameraDefaultxgeCameraPerspective

完整代码

将以下代码保存为 ch15_main.c,编译后运行即可观察动态 FOV 呼吸效果:

#include "xge.h"
#include <math.h>

static int onFrame(void* pUser) {
    (void)pUser;
    double t = xgeTimer();

    // FOV 在 50°~70° 之间正弦呼吸
    float fov = 60.0f + 10.0f * (float)sin(t * 0.8);

    xge_camera_t cam = xgeCameraPerspective(800.0f, 600.0f, fov, 0.1f, 800.0f);
    xgeCameraSet(&cam);

    xgeClear(0x081114FF);

    // 绘制参考图形(透视效果下会随 FOV 变化)
    xgeShapeRectFill(250, 200, 300, 200, 0x4FD8C2FF);
    xgeShapeCircleFill(400, 300, 60, 0xFFB454FF);

    return XGE_OK;
}

int main(void) {
    xge_desc_t d = {0};
    d.iWidth  = 800;
    d.iHeight = 600;
    d.sTitle  = "ch15 - Perspective Camera";
    d.iFlags  = XGE_INIT_VSYNC;
    xgeInit(&d);
    xgeRun(onFrame, NULL);
    xgeUnit();
    return 0;
}

代码讲解

  • xgeCameraPerspective(w, h, fov, near, far) 创建透视相机,fov 单位为度。
  • xgeTimer() 返回引擎启动以来的秒数,驱动 FOV 正弦动画。
  • FOV 越大视野越广、物体越小;越小则类似长焦镜头。
  • 透视相机主要影响 3D 绘制函数,普通 2D Shape 仍用屏幕坐标。

要点与陷阱

  • 近远裁剪面:fNearZ 不能为 0(会导致除零),推荐 0.1。fFarZ 过大会降低深度精度。
  • FOV 单位是度:不是弧度。60° 是常用默认值。
  • 配合深度测试:透视场景中物体有真实前后关系,应开启 xgeDepthTestSet(1)。
  • 2D 绘制不受影响:透视相机只影响 3D 绘制函数(如 xgeDrawQuad3D)。普通 2D Shape 绘制仍使用屏幕坐标。
  • fPerspectiveDistance:由引擎根据 FOV 和视口高度自动计算,通常不需手动设置。

进阶练习

  1. 用透视相机 + xgeDrawQuad3D 绘制一个旋转的立方体(6 个面)。
  2. 实现"鱼眼"效果:将 FOV 设为 150°+,观察极端畸变。
  3. 实现一个相机动画:从正交平滑过渡到透视(插值 iProjectionMode 相关参数)。
相机系统:透视投影效果
图:相机系统:透视投影渲染效果