void OgreMeshRay::GetMeshInformation(const Ogre::ManualObject* manual, size_t& vertex_count, Ogre::Vector3*& vertices, size_t& index_count, unsigned long*& indices, const Ogre::Vector3& position, const Ogre::Quaternion& orient, const Ogre::Vector3& scale) { std::vector<Ogre::Vector3> returnVertices; std::vector<unsigned long> returnIndices; unsigned long thisSectionStart = 0; for (unsigned int i = 0, size = manual->getNumSections(); i < size; ++i) { Ogre::ManualObject::ManualObjectSection* section = manual->getSection( i); Ogre::RenderOperation* renderOp = section->getRenderOperation(); std::vector<Ogre::Vector3> pushVertices; //Collect the vertices { const Ogre::VertexElement* vertexElement = renderOp->vertexData->vertexDeclaration->findElementBySemantic( Ogre::VES_POSITION); Ogre::HardwareVertexBufferSharedPtr vertexBuffer = renderOp->vertexData->vertexBufferBinding->getBuffer( vertexElement->getSource()); char* verticesBuffer = static_cast<char*>(vertexBuffer->lock( Ogre::HardwareBuffer::HBL_READ_ONLY)); float* positionArrayHolder; thisSectionStart = returnVertices.size() + pushVertices.size(); pushVertices.reserve(renderOp->vertexData->vertexCount); for (unsigned int j = 0; j < renderOp->vertexData->vertexCount; ++j) { vertexElement->baseVertexPointerToElement( verticesBuffer + j * vertexBuffer->getVertexSize(), &positionArrayHolder); Ogre::Vector3 vertexPos = Ogre::Vector3(positionArrayHolder[0], positionArrayHolder[1], positionArrayHolder[2]); vertexPos = (orient * (vertexPos * scale)) + position; pushVertices.push_back(vertexPos); } vertexBuffer->unlock(); } //Collect the indices { if (renderOp->useIndexes) { Ogre::HardwareIndexBufferSharedPtr indexBuffer = renderOp->indexData->indexBuffer; if (indexBuffer.isNull() || renderOp->operationType != Ogre::RenderOperation::OT_TRIANGLE_LIST) { //No triangles here, so we just drop the collected vertices and move along to the next section. continue; } else { returnVertices.reserve( returnVertices.size() + pushVertices.size()); returnVertices.insert(returnVertices.end(), pushVertices.begin(), pushVertices.end()); } unsigned int* pLong = static_cast<unsigned int*>(indexBuffer->lock( Ogre::HardwareBuffer::HBL_READ_ONLY)); unsigned short* pShort = reinterpret_cast<unsigned short*>(pLong); returnIndices.reserve( returnIndices.size() + renderOp->indexData->indexCount); for (size_t j = 0; j < renderOp->indexData->indexCount; ++j) { unsigned long index; //We also have got to remember that for a multi section object, each section has //different vertices, so the indices will not be correct. To correct this, we //have to add the position of the first vertex in this section to the index //(At least I think so...) if (indexBuffer->getType() == Ogre::HardwareIndexBuffer::IT_32BIT) index = static_cast<unsigned long>(pLong[j]) + thisSectionStart; else index = static_cast<unsigned long>(pShort[j]) + thisSectionStart; returnIndices.push_back(index); } indexBuffer->unlock(); } } } //Now we simply return the data. index_count = returnIndices.size(); vertex_count = returnVertices.size(); vertices = new Ogre::Vector3[vertex_count]; for (unsigned long i = 0; i < vertex_count; ++i) vertices[i] = returnVertices[i]; indices = new unsigned long[index_count]; for (unsigned long i = 0; i < index_count; ++i) indices[i] = returnIndices[i]; //All done. return; }
void Renderer::FindClosestPolygon(Ogre::Entity* entity, float& closestDistance, Ogre::Vector3& position, Ogre::Vector3& normal) { closestDistance = std::numeric_limits<float>::max(); // default value (means // nothing detected) // Get transformation Ogre::SceneNode* parentNode = entity->getParentSceneNode(); Ogre::Vector3 parentPos; Ogre::Quaternion parentOrientation; Ogre::Vector3 parentScale; if (parentNode) { parentPos = parentNode->_getDerivedPosition(); parentOrientation = parentNode->_getDerivedOrientation(); parentScale = parentNode->_getDerivedScale(); } else { parentPos = Ogre::Vector3::ZERO; parentOrientation = Ogre::Quaternion::IDENTITY; parentScale = Ogre::Vector3::UNIT_SCALE; } // Handle animated entities bool isAnimated = entity->hasSkeleton(); if (isAnimated) { entity->addSoftwareAnimationRequest(false); entity->_updateAnimation(); } // Loop through each submesh Ogre::MeshPtr mesh = entity->getMesh(); for (uint i = 0; i < mesh->getNumSubMeshes(); ++i) { Ogre::SubMesh* subMesh = mesh->getSubMesh(i); // Ignore anything that isn't a triangle List if (subMesh->operationType != Ogre::RenderOperation::OT_TRIANGLE_LIST) continue; // Get the vertex data Ogre::VertexData* vertexData; if (subMesh->useSharedVertices) { if (isAnimated) vertexData = entity->_getSkelAnimVertexData(); else vertexData = mesh->sharedVertexData; } else { if (isAnimated) vertexData = entity->getSubEntity(i)->_getSkelAnimVertexData(); else vertexData = subMesh->vertexData; } // Get the size of one vertex const Ogre::VertexElement* posEl = vertexData->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION); Ogre::HardwareVertexBufferSharedPtr vBuff = vertexData->vertexBufferBinding->getBuffer(posEl->getSource()); uint vertexSize = vBuff->getVertexSize(); // Save pointer to first vertex short* pVertex = (short*)vBuff->lock(Ogre::HardwareBuffer::HBL_READ_ONLY); short* pStartVertex = pVertex; // Get the index buffer // If it is null then skip as it must be a point cloud Ogre::HardwareIndexBufferSharedPtr iBuff = subMesh->indexData->indexBuffer; if (iBuff.isNull()) continue; uint* pLong = (uint*)iBuff->lock(Ogre::HardwareBuffer::HBL_READ_ONLY); uint16_t* pShort = (uint16_t*)pLong; // Look through each vertex and check each triangle with the ray Ogre::Vector3 vertexPos; Ogre::Vector3 vertex1; Ogre::Vector3 vertex2; float* pReal; uint index; for (uint k = 0; k < subMesh->indexData->indexCount; k++) { // Read index value if (iBuff->getType() == Ogre::HardwareIndexBuffer::IT_32BIT) // if 32bit indexes { index = (uint)pLong[k]; } else { index = (uint)pShort[k]; } // Read referenced vertex pVertex = pStartVertex + (vertexSize * index); // calculate pointer posEl->baseVertexPointerToElement(pVertex, &pReal); // read vertex vertexPos = Ogre::Vector3(pReal[0], pReal[1], pReal[2]); // read position values // Apply world transformations if (parentNode) vertexPos = (parentOrientation * (vertexPos * parentScale)) + parentPos; // Figure out triangle and calculate the distance if it's the closest switch (k % 3) { case 0: vertex1 = vertexPos; break; case 1: vertex2 = vertexPos; break; case 2: RayToTriangleCheck(vertex1, vertex2, vertexPos, closestDistance, position, normal); break; default: break; } } iBuff->unlock(); vBuff->unlock(); } if (isAnimated) { entity->removeSoftwareAnimationRequest(false); } }
// Get the mesh information for the given mesh. // Code found in Wiki: www.ogre3d.org/wiki/index.php/RetrieveVertexData void OgreMeshRay::GetMeshInformation(const Ogre::MeshPtr mesh, size_t &vertex_count, Ogre::Vector3*& vertices, size_t& index_count, unsigned long*& indices, const Ogre::Vector3& position, const Ogre::Quaternion& orient, const Ogre::Vector3& scale) { bool added_shared = false; size_t current_offset = 0; size_t shared_offset = 0; size_t next_offset = 0; size_t index_offset = 0; vertex_count = index_count = 0; // Calculate how many vertices and indices we're going to need for (unsigned short i = 0, size = mesh->getNumSubMeshes(); i < size; ++i) { Ogre::SubMesh* submesh = mesh->getSubMesh(i); // We only need to add the shared vertices once if (submesh->useSharedVertices) { if (!added_shared) { vertex_count += mesh->sharedVertexData->vertexCount; added_shared = true; } } else { vertex_count += submesh->vertexData->vertexCount; } // Add the indices index_count += submesh->indexData->indexCount; } // Allocate space for the vertices and indices vertices = new Ogre::Vector3[vertex_count]; indices = new unsigned long[index_count]; added_shared = false; // Run through the submeshes again, adding the data into the arrays for (unsigned short i = 0, size = mesh->getNumSubMeshes(); i < size; ++i) { Ogre::SubMesh* submesh = mesh->getSubMesh(i); Ogre::VertexData* vertex_data = submesh->useSharedVertices ? mesh->sharedVertexData : submesh->vertexData; if ((!submesh->useSharedVertices) || (submesh->useSharedVertices && !added_shared)) { if (submesh->useSharedVertices) { added_shared = true; shared_offset = current_offset; } const Ogre::VertexElement* posElem = vertex_data->vertexDeclaration->findElementBySemantic( Ogre::VES_POSITION); Ogre::HardwareVertexBufferSharedPtr vbuf = vertex_data->vertexBufferBinding->getBuffer( posElem->getSource()); unsigned char* vertex = static_cast<unsigned char*>(vbuf->lock( Ogre::HardwareBuffer::HBL_READ_ONLY)); // There is _no_ baseVertexPointerToElement() which takes an Ogre::Real or a double // as second argument. So make it float, to avoid trouble when Ogre::Real will // be comiled/typedefed as double: // Ogre::Real* pReal; float* pReal; for (size_t j = 0; j < vertex_data->vertexCount; ++j, vertex += vbuf->getVertexSize()) { posElem->baseVertexPointerToElement(vertex, &pReal); Ogre::Vector3 pt(pReal[0], pReal[1], pReal[2]); vertices[current_offset + j] = (orient * (pt * scale)) + position; } vbuf->unlock(); next_offset += vertex_data->vertexCount; } Ogre::IndexData* index_data = submesh->indexData; size_t numTris = index_data->indexCount / 3; Ogre::HardwareIndexBufferSharedPtr ibuf = index_data->indexBuffer; if (ibuf.isNull()) continue; // need to check if index buffer is valid (which will be not if the mesh doesn't have triangles like a pointcloud) bool use32bitindexes = (ibuf->getType() == Ogre::HardwareIndexBuffer::IT_32BIT); unsigned long* pLong = static_cast<unsigned long*>(ibuf->lock( Ogre::HardwareBuffer::HBL_READ_ONLY)); unsigned short* pShort = reinterpret_cast<unsigned short*>(pLong); size_t offset = (submesh->useSharedVertices) ? shared_offset : current_offset; size_t index_start = index_data->indexStart; size_t last_index = numTris * 3 + index_start; if (use32bitindexes) { for (size_t k = index_start; k < last_index; ++k) { indices[index_offset++] = pLong[k] + static_cast<unsigned long>(offset); } } else { for (size_t k = index_start; k < last_index; ++k) { indices[index_offset++] = static_cast<unsigned long>(pShort[k]) + static_cast<unsigned long>(offset); } } ibuf->unlock(); current_offset = next_offset; } }
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; }