field.cpp
来自「x3d_new.rar」· C++ 代码 · 共 472 行 · 第 1/2 页
CPP
472 行
fAverage = (GetHeight(ex, sz) + GetHeight(sx, ez)) >> 1;
nError = max(nError, abs_int(fAverage - GetHeight(pTile->m_cx, pTile->m_cz)));
return nError;
}
int CField::CalculateMaxTileNum(int nSize)
{
int nMaxTilesNum = 0;
int nSteps = log2(nSize);
for(int i = 0; i < nSteps; ++i)
nMaxTilesNum = (nMaxTilesNum * 4 + 1);
return nMaxTilesNum;
}
int CField::CalculateMaxTouchNum(int nFieldSize)
{
if(nFieldSize > 8)
return ((log2(nFieldSize) - 2) << 1) + CalculateMaxTouchNum(nFieldSize >> 1);
else
return 0;
}
// 使用"中点位移"算法随机生成高度图
void CField::MakeHeightsPlasma(float* fHeights, float* fMinHeight, float* fMaxHeight, float fRoughness)
{
assert(m_nBorderSize > 2);
// 开始生成
float fRandRange = (float)m_nFieldSize;
int nRectSize = m_nFieldSize;
while(nRectSize > 1)
{
int iHalfRect = nRectSize >> 1;
// 确定中心点高度(*菱形步骤*)
for(int iy = 0; iy < m_nFieldSize; iy += nRectSize)
{
for(int ix = 0; ix < m_nFieldSize; ix += nRectSize)
{
// 右下角坐标
int iex = ix + nRectSize;
int iey = iy + nRectSize;
// 中心坐标
int imx = ix + iHalfRect;
int imy = iy + iHalfRect;
// 确定中心点高度
fHeights[imy * m_nBorderSize + imx] = (fHeights[iy * m_nBorderSize + ix ]
+ fHeights[iy * m_nBorderSize + iex]
+ fHeights[iey * m_nBorderSize + iex]
+ fHeights[iey * m_nBorderSize + ix ]) / 4
+ RandFloat(-fRandRange, fRandRange);
*fMinHeight = min(*fMinHeight, fHeights[imy * m_nBorderSize + imx]);
*fMaxHeight = max(*fMaxHeight, fHeights[imy * m_nBorderSize + imx]);
}
}
// 确定各边中点高度(*方形步骤*)
// 上个步骤已经确定菱形中心点高度,而各边中心点都有菱形中心点高度确定
// 仅设置左、上两个边就可以了,右、下两个边会被下个循环设定,避免重复。
for(int iy = 0; iy < m_nFieldSize; iy += nRectSize)
{
for(int ix = 0; ix < m_nFieldSize; ix += nRectSize)
{
// 右下角
int iex = ix + nRectSize;
int iey = iy + nRectSize;
// 中心
int imx = ix + iHalfRect;
int imy = iy + iHalfRect;
int il = ix - iHalfRect;
int it = iy - iHalfRect;
if(il < 0)il += nRectSize;
if(it < 0)it += nRectSize;
// 确定左边中心高度
fHeights[imy * m_nBorderSize + ix] = (fHeights[imy * m_nBorderSize + il ]
+ fHeights[iy * m_nBorderSize + ix ]
+ fHeights[imy * m_nBorderSize + imx]
+ fHeights[iey * m_nBorderSize + ix ]) / 4
+ RandFloat(-fRandRange, fRandRange);
// 确定上边中心高度
fHeights[iy * m_nBorderSize + imx] = (fHeights[iy * m_nBorderSize + ix ]
+ fHeights[it * m_nBorderSize + imx]
+ fHeights[iy * m_nBorderSize + iex]
+ fHeights[imy * m_nBorderSize + imx]) / 4
+ RandFloat(-fRandRange, fRandRange);
*fMinHeight = min(min(*fMinHeight, fHeights[imy * m_nBorderSize + ix]), fHeights[iy * m_nBorderSize + imx]);
*fMaxHeight = max(max(*fMaxHeight, fHeights[imy * m_nBorderSize + ix]), fHeights[iy * m_nBorderSize + imx]);
// 确定右边中心高度
if(iex == m_nFieldSize)
{
int ir = iex + iHalfRect;
if(ir > m_nFieldSize)ir -= nRectSize;
// 确定右边中心高度
fHeights[imy * m_nBorderSize + iex] = (fHeights[imy * m_nBorderSize + imx]
+ fHeights[iy * m_nBorderSize + iex]
+ fHeights[imy * m_nBorderSize + ir ]
+ fHeights[iey * m_nBorderSize + iex]) / 4
+ RandFloat(-fRandRange, fRandRange);
*fMinHeight = min(*fMinHeight, fHeights[imy * m_nBorderSize + iex]);
*fMaxHeight = max(*fMaxHeight, fHeights[imy * m_nBorderSize + iex]);
}
// 确定下边中心高度
if(iey == m_nFieldSize)
{
int ib = iey + iHalfRect;
if(ib > m_nFieldSize)ib -= nRectSize;
// 确定下边中心高度
fHeights[iey * m_nBorderSize + imx] = (fHeights[iey * m_nBorderSize + ix ]
+ fHeights[imy * m_nBorderSize + imx]
+ fHeights[iey * m_nBorderSize + iex]
+ fHeights[ib * m_nBorderSize + imx]) / 4
+ RandFloat(-fRandRange, fRandRange);
*fMinHeight = min(*fMinHeight, fHeights[iey * m_nBorderSize + imx]);
*fMaxHeight = max(*fMaxHeight, fHeights[iey * m_nBorderSize + imx]);
}
}
}
// 更新迭代
nRectSize /= 2;
fRandRange *= std::pow(2.0f, - fRoughness);
}
}
// 功能:让各点高度值接近最高或最低点, 趋近于板块, 增加对比度
void CField::SlabHeights(float* fHeights, float* fMinHeight, float* fMaxHeight, float fDegree)
{
for(int i = 0; i < m_nHeightsNum; ++i)
{
if(fHeights[i] <= 0.000001f && fHeights[i] >= -0.000001f)
continue;
if(fHeights[i] > 0.0f)
fHeights[i] *= 1 + fDegree * (*fMaxHeight - fHeights[i]) / fHeights[i];
else
fHeights[i] *= 1 + fDegree * (*fMinHeight - fHeights[i]) / fHeights[i];
}
}
// 功能:对高度图进行模糊,以更平滑
void CField::BlurHeights(float* fHeights, float* fMinHeight, float* fMaxHeight, int nTimes)
{
assert(fHeights);
float* fTempHeights = new float[m_nHeightsNum];
if(!fTempHeights)return;
*fMinHeight = 0.0f;
*fMaxHeight = 0.0f;
for(int i = 0; i < nTimes; ++i)
{
for(int iy = 0; iy < m_nBorderSize; ++iy)
{
for(int ix = 0; ix < m_nBorderSize; ++ix)
{
int il = ix - 1;
if(il < 0)il = ix + 1;
int it = iy - 1;
if(it < 0)it = iy + 1;
int ir = ix + 1;
if(ir == m_nBorderSize)ir = ix - 1;
int ib = iy + 1;
if(ib == m_nBorderSize)ib = iy - 1;
float fAverage = (fHeights[iy * m_nBorderSize + ix]
+fHeights[iy * m_nBorderSize + il]
+fHeights[it * m_nBorderSize + ix]
+fHeights[iy * m_nBorderSize + ir]
+fHeights[ib * m_nBorderSize + ix]) / 5;
fTempHeights[iy * m_nBorderSize + ix] = fAverage;
*fMinHeight = min(*fMinHeight, fAverage);
*fMaxHeight = max(*fMaxHeight, fAverage);
}
}
memcpy(fHeights, fTempHeights, sizeof(float) * m_nHeightsNum);
}
delete[] fTempHeights;
}
// "标准化"高度图,将高度数据限定在指定整数范围内
void CField::NormalizeHeights(float* fHeights, float fMinHeight, float fMaxHeight)
{
float fRange = fMaxHeight - fMinHeight;
m_byMaxHeight = (unsigned char)min(fRange, 255.0f);
for(int i = 0; i < m_nHeightsNum; ++i)
m_byHeights[i] = unsigned char(m_byMaxHeight * (fMaxHeight - fHeights[i]) / fRange);
}
void CField::RandomHeight(float fRoughness /*= 0.5f*/, float fSlab /*= 0.5f*/, int nBlur /*= 2*/)
{
// 分配内存
float* fTempHeights = new float[m_nHeightsNum];
if(!fTempHeights)return;
for(int i = 0; i < m_nHeightsNum; ++i)
fTempHeights[i] = 0.0f;
// 最大、最小高度
float fMinHeight = 0.0f;
float fMaxHeight = 0.0f;
// 开始生成
MakeHeightsPlasma(fTempHeights, &fMinHeight, &fMaxHeight, fRoughness);
SlabHeights(fTempHeights, &fMinHeight, &fMaxHeight, fSlab);
BlurHeights(fTempHeights, &fMinHeight, &fMaxHeight, nBlur);
NormalizeHeights(fTempHeights, fMinHeight, fMaxHeight);
delete[] fTempHeights;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?