Пример #1
0
	/*求对象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;
	}
//------------------------------------------------------------------------------------------------
void DebugLines::draw()
{
    if (_drawn || _points.empty()) 
        return;
    else 
        _drawn = true;

    // Initialization stuff
    mRenderOp.vertexData->vertexCount = _points.size();

    Ogre::VertexDeclaration *decl = mRenderOp.vertexData->vertexDeclaration;
    Ogre::VertexBufferBinding *bind = mRenderOp.vertexData->vertexBufferBinding;

	HardwareVertexBufferSharedPtr vbuf;
	if(decl->getElementCount() == 0)
	{
		decl->addElement(0, 0, VET_FLOAT3, VES_POSITION);
		decl->addElement(0, 12, VET_FLOAT1, VES_TEXTURE_COORDINATES);
		if ( mHasColours )
			decl->addElement(0, 16, VET_COLOUR, VES_DIFFUSE);


		vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
			decl->getVertexSize(0),
			mRenderOp.vertexData->vertexCount,
			HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE);

		bind->setBinding(0, vbuf);
	}
	else
	{
		bind->unsetAllBindings();

		 vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
			decl->getVertexSize(0),
			mRenderOp.vertexData->vertexCount,
			HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE);

		bind->setBinding(0, vbuf); 
	}

    // Drawing stuff
    unsigned int size = (unsigned int)_points.size();
    Ogre::Vector3 vaabMin = _points[0];
    Ogre::Vector3 vaabMax = _points[0];

    float *prPos = static_cast<float*>(vbuf->lock(HardwareBuffer::HBL_DISCARD));

    for(unsigned int i = 0; i < size; i++)
    {
        *prPos++ = _points[i].x;
        *prPos++ = _points[i].y;
        *prPos++ = _points[i].z;
		*prPos++ = 0;
		
		if ( mHasColours ) {
			unsigned int* colorPtr = reinterpret_cast<unsigned int*>(prPos++);
			Ogre::ColourValue col = _colours[i];
			//col.setHSB( (float)(i%256)/256.0f, 1.0f, 1.0f );
			Ogre::Root::getSingleton().convertColourValue(col, colorPtr);
		}
			
        if (_points[i].x < vaabMin.x)
			vaabMin.x = _points[i].x;
		else if (_points[i].x > vaabMax.x)
			vaabMax.x = _points[i].x;

        if (_points[i].y < vaabMin.y)
			vaabMin.y = _points[i].y;
		else if (_points[i].y > vaabMax.y)
			vaabMax.y = _points[i].y;

        if (_points[i].z < vaabMin.z)
			vaabMin.z = _points[i].z;
		else if (_points[i].z > vaabMax.z)
			vaabMax.z = _points[i].z;
    }

    vbuf->unlock();

    mBox.setInfinite();
	//mBox.Extents(vaabMin, vaabMax);
}