光源類型
定向光
當一個光源很遠的時候,來自光源的每條光線接近于平行。這看起來就像所有的光線來自于同一個方向,無論物體和觀察者在哪兒。當一個光源被設定為無限遠時,它被稱為
定向光
(Directional Light),因為所有的光線都有着同一個方向;它會獨立于光源的位置。

//光源位置 第四個參數 0.0 平行光 1.0 點光源
light->setPosition(osg::Vec4(0.0, 0.0, 0.0, 0.0));
//光源方向
light->setDirection(osg::Vec3(0.0, 0.0, -1.0));
點光
點光
是一個在時間裡有位置的光源,它向所有方向發光,光線随距離增加逐漸變暗。
//光源位置 第四個參數 0.0 平行光 1.0 點光源
light->setPosition(osg::Vec4(0.0, 0.0, 0.0, 1.0));
//設定恒定衰減系數
light->setConstantAttenuation(1.0);
//設定一次衰減系數
light->setLinearAttenuation(0.7);
//設定二次衰減系數
light->setQuadraticAttenuation(1.8);
聚光
聚光
是一種位于環境中某處的光源,它不是向所有方向照射,而是隻朝某個方向照射。結果是隻有一個聚光照射方向的确定半徑内的物體才會被照亮,其他的都保持黑暗。
//光源位置 第四個參數 0.0 平行光 1.0 點光源
light->setPosition(osg::Vec4(0.0, 0.0, 0.0, 1.0));
//光源方向
light->setDirection(osg::Vec3(0.0, 0.0, -1.0));
//光強度分布
light->setSpotExponent(1.0);
//擴散角
light->setSpotCutoff(45.0);
光照基礎
馮氏光照模型(Phong Lighting Model)的主要結構由3個元素組成:環境(Ambient)、漫反射(Diffuse)和鏡面(Specular)光照。這些光照元素看起來像下面這樣:
環境光照(Ambient Lighting)
即使在黑暗的情況下,世界上也仍然有一些光亮(月亮、一個來自遠處的光),是以物體永遠不會是完全黑暗的。我們使用環境光照來模拟這種情況,也就是無論如何永遠都給物體一些顔色。
漫反射光照(Diffuse Lighting)
模拟一個發光物對物體的方向性影響(Directional Impact)。它是馮氏光照模型最顯著的組成部分。面向光源的一面比其他面會更亮。
鏡面光照(Specular Lighting)
模拟有光澤物體上面出現的亮點。鏡面光照的顔色,相比于物體的顔色更傾向于光的顔色。
//環境光
light->setAmbient(osg::Vec4(0.2, 0.2, 0.2, 1.0));
//漫反射光
light->setDiffuse(osg::Vec4(0.5, 0.5, 0.5, 1.0));
//鏡面反射光
light->setSpecular(osg::Vec4(1.0, 1.0, 1.0, 1.0));
法向量
法向量
(Normal Vector)是垂直于頂點表面的(機關)向量。由于頂點自身并沒有表面(它隻是空間中一個獨立的點),我們利用頂點周圍的頂點計算出這個頂點的表面。我們能夠使用叉乘這個技巧為立方體所有的頂點計算出法線,但是由于3D立方體不是一個複雜的形狀,是以我們可以簡單的把法線資料手工添加到頂點資料中。更新的頂點資料數組可以在這裡找到。試着去想象一下,這些法向量真的是垂直于立方體的各個面的表面的(一個立方體由6個面組成)。
//手動定義法線
osg::ref_ptr<osg::Vec3Array> normal=new osg::Vec3Array();
normal->push_back(osg::Vec3(0.0,0.0,-1.0));
geometry->setNormalArray(normal,osg::Geometry::BIND_OVERALL);
//自動生成法線
osgUtil::SmoothingVisitor::smooth(*geode);
材質
在真實世界裡,每個物體會對光産生不同的反應。鋼看起來比陶瓷花瓶更閃閃發光,一個木頭箱子不會像鋼箱子一樣對光産生很強的反射。每個物體對鏡面高光也有不同的反應。有些物體不會散射(Scatter)很多光卻會反射(Reflect)很多光,結果看起來就有一個較小的高光點(Highlight),有些物體散射了很多,它們就會産生一個半徑更大的高光。如果我們想要在OpenGL中模拟多種類型的物體,我們必須為每個物體分别定義材質(Material)屬性。
ambient
材質向量定義了在環境光照下這個物體反射的是什麼顔色;通常這是和物體顔色相同的顔色。
diffuse
材質向量定義了在漫反射光照下物體的顔色。漫反射顔色被設定為(和環境光照一樣)我們需要的物體顔色。
specular
材質向量設定的是物體受到的鏡面光照的影響的顔色(或者可能是反射一個物體特定的鏡面高光顔色)。最後,
shininess
影響鏡面高光的散射/半徑。
//環境光
material->setAmbient(osg::Material::FRONT, osg::Vec4(0.0215, 0.1725, 0.0215, 1.0));
//漫反射光
material->setDiffuse(osg::Material::FRONT, osg::Vec4(0.07568, 0.61424, 0.07568, 1.0));
//鏡面光
material->setSpecular(osg::Material::FRONT, osg::Vec4(0.633, 0.727811, 0.633, 1.0));
//光澤度
material->setShininess(osg::Material::FRONT, 0.6*128.0);
測試
osg::LightSource* createDirectLight()
{
osg::ref_ptr<osg::Light> light = new osg::Light();
light->setLightNum(0);
//光源位置 第四個參數 0.0 平行光 1.0 點光源
light->setPosition(osg::Vec4(0, 0, 1, 0));
//環境光
light->setAmbient(osg::Vec4(1.0, 1.0, 1.0, 1.0));
//漫反射光
light->setDiffuse(osg::Vec4(1.0, 1.0, 1.0, 1.0));
//鏡面反射光
light->setSpecular(osg::Vec4(1.0, 1.0, 1.0, 1.0));
osg::ref_ptr<osg::LightSource> light_source = new osg::LightSource();
light_source->setLight(light);
return light_source.release();
}
osg::LightSource* createPointLight()
{
osg::ref_ptr<osg::Light> light = new osg::Light();
light->setLightNum(0);
//光源位置 第四個參數 0.0 平行光 1.0 點光源
light->setPosition(osg::Vec4(0.0, 0.0, 2.0, 1.0));
//設定恒定衰減系數
light->setConstantAttenuation(1.0);
//設定一次衰減系數
light->setLinearAttenuation(0.045);
//設定二次衰減系數
light->setQuadraticAttenuation(0.0075);
//環境光
light->setAmbient(osg::Vec4(1.0, 1.0, 1.0, 1.0));
//漫反射光
light->setDiffuse(osg::Vec4(1.0, 1.0, 1.0, 1.0));
//鏡面反射光
light->setSpecular(osg::Vec4(1.0, 1.0, 1.0, 1.0));
osg::ref_ptr<osg::LightSource> light_source = new osg::LightSource();
light_source->setLight(light);
return light_source.release();
}
osg::LightSource* createSpotLight()
{
osg::ref_ptr<osg::Light> light = new osg::Light();
light->setLightNum(0);
//光源位置 第四個參數 0.0 平行光 1.0 點光源
light->setPosition(osg::Vec4(0.0, 0.0, 2.0, 1.0));
//光源方向
light->setDirection(osg::Vec3(1.0, 0.0, 0.0));
//擴散角
light->setSpotCutoff(30.0);
//環境光
light->setAmbient(osg::Vec4(1.0, 1.0, 1.0, 1.0));
//漫反射光
light->setDiffuse(osg::Vec4(1.0, 1.0, 1.0, 1.0));
//鏡面反射光
light->setSpecular(osg::Vec4(1.0, 1.0, 1.0, 1.0));
osg::ref_ptr<osg::LightSource> light_source = new osg::LightSource();
light_source->setLight(light);
return light_source.release();
}
osg::Node* createSphere()
{
osg::ref_ptr<osg::Geode> geode = new osg::Geode();
osg::ref_ptr<osg::TessellationHints> hints = new osg::TessellationHints();
hints->setDetailRatio(5.0);
geode->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(0.0, 0.0, 0.0), 1.0f), hints));
geode->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(3.0, 0.0, 0.0), 1.0f), hints));
geode->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(6.0, 0.0, 0.0), 1.0f), hints));
osg::ref_ptr<osg::Material> material = new osg::Material();
//環境光
material->setAmbient(osg::Material::FRONT, osg::Vec4(0.0215, 0.1725, 0.0215, 1.0));
//漫反射光
material->setDiffuse(osg::Material::FRONT, osg::Vec4(0.07568, 0.61424, 0.07568, 1.0));
//鏡面光
material->setSpecular(osg::Material::FRONT, osg::Vec4(0.633, 0.727811, 0.633, 1.0));
//光澤度
material->setShininess(osg::Material::FRONT, 0.6*128.0);
//設定材質
geode->getOrCreateStateSet()->setAttributeAndModes(material);
return geode.release();
}
int main()
{
osgViewer::Viewer viewer;
osg::ref_ptr<osg::Group> group = new osg::Group();
group->addChild(createSphere());
group->addChild(createDirectLight());
viewer.addEventHandler(new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()));
viewer.setSceneData(group);
return viewer.run();
}