📄 ogrepaginglandscaperayscenequery.cpp
字号:
/***************************************************************************
OgrePagingLandScapeRaySceneQuery.cpp - description
-------------------
begin : Fri Sep 10 2003
copyright : (C) 2003 by Jose A Milan
email : spoke2@supercable.es
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation; either version 2 of the *
* License, or (at your option) any later version. *
* *
***************************************************************************/
#include <OgreEntity.h>
#include "OgrePagingLandScapeRaySceneQuery.h"
#include "OgrePagingLandScapePrerequisites.h"
namespace Ogre
{
//----------------------------------------------------------------------------
// This function return the vertex interpolated height.
// Supplied by Praetor. Thanks a lot. ]:)
void PagingLandScapeRaySceneQuery::execute(RaySceneQueryListener* listener)
{
clearFragmentList();
unsigned long mask = getQueryMask();
SceneQuery::WorldFragment* frag;
if(mask & RSQ_Height)
{
// we don't want to bother checking for entities because a
// UNIT_Y ray is assumed to be a height test, not a ray test
frag = new SceneQuery::WorldFragment();
fragmentList.push_back(frag);
frag->fragmentType = SceneQuery::WFT_SINGLE_INTERSECTION;
Vector3 origin = mRay.getOrigin();
origin.y = 0; // ensure that it's within bounds
frag->singleIntersection = getHeightAt(origin);
listener->queryResult(frag, 0);
}
else
{
// Check for entity contacts
if(mask & RSQ_Entities)
{
DefaultRaySceneQuery::execute(listener);
}
if(mask & RSQ_AllTerrain || mask & RSQ_FirstTerrain)
{
Vector3 ray = mRay.getOrigin();
Vector3 land = getHeightAt(ray);
Real dist = 0, resFactor = 1;
// Only bother if the non-default mask has been set
if((mask & RSQ_1xRes) == 0)
{
if(mask & RSQ_2xRes)
{
resFactor = 0.5;
}
else if(mask & RSQ_4xRes)
{
resFactor = 0.25;
}
else if(mask & RSQ_8xRes)
{
resFactor = 0.125;
}
}
while(land.y != -1)
{
ray += mRay.getDirection() * resFactor;
dist += 1 * resFactor;
land = getHeightAt(ray);
if(ray.y < land.y)
{
frag = new SceneQuery::WorldFragment();
fragmentList.push_back(frag);
frag->fragmentType = SceneQuery::WFT_SINGLE_INTERSECTION;
frag->singleIntersection = land;
listener->queryResult(frag, dist);
if(mask & RSQ_FirstTerrain)
{
return;
}
}
}
}
}
}
//----------------------------------------------------------------------------
Vector3 PagingLandScapeRaySceneQuery::getHeightAt(const Vector3& origin)
{
return Vector3(origin.x, static_cast<PagingLandScapeSceneManager*>(mParentSceneMgr) -> getRealWorldHeight (origin.x, origin.z), origin.z);
}
/*
PagingLandScapeSceneManager* sceneMgr = static_cast<PagingLandScapeSceneManager*>(mParentSceneMgr);
Real nearest[4] = {0, 0, 0, 0}, alpha, beta, gamma;
int xBase, zBase;
Real xFactor, zFactor;
PagingLandScapePage* page;
HardwareVertexBufferSharedPtr vertexBuffer, neighborBuffer;
RenderOperation rOp, rOp1, rOp2, rOp3;
Real *vertexData, *neighborData;
PagingLandScapeTile *tile, *base, *neighborX, *neighborZ, *neighborSE;
////////////////////////////////////////////////
// Iterate through all of the page rows
for(int pz = 0;pz < mOptions->world_height;pz++)
{
////////////////////////////////////////////////
// Iterate through all of the page columns
for(int px = 0;px < mOptions->world_width;px++)
{
////////////////////////////////
// Check if the page is loaded
page = sceneMgr->mPages[px][pz];
if(page->isLoaded() == true)
{
////////////////////////////////////////////
// Check if the camera is within the page
if(page->isCameraIn(origin) != PAGE_OUTSIDE)
{
// Iterate through all of the tile columns
for(unsigned int tx = 0;tx < page->mTiles.size();tx++)
{
//////////////////////////////////////////////////////////
// Iterate through all of the tile rows
for(unsigned int tz = 0;tz < page->mTiles[tx].size();tz++)
{
base = tile = page->mTiles[tx][tz];
/////////////////////////////////////////////
// Determine if the point is within the tile
const AxisAlignedBox& box = tile->getBoundingBox();
const Vector3& vMin = box.getMinimum();
const Vector3& vMax = box.getMaximum();
//if(vectorIsInside(origin, vMin, vMax))
if (((AxisAlignedBox)tile->getBoundingBox()).intersects(origin))
{
////////////////////////////////////////////
// If we don't find a valid tile, then just
// default to the old nearest vertex result
if((tile = getNonDividedTile(tile, origin)) == 0)
{
return Vector3(origin.x, page->_getWorldHeight((int)origin.x, (int)origin.z), origin.z);
}
/////////////////////////////
// Localize the coordinates
const AxisAlignedBox& box2 = tile->getBoundingBox();
const Vector3& tMin = box2.getMinimum();
const Vector3& tMax = box2.getMaximum();
//////////////////////////////////////////
// Get the dimensions of the tile and the
// relative coordinates
Vector3 tSize = tMax - tMin;
Vector3 relPos = origin - tMin;
///////////////////////////////////////////////////
// Find out the relative dimensions of each vertex
// *Note: there is only a 5x5 grid of vertices
Vector3 relSize = tSize / 5;
/////////////////////////////////////////////
// Finally, we can assign the vertex offsets
Vector3 localPos;
localPos.x = relPos.x / relSize.x;
localPos.z = relPos.z / relSize.z;
xBase = (int)localPos.x;
zBase = (int)localPos.z;
xFactor = localPos.x - (xBase);
zFactor = localPos.z - (zBase);
////////////////////////////////////////
// Okay, we finally have a valid tile,
// now we can finally query the vertex
// data and get on with life
tile->mRenderable->getRenderOperation(rOp);
vertexBuffer = rOp.vertexData->vertexBufferBinding->getBuffer(POSITION_BINDING);
if(vertexBuffer->isLocked())
{
return Vector3(origin.x, page->_getWorldHeight((int)origin.x, (int)origin.z), origin.z);
}
vertexData = static_cast<Real*>(vertexBuffer->lock(HardwareBuffer::HBL_NORMAL));
if(xFactor == 0 && zFactor == 0)
{
// We're on top of a vertex, so we'll just use that data
Real tHeight = vertexData[1 + ((xBase + (zBase * 5)) * 3)];
vertexBuffer->unlock();
return Vector3(origin.x, tHeight, origin.z);
}
//////////////////////////////////
// Get the nearest four vertices
// First, we need to see if we're in a border region and
// if so we need to load a neighboring tile
nearest[0] = vertexData[1 + ((xBase + (zBase * 5)) * 3)];
/////////////////////////////////
// If xBase >= 4 then it means that we need to load the next
// tile from the X-axis
if(xBase >= 4)
{
neighborX = getNonDividedTile(base, Vector3(origin.x + relSize.x, origin.y, origin.z));
if(neighborX != 0)
{
neighborX->mRenderable->getRenderOperation(rOp1);
neighborBuffer = rOp1.vertexData->vertexBufferBinding->getBuffer(POSITION_BINDING);
if(neighborBuffer->isLocked())
{
nearest[1] = vertexData[1 + ((xBase + (zBase * 5)) * 3)];
}
else
{
neighborData = static_cast<Real*>(neighborBuffer->lock(HardwareBuffer::HBL_NORMAL));
nearest[1] = neighborData[(zBase * 15) + 1];
}
// If we're not in a corner, we'll need another vertex
// from here
if(zBase < 4)
{
nearest[2] = neighborData[((zBase + 1) * 15) + 1];
}
neighborBuffer->unlock();
}
else
{
nearest[1] = vertexData[1 + ((xBase + (zBase * 5)) * 3)];
}
}
else
{
nearest[1] = vertexData[1 + (((xBase + 1) + (zBase * 5)) * 3)];
}
/////////////////////////////////
// If zBase >= 4 then we need to load the next tile down the Z axis
if(zBase >= 4)
{
neighborZ = getNonDividedTile(base, Vector3(origin.x, origin.y, origin.z + relSize.z));
if(neighborZ != 0)
{
neighborZ->mRenderable->getRenderOperation(rOp2);
neighborBuffer = rOp2.vertexData->vertexBufferBinding->getBuffer(POSITION_BINDING);
if(neighborBuffer->isLocked())
{
nearest[3] = vertexData[1 + ((xBase + (zBase * 5)) * 3)];
}
else
{
neighborData = static_cast<Real*>(neighborBuffer->lock(HardwareBuffer::HBL_NORMAL));
nearest[3] = neighborData[(xBase * 3) + 1];
}
// If we're not in a corner, we'll need another vertex
// from here
if(xBase < 4)
{
nearest[2] = neighborData[((xBase + 1) * 3) + 1];
}
neighborBuffer->unlock();
}
else
{
nearest[3] = vertexData[1 + ((xBase + (zBase * 5)) * 3)];
}
}
else
{
nearest[3] = vertexData[1 + ((xBase + ((zBase + 1) * 5)) * 3)];
}
/////////////////////////////////
// If they both are 4 that means we're in a corner and need
// to load the tile to the southeast. We'll just move east from
// the southern loaded tile since both should exist
if(xBase >= 4 && zBase >= 4)
{
neighborSE = getNonDividedTile(base, Vector3(origin.x + relSize.x, origin.y, origin.z + relSize.z));
if(neighborSE != 0)
{
neighborSE->mRenderable->getRenderOperation(rOp3);
neighborBuffer = rOp3.vertexData->vertexBufferBinding->getBuffer(POSITION_BINDING);
if(neighborBuffer->isLocked())
{
nearest[2] = vertexData[1 + ((xBase + (zBase * 5)) * 3)];
}
else
{
neighborData = static_cast<Real*>(neighborBuffer->lock(HardwareBuffer::HBL_NORMAL));
nearest[2] = neighborData[1];
}
neighborBuffer->unlock();
}
else
{
nearest[2] = vertexData[1 + ((xBase + (zBase * 5)) * 3)];
}
}
else if(xBase < 4 && zBase < 4)
{
nearest[2] = vertexData[1 + (((xBase + 1) + ((zBase + 1) * 5)) * 3)];
}
vertexBuffer->unlock();
/////////////////////////////////
// Interpolate along the x axis
alpha = nearest[0] + ((nearest[1] - nearest[0]) * xFactor);
beta = nearest[3] + ((nearest[2] - nearest[3]) * xFactor);
/////////////////////////////////
// Interpolate along the z axis
gamma = alpha + ((beta - alpha) * zFactor);
/////////////////////////////////
// Return the results
return Vector3(origin.x, gamma, origin.z);
}
}
}
}
}
}
}
return Vector3(-1, -1, -1);
}
*/
/*
//----------------------------------------------------------------------------
PagingLandScapeTile* PagingLandScapeRaySceneQuery::getNonDividedTile(PagingLandScapeTile* tile, const Vector3& origin)
{
PagingLandScapeTile* retTile = 0;
//////////////////////////////////////////////////
// Determine if the camera is within the tile.
if (((AxisAlignedBox)tile->getBoundingBox()).intersects(origin))
{
///////////////////////////////////////////////
// Check to see if this tile is divided.
if(tile->isDivided())
{
///////////////////////////////////////////
// If the tile is divided, recurse through
// its children
for(int i = 0;i < 4;i++)
{
///////////////////////////////////////
// If we find the tile, return it
if((retTile = getNonDividedTile(tile->mTile[i], origin)) != 0)
{
return retTile;
}
}
///////////////////////////////////////
// If we ever get here, it means we
// didn't find a suitable tile
return 0;
}
else
{
return tile;
}
}
///////////////////////////////////////////////////
// Otherwise if the point is not in this tile
// return an invalid pointer
else
{
return 0;
}
///////////////////////////
// Should never reach here
return 0;
}
*/
} // namespace Ogre
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -