您的位置:首页 > 其它

Havok动画渲染Demo(使用Ogre)

2012-07-06 16:52 239 查看
http://blog.csdn.net/shangguanwaner

Havok的Animation组件是比较强大的,并且可以和物理场景进行交互,其实可以完全不用Ogre的骨骼动画系统,动画的处理完全交给Havok,Ogre只管显示即可。

花了点时间,做了个测试程序,将二者结合到一起,导入Havok的一个角色动画,然后播放这个动画,Ogre实时渲染出来。截图如下:









这里吐槽下,Havok SDK自带的Demo,特别是一些和图形渲染相关的代码,很多都不提供源代码和参考例子。写代码中间几次卡住,抓狂到极点。无耐只能自己跟踪程序,看他的一些关键点的输出,进行分析。

例子是Havok自带的例子改过来的,见Havok SDK目录Demo\Demos\Animation\Api\MeshAndDeformation\Skinning。我就说下和Ogre的整合方法。最主要的是hkxMeshSection这个数据结构,它包含了Mesh的顶点、Normal、UV坐标等等数据,把他导出,在Ogre中手动建立Mesh,再实时的在Ogre中更新这个Mesh即可。给出主要的功能代码:

int SkinningMesh::AllocateMesh(hkxMeshSection* meshsec)

