/*求对象rend和射线ray的全部交点到射线原点的距离 */ vector<Ogre::Real> BaseManager::Intersect(const Ogre::Ray& ray,Ogre::Renderable *rend){ Ogre::RenderOperation op; Ogre::VertexElementType vtype; size_t offset,pkgsize,source,indexNums,vertexNums; vector<Ogre::Real> result; rend->getRenderOperation( op ); if( !op.indexData || op.operationType==Ogre::RenderOperation::OT_LINE_LIST || op.operationType==Ogre::RenderOperation::OT_LINE_STRIP || op.operationType==Ogre::RenderOperation::OT_POINT_LIST ) return result; Ogre::VertexDeclaration* pvd = op.vertexData->vertexDeclaration; source = -1; for( size_t i = 0;i < pvd->getElementCount();++i ){ if( pvd->getElement(i)->getSemantic()==Ogre::VES_POSITION ){ source = pvd->getElement(i)->getSource(); offset = pvd->getElement(i)->getOffset(); vtype = pvd->getElement(i)->getType(); break; } } if( source == - 1 || vtype != Ogre::VET_FLOAT3 ) //别的格式目前没有考虑 return result; /*source对应与一个缓存区 getVertexSize(source)求缓存区中一个紧密数据包的大小 例如:一个数据包里面包括POSITION,COLOR,NORMAL,TEXCROOD然后在这个缓冲 区中循环。而getVertexSize求出这个包的字节大小 例如POSITION(FLOAT3) TEXCROOD(FLOAT2) 这样前面的是12字节后面的是8字节 getVertexSize返回20 */ pkgsize = pvd->getVertexSize(source); Ogre::HardwareVertexBufferSharedPtr hvb = op.vertexData->vertexBufferBinding->getBuffer(source); Ogre::HardwareIndexBufferSharedPtr ivb = op.indexData->indexBuffer; Ogre::HardwareIndexBuffer::IndexType indexType = op.indexData->indexBuffer->getType(); /*先将顶点数据复制一份,然后变换到世界坐标系 */ vertexNums = hvb->getNumVertices(); indexNums = ivb->getNumIndexes(); boost::scoped_array<float> vp( new float[3*vertexNums] ); boost::scoped_array<unsigned int> ip( new unsigned int[indexNums] ); { Ogre::Vector3 p3; Ogre::Matrix4 mat; rend->getWorldTransforms( &mat ); float* preal = (float*)hvb->lock( Ogre::HardwareBuffer::HBL_READ_ONLY ); float* ptarget = vp.get(); //这里考虑到对齐,我假设offset和pkgsize都可以被sizeof(float)整除 preal += offset/sizeof(float); size_t strip = pkgsize/sizeof(float); for( size_t i = 0; i < vertexNums;++i ){ p3.x = *preal; p3.y = *(preal+1); p3.z = *(preal+2); p3 = mat * p3; *ptarget++ = p3.x; *ptarget++ = p3.y; *ptarget++ = p3.z; preal += strip; } hvb->unlock(); } //拷贝出顶点数据 { unsigned int* pindex32 = ip.get(); if( indexType==Ogre::HardwareIndexBuffer::IT_16BIT ){ unsigned short* pi16 = (unsigned short*)ivb->lock( Ogre::HardwareBuffer::HBL_READ_ONLY ); copy( pi16,pi16+indexNums,pindex32 ); }else memcpy( pindex32,ivb->lock( Ogre::HardwareBuffer::HBL_READ_ONLY ),ivb->getSizeInBytes() ); ivb->unlock(); } /*数据都准备好了,vp保存了变换好的顶点,ip保存了顶点索引 下面根据情况求交点 */ switch( op.operationType ){ case Ogre::RenderOperation::OT_TRIANGLE_LIST: { /* 0,1,2 组成一个三角 3,4,5 下一个... */ Ogre::Vector3 a[3],n; int index,k = 0; float* preal = vp.get(); unsigned int* pindex = ip.get(); for( size_t i = 0;i<indexNums;++i ){ if( pindex[i] < vertexNums ){ index = pindex[i]*3; //对应与格式VET_FLOAT3 a[k].x = preal[index]; a[k].y = preal[index+1]; a[k].z = preal[index+2]; if( k == 2 ){//三个点都填满了 //这里使用的是Math3d的求交函数,而不是Ogre::Math的 //原因就在于Ogre::Math的求交点函数不能得到射线背面那个负的交点 std::pair<bool,Ogre::Real> res = Math3d::intersects(ray,a[0],a[1],a[2],true,true); if( res.first ) result.push_back( res.second ); k = 0; }else k++; }else{ WARNING_LOG("Game::Intersect"<<" Invalid index rang out" << " pindex["<<i<<"]="<<pindex[i] << "("<<vertexNums<<")"); return result; } } } break; case Ogre::RenderOperation::OT_TRIANGLE_FAN: {/* 0,1,2组成一个三角 0,2,3 组成下一个 0,3,4... */ assert( false||"Game::Intersect can't support OT_TRIANGLE_FAN " ); } break; case Ogre::RenderOperation::OT_TRIANGLE_STRIP: {//0,1,2组成第一个三角 1,2,3 组成下一个 2,3,4... assert( false||"Game::Intersect can't support OT_TRIANGLE_STRIP " ); } break; default:; } return result; }
bool ShaderParticleRenderer::allocateBuffers(size_t iNumParticles) { // prepare vertex declaration if (mVertexData->vertexDeclaration->getElementCount() == 0) { VertexDeclaration* pDecl = mVertexData->vertexDeclaration; size_t ofs = 0; ofs += pDecl->addElement(0, ofs, VET_FLOAT4, VES_POSITION).getSize(); // position if (mVertexFormatColour) ofs += pDecl->addElement(0, ofs, VET_FLOAT4, VES_DIFFUSE).getSize(); // diffuse colour // other data are stored in vertex as texture coordinates ushort ix = 0; if (mVertexFormatTexture) ofs += pDecl->addElement(0, ofs, VET_FLOAT2, VES_TEXTURE_COORDINATES, ix++).getSize(); // general texture coord if (mVertexFormatSize) ofs += pDecl->addElement(0, ofs, VET_FLOAT2, VES_TEXTURE_COORDINATES, ix++).getSize(); // particle size if (mVertexFormatRotation || mVertexFormatRotationSpeed) { if (mVertexFormatRotation && mVertexFormatRotationSpeed) ofs += pDecl->addElement(0, ofs, VET_FLOAT2, VES_TEXTURE_COORDINATES, ix++).getSize(); // current rotation and rotation speed else ofs += pDecl->addElement(0, ofs, VET_FLOAT1, VES_TEXTURE_COORDINATES, ix++).getSize(); // current rotation or rotation speed } if (mVertexFormatDirection) ofs += pDecl->addElement(0, ofs, VET_FLOAT3, VES_TEXTURE_COORDINATES, ix++).getSize(); // particle direction (as speed) // add packed times size_t iNumTimes = 0; if (mVertexFormatTTL) iNumTimes++; if (mVertexFormatTotalTTL) iNumTimes++; if (mVertexFormatTimeFragment) iNumTimes++; if (mVertexFormatTimeFragmentInv) iNumTimes++; switch(iNumTimes) { case 1: ofs += pDecl->addElement(0, ofs, VET_FLOAT1, VES_TEXTURE_COORDINATES, ix++).getSize(); break; case 2: ofs += pDecl->addElement(0, ofs, VET_FLOAT2, VES_TEXTURE_COORDINATES, ix++).getSize(); break; case 3: ofs += pDecl->addElement(0, ofs, VET_FLOAT3, VES_TEXTURE_COORDINATES, ix++).getSize(); break; case 4: ofs += pDecl->addElement(0, ofs, VET_FLOAT4, VES_TEXTURE_COORDINATES, ix++).getSize(); break; } // add custom parameters ofs += pDecl->addElement(0, ofs, VET_FLOAT4, VES_TEXTURE_COORDINATES, ix++).getSize(); assert(ix <= 8); // cache vertex size mVertexSize = pDecl->getVertexSize(0); } Ogre::HardwareVertexBufferSharedPtr pVB; if (mVertexData->vertexBufferBinding->isBufferBound(0)) pVB = mVertexData->vertexBufferBinding->getBuffer(0); // prepare vertex buffer if (pVB.isNull() || pVB->getNumVertices() < iNumParticles * 4) { assert(iNumParticles * 4 < 65536); // we are using 16bit index buffer pVB = Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(mVertexSize, 4 * iNumParticles, Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE); if (pVB.isNull()) return false; mVertexData->vertexBufferBinding->setBinding(0, pVB); } // prepare index buffer Ogre::HardwareIndexBufferSharedPtr pIB = mIndexData->indexBuffer; if (pIB.isNull() || pIB->getNumIndexes() < iNumParticles * 6) { pIB = Ogre::HardwareBufferManager::getSingleton().createIndexBuffer(Ogre::HardwareIndexBuffer::IT_16BIT, iNumParticles * 6, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY); if (pIB.isNull()) return false; mIndexData->indexBuffer = pIB; // fill Ogre::uint16* pDataIB = reinterpret_cast<Ogre::uint16*>(pIB->lock(Ogre::HardwareBuffer::HBL_NORMAL)); for (Ogre::uint16 k=0; k<static_cast<Ogre::uint16>(iNumParticles); ++k) { pDataIB[0] = k*4 + 0; pDataIB[1] = k*4 + 1; pDataIB[2] = k*4 + 2; pDataIB[3] = k*4 + 0; pDataIB[4] = k*4 + 2; pDataIB[5] = k*4 + 3; pDataIB += 6; } pIB->unlock(); } return true; }