中级OpenGL教程 012:手把手封装光照基类、平行光、环境光

0 阅读5分钟

✨ 前言

在三维图形学开发中,光照系统是撑起画面质感的核心基石,和材质 Material 类的设计思路高度相似。合理的面向对象封装,能让各类光源做到结构解耦、易于扩展、复用性拉满。 本文将从零带大家搭建一套标准的光照类继承体系:顶层抽象父类 Light + 派生子类平行光 DirectionalLight环境光 AmbientLight,全程遵循工程化编码规范,拆分头文件与实现文件,适配后续渲染器接入与功能迭代。


Bilibili 同步视频

中级OpenGL教程 012:手把手封装光照基类、平行光、环境光


🌿 一、整体架构规划与目录设计

为了项目结构清晰、便于后期维护,我们在项目 framework 根目录下,单独新建 light 专用文件夹,统一存放所有光照相关类文件:

framework/
└── light/
    ├── Light.h        // 光照基类头文件
    ├── Light.cpp     // 光照基类实现文件
    ├── DirectionalLight.h  // 平行光头文件
    ├── DirectionalLight.cpp// 平行光实现文件
    ├── AmbientLight.h      // 环境光头文件
    └── AmbientLight.cpp    // 环境光实现文件

设计思路:

  1. 所有光源统一继承自 Light 基类,抽取通用光照属性

  2. 不同子类仅扩展自身独有特性,符合面向对象继承、多态思想

  3. 头文件 .h 负责类声明,源文件 .cpp 负责函数实现,隔离声明与定义,预留未来扩展空间。

💡 开发小知识点 哪怕当前构造、析构函数暂无业务逻辑,也要严格拆分 h 与 cpp 文件。后期若需要给光源增加阴影计算、光照衰减、Shader 传参等逻辑,无需改动头文件结构,直接在 cpp 中扩展即可,极大提升项目可维护性。


☀️ 二、光照基类 Light 封装实现

所有光源(平行光、环境光等)都具备两个通用核心属性

  • 光源颜色 / 光照强度 m_color

  • 镜面反射高光强度 m_specular

2.1 Light.h 基类头文件

#pragma once
// 引入图形学必备数学库 glm
#include <glm/glm.hpp>

// 光照顶层基类
class Light
{
public:
    // 构造函数
    Light();
    // 析构函数
    ~Light();

public:
    // 光照颜色,默认初始化为白光 (1.0,1.0,1.0)
    glm::vec3 m_color = glm::vec3(1.0f, 1.0f, 1.0f);

    // 镜面反射高光强度,默认最大强度 1.0
    float m_specular = 1.0f;
};

2.2 Light.cpp 基类实现文件

#include "Light.h"

Light::Light()
{
    // 预留扩展接口:后期可初始化光照参数、绑定全局配置等
}

Light::~Light()
{
    // 预留资源释放接口:后期可释放光照缓存、注销GPU资源等
}

2.3 设计细节解析

  1. 成员变量与成员函数均使用 public 修饰,教学场景下方便快速调用与测试;正式商业工程中建议改为 private,提供对外 get/set 接口做封装

  2. m_color 采用 glm::vec3 存储,分别对应 R、G、B 三个通道,默认白光;

  3. m_specular 控制物体受光后的镜面反射强弱,值越大高光越锐利;

  4. 空构造与空析构不是多余写法,是工程化前置设计,为一年半载后的功能迭代留足扩展入口。


🧭 三、平行光 DirectionalLight 子类实现

平行光特性:仅有照射方向,无实际空间位置,适用于模拟太阳光、远距离自然光等场景。 在继承 Light 基类通用属性基础上,只需额外扩展光照方向独有成员。

3.1 DirectionalLight.h 平行光头文件

#pragma once
#include <glm/glm.hpp>
// 引入父类头文件
#include "Light.h"

// 平行光类,公有继承自Light基类
class DirectionalLight : public Light
{
public:
    DirectionalLight();
    ~DirectionalLight();

public:
    // 平行光照射方向,默认初始化 x/y/z 均为 -1
    glm::vec3 m_direction = glm::vec3(-1.0f, -1.0f, -1.0f);
};

3.2 DirectionalLight.cpp 平行光实现文件

#include "DirectionalLight.h"

DirectionalLight::DirectionalLight()
{
    // 可扩展:方向归一化、默认朝向校准等逻辑
}

DirectionalLight::~DirectionalLight()
{
    // 预留资源回收扩展
}

3.4 核心特性说明

  • 平行光不具备位置属性,只靠 m_direction 决定光线照射角度;

  • 初始化为 (-1,-1,-1) 是图形学常用默认朝向,可根据项目需求自由调整;

  • 自动继承父类 m_colorm_specular 属性,无需重复定义,代码高度复用。


🌤 四、环境光 AmbientLight 子类实现

环境光作用:模拟场景中漫反射的基础环境亮度,让阴影区域不至于完全死黑。 设计极简:环境光仅需要基础光照颜色,所有通用属性已在 Light 基类中定义,子类无需额外扩展任何成员变量

4.1 AmbientLight.h 环境光头文件

#pragma once
#include <glm/glm.hpp>
#include "Light.h"

// 环境光类,公有继承自Light基类
class AmbientLight : public Light
{
public:
    AmbientLight();
    ~AmbientLight();
};

4.2 AmbientLight.cpp 环境光实现文件

#include "AmbientLight.h"

AmbientLight::AmbientLight()
{
    // 可扩展:全局环境亮度统一配置、色调微调等
}

AmbientLight::~AmbientLight()
{

}

4.3 设计亮点

极致精简的继承设计,避免冗余代码; 后期如需给环境光增加全局雾效、环境贴图映射等功能,仅需在子类中少量扩展即可,架构兼容性极强。


📌 五、整体体系总结与后续拓展方向

1. 类体系关系梳理

  • 父类 Light:抽取所有光源通用属性(颜色、高光强度);

  • 子类 DirectionalLight:扩展光照方向,适配太阳光;

  • 子类 AmbientLight:复用基类全部属性,适配全局环境补光。

2. 后续开发规划

当前仅完成光照类体系架构搭建,后续接入渲染器后,可继续实现:

  • 将光照参数传递至 Shader 着色器;

  • 新增点光源、聚光源子类,扩展完整光照类型;

  • 加入光照衰减、阴影映射、PBR 物理光照等高级特性;

  • 统一封装光照管理器,批量管理场景中所有光源对象。

3. 工程化开发心得

图形学开发中,先搭架构、后写业务永远是最优解。通过继承分层、文件拆分、预留扩展接口,既能满足当下开发需求,又能适配长期项目迭代,也是 C++ 大型图形项目的标准设计范式 ✨。

中级OpenGL教程 012:手把手封装光照基类、平行光、环境光