{

const hkxVertexDescription& vdesc = meshsec->m_vertexBuffer->getVertexDesc();

const hkxVertexDescription::ElementDecl* pdecl = vdesc.getElementDecl(hkxVertexDescription::HKX_DU_POSITION, 0);

const hkxVertexDescription::ElementDecl* ndecl = vdesc.getElementDecl(hkxVertexDescription::HKX_DU_NORMAL, 0);

const hkxVertexDescription::ElementDecl* tdecl = vdesc.getElementDecl(hkxVertexDescription::HKX_DU_TEXCOORD, 0);

hkxVertexBuffer* vbuf = meshsec->m_vertexBuffer;

Ogre::String strName = "SkinningMesh" + Ogre::StringConverter::toString(m_nMeshNum++);

int nVertexCount = vbuf->getNumVertices();

//DBGSTRING("nVertexCount: %d", nVertexCount);

VERTEXSET_DATA* pVertexSetData = new VERTEXSET_DATA();

pVertexSetData->vertexSet.SetVertexNum(nVertexCount);

pVertexSetData->mesh = Ogre::MeshManager::getSingleton().createManual(

strName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);

Ogre::SubMesh* submesh = pVertexSetData->mesh->createSubMesh();

submesh->useSharedVertices = false;

//顶点缓冲区

submesh->vertexData = new Ogre::VertexData();

submesh->vertexData->vertexStart = 0;

submesh->vertexData->vertexCount = nVertexCount;

Ogre::VertexDeclaration* vdecl = submesh->vertexData->vertexDeclaration;

Ogre::VertexBufferBinding* vbind = submesh->vertexData->vertexBufferBinding;

//数据格式声明

vdecl->addElement(0, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION);

vdecl->addElement(1, 0, Ogre::VET_FLOAT3, Ogre::VES_NORMAL);

vdecl->addElement(2, 0, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES); //UV坐标

//建立顶点缓冲区

Ogre::HardwareVertexBufferSharedPtr posVertexBuffer =

Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(3*sizeof(Ogre::Real),

nVertexCount,

Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE);

vbind->setBinding(0, posVertexBuffer);

//建立Normal

Ogre::HardwareVertexBufferSharedPtr normalVertexBuffer =

Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(3*sizeof(Ogre::Real),

nVertexCount,

Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE);

vbind->setBinding(1, normalVertexBuffer);

//建立UV

Ogre::HardwareVertexBufferSharedPtr uvVertexBuffer =

Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(2*sizeof(Ogre::Real),

nVertexCount,

Ogre::HardwareBuffer::HBU_STATIC);



vbind->setBinding(2, uvVertexBuffer);

pVertexSetData->posVertexBuffer = posVertexBuffer;

pVertexSetData->normalVertexBuffer = normalVertexBuffer;

Ogre::AxisAlignedBox meshBounds(0, 0, 0, 10, 0, 10);

pVertexSetData->mesh->_setBounds(meshBounds);

//写入顶点数据

//顶点

if(pdecl){

void* pBuffer = (meshsec->m_vertexBuffer->getVertexDataPtr((*pdecl)));



if(pBuffer == NULL){

::MessageBoxA(NULL, "GetRenderData getVertexDataPtr 顶点数据 失败", "Havok System Error", MB_OK|MB_ICONSTOP);

return -1;

}

int nNum = meshsec->m_vertexBuffer->getNumVertices();

void* pOutBuf = malloc(posVertexBuffer->getSizeInBytes());

memset(pOutBuf, 0, posVertexBuffer->getSizeInBytes());

for(int i=0; i<nNum; i++){

const float* pCurr = reinterpret_cast<float*>((char*)pBuffer + (pdecl->m_byteStride * i));

memcpy((char*)pOutBuf + i*3*sizeof(float), pCurr, 3*sizeof(float));

}

posVertexBuffer->writeData(0,

posVertexBuffer->getSizeInBytes(),

pOutBuf,

true);

free(pOutBuf);

}

//Normal

if(ndecl){

void* pBuffer = (meshsec->m_vertexBuffer->getVertexDataPtr((*ndecl)));

if(pBuffer == NULL){

::MessageBoxA(NULL, "GetRenderData getVertexDataPtr Normal数据 失败", "Havok System Error", MB_OK|MB_ICONSTOP);

return -1;

}

int nNum = meshsec->m_vertexBuffer->getNumVertices();

void* pOutBuf = malloc(normalVertexBuffer->getSizeInBytes());

memset(pOutBuf, 0, normalVertexBuffer->getSizeInBytes());

for(int i=0; i<nNum; i++){

const float* pCurr = reinterpret_cast<float*>((char*)pBuffer + (ndecl->m_byteStride * i));

memcpy((char*)pOutBuf + i*3*sizeof(float), pCurr, 3*sizeof(float));

}



normalVertexBuffer->writeData(0,

normalVertexBuffer->getSizeInBytes(),

pOutBuf,

true);

free(pOutBuf);

}

//TextureCoord

if(tdecl){

void* pBuffer = (meshsec->m_vertexBuffer->getVertexDataPtr((*tdecl)));

if(pBuffer == NULL){

::MessageBoxA(NULL, "GetRenderData getVertexDataPtr Normal数据 失败", "Havok System Error", MB_OK|MB_ICONSTOP);

return -1;

}



void* pOutBuf = malloc(2*sizeof(float)*nVertexCount);

memset(pOutBuf, 0, 2*sizeof(float)*nVertexCount);

hkxVertexDescription::DataType TextDataType = vdesc.getElementType(hkxVertexDescription::HKX_DU_TEXCOORD, 0);

int nNum = meshsec->m_vertexBuffer->getNumVertices();

for(int i=0; i<nNum; i++){

if(TextDataType == hkxVertexDescription::HKX_DT_INT16){

unsigned short* pCurr = reinterpret_cast<unsigned short*>((char*)pBuffer + (tdecl->m_byteStride * i));

float uv[2] = { 0.0f};

uv[0] = pCurr[0] / 3276.7f;

uv[1] = 1 - (pCurr[1] / 3276.7f);

memcpy((char*)pOutBuf + i*2*sizeof(float), (const void*)uv, 2*sizeof(float));

}else if(TextDataType == hkxVertexDescription::HKX_DT_FLOAT){

float* pCurr = reinterpret_cast<float*>((char*)pBuffer + (tdecl->m_byteStride * i));

float uv[2] = { 0.0f};

uv[0] = pCurr[0];

uv[1] = pCurr[1];

memcpy((char*)pOutBuf + i*2*sizeof(float), (const void*)uv, 2*sizeof(float));

}

}

uvVertexBuffer->writeData(0,

uvVertexBuffer->getSizeInBytes(),

pOutBuf,

true);

free(pOutBuf);

}

//索引缓冲区

int nTriCount = meshsec->getNumTriangles();

if(nTriCount > 0){

Ogre::HardwareIndexBufferSharedPtr indexBuffer =

Ogre::HardwareBufferManager::getSingleton().createIndexBuffer(

Ogre::HardwareIndexBuffer::IT_16BIT,

nTriCount*3, //三角形数

Ogre::HardwareBuffer::HBU_STATIC, true);

//锁定mesh缓存,写入索引数据

unsigned short* faceVertexIndices = (unsigned short*)indexBuffer->lock(

0, nTriCount*3*2, Ogre::HardwareBuffer::HBL_DISCARD);

int nIndex = 0;

for(int i=0; i<nTriCount; i++){

hkUint32 a, b, c;

meshsec->getTriangleIndices(i, a, b, c);

//DBGSTRING("Triangle (%d, %d, %d)", a, b, c);

faceVertexIndices[nIndex++] = (unsigned short)a;

faceVertexIndices[nIndex++] = (unsigned short)b;

faceVertexIndices[nIndex++] = (unsigned short)c;

}

indexBuffer->unlock();

submesh->indexData->indexBuffer = indexBuffer;

submesh->indexData->indexStart = 0;

submesh->indexData->indexCount = nTriCount*3;

}

hkxMaterial* material = meshsec->m_material;

if(material != HK_NULL){

DBGSTRING("MaterialName: %s", material->m_name.cString());

Ogre::String strMatName = material->m_name.cString();

submesh->setMaterialName(strMatName);

}

pVertexSetData->mesh->load();

pVertexSetData->mesh->touch();

m_map.insert(VERTEXSET_MAP::value_type(meshsec, pVertexSetData));

return m_nMeshNum -1;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: