一、光照

OSG全面支持OpenGL的光照特性,包括材质属性(material property)、光照属性(light property)和光照模型(lighting model)与OpenGL相似,OSG中的光源也是不可见的,而非渲染一-个灯泡或其他自然形状。同样,光源会创建着色效果,但并不创建阴影,osgShadow 可以用来创建阴影。

二、 osg::Light 类

OSG将OpenGL中的glLight(0作了-一个 light状态的类封装,用于保存灯光的模式与属性参数息。osg:Light类派生自os::tateAtribute类,继承了对模式与属性参数信息的操作接口。在os:light类中通过apply (State&state) 函数将灯光的状态参数信息应用到OpenGL的状态机中。

2.1 osg::Light类包括的属性参数如下:

int lightnum; /灯光数量
Vec4 ambient; //环境光颜色
Vec4_ diffuse; //漫射光颜色
Vec4 specular; //镜面光颜色
Vec4_ position; //光源的位置信息
Vec3 direction; //光源的方向
float_ constant attenuation; //常量衰减
float linear attenuation; //线性衰减
float quadratic attenuatin//二次方衰减
float spot exponent; /指数衰减
float spot cutof, /I关闭衰减 (spread)

上面的参数应该都比较容易理解。OSG支持最多8个光源,即GL. _LIGHTO~ GL_ LIGHT7,这与读者的OpenGL版本也有关系。

2.2osg:LightSource类

osg:LightSource类直接继承自osg::Group。 作为-一个灯光管理类,继承了osg::Group 类的管理节点的接口;将灯光作为-一个节点可以加入到场景图中进行渲染。

osg::LightSource类中的成员函数为:

void setReferenceFrame (ReferenceFrame rf//设置帧引用

帧引用包括如下两个枚举变量:enum ReferenceFrame

RELATIVE RF,
//相对帧引用
ABSOLUTE RF
//绝对帧引用

设置光源的引用帧时,不是相对于父节点的帧引用,就是相对于绝对坐标的帧,默认的设置为RELATIVE RF,设置帧引用为RELATIVE RF同样会设置CullingActive的标志量为开(ON)状态,并且对它的父节点也起作用:否则,对它与它所有的父节点都禁用拣选(Culling),对防止不合适的拣选是必需的,如果绝对光源在场景图的深处将会对拣选的时间有影响,因此,推荐在场景的顶部使用绝对的光源。

三、 场景中使用光源

在一个场景中添加光源主要包括以下步骤:

(1)指定场景模型的法线。

(2)允许光照并设置光照状态。

(3)指定光源属性并关联到场景图形。

对于场景中的模型,只有当其中没有单位法线时才会正确地显示光照。当场景中的模型没有指定法线时,可以用前面讲到的ostUi::SmoothingVisitor自动生成法线。需要注意的是,法向量必须单位化。有时场景中的模型虽然指定了单位法向量,但是光照的计算结果过于明亮或过于暗淡(可能是缩放变换造成的),这时最有效的解决方案是在StateSet中允许法线的重放缩模式,代码如下:

osg:StateSet*state - geode >setOrCreateStateSetO;
state->setMode(GL RESCALE NORMAL, osg:StateAtribute::ON);

与在OpenGL中相同,这特性可以保证法线在均匀放缩变换时仍然保持单位长度。如果场最中的放缩变换是非均匀的,那么读者可以允许法线归-化模式,以保证法线为单位长度。由于要进行法线的重新放缩,归一化模式往往会耗费大量的时间,编程时要尽量避免。归一化模式的代码如下:

osg:StateSet*state = geode >setOrCreateStateSctO;
state- >setMode(GL NORMALIZE, osg:StateAttribute::ON);

要在OSG中获得光照效果,需要允许光照并至少允许一个光源。程序osgviewer在默认情况下就是这样做的,它在根节点的StateSet 中已经设置了相应的模式。读者可以在自己的程序中进行相同的设置。下面的代码段用于允许光照并为根节点的StateSet允许两个光源(GL LIGHTO和GL LIGHT1):

osg:StateSet*state = root->getOrCreateStateSetO;
state->setMode(GL LIGHTING, osg:tatatribte::ON):
state- >setMode(GL LIGHTO, osg:StatcAtribute::ON);
state- >setMode(GL LIGHTI, osg::StateAttribute::ON);

在场景中添加一一个光源,可以创建一个osg:Light对象以定义光源参数,然后将osg:Light添加到一个osg:LightSource节点中,并将LightSource节点添加到场景图形。osg:LightSource 是一个包含了唯-的Light定义的高效的组节点,而由osg:Light定义的光源将对整个场景产生影响。下面的代码实现将osg:Light添加到osg:LightSource对象中:

og:ref ptrosg:LightSource> Is = new osg:LightSource;

在实际生活中,当光照照射到物体上时都会反射等现象,所以,在对光源的设置完成以后需要设

置模型的表面材质。

四、实例(聚光灯)

#include <osg/Node>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/Group>
#include <osg/Camera>
#include <osg/MatrixTransform> //移动节点的矩阵类,最常用的移动节点的类。可随动、旋转控制节点。
#include <osg/PositionAttitudeTransform>
#include <osg/Light> //继承自osg::StateAttribute,保存灯光的模式与属性参数信息
#include <osg/LightSource> //继承自osg::Group,灯光管理类,继承了osg::Group类的管理节点的接口,将灯光作为一个节点加入到场景图中进行渲染
#include <osg/ShapeDrawable>
#include <osg/TexGen>
#include <osg/Texture2D>
#include <osg/TexGenNode>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osgUtil/Optimizer>
#include <osgViewer/Viewer>
#include "../Delaunay/Tex.h"
/**创建聚光灯纹理贴图*创建聚光灯状态属性(前面的纹理贴图也是渲染状态属性之一)*创建聚光灯节点*创建路径动画*创建地形平面(在场景中将之直接设置为模型牛)*创建动画模型(路径为前面设置好的路径动画),将聚光灯节点添加添加到其中,则聚光灯是动态的(飞机)*创建场景:创建动画模型和地形平面(此处设为飞机),动画模型为聚光灯位置,地形平面(牛)为聚光灯照射的地方;将状态属性添加到组节点*则飞机飞到哪个地方(即聚光灯在哪里),牛的哪个地方就照亮
*/
//创建聚光灯纹理的mipmap贴图
osg::ref_ptr<osg::Image> createSpotLightImage(const osg::Vec4 centerColour, const osg::Vec4& backgroudColour, unsigned int size, float power)
{//创建Image对象osg::ref_ptr<osg::Image> image = new osg::Image();//动态分配一个size*size大小的imageimage->allocateImage(size, size, 1, GL_RGBA, GL_UNSIGNED_BYTE);//填充image//以中心为原点,颜色逐渐向四周衰减float mid = (float(size) - 1) * 0.5f;//float div = 2.0f / float(size);float div = 4.0f / float(size);for (unsigned int r = 0; r < size; ++r){unsigned char* ptr = image->data(0, r, 0);for (unsigned int c = 0; c < size; ++c){float dx = (float(c) - mid) * div;float dy = (float(r) - mid) * div;float r = powf(1.0f - sqrtf(dx * dx + dy * dy), power);if (r < 0.0f)r = 0.0f;osg::Vec4 color = centerColour * r + backgroudColour * (1.0f - r);*ptr++ = (unsigned char)((color[0]) * 255.0f);*ptr++ = (unsigned char)((color[1]) * 255.0f);*ptr++ = (unsigned char)((color[2]) * 255.0f);*ptr++ = (unsigned char)((color[3]) * 255.0f);}}return image.release();
}
//创建聚光灯状态属性
osg::ref_ptr<osg::StateSet> createSpotLightDecoratorState(unsigned int lightNum, unsigned int textureUnit)
{//设置中心的颜色和环境光的颜色osg::Vec4 centerColour(1.0f, 1.0f, 1.0f, 1.0f);osg::Vec4 ambientColour(0.5f, 0.5f, 0.5f, 1.0f);//创建聚光灯纹理osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D();texture->setImage(createSpotLightImage(centerColour, ambientColour, 64, 1.0));texture->setBorderColor(osg::Vec4(ambientColour));texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_BORDER);texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_BORDER);texture->setWrap(osg::Texture::WRAP_R, osg::Texture::CLAMP_TO_BORDER);osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet();//开启ID为lightNum的光照stateset->setMode(GL_LIGHT0 + lightNum, osg::StateAttribute::ON);//设置自动生成纹理坐标stateset->setTextureMode(textureUnit, GL_TEXTURE_GEN_S, osg::StateAttribute::ON);stateset->setTextureMode(textureUnit, GL_TEXTURE_GEN_T, osg::StateAttribute::ON);stateset->setTextureMode(textureUnit, GL_TEXTURE_GEN_R, osg::StateAttribute::ON);stateset->setTextureMode(textureUnit, GL_TEXTURE_GEN_Q, osg::StateAttribute::ON);//打开纹理单元stateset->setTextureAttributeAndModes(textureUnit, texture.get(), osg::StateAttribute::ON);return stateset.release();
}
//创建聚光灯节点
osg::ref_ptr<osg::Node> createSpotLightNode(const osg::Vec3& position, const osg::Vec3& direction, float angle, unsigned int lightNum, unsigned int textureUnit)
{//创建光源osg::ref_ptr<osg::LightSource> lightsource = new osg::LightSource();osg::ref_ptr<osg::Light> light = lightsource->getLight();light->setLightNum(lightNum);light->setPosition(osg::Vec4(position, 1.0f));light->setAmbient(osg::Vec4(0.00f, 0.00f, 0.05f, 1.0f));light->setDiffuse(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f));//计算法向量osg::Vec3 up(0.0f, 0.0f, 1.0f);up = (direction ^ up) ^ direction;up.normalize();//创建自动生成纹理坐标节点osg::ref_ptr<osg::TexGenNode> texgenNode = new osg::TexGenNode();//关联纹理单元texgenNode->setTextureUnit(textureUnit);//设置纹理坐标生成器osg::ref_ptr<osg::TexGen> texgen = texgenNode->getTexGen();//设置模式为视觉线性texgen->setMode(osg::TexGen::EYE_LINEAR);//从视图中指定参考平面texgen->setPlanesFromMatrix(osg::Matrixd::lookAt(position, position + direction, up) * osg::Matrixd::perspective(angle, 1.0, 0.1, 100));osg::ref_ptr<osg::Group> group = new osg::Group();group->addChild(lightsource);group->addChild(texgenNode.get());return group.release();
}
//创建动画路径
osg::ref_ptr<osg::AnimationPath> createAnimationPath(const osg::Vec3 center, float radius, double looptime)
{osg::ref_ptr<osg::AnimationPath> animationPath = new osg::AnimationPath();animationPath->setLoopMode(osg::AnimationPath::LOOP);int numSamples = 40;float yaw = 0.0f;float yaw_delta = 2.0f * osg::PI / ((float)numSamples - 1.0f);float roll = osg::inDegrees(30.0f);double time = 0.0f;double time_delta = looptime / (double)numSamples;for (int i = 0; i < numSamples; ++i){osg::Vec3 position(center + osg::Vec3(sinf(yaw) * radius, cosf(yaw) * radius, 0.0f));osg::Quat rotation(osg::Quat(roll, osg::Vec3(0.0, 1.0, 0.0)) * osg::Quat(-(yaw + osg::inDegrees(90.0f)), osg::Vec3(0.0, 0.0, 1.0)));animationPath->insert(time, osg::AnimationPath::ControlPoint(position, rotation));yaw += yaw_delta;time += time_delta;}return animationPath.release();
}
//创建地形平面
osg::ref_ptr<osg::Node> createBase(const osg::Vec3 center, float radius)
{osg::ref_ptr<osg::Geode> geode = new osg::Geode;osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet();osg::ref_ptr<osg::Image> image = osgDB::readImageFile("Images/lz.rgb");if (image.get()){osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D();texture->setImage(image.get());stateset->setTextureAttributeAndModes(0, texture.get(), osg::StateAttribute::ON);}geode->setStateSet(stateset.get());osg::ref_ptr<osg::HeightField> grid = new osg::HeightField();grid->allocate(38, 39);grid->setOrigin(center + osg::Vec3(-radius, -radius, 0.0f));grid->setXInterval(radius * 2.0f / (float)(38 - 1));grid->setYInterval(radius * 2.0f / (float)(39 - 1));float minHeight = FLT_MAX;float maxHeight = -FLT_MAX;unsigned int r;for (r = 0; r < 39; ++r){for (unsigned int c = 0; c < 38; ++c){//error:vertex未定义float h = vertex[r + c * 39][2];if (h > maxHeight)maxHeight = h;if (h < minHeight)minHeight = h;}}float heightScale = radius * 0.5f / (maxHeight - minHeight);float heightOffset = -(minHeight + maxHeight) * 0.5f;for (r = 0; r < 39; ++r){for (unsigned int c = 0; c < 38; ++c){//error:vertex未定义float h = vertex[r + c * 39][2];grid->setHeight(c, r, (h + heightOffset) * heightScale);}}geode->addDrawable(new osg::ShapeDrawable(grid.get()));osg::ref_ptr<osg::Group> group = new osg::Group();group->addChild(geode.get());return group.get();
}
//创建动画模型
osg::ref_ptr<osg::Node> createMovingModel(const osg::Vec3 center, float radius)
{osg::ref_ptr<osg::Group> model = new osg::Group();osg::ref_ptr<osg::Node> cessna = osgDB::readNodeFile("cessna.osg");if (cessna.get()){const osg::BoundingSphere& bs = cessna->getBound();float size = radius / bs.radius() * 0.3f;osg::ref_ptr<osg::MatrixTransform> positioned = new osg::MatrixTransform();positioned->setDataVariance(osg::Object::STATIC);positioned->setMatrix(osg::Matrix::translate(-bs.center()) * osg::Matrix::scale(size, size, size) * osg::Matrix::rotate(osg::inDegrees(180.0f), 0.0f, 0.0f, 2.0f));positioned->addChild(cessna.get());float animationLength = 10.0f;osg::ref_ptr<osg::AnimationPath> animationPath = createAnimationPath(center, radius, animationLength);osg::ref_ptr<osg::MatrixTransform> xform = new osg::MatrixTransform();xform->setUpdateCallback(new osg::AnimationPathCallback(animationPath, 0.0f, 2.0));xform->addChild(positioned);//添加聚光灯节点xform->addChild(createSpotLightNode(osg::Vec3(0.0f, 0.0f, 0.0f), osg::Vec3(0.0f, 1.0f, -1.0f), 60.0f, 0, 1));model->addChild(xform.get());}return model.release();
}
//创建场景
osg::ref_ptr<osg::Node> createModel()
{osg::Vec3 center(0.0f, 0.0f, 0.0f);float radius = 100.0f;//创建动画模型osg::ref_ptr<osg::Node> shadower = createMovingModel(center, radius * 0.5f);//创建地形平面osg::ref_ptr<osg::Node> shadowed = osgDB::readNodeFile("cow.osg");osg::ref_ptr<osg::Node> shadowed1 = createBase(center - osg::Vec3(0.0f, 0.0f, radius * 0.1), radius);//创建场景组节点osg::ref_ptr<osg::Group> root = new osg::Group();//设置状态属性root->setStateSet(createSpotLightDecoratorState(0, 1));//添加子节点root->addChild(shadower.get());root->addChild(shadowed.get());root->addChild(shadowed1.get());return root.release();
}
int main()
{osg::ref_ptr<osg::Group> root = new osg::Group();root->addChild(createModel());//优化场景数据osgUtil::Optimizer optimizer;optimizer.optimize(root.get());osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();viewer->setSceneData(root.get());viewer->realize();return viewer->run();
}

快速学习OSG(5)——light-聚光灯相关推荐

  1. 快速学习OSG(2)——光照

    一.光照简介         OSG 全面支持 OpenGL 的光照特性,包括材质属性(material property),光照属性(light property)和光照模型(lighting mo ...

  2. 快速学习OSG(6)——立方图纹理(天空盒)

    一.立方图 立方图纹理是一种特殊的技术,它是-一个由6幅二维图像构成的.以原点为中心的纹理立方体.对于每个片段而言,纹理坐标(S,T,R)都被 当作-个方向向量来看待,每个纹理单元表示从原点所看到的纹 ...

  3. 快速学习OSG(7)——几何体操作(简化几何体和三角网的绘制)

    一.几何体 大家都知道场景都是由基本的绘图基元构成的,基本的绘图基元构成简单的几何体,简单的儿何体构成复杂的几何体,复杂的几何体最终构造成复杂的场景.当多个几何体组合时,可能存在多种降低场景渲染效率的 ...

  4. Unity 3D光源-Spot Light聚光灯用法详解、模拟手电筒、台灯等线性教程

    Unity4大光源之聚光灯 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人! (拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- 心分享 ...

  5. 低俗英语一百句----快速学习英语的一个好方法

    低俗英语一百句----快速学习英语的一个好方法 1.I asked God for a bike, but I know God doesn't work that way. So I stole a ...

  6. 业余快速学习虚幻引擎教程

    仅用5小时学会虚幻引擎! 你会学到什么 专为希望在业余时间打造虚幻引擎技能的艺术家和开发人员量身定制的专业技术 从几何图形到材料,从照明到互动,所有方面的提示 探索如何创造建筑水的效果 如何使用顶点绘 ...

  7. 零基础快速学习Java技术的方法整理

    在学习java技术这条道路上,有很多都是零基础学员,他们对于java的学习有着很多的不解,不知怎么学习也不知道如何下手,其实Java编程涉及到的知识点还是非常多的,我们需要制定java学习路线图这样才 ...

  8. 怎样快速学习html5,如何快速学习HTML5?带你了解HTML5学什么?

    今天小编要为大家分享的文章是关于如何快速学习HTML5?HTML5主要学些什么的文章.近年来前端开发非常热门,前端开发工程师也很稀缺,于是很多人将其视为高薪行业的代名词.HTML5前端开发工程师被称作 ...

  9. 新手搭ssm要多久_如何快速学习ssm 框架?

    要快速学习SSM框架,你需要一套学习曲线平滑的教程 1. 很快可以看到效果 SSM框架这种教程的,在百度或者git上一搜一大把,不过很遗憾,大部分你照着上面的流程做,是做不出来的,要么缺少包,要么配置 ...

  10. MySQL主从原理,基于快速学习一门技术的3种方式!

    根据经验,想要快速学习一门技术有3种方式. 第一种方式是通过代码来理解它的实现,反推它的逻辑. 这种方式的难度很大,而且起点相对高,能够沉浸其中的人非常少,过程相对来说是苦闷的,但如果能够沉下心来看代 ...

最新文章

  1. crt证书iis 中引用 程序目录提示 System.UnauthorizedAccessException:拒绝访问
  2. MySQL中定义fk语句_MySQL基础篇/第3篇:MySQL基本操作语句.md · qwqoo/MySQL-Review - Gitee.com...
  3. python gzipped source tarball,下载及安装Python详细步骤
  4. 调整搜索二叉树中两个错误的节点
  5. 洛谷P2016战略游戏
  6. SAP Spartacus B2B页面的BodyContent position
  7. RED5 安装及问题
  8. mysql binlog 备份恢复数据_Mysql结合备份+binlog恢复误删除操作数据
  9. 动态设置HTML:v-html
  10. OFFICE拼写语法检查:全部忽略、全部更正的功能
  11. Python机器学习实战1
  12. php 度分秒和小数转化
  13. MySql 查询比其中某一位讲师工资少的教师姓名、工资和职称
  14. Ubuntu12.10 使用DNW传数据 进行ARM开发板烧写
  15. 怎样清理苹果手机内存空间_你还不知道?苹果手机这样清理垃圾,轻松腾出10G内存!...
  16. Thread 1: signal SIGABRT解决方法之一
  17. ElasticSearch 从零到入门
  18. Nginx 对俄罗斯动手了。。。
  19. NFC无线充电(WLC)介绍
  20. linux 打印两个文件内容相同行和不同行(交集和差集)

热门文章

  1. 进程结构之CKPT与SCN (小猫爪印二)
  2. 用AI加码,CES Asia 2018将如何成就珍贵稀缺的科技盛会?
  3. 持续集成(CI)、自动化构建和自动化测试--初探
  4. 在中国怎么做咨询?中国企业需要什么样的咨询?
  5. Memos-碎片化知识卡片管理工具
  6. msbuild不是内部或外部命令
  7. wangEditor富文本编辑器的调用开发实录(v5版本、获取HTML内容、上传图片、隐藏上传视频)
  8. NCTF-2019-Crypto部分 复现
  9. 愚人节不愚人:用H5营销引爆朋友圈
  10. 新一代存储卡标准“SDXC”迈向2TB!