OSG编程指南<十七>:OSG光照与材质

1、OSG光照

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

1.1 osg::Light 类

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

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

int _lightnum; //灯光数量
Vec4 _ambient; //环境光颜色
Vec4 _diffuse; //漫射光颜色
Vec4 _specular; //镜面光颜色
Vec4 _position; //光源的位置信息
Vec3 _direction; //光源的方向
float _constant_attenuation; //常量衰减
float _linear_attenuation; //线性衰减
float _quadratic_attenuation;//二次方衰减
float _spot_exponent; //指数衰减
float _spot_cutoff; //关闭衰减(spread)

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

1.2 osg::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.3 场景中使用光源

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

(1)指定场景模型的法线。
(2)允许光照并设置光照状态。
(3)指定光源属性并关联到场景图形。

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

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

osg::ref_ptr<osg::LightSource> ls = new osg::LightSource;
ls->setLight(light.get());

  在实际生活中,当光照照射到物体上时都会反射等现象,所以,在对光源的设置完成以后需要设置模型的表面材质,下面先看看关于光照的两个示例。

1.4 简单光源示例

在这里插入图片描述

#include <windows.h>
#include <osgViewer/Viewer>
#include <osg/Vec3>
#include <osg/Vec4>
#include <osg/Quat>
#include <osg/Matrix>
#include <osg/ShapeDrawable>
#include <osg/Geometry>
#include <osg/Geode>
#include <osg/Notify>
#include <osg/MatrixTransform>
#include <osg/Texture3D>
#include <osg/Stencil>
#include <osg/ColorMask>
#include <osg/GLExtensions>
#include <osg/Depth>
#include <osg/AnimationPath>
#include <osg/Transform>
#include <osg/Material>
#include <osg/NodeCallback>
#include <osg/Depth>
#include <osg/CullFace>
#include <osg/TexMat>
#include <osg/TexGen>
#include <osg/TexEnv>
#include <osg/TextureCubeMap>
#include <osgViewer/ViewerEventHandlers> //事件监听
#include <osgGA/StateSetManipulator> //事件响应类,对渲染状态进行控制
#include <osgUtil/Simplifier> //简化几何体
#include <osgDB/WriteFile>
#include <osgDB/ReadFile>
#include <osg/Camera>
#include <osg/Light>
#include <osg/LightSource>
#include <osg/BoundingSphere>
#include <osg/BoundingBox>
#include <osgUtil/Optimizer>#include <iostream>#pragma comment(lib, "OpenThreadsd.lib")
#pragma comment(lib, "osgd.lib")
#pragma comment(lib, "osgDBd.lib")
#pragma comment(lib, "osgUtild.lib")
#pragma comment(lib, "osgGAd.lib")
#pragma comment(lib, "osgViewerd.lib")
#pragma comment(lib, "osgTextd.lib")//向场景中添加光源
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, 0.0f, 1.0f));//设置位置light->setPosition(osg::Vec4(bs.center().x(), bs.center().y(), bs.center().z() + bs.radius(), 1.0f));//设置环境光的颜色light->setAmbient(osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f));//设置散射光的颜色light->setDiffuse(osg::Vec4(1.0f, 0.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.get());lightRoot->addChild(lightSource.get());return lightRoot.get();
}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("cessna.osgt");//向场景中添加光源root->addChild(createLight(node.get()));//优化场景数据osgUtil::Optimizer optimzer;optimzer.optimize(root.get());//方便查看在多边形之间切换,以查看三角网viewer->addEventHandler(new osgGA::StateSetManipulator(viewer->getCamera()->getOrCreateStateSet()));viewer->addEventHandler(new osgViewer::StatsHandler());viewer->addEventHandler(new osgViewer::WindowSizeHandler());viewer->setSceneData(root.get());viewer->setUpViewInWindow(600, 600, 800, 600);return viewer->run();
}

1.5 聚光灯示例

在这里插入图片描述

