【OSG学习笔记】Day 33: osg::Light和osg::LightSource实现光源
osg::Light 与 osg::LightSource 光源在 OpenSceneGraphOSG三维渲染开发中光照系统是提升场景真实感、塑造模型质感的核心模块。osg::Light负责定义光源的物理属性osg::LightSource负责将光源挂载到场景节点二者协同工作实现平行光、点光源、聚光灯等各类光照效果。本文将从继承关系、核心原理、源码解析、实战代码、效果调优五个维度全面讲解 OSG 光照系统的使用方法。核心类继承关系底层架构OSG 的光照类严格遵循场景图渲染架构清晰的继承关系能帮我们快速理解类的功能定位1. osg::Light 继承链osg::Object → osg::StateAttribute → osg::Lightosg::ObjectOSG 所有对象的基类提供引用计数、克隆等基础能力osg::StateAttribute渲染状态属性基类负责封装 OpenGL 渲染状态如纹理、材质、光照osg::Light光源参数容器仅存储光源的位置、颜色、衰减、方向等数据不参与场景图遍历是「纯数据类」。2. osg::LightSource 继承链osg::Object → osg::Node → osg::LightSourceosg::NodeOSG 场景图节点基类具备遍历、渲染、空间变换能力osg::LightSource光源挂载节点将osg::Light绑定到场景图中控制光源的生效范围、坐标系、渲染时机是「场景执行类」。核心区别总结类功能定位核心作用osg::Light渲染状态StateAttribute定义「光源长什么样」osg::LightSource场景节点Node控制「光源放在哪、何时生效」OSG 光照核心原理OSG 光照完全基于OpenGL 固定管线光照模型实现遵循「全局开关→光源配置→节点挂载→材质配合」的渲染流程开启全局光照必须启用GL_LIGHTING总开关否则所有光源失效启用光源通道OpenGL 最多支持 8 个独立光源GL_LIGHT0~GL_LIGHT7需与osg::Light的编号对应光源属性计算通过环境光、漫反射光、高光、衰减参数模拟真实光照物理效果材质交互光照必须与osg::Material配合材质决定模型对光线的反射能力金属/塑料/哑光质感场景遍历生效osg::LightSource作为场景节点在渲染遍历中传递光源参数到 GPU。关键 API 与参数解析1. osg::Light 核心 API// 设置光源编号对应 GL_LIGHT0~GL_LIGHT7voidsetLightNum(intnum);// 设置光源位置/方向w1.0点光源w0.0平行光voidsetPosition(constVec4pos);// 设置光源颜色环境光/漫反射光/高光voidsetAmbient(constVec4color);// 全局弱光避免背光面全黑voidsetDiffuse(constVec4color);// 主光源决定模型基础亮度voidsetSpecular(constVec4color);// 高光塑造金属/镜面质感// 光源衰减仅点光源/聚光灯生效voidsetConstantAttenuation(floatvalue);// 恒定衰减voidsetLinearAttenuation(floatvalue);// 线性衰减voidsetQuadraticAttenuation(floatvalue);// 二次衰减// 聚光灯参数voidsetSpotCutoff(floatangle);// 聚光角度0~90°voidsetSpotDirection(constVec3dir);// 照射方向2. osg::LightSource 核心 API// 绑定光源对象voidsetLight(osg::Light*light);// 设置光源坐标系RELATIVE_RF随父节点移动ABSOLUTE_RF世界坐标固定voidsetReferenceFrame(ReferenceFrame frame);完整实战代码可直接编译运行以下代码实现通用光照系统支持任意模型加载自动适配光源位置包含完整注释与效果调优参数#includeosgViewer/Viewer#includeosg/Group#includeosg/Light#includeosg/LightSource#includeosg/Material#includeosgDB/ReadFile#includeosgUtil/Optimizer#includeiostream// 为模型添加光照的工具函数osg::ref_ptrosg::GroupcreateLightedScene(osg::ref_ptrosg::Nodemodel){osg::ref_ptrosg::Grouprootnewosg::Group;root-addChild(model);// 1. 获取渲染状态集开启光照开关osg::ref_ptrosg::StateSetstatesetroot-getOrCreateStateSet();stateset-setMode(GL_LIGHTING,osg::StateAttribute::ON);// 全局光照总开关stateset-setMode(GL_LIGHT0,osg::StateAttribute::ON);// 启用0号光源通道// 2. 计算模型包围球自动适配光源位置model-computeBound();constosg::BoundingSphereboundmodel-getBound();// 3. 创建光源对象osg::Lightosg::ref_ptrosg::Lightlightnewosg::Light;light-setLightNum(0);// 绑定 GL_LIGHT0// 光源位置模型正上方 1.5 倍半径处w1.0 → 点光源light-setPosition(osg::Vec4(bound.center().x(),bound.center().y(),bound.center().z()bound.radius()*1.5f,1.0f));// 光源颜色配置通用白色光源适配所有场景light-setAmbient(osg::Vec4(0.3f,0.3f,0.3f,1.0f));// 环境光light-setDiffuse(osg::Vec4(1.0f,1.0f,1.0f,1.0f));// 漫反射光light-setSpecular(osg::Vec4(1.0f,1.0f,1.0f,1.0f));// 高光// 衰减参数无衰减保证模型全亮light-setConstantAttenuation(1.0f);light-setLinearAttenuation(0.0f);light-setQuadraticAttenuation(0.0f);// 4. 创建光源节点osg::LightSource挂载到场景osg::ref_ptrosg::LightSourcelightSourcenewosg::LightSource;lightSource-setLight(light);// 光源坐标系相对父节点随模型移动lightSource-setReferenceFrame(osg::LightSource::RELATIVE_RF);root-addChild(lightSource);// 5. 配置材质光照生效的关键osg::ref_ptrosg::Materialmaterialnewosg::Material;// 基础材质参数material-setAmbient(osg::Material::FRONT,osg::Vec4(1.0f,1.0f,1.0f,1.0f));material-setDiffuse(osg::Material::FRONT,osg::Vec4(1.0f,1.0f,1.0f,1.0f));// 金属质感核心高光泽强高光material-setSpecular(osg::Material::FRONT,osg::Vec4(0.9f,0.9f,0.9f,1.0f));material-setShininess(osg::Material::FRONT,128.0f);// 高光集中度0~128stateset-setAttributeAndModes(material,osg::StateAttribute::ON);returnroot;}intmain(){osgViewer::Viewer viewer;// 加载模型替换为你的模型路径如 cow.osg、teapot.osgosg::ref_ptrosg::NodemodelosgDB::readNodeFile(cow.osg);if(!model){std::cerr错误模型加载失败std::endl;return-1;}// 构建带光照的场景osg::ref_ptrosg::GroupscenecreateLightedScene(model);// 优化场景提升渲染性能osgUtil::Optimizer optimizer;optimizer.optimize(scene);// 运行渲染viewer.setSceneData(scene);returnviewer.run();}代码核心逻辑解析光照开关GL_LIGHTING是全局总开关GL_LIGHT0是具体光源通道必须一一对应自动适配位置通过模型包围球计算光源位置无需手动调整适配任意大小模型光源类型setPosition的w分量决定光源类型1.0点光源、0.0平行光材质关键无材质则光照不生效setShininess控制高光集中度是塑造金属质感的核心参数坐标系RELATIVE_RF让光源随模型移动适合车灯、设备自带光源ABSOLUTE_RF适合场景固定光源如路灯、太阳光。光源类型快速切换1. 平行光太阳光// w0.0 → 方向为 (0,0,-1)从正上方照射light-setPosition(osg::Vec4(0.0f,0.0f,-1.0f,0.0f));2. 聚光灯手电筒light-setPosition(osg::Vec4(0,0,5,1.0f));light-setDirection(osg::Vec3(0,0,-1));light-setSpotCutoff(30.0f);// 30°聚光角度light-setSpotExponent(16.0f);// 聚光强度常见问题与解决方案模型全黑未开启GL_LIGHTING、未配置osg::Material、光源编号与通道不匹配无金属质感材质setSpecular颜色过暗、setShininess值过低建议 80~128光源不随模型移动将LightSource坐标系改为RELATIVE_RF多光源失效OpenGL 最多支持 8 个光源需分配不同编号GL_LIGHT0~GL_LIGHT7。总结架构核心osg::Light是「光源数据」osg::LightSource是「场景节点」继承关系决定功能定位生效三要素开启光照开关、配置光源参数、绑定材质质感塑造通过高光Specular和光泽度Shininess实现金属、哑光、塑料等不同效果实战价值本文代码可直接复用适配任意模型是 OSG 三维场景渲染的基础必备模块。