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 + -
显示快捷键?