Pbr的间接光用到立方体贴图,所以,先用shader进行立方体贴图。
立方体贴图很简单,就是用方向向量(不一定是单位向量)采样cubeMap的颜色。
也就是在片元着色器中传递。
"float x = outPos.r;\n"
"float y = outPos.g;\n"
"float z = outPos.b;\n"
"vec3 dir = vec3(x,y,z);\n"
"gl_FragColor = texture(tex0,dir);\n"
也就是需要把位置数组传递到shader中,可以用个NodeVisitor
class MyNodeVisitor : public osg::NodeVisitor
{
public:
MyNodeVisitor() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
{
}
void apply(osg::Geode& geode)
{
int count = geode.getNumDrawables();
for (int i = 0; i < count; i++)
{
osg::ref_ptr geometry = geode.getDrawable(i)->asGeometry();
if (!geometry.valid())
{
continue;
}
osg::Array* vertexArray = geometry->getVertexArray();
geometry->setVertexAttribArray(1, vertexArray);//这里传递位置数组。
}
traverse(geode);
}
};
cubeMap需要把六个面的图片都加上,即。
osg::ref_ptrosg::TextureCubeMap tcm = new osg::TextureCubeMap;
tcm->setImage(osg::TextureCubeMap::POSITIVE_X, imagePosX);
tcm->setImage(osg::TextureCubeMap::NEGATIVE_X, imageNegX);
tcm->setImage(osg::TextureCubeMap::POSITIVE_Y, imagePosY);
tcm->setImage(osg::TextureCubeMap::NEGATIVE_Y, imageNegY);
tcm->setImage(osg::TextureCubeMap::POSITIVE_Z, imagePosZ);
tcm->setImage(osg::TextureCubeMap::NEGATIVE_Z, imageNegZ);
随便贴到一个Osg::box就行。
osg::ref_ptr stateset = geode->getOrCreateStateSet();
stateset->setTextureAttributeAndModes(0, tcm, osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);
接下来在shader的c++端传递位置数组和纹理
program1->addBindAttribLocation("aPos", 1);
osg::ref_ptr tex0Uniform = new osg::Uniform("tex0", 0);
stateset->addUniform(tex0Uniform);
如下图所示
完整代码如下:
#include
#include
#include
#include
#include
#include
#include
#include
static const char * vertexShader =
{
“in vec3 aPos;\n”
“varying vec3 outPos;”
“void main(void)\n”
“{\n”
“outPos = aPos;\n”
" gl_Position = ftransform();\n"
“}\n”
};
static const char *psShader =
{
“varying vec3 outPos;”
“uniform samplerCube tex0;”
“void main(void)\n”
“{\n”
“float x = outPos.r;\n”
“float y = outPos.g;\n”
“float z = outPos.b;\n”
“vec3 dir = vec3(x,y,z);\n”
“gl_FragColor = texture(tex0,dir);\n”
“}\n”
};
class MyNodeVisitor : public osg::NodeVisitor
{
public:
MyNodeVisitor() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
{
}
void apply(osg::Geode& geode)
{
int count = geode.getNumDrawables();
for (int i = 0; i < count; i++)
{
osg::ref_ptr geometry = geode.getDrawable(i)->asGeometry();
if (!geometry.valid())
{
continue;
}
osg::Array* vertexArray = geometry->getVertexArray();
geometry->setVertexAttribArray(1, vertexArray);
}
traverse(geode);
}
};
int main()
{
osg::ref_ptrosg::TextureCubeMap tcm = new osg::TextureCubeMap;
tcm->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP);
tcm->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP);
tcm->setWrap(osg::Texture::WRAP_R, osg::Texture::CLAMP);
std::string strImagePosX = "D:/OpenSceneGraph-master/OpenSceneGraph-Data-master/Cubemap_axis/posx.bmp";
osg::ref_ptr imagePosX = osgDB::readImageFile(strImagePosX);
tcm->setImage(osg::TextureCubeMap::POSITIVE_X, imagePosX);
std::string strImageNegX = "D:/OpenSceneGraph-master/OpenSceneGraph-Data-master/Cubemap_axis/negx.bmp";
osg::ref_ptr imageNegX = osgDB::readImageFile(strImageNegX);
tcm->setImage(osg::TextureCubeMap::NEGATIVE_X, imageNegX);
std::string strImagePosY = "D:/OpenSceneGraph-master/OpenSceneGraph-Data-master/Cubemap_axis/posy.bmp";
osg::ref_ptr imagePosY = osgDB::readImageFile(strImagePosY);
tcm->setImage(osg::TextureCubeMap::POSITIVE_Y, imagePosY);
std::string strImageNegY = "D:/OpenSceneGraph-master/OpenSceneGraph-Data-master/Cubemap_axis/negY.bmp";
osg::ref_ptr imageNegY = osgDB::readImageFile(strImageNegY);
tcm->setImage(osg::TextureCubeMap::NEGATIVE_Y, imageNegY);
std::string strImagePosZ = "D:/OpenSceneGraph-master/OpenSceneGraph-Data-master/Cubemap_axis/posZ.bmp";
osg::ref_ptr imagePosZ = osgDB::readImageFile(strImagePosZ);
tcm->setImage(osg::TextureCubeMap::POSITIVE_Z, imagePosZ);
std::string strImageNegZ = "D:/OpenSceneGraph-master/OpenSceneGraph-Data-master/Cubemap_axis/negZ.bmp";
osg::ref_ptr imageNegZ = osgDB::readImageFile(strImageNegZ);
tcm->setImage(osg::TextureCubeMap::NEGATIVE_Z, imageNegZ);
osg::ref_ptr box = new osg::Box(osg::Vec3(0, 0, 0), 1);
osg::ref_ptr drawable = new osg::ShapeDrawable(box);
osg::ref_ptr geode = new osg::Geode;
geode->addDrawable(drawable);
MyNodeVisitor nv;
geode->accept(nv);
osg::ref_ptr stateset = geode->getOrCreateStateSet();
stateset->setTextureAttributeAndModes(0, tcm, osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);
//shader
osg::ref_ptr vs1 = new osg::Shader(osg::Shader::VERTEX, vertexShader);
osg::ref_ptr ps1 = new osg::Shader(osg::Shader::FRAGMENT, psShader);
osg::ref_ptr program1 = new osg::Program;
program1->addShader(vs1);
program1->addShader(ps1);
program1->addBindAttribLocation("aPos", 1);
osg::ref_ptr tex0Uniform = new osg::Uniform("tex0", 0);
stateset->addUniform(tex0Uniform);
stateset->setAttribute(program1, osg::StateAttribute::ON);
osg::ref_ptr viewer = new osgViewer::Viewer;
viewer->setSceneData(geode);
viewer->realize();
return viewer->run();
}