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

一、光照简介

        OSG 全面支持 OpenGL 的光照特性,包括材质属性( material property ),光照属性( light property )和光照模型( lighting model )。与 OpenGL 相似, OSG 的光源也是不可见的,而非渲染一个灯泡或其他自然形状。同样,光源会创建着 色效果,但是并不创建阴影—— osgShadow 可以用来创建阴影。 如果要在用户程序中使用光照,需要遵循下面的步骤:
        1 指定几何体法线。
        2 允许光照并设置光照状态。
        3 指定光源属性并关联到场景图形。
        4指定表面材质属性。
本节针对上面的每一步进行讲解。

二、法线

      只有几何体数据中设有单位长度法线时,才可以实现正确的光照。 “叶节点( Geode )和几何信息”已经对法线数组的设置和绑定到 Geometry 对象 作了介绍。
     在大多数 3D API 中,法线数据必须单位化以得到正确的结果。注意缩放变 换的动作会改变法线的长度。如果你的 Geometry 对象中已经包含了单位长度的 1 法线数组,但是光照的计算结果过于明亮或过于暗淡,那么这一现象可能是缩放 变换造成的。最有效的解决方案是在 StateSet 中允许法线的重放缩模式。
osg::StateSet* state = geode->setOrCreateStateSet(); 
state->setMode( GL_RESCALE_NORMAL, osg::StateAttribute::ON );
       与 OpenGL 中相同,这一特性可以保证法线在均匀放缩变换时仍然保持单位 长度。如果场景中的放缩变换是非均匀的,那么你可以允许法线归一化模式,以 保证法线为单位长度。
osg::StateSet* state = geode->setOrCreateStateSet(); 
state->setMode( GL_NORMALIZE, osg::StateAttribute::ON );
       由于要进行法线的重新放缩,归一化模式往往会耗费大量的时间。编程时要 尽量避免。

三、光照状态

        要在 OSG 中获得光照效果,你需要允许光照并至少允许一个光源。程序 osgviewer 在缺省情况下就是这样做的,它在根节点的 StateSet 中已经设置了相应 的模式。你可以在自己的程序中进行相同的设置。下面的代码段用于允许光照并 为根节点的 StateSet 允许两个光源( GL_LIGHT0 GL_LIGHT1 )。