#include <windows.h>
#include <osgViewer/Viewer>
#include <osg/Vec3>
#include <osg/Vec4>
#include <osg/Quat>
#include <osg/Matrix>
#include <osg/ShapeDrawable>
#include <osg/Geometry>
#include <osg/Geode>
#include <osg/Notify>
#include <osg/MatrixTransform>
#include <osg/Texture3D>
#include <osg/Stencil>
#include <osg/ColorMask>
#include <osg/GLExtensions>
#include <osg/Depth>
#include <osg/AnimationPath>
#include <osg/Transform>
#include <osg/Material>
#include <osg/NodeCallback>
#include <osg/Depth>
#include <osg/CullFace>
#include <osg/TexMat>
#include <osg/TexGen>
#include <osg/TexEnv>
#include <osg/TextureCubeMap>
#include <osgViewer/ViewerEventHandlers> //事件监听
#include <osgGA/StateSetManipulator> //事件响应类,对渲染状态进行控制
#include <osgUtil/Simplifier> //简化几何体
#include <osgDB/WriteFile>
#include <osgDB/ReadFile>
#include <osg/Camera>
#include <osg/Light>
#include <osg/LightSource>
#include <osg/BoundingSphere>
#include <osg/BoundingBox>
#include <osgUtil/Optimizer>
#include <osg/TexGenNode>
#include <osgUtil/DelaunayTriangulator>
#include <iostream>
#include <osg/Material>
#include <osg/CullFace>#pragma comment(lib, "OpenThreadsd.lib")
#pragma comment(lib, "osgd.lib")
#pragma comment(lib, "osgDBd.lib")
#pragma comment(lib, "osgUtild.lib")
#pragma comment(lib, "osgGAd.lib")
#pragma comment(lib, "osgViewerd.lib")
#pragma comment(lib, "osgTextd.lib")/**创建聚光灯纹理贴图*创建聚光灯状态属性(前面的纹理贴图也是渲染状态属性之一)*创建聚光灯节点*创建路径动画*创建地形平面(变量vertex报错,注释掉这个类,在场景中将之直接设置为模型牛)*创建动画模型(路径为前面设置好的路径动画),将聚光灯节点添加添加到其中,则聚光灯是动态的(飞机)*创建场景:创建动画模型和地形平面(地形平面出错,此处设为飞机),动画模型为聚光灯位置,地形平面(牛)为聚光灯照射的地方;将状态属性添加到组节点*则飞机飞到哪个地方(即聚光灯在哪里),牛的哪个地方就照亮
*/
//创建聚光灯纹理的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);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> 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> createBase()
{//创建顶点数组osg::ref_ptr<osg::Vec3Array> coords = new osg::Vec3Array();//添加顶点数据int nMin = -5;int nMax = 10;for (int i = -100; i < 100; i += 10){if (i > -100 && i < 0){nMin = -6;nMax = 3;}else if (i > 0 && i < 50){nMin = -3;nMax = 7;}else if (i > 50 && i < 100){nMin = 5;nMax = 3;}for (int j = -100; j < 100; j += 10){float nZ = (float)(nMin, nMax) / 2;osg::Vec3 vertex(i, j, nZ);coords->push_back(vertex);}}//创建颜色数组osg::ref_ptr<osg::Vec4Array> color = new osg::Vec4Array();//添加颜色数据 for (unsigned int i = 0; i < 400; i++){int nR = rand() % 10 + 2;color->push_back(osg::Vec4(0.0f, (double)nR / 10.0, 0.0f, 0.5f));}//创建Delaunay三角网对象osg::ref_ptr<osgUtil::DelaunayTriangulator> dt = new osgUtil::DelaunayTriangulator(coords.get());//生成三角网dt->triangulate();//创建几何体osg::ref_ptr<osg::Geometry> pGeometry = new osg::Geometry();//设置顶点数组pGeometry->setVertexArray(coords.get());osg::ref_ptr<osg::Image> sImagePath = osgDB::readImageFile("Terrain.png");if (sImagePath.get()){osg::ref_ptr<osg::Texture2D> texture2D = new osg::Texture2D;texture2D->setImage(sImagePath.get());// 绑定纹理后,释放内部的ref_ptr<Image>,删除image图像texture2D->setUnRefImageDataAfterApply(true);// 建立纹理顶点osg::ref_ptr<osg::Vec2Array> pVec2Array = new osg::Vec2Array;for (int i = -100; i < 100; i += 10){for (int j = -100; j < 100; j += 10){osg::Vec2 textCoord(0.0, 0.0);textCoord.x() = (double)(j + 100.0) / 200.0;textCoord.y() = (double)(i + 100.0) / 200.0;pVec2Array->push_back(textCoord);}}// Texture类关联到渲染状态StateSetosg::ref_ptr<osg::StateSet> pStateSet = pGeometry->getOrCreateStateSet();// 将纹理关联给StateSet纹理单元0、osg::StateAttribute::OFF关闭纹理pStateSet->setTextureAttributeAndModes(0, texture2D.get(), osg::StateAttribute::ON);pGeometry->setTexCoordArray(0, pVec2Array.get());// 建立法线数组normalosg::ref_ptr<osg::Vec3Array> pVec3ArrayNormal = new osg::Vec3Array;pGeometry->setNormalArray(pVec3ArrayNormal.get());pGeometry->setNormalBinding(osg::Geometry::BIND_OVERALL);//垂直于Z轴负方向pVec3ArrayNormal->push_back(osg::Vec3(0.0, 0.0, 1.0));pGeometry->setStateSet(pStateSet);}else{//设置颜色数组pGeometry->setColorArray(color.get());//设置颜色的绑定方式为单个顶点pGeometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);}//添加到绘图基元pGeometry->addPrimitiveSet(dt->getTriangles());osg::ref_ptr <osg::Geode> pGNode = new osg::Geode;pGNode->addChild(pGeometry);return pGNode.release();}//创建场景
osg::ref_ptr<osg::Node> createModel()
{osg::Vec3 center(0.0f, 0.0f, 0.0f);float radius = 60.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> shadowed = 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());return root.release();
}int main()
{osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();osg::ref_ptr<osg::Group> root = new osg::Group();//添加场景root->addChild(createModel());//优化场景数据osgUtil::Optimizer optimzer;optimzer.optimize(root.get());//方便查看在多边形之间切换,以查看三角网viewer->addEventHandler(new osgGA::StateSetManipulator(viewer->getCamera()->getOrCreateStateSet()));viewer->addEventHandler(new osgViewer::StatsHandler());viewer->addEventHandler(new osgViewer::WindowSizeHandler());viewer->setSceneData(root.get());viewer->setUpViewInWindow(600, 600, 800, 600);return viewer->run();return 0;
}

