📄 ettile.cpp
字号:
}
void Tile::getRenderOperation(RenderOperation& op)
{
op.useIndexes = true;
op.operationType = RenderOperation::OT_TRIANGLE_LIST;
op.vertexData = mTerrain;
op.indexData = getIndexData();
}
void Tile::_updateRenderQueue(RenderQueue* queue)
{
mLightListDirty = true;
queue->addRenderable(this, mRenderQueueID);
}
void Tile::_updateCustomGpuParameter(const GpuProgramParameters::AutoConstantEntry& constEntry,
GpuProgramParameters* params) const
{
if (constEntry.data == MORPH_CUSTOM_PARAM_ID)
{
params->_writeRawConstant(constEntry.physicalIndex, mLODMorphFactor);
}
else
{
Renderable::_updateCustomGpuParameter(constEntry, params);
}
}
Vector3 Tile::getVector(size_t x, size_t z) const
{
float posX = mInfo.getOffset().x + (mStartX + x)*mInfo.getScaling().x;
float posZ = mInfo.getOffset().z + (mStartZ + z)*mInfo.getScaling().z;
return Vector3(posX, mInfo.getHeightAt(posX, posZ), posZ);
}
void Tile::calculateMinLevelDist2()
{
Real C = mOpt.factorC;
// LOD 0 has no distance
mLODChangeMinDistSqr[0] = 0.0f;
for (unsigned int level = 1; level < mOpt.maxMipMapLevel; ++level)
{
mLODChangeMinDistSqr[level] = 0.0f;
size_t step = 1 << level;
size_t higherstep = step >> 1;
float* pDeltas = 0;
// for LOD morphing, lock the according delta buffer now
if (mOpt.useLODMorph)
{
// indexed at LOD-1, because there are only maxLOD-1 transitions between LODs...
emptyBuffer(mDeltaBuffers[level-1]);
pDeltas = static_cast<float*>(mDeltaBuffers[level-1]->lock(HardwareBuffer::HBL_NORMAL));
}
// for every vertex that is not used in the current LOD we calculate its interpolated
// height and compare against its actual height. the largest difference of a vertex
// is then used to determine the minimal distance for this LOD.
for (size_t j = 0; j < mOpt.tileSize - step; j += step)
{
for (size_t i = 0; i < mOpt.tileSize - step; i += step)
{
Vector3 v1 = getVector(i, j);
Vector3 v2 = getVector(i+step, j);
Vector3 v3 = getVector(i, j+step);
Vector3 v4 = getVector(i+step, j+step);
Plane t1 (v1, v3, v2);
Plane t2 (v2, v3, v4);
size_t zubound = (j == (mOpt.tileSize - step) ? step : step - 1);
for (size_t z = 0; z <= zubound; ++z)
{
size_t xubound = (i == (mOpt.tileSize - step) ? step : step - 1);
for (size_t x = 0; x < xubound; ++x)
{
size_t fulldetailx = i + x;
size_t fulldetailz = j + z;
if (fulldetailx % step == 0 && fulldetailz % step == 0)
{
continue;
}
Real zpct = Real(z) / Real(step);
Real xpct = Real(x) / Real(step);
Vector3 actualPos = getVector(fulldetailx, fulldetailz);
Real interp_h;
if (xpct + zpct <= 1.0f)
{
interp_h = (
-(t1.normal.x * actualPos.x)
- t1.normal.z * actualPos.z
- t1.d) / t1.normal.y;
}
else
{
interp_h = (
-(t2.normal.x * actualPos.x)
- t2.normal.z * actualPos.z
- t2.d) / t2.normal.y;
}
Real actual_h = getVector(fulldetailx, fulldetailz).y;
Real delta = fabs(interp_h - actual_h);
Real D2 = delta * delta * C * C;
if (mLODChangeMinDistSqr[level] < D2)
mLODChangeMinDistSqr[level] = D2;
// for LOD morphing, store the difference in the delta buffer
if (mOpt.useLODMorph &&
fulldetailx != 0 && fulldetailx != (mOpt.tileSize-1) &&
fulldetailz != 0 && fulldetailz != (mOpt.tileSize-1))
{
pDeltas[fulldetailx + (fulldetailz * mOpt.tileSize)] = interp_h - actual_h;
}
}
}
}
}
// unlock delta buffers
if (mOpt.useLODMorph)
mDeltaBuffers[level-1]->unlock();
}
// post validate
for (unsigned int i = 1; i < mOpt.maxMipMapLevel; ++i)
{
// ensure level distances are increasing
if (mLODChangeMinDistSqr[i] < mLODChangeMinDistSqr[i-1])
mLODChangeMinDistSqr[i] = mLODChangeMinDistSqr[i-1];
}
}
void Tile::_notifyCurrentCamera(Camera* cam)
{
MovableObject::_notifyCurrentCamera(cam);
Vector3 cpos = cam->getDerivedPosition();
const AxisAlignedBox& aabb = getWorldBoundingBox(true);
Vector3 diff(0, 0, 0);
diff.makeFloor(cpos - aabb.getMinimum());
diff.makeCeil(cpos - aabb.getMaximum());
// find the LOD to use for this tile
Real L = diff.squaredLength();
mLOD = mOpt.maxMipMapLevel-1;
for (unsigned int i = 1; i < mOpt.maxMipMapLevel; ++i)
{
if (mLODChangeMinDistSqr[i] > L)
{
mLOD = i - 1;
break;
}
}
if (mOpt.useLODMorph)
{
// find the next LOD after the current one
unsigned int nextLevel = mLOD + 1;
for (unsigned int i = nextLevel; i < mOpt.maxMipMapLevel; ++i)
{
if (mLODChangeMinDistSqr[i] > mLODChangeMinDistSqr[mLOD])
{
nextLevel = i;
break;
}
}
// determine the LOD morph factor between the two LODs
if (nextLevel == mOpt.maxMipMapLevel)
{
mLODMorphFactor = 0;
}
else
{
Real range = mLODChangeMinDistSqr[nextLevel] - mLODChangeMinDistSqr[mLOD];
Real percent = (L - mLODChangeMinDistSqr[mLOD]) / range;
Real rescale = 1.0f / (1.0f - mOpt.lodMorphStart);
mLODMorphFactor = std::max((percent - mOpt.lodMorphStart), Real(0));
}
if (mLastNextLevel != nextLevel)
{
if (nextLevel != mOpt.maxMipMapLevel)
{
mTerrain->vertexBufferBinding->setBinding(DELTA_BINDING, mDeltaBuffers[nextLevel-1]);
}
else
{
// bind dummy
mTerrain->vertexBufferBinding->setBinding(DELTA_BINDING, mDeltaBuffers[0]);
}
}
mLastNextLevel = nextLevel;
}
}
unsigned int Tile::getLOD() const
{
return mLOD;
}
void Tile::updateTerrain(size_t startx, size_t startz, size_t endx, size_t endz)
{
// determine the area of this tile that needs to be updated
size_t fromX = std::max(mStartX, startx);
size_t fromZ = std::max(mStartZ, startz);
size_t toX = std::min(endx, mStartX+mOpt.tileSize-1);
size_t toZ = std::min(endz, mStartZ+mOpt.tileSize-1);
const VertexElement* posElem = mTerrain->vertexDeclaration->findElementBySemantic(VES_POSITION);
unsigned char* pBase = static_cast<unsigned char*>(mMainBuffer->lock(HardwareBuffer::HBL_NORMAL));
// update all necessary vertices
for (size_t j = fromZ; j <= toZ; ++j)
{
for (size_t i = fromX; i <= toX; ++i)
{
size_t tX = i - mStartX;
size_t tZ = j - mStartZ;
unsigned char* pBasePos = pBase + (tZ*mOpt.tileSize + tX) * mMainBuffer->getVertexSize();
Real height = mInfo.getOffset().y + mInfo.at(i, j) * mInfo.getScaling().y;
float* pPos;
posElem->baseVertexPointerToElement(pBasePos, &pPos);
pPos[1] = height;
}
}
mMainBuffer->unlock();
// update the extents of this terrain tile
size_t ex = mStartX + mOpt.tileSize;
size_t ez = mStartZ + mOpt.tileSize;
// find min and max heights
Real minHeight = mInfo.getOffset().y + mInfo.getScaling().y, maxHeight = mInfo.getOffset().y;
for (size_t j = mStartZ; j < ez; ++j)
{
for (size_t i = mStartX; i < ex; ++i)
{
Real height = mInfo.getOffset().y + mInfo.at(i, j)*mInfo.getScaling().y;
if (height < minHeight)
minHeight = height;
if (height > maxHeight)
maxHeight = height;
}
}
mBounds.setMinimumY(minHeight);
mBounds.setMaximumY(maxHeight);
mCenter = mBounds.getCenter();
mBoundingRadius = (mBounds.getMaximum() - mCenter).length();
// recalculate the distances at which to switch LOD
calculateMinLevelDist2();
// recalculate vertex normals, if necessary
if (mOpt.vertexNormals)
calculateVertexNormals();
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -