ogre中提取阴影锥的方法
目前3d渲染显示阴影有两种方法,模板阴影和纹理阴影。其中模板阴影是根据模型的外包轮廓延光照方向生成轮廓体即阴影锥,然后进行zpass或zfail算法来实现的。有些时候我们需要提取这个阴影锥,做一些其他应用。本文介绍在ogre中如何提取阴影锥并生成个mesh文件。
上代码:
//实体对象
Entity *ent;
//光源
Light *light;
//注意光源是new处理的这里我并不想让scenemanager来使用它,它仅作为生成阴影锥的一个参数
light = new Light("light1");
light->setType(Light::LT_DIRECTIONAL);
light->setDirection(1, -1, 1);
//mSceneMgr为Scenemanager指针
mSceneMgr->setAmbientLight(Ogre::ColourValue(0.5, 0.5, 0.5));
//导入一个模型
ent = mSceneMgr->createEntity("tudorhouse.mesh");
//是否有边界,无则创建
bool belist = ent->hasEdgeList();
if (!belist)
{
Ogre::MeshPtr pMeshPtr = ent->getMesh();
pMeshPtr->buildEdgeList();
}
//创建阴影锥缓存
int mShadowIndexBufferSize = 51200;
HardwareIndexBufferSharedPtr mShadowIndexBuffer = HardwareBufferManager::getSingleton().
createIndexBuffer(HardwareIndexBuffer::IT_16BIT,
mShadowIndexBufferSize,
HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE,
false);
ShadowCaster* caster = ent;
//创建阴影锥renderable,一定要设置成SHADOWTYPE_STENCIL_MODULATIVE
ShadowCaster::ShadowRenderableListIterator iShadowRenderables =
caster->getShadowVolumeRenderableIterator(SHADOWTYPE_STENCIL_MODULATIVE,
light, &mShadowIndexBuffer, true,
10000, SRF_INCLUDE_LIGHT_CAP|SRF_INCLUDE_DARK_CAP);//ShadowRenderableFlags::SRF_EXTRUDE_TO_INFINITY);
//此处应该是
// while (iShadowRenderables.hasMoreElements())
// {
//这里为了简单就不写顶点和索引合并的了,例子中的tudorhouse.mesh好像也只有一个ShadowRenderable,吼吼
ShadowRenderable* sr = iShadowRenderables.getNext();
Ogre::RenderOperation op;
sr->getRenderOperation(op);
VertexData* pVertexData = op.vertexData;
IndexData* pIndex = op.indexData;
//会发现pVertexData有2个VertexElement,一个是顶点坐标(float3,我们想 要的),还有一个是的纹理坐标(float1),但不在同一资源
// VertexDeclaration* pDecl = pVertexData->vertexDeclaration;
// int isize = pDecl->getElementCount();
// for (int i=0; i < isize; i++)
// {
// const VertexElement* pElmt = pDecl->getElement(i);
// }
//只要顶点坐标,故getBuffer(0);
HardwareVertexBufferSharedPtr vbuf =
pVertexData->vertexBufferBinding->getBuffer(0);
//x,y,z有3位吗,当然*3了
std::vector<float> vctData(pVertexData->vertexCount*3);
float *prPos = static_cast<float*>(vbuf->lock(HardwareBuffer::HBL_DISCARD));
{
for(int i = 0; i < pVertexData->vertexCount; i++)
{
vctData[i*3 ] = *prPos++;
vctData[i*3 +1] = *prPos++;
vctData[i*3 +2] = *prPos++;
}
}
vbuf->unlock();
//取索引,不废话了
Ogre::int16* index = new Ogre::int16[pIndex->indexCount];
pIndex->indexBuffer->readData(0,pIndex->indexCount*sizeof(Ogre::int16),index);
//建立ManualObject,也只是简单的new
ManualObject* pManu = new ManualObject("TestManual");
pManu->begin("BaseWhiteNoLighting");
for (int i =0 ; i< pVertexData->vertexCount; i ++)
{
pManu->position(vctData[i*3],vctData[i*3 +1],vctData[i*3 +2]);
}
for (int i = 0; i < pIndex->indexCount; i ++)
{
pManu->index(index[i]);
}
pManu->end();
//建立mesh
MeshPtr ptrMesh = pManu->convertToMesh("testmesh");
MeshSerializer messs;
messs.exportMesh(ptrMesh.get(),"C:\\testmesh.mesh");
//最后做清理,不写了
delete all have to be deleted;