2、OSG材质

2.1 材质类

  OSG 材质类(osg::Material)继承自 osg::StateAttribute 类。osg::Material 封装了 OpenGL 的 glMaterial()和 glColorMaterial()指令的函数功能。

在场景中设置节点的材质属性,首先要创建一个 osg::Material 对象,然后设置颜色和其他参数,再关联到场景图形的 StateSet 中,如下面的代码:

osg::StateSet* state = node->getOrCreateStateSet();
osg::ref_ptr<osg::Material> mat = new osg::Material;
state->setAttribute( mat.get() );

osg::Material 类包含的主要属性如下:

bool _ambientFrontAndBack; //前面与后面的环境光
Vec4 _ambientFront; //前面的环境光, r、g、b、w
Vec4 _ambientBack; //后面的环境光,r、g、b、w
bool _diffuseFrontAndBack; //前面与后面的漫射光
Vec4 _diffuseFront; //前面的漫射光,r、g、b、w
Vec4 _diffuseBack; //后面的漫射光,r、g、b、w
bool _specularFrontAndBack; //前面与后面的镜面光
Vec4 _specularFront; //前面的镜面光,r、g、b、w
Vec4 _specularBack; //后面的镜面光,r、g、b、w
bool _emissionFrontAndBack; //前面与后面的发射光(emission)
Vec4 _emissionFront; //前面的 emission,r、g、b、w
Vec4 _emissionBack; //后面的 emission,r、g、b、w
bool _shininessFrontAndBack; //前面与后面的发光(shininess)
float _shininessFront; //前面的 shininess
float _shininessBack; //后面的 shininess

注意:shininess 是一个在 0~128.0 之间的值,值越大,亮点越小、越亮。

OSG 材质的面如下:

enum Face
{
FRONT = GL_FRONT, //前
BACK = GL_BACK, //后
FRONT_AND_BACK = GL_FRONT_AND_BACK //前、后
};

OSG 材质的颜色模式如下:

enum ColorMode
{
AMBIENT = GL_AMBIENT, //环境光颜色
DIFFUSE = GL_DIFFUSE, //漫射光颜色
SPECULAR = GL_SPECULAR, //镜面光颜色
EMISSION = GL_EMISSION, //发射光颜色
AMBIENT_AND_DIFFUSE = GL_AMBIENT_AND_DIFFUSE, //环境与漫射光颜色
OFF //关闭模式
};

  在进行很多 OpenGL 的操作时,直接设置材质属性可能会过于耗费资源,而 OSG 提供了一种颜色跟踪材质的高效方法,操作比直接修改材质属性的效率更高,颜色跟踪材质(color material)允许用户程序通过改变当前颜色的方法,自动改变某一特定的材质属性。在许多情形下,这一操作比直接修改材质属性的效率要高,能加强光照场景和无光照场景的联系,并满足应用程序对材质的需要。

  允许颜色跟踪材质的特性需要调用 setColorMode()方法。osg::Material 类为之定义了枚举量AMBIENT、DIFFUSE、SPECULAR、EMISSION、AMBIENT_AND_DIFFUSE 以及 OFF。默认情况下,颜色跟踪模式被设置为 OFF,颜色跟踪材质被禁止。如果用户程序设置颜色跟踪模式为其他的值,那么 OSG 将为特定的材质属性开启颜色跟踪材质特性,此时主颜色的改变将会改变相应的材质属性。

  注意:根据颜色跟踪模式的取值不同,Material 类会自动允许或禁止GL_COLOR_MATERIAL。因此,用户程序不需要调用 setAttributeAndModes()来允许或禁止相关的模式值。