osg::StateSet* state = root->getOrCreateStateSet(); 
state->setMode( GL_LIGHTING, osg::StateAttribute::ON ); 
state->setMode( GL_LIGHT0, osg::StateAttribute::ON ); 
state->setMode( GL_LIGHT1, osg::StateAttribute::ON );
        下面的部分将叙述如何控制独立的光源属性,例如它的位置和颜色,以及 OpenGL 颜色跟踪材质的特性(包括便面材质颜色的设置)。
        OSG 还提供了从 StateAttribute 派生的 osg::LightModel 属性,用以控制全局 的环境颜色,局部视图,双面光照,以及分离镜面颜色( separate specular color OpenGL 特性。

四、光源

        要在场景中添加一个光源,可以创建一个 osg::Light 对象以定义光源参数。 然后将 Light 添加到一个 osg::LightSource 节点中,并将 LightSource 节点添加到 场景图形。 LightSource 是一个包含了唯一的 Light 定义的高效的组节点。而由 Light 定义的光源将对整个场景产生影响。 OSG 支持最多八个光源,从 GL_LIGHT0 GL_LIGHT7 ,这与你的 OpenGL 版本也有关系。你可以使用前述的 setMode() 方法来允许这些光源。如果要把一 Light 对象与 OpenGL 的光源联系起来,可以使用设置光的位置数的方法。例 如要把一个 Light 对象与 GL_LIGHT2 相关联,则设置位置数为 2
// 创建一个 Light 对象来控制 GL_LIGHT2 的参数。
osg::ref_ptr<osg::Light> light = new osg::Light; 
light->setLightNum( 2 ); 
//缺省情况下光源的位置数为 0。
        Light 类实现了 OpenGL glLight() 命令的大部分功能。用户程序可以使用 其方法设置光的环境色,散射颜色,镜面反射颜色。用户可以创建点光,直线光 或者锥光,也可以指定衰减数,使得光的密度根据距离的不同逐渐削减。下面 的代码创建了一个 Light 对象并设置了一些常用的参数:
// 创建一个白色的锥光光源。
osg::ref_ptr<osg::Light> light = new osg::Light; 
light->setAmbient( osg::Vec4( .1f, .1f, .1f, 1.f )); 
light->setDiffuse( osg::Vec4( .8f, .8f, .8f, 1.f )); 
light->setSpecular( osg::Vec4( .8f, .8f, .8f, 1.f )); 
light->setPosition( osg::Vec3( 0.f, 0.f, 0.f )); 
light->setDirection( osg::Vec3( 1.f, 0.f, 0.f )); 
light->setSpotCutoff(25.f );
        要添加 Light 对象到场景中,首先要创建一个 LightSource 节点,将 Light LightSource 中,并将 LightSource 关联到场景图形中。灯光的位置可以由 LightSource 节点在场景图形中的位置决定。 OSG 根据当前 LightSource 节点的变 换状态来改变灯光的位置。

五、案例

#include <osgViewer/Viewer>

#include <osg/Node>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/Group>
#include <osg/Camera>
#include <osg/Light>
#include <osg/LightSource>
#include <osg/BoundingSphere>
#include <osg/BoundingBox>

#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osgGA/StateSetManipulator>
#include <osgUtil/Optimizer>

//向场景中添加光源
osg::ref_ptr<osg::Group> createLight(osg::ref_ptr<osg::Node> node)
{
	osg::ref_ptr<osg::Group> lightRoot = new osg::Group();
	lightRoot->addChild(node);

	//开启光照
	osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet();
	stateset = lightRoot->getOrCreateStateSet();
	stateset->setMode(GL_LIGHTING, osg::StateAttribute::ON);
	stateset->setMode(GL_LIGHT0, osg::StateAttribute::ON);

	//计算包围盒
	osg::BoundingSphere bs;
	node->computeBound();
	bs = node->getBound();

	//创建一个Light对象
	osg::ref_ptr<osg::Light> light = new osg::Light();
	light->setLightNum(0);
	//设置方向
	light->setDirection(osg::Vec3(0.0f, 1.0f, 0.0f));
	//设置位置
	light->setPosition(osg::Vec4(bs.center().x(), bs.center().y(), bs.center().z() + bs.radius(), 1.0f));
	//设置环境光的颜色
	light->setAmbient(osg::Vec4(1.0f, .0f, .0f, 1.0f));
	//设置散射光颜色
	light->setDiffuse(osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f));
	//设置恒衰减指数
	light->setConstantAttenuation(1.0f);
	//设置线形衰减指数
	light->setLinearAttenuation(0.0f);
	//设置二次方衰减指数
	light->setQuadraticAttenuation(0.0f);

	//创建光源
	osg::ref_ptr<osg::LightSource> lightSource = new osg::LightSource();
	lightSource->setLight(light);

	lightRoot->addChild(lightSource);

	return lightRoot;
}

int main()
{
	osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();
	osg::ref_ptr<osg::Group> root = new osg::Group();

	//读取模型
	osg::ref_ptr<osg::Node> node = osgDB::readNodeFile("cow.osg");

	//向场景中添加光源
	root->addChild(createLight(node));
	//root->addChild(node.get());
	//优化场景数据
	osgUtil::Optimizer optimizer;
	optimizer.optimize(root);

	//设置场景数据
	viewer->setSceneData(root);
	//事件响应类,对渲染状态进行控制,按w在体/线/点模式间切换,
	// 按l在照明与非照明模式下切换,按b在是否开启背面剔除模式下切换,按t在是否开启纹理的情况下切换
	viewer->addEventHandler(new osgGA::StateSetManipulator(viewer->getCamera()->getOrCreateStateSet()));
	//初始化并创建窗口
	viewer->realize();
	//开始渲染
	viewer->run();

	return 0;
}

        也许大家会有一个疑问,为什么光照须有法线?

解释:光照必须实在一个模型或者物体的有发现的基础上区形成的,也就是说如果没有法线的画,其光照也是不会有的。

后续继续更新..........

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小气鬼944

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值