2.2 材质类示例

在这里插入图片描述

#include <windows.h>
#include <osgViewer/Viewer>
#include <osg/Vec3>
#include <osg/Vec4>
#include <osg/Quat>
#include <osg/Matrix>
#include <osg/ShapeDrawable>
#include <osg/Geometry>
#include <osg/Geode>
#include <osg/Notify>
#include <osg/MatrixTransform>
#include <osg/Texture3D>
#include <osg/Stencil>
#include <osg/ColorMask>
#include <osg/GLExtensions>
#include <osg/Depth>
#include <osg/AnimationPath>
#include <osg/Transform>
#include <osg/Material>
#include <osg/NodeCallback>
#include <osg/Depth>
#include <osg/CullFace>
#include <osg/TexMat>
#include <osg/TexGen>
#include <osg/TexEnv>
#include <osg/TextureCubeMap>
#include <osgViewer/ViewerEventHandlers> //事件监听
#include <osgGA/StateSetManipulator> //事件响应类,对渲染状态进行控制
#include <osgUtil/Simplifier> //简化几何体
#include <osgDB/WriteFile>
#include <osgDB/ReadFile>
#include <osg/Camera>
#include <osg/Light>
#include <osg/LightSource>
#include <osg/BoundingSphere>
#include <osg/BoundingBox>
#include <osgUtil/Optimizer>
#include <osg/TexGenNode>
#include <osgUtil/DelaunayTriangulator>
#include <iostream>
#include <osg/Material>
#include <osg/CullFace>#pragma comment(lib, "OpenThreadsd.lib")
#pragma comment(lib, "osgd.lib")
#pragma comment(lib, "osgDBd.lib")
#pragma comment(lib, "osgUtild.lib")
#pragma comment(lib, "osgGAd.lib")
#pragma comment(lib, "osgViewerd.lib")
#pragma comment(lib, "osgTextd.lib")//创建一个四边形节点
osg::ref_ptr<osg::Node> createNode()
{osg::ref_ptr<osg::Geode> geode = new osg::Geode();osg::ref_ptr<osg::Geometry> geom = new osg::Geometry();//设置顶点osg::ref_ptr<osg::Vec3Array> vc = new osg::Vec3Array();vc->push_back(osg::Vec3(0.0f, 0.0f, 0.0f));vc->push_back(osg::Vec3(1.0f, 0.0f, 0.0f));vc->push_back(osg::Vec3(1.0f, 0.0f, 1.0f));vc->push_back(osg::Vec3(0.0f, 0.0f, 1.0f));geom->setVertexArray(vc.get());//设置纹理坐标osg::ref_ptr<osg::Vec2Array> vt = new osg::Vec2Array();vt->push_back(osg::Vec2(0.0f, 0.0f));vt->push_back(osg::Vec2(1.0f, 0.0f));vt->push_back(osg::Vec2(1.0f, 1.0f));vt->push_back(osg::Vec2(0.0f, 1.0f));geom->setTexCoordArray(0, vt.get());//设置法线osg::ref_ptr<osg::Vec3Array> nc = new osg::Vec3Array();nc->push_back(osg::Vec3(0.0f, -1.0f, 0.0f));geom->setNormalArray(nc.get());geom->setNormalBinding(osg::Geometry::BIND_OVERALL);//添加图元geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4));//绘制geode->addDrawable(geom.get());return geode.get();
}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 = createNode();//得到状态属性osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet();stateset = node->getOrCreateStateSet();//创建材质对象osg::ref_ptr<osg::Material> mat = new osg::Material();//设置正面散射颜色mat->setDiffuse(osg::Material::FRONT, osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f));//设置正面镜面颜色mat->setSpecular(osg::Material::FRONT, osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f));//设置正面指数mat->setShininess(osg::Material::FRONT, 90.0f);stateset->setAttribute(mat.get());//设置背面剔除osg::ref_ptr<osg::CullFace> cullface = new osg::CullFace(osg::CullFace::BACK);stateset->setAttribute(cullface.get());stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);root->addChild(node.get());//优化场景数据osgUtil::Optimizer optimzer;optimzer.optimize(root.get());//方便查看在多边形之间切换,以查看三角网viewer->addEventHandler(new osgGA::StateSetManipulator(viewer->getCamera()->getOrCreateStateSet()));viewer->addEventHandler(new osgViewer::StatsHandler());viewer->addEventHandler(new osgViewer::WindowSizeHandler());viewer->setSceneData(root.get());viewer->setUpViewInWindow(600, 600, 800, 600);return viewer->run();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/186283.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

工博会新闻稿汇总

23届工博会媒体报道汇总 点击文章标题即可进入详情页 9月23日&#xff0c;第23届工博会圆满落幕&#xff01;本届工博会规模之大、能级之高、新展品之多创下历史之最。高校展区在规模、能级和展品上均也创下新高。工博会系列报道深入探讨了高校科技发展的重要性和多方面影响。…

【合集】MQ消息队列——Message Queue消息队列的合集文章 RabbitMQ入门到使用

前言 RabbitMQ作为一款常用的消息中间件&#xff0c;在微服务项目中得到大量应用&#xff0c;其本身是微服务中的重点和难点。本篇博客是Message Queue相关的学习博客文章的合集篇&#xff0c;目前主要是RabbitMQ入门到使用文章&#xff0c;后续会扩展其他MQ。 目录 前言一、R…

自定义链 SNAT / DNAT 实验举例

参考原理图 实验前的环境搭建 1. 准备三台虚拟机&#xff0c;定义为内网&#xff0c;外网以及网卡服务器 2. 给网卡服务器添加网卡 3. 将三台虚拟机的防火墙和安全终端全部关掉 systemctl stop firewalld && setenforce 0 4. 给内网虚拟机和外网虚拟机 yum安装 httpd…

阿里云国际短信业务网络超时排障指南

选取一台或多台线上的应用服务器或选取相同网络环境下的机器&#xff0c;执行以下操作。 获取公网出口IP。 curl ifconfig.me 测试连通性。 &#xff08;推荐&#xff09;执行MTR命令&#xff08;可能需要sudo权限&#xff09;&#xff0c;检测连通性&#xff0c;执行30秒。 m…

Scrapy框架中间件(一篇文章齐全)

1、Scrapy框架初识&#xff08;点击前往查阅&#xff09; 2、Scrapy框架持久化存储&#xff08;点击前往查阅&#xff09; 3、Scrapy框架内置管道&#xff08;点击前往查阅&#xff09; 4、Scrapy框架中间件 Scrapy 是一个开源的、基于Python的爬虫框架&#xff0c;它提供了…

HashMap的实现原理

1.HashMap实现原理 HashMap的数据结构&#xff1a; *底层使用hash表数据结构&#xff0c;即数组链表红黑树 当我们往HashMap中put元素时&#xff0c;利用key的hashCode重新hash计算出当前对象的元素在数组中的下标 存储时&#xff0c;如果出现hash值相同的key&#xff0c;此时…

自动化测试 —— 如何优雅实现方法的依赖!

在 seldom 3.4.0 版本实现了该功能。 在复杂的测试场景中&#xff0c;常常会存在用例依赖&#xff0c;以一个接口自动化平台为例&#xff0c;依赖关系&#xff1a; 创建用例 --> 创建模块 --> 创建项目 --> 登录。 用例依赖的问题 •用例的依赖对于的执行顺序有严格…

一文讲透Python机器学习特征工程中的特征标准化

在Python中&#xff0c;可通过scikit-learn模块中的StandardScaler()函数实现对特征的标准化处理。StandardScaler()函数处理的数据对象同样是每一列&#xff0c;也就是每一维特征。StandardScaler()函数通过去除平均值和缩放到单位方差来标准化特征&#xff0c;将样本特征值转…

使用最小花费爬楼梯(力扣LeetCode)动态规划

使用最小花费爬楼梯 题目描述 给你一个整数数组 cost &#xff0c;其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用&#xff0c;即可选择向上爬一个或者两个台阶。 你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。 请你计算并返回达到楼梯顶…

使用canvas实现代码雨高级升阶版【附带源码和使用方法】

文章目录 前言基本绿色的彩色版本飘散雪花状后言 前言 hello world欢迎来到前端的新世界 &#x1f61c;当前文章系列专栏&#xff1a;前端面试 &#x1f431;‍&#x1f453;博主在前端领域还有很多知识和技术需要掌握&#xff0c;正在不断努力填补技术短板。(如果出现错误&…

SS8812T 36V/1.6A 两通道 H 桥驱动芯片 替代DRV8812

SS8812T 为打印机和其它电机一体化应用提 供一种双通道集成电机驱动方案。 SS8812T 有两 路 H 桥驱动&#xff0c;每个 H 桥可提供最大输出电流 1.6A (在 24V 和 Ta 25C 适当散热条件下)&#xff0c;可驱动两 个刷式直流电机&#xff0c;或者一个双极步进电机&#xff0…

每日一练2023.11.30——验证身份【PTA】

题目链接 &#xff1a;验证身份 题目要求&#xff1a; 一个合法的身份证号码由17位地区、日期编号和顺序编号加1位校验码组成。校验码的计算规则如下&#xff1a; 首先对前17位数字加权求和&#xff0c;权重分配为&#xff1a;{7&#xff0c;9&#xff0c;10&#xff0c;5&a…

windows文件删除权限

一、普通文件 这里指的是所有可以被随意删除的文件。 二、可更改权限的文件 如果想要删除的文件无法被删除&#xff0c;那大概是权限不够&#xff0c;这时候&#xff1a;鼠标右键、属性、安全、编辑、选择相应的组或用户&#xff08;如果不知道哪个可以全选&#xff0c;反正…

麒麟操作系统进入单用户模式

Kylin V4 桌面版&#xff1a; 启动系统后&#xff0c;在启动菜单界面选择 Kylin 4.0.2 高级选项后回车。 在高级模式选项下选择第二行 recovery mode 模式后&#xff0c;按 e 编辑。 按 e 后如下图&#xff0c;找到 linux 开头的一行&#xff0c;修改 ro 为 rw 后&#xff0c…

北邮22级信通院数电:Verilog-FPGA(11)第十一周实验(2)设计一个24秒倒计时器

北邮22信通一枚~ 跟随课程进度更新北邮信通院数字系统设计的笔记、代码和文章 持续关注作者 迎接数电实验学习~ 获取更多文章&#xff0c;请访问专栏&#xff1a; 北邮22级信通院数电实验_青山如墨雨如画的博客-CSDN博客 目录 一.代码部分 1.1 counter_24.v 1.2 divid…

linux系统下的nginx服务安装

一. 环境 在安装nginx前&#xff0c;需要提前配置的环境包括 pcre&#xff1a;rewrite正则相关pcre:URL重写软件&#xff0c;实现伪静态\URL跳转等、SEO优化。 openssl&#xff1a;https加密访问用它 zlib&#xff1a;提供数据压缩用1.安装pcre 1.1 检查版本 执行&#xff…

Selenium——isDisplayed()、isEnabled()、isSelected()

判断页面是否存在某元素 Selenium没有直接提供判断是否存在的方法&#xff0c;可以使用findElements返回的数量判断&#xff1b;或者判断findElement是否抛出异常 webDriver.findElements(By.xpath("(//div[classel-button-group]//button)[1]")).size()isDisplaye…

window10家庭版中文转专业版流程

1.确认当前为家庭中文版 2.用管理员权限打开cmd窗口 3.输入 dism /online /get-targeteditions &#xff0c;查询当前支持的升级的版本 4.专业版密钥&#xff1a;VK7JG-NPHTM-C97JM-9MPGT-3V66T 5.changepk.exe /productkey VK7JG-NPHTM-C97JM-9MPGT-3V66T

C#,《小白学程序》第二十三课:大数的除法(BigInteger Divide)

1 文本格式 /// <summary> /// 比较a&#xff0c;b的大小&#xff0c;返回1&#xff0c;0&#xff0c;-1 /// 数据从低位&#xff08;右&#xff09;往高位&#xff08;左&#xff09;存储; /// </summary> /// <param name"a"></param> ///…

【Qt绘图】之绘制坦克

使用绘图事件&#xff0c;绘制坦克。 效果 效果很逼真&#xff0c;想象力&#xff0c;有没有。 示例 代码像诗一样优雅&#xff0c;有没有。 包含头文件 #include <QApplication> #include <QWidget> #include <QPainter>绘制坦克类 class TankWidge…