📄 terrain.cpp
字号:
// 取整后的高度值, 得到X方向上对指定位置取整后左边点的的高度值
GLubyte ubLow = GetHeightAtPoint( static_cast<GLint> (fScaledX), static_cast<GLint> (fScaledZ) );
// 计算X轴上加1后的高度值
if( (fScaledX + 1) >= m_iHeightMapSize )
{
// 处理高度图边缘的情况,直接返回而不进行差值
return ubLow;
}
else
{
ubHighX = GetHeightAtPoint( static_cast<GLint> (fScaledX + 1), static_cast<GLint> (fScaledZ) );
}
GLfloat fInterpolation = fScaledX - static_cast<GLint> (fScaledX); // 计算(x, z)和(x + 1, z)的差值量
GLfloat fInterpolationX = (ubHighX - ubLow)*fInterpolation + ubLow; // 得到差值后的X方向的高度值
// 对Z方向进行相同的操作
if( (fScaledZ + 1) >= m_iHeightMapSize )
{
return ubLow;
}
else
{
ubHighZ = GetHeightAtPoint( static_cast<GLint> (fScaledX + 1), static_cast<GLint> (fScaledZ + 1) );
}
fInterpolation = fScaledZ - static_cast<GLint> (fScaledZ); // (x, z)和(x, z + 1)的差值量
GLfloat fInterpolationZ = (ubHighZ - ubLow)*fInterpolation + ubLow; // 得到差值后的Z方向的高度值
// 计算两方向差值后高度的平均值,其实是真实值的近似值
return static_cast<GLubyte> ( (fInterpolationX + fInterpolationZ)/2 ) ;
}
//------------------------------------------------------------
// 函数名称:HeightMap::CalulateContributionPercent - private
// 描述:根据指定的地形高度值提取此纹理砖瓦的颜色贡献百分比
// 参数:tileIndex - 纹理砖瓦索引
// height - 地形高度值
// 返回:GLfloat - 颜色贡献百分比
//------------------------------------------------------------
GLfloat HeightMap::CalulateContributionPercent(GLint tileIndex, GLubyte height)
{
// 不在此纹理的作用范围内
if ( height < m_TextureTileManeger.m_vecTextureRegion[tileIndex]->m_iLowHeight ||
height > m_TextureTileManeger.m_vecTextureRegion[tileIndex]->m_iHighHeight )
{
return 0.0f;
}
// 临时变量
GLfloat fTemp1;
GLfloat fTemp2;
// 位于作用区域内
// 小于最佳高度值
if (height < m_TextureTileManeger.m_vecTextureRegion[tileIndex]->m_iOptimalHeight)
{
fTemp1 = static_cast<GLfloat> ( height - m_TextureTileManeger.m_vecTextureRegion[tileIndex]->m_iLowHeight );
fTemp2 = static_cast<GLfloat> ( m_TextureTileManeger.m_vecTextureRegion[tileIndex]->m_iOptimalHeight -
m_TextureTileManeger.m_vecTextureRegion[tileIndex]->m_iLowHeight );
return fTemp1/fTemp2;
}
else if (height > m_TextureTileManeger.m_vecTextureRegion[tileIndex]->m_iOptimalHeight)
{
// 大于最佳高度值
fTemp1 = static_cast<GLfloat> ( m_TextureTileManeger.m_vecTextureRegion[tileIndex]->m_iHighHeight -
m_TextureTileManeger.m_vecTextureRegion[tileIndex]->m_iOptimalHeight );
return ( fTemp1 - (height - m_TextureTileManeger.m_vecTextureRegion[tileIndex]->m_iOptimalHeight) )/fTemp1;
}
// 为最佳高度值
return 1.0f;
}
//------------------------------------------------------
// 函数名称:HeightMap::GenerateTerrainTexture - public
// 描述:生成地形纹理
// 参数:size - 地形纹理尺寸,为2的N次方
// 返回:GL_TRUE - 成功生成地形纹理
// GL_FALSE - 生成地形纹理失败
//------------------------------------------------------
GLboolean HeightMap::GenerateTerrainTexture(GLint size)
{
// 错误检测
if (size <= 0)
{
// 错误信息:地形纹理尺寸不合法
return GL_FALSE;
}
// 释放旧的地形纹理数据资源
CleanUpTerrainTextureData();
size_t i; // 临时变量
GLint iLastEffectiveHeight = -1; // 上一个起作用的高度
// 循环计算各个纹理的作用高度区域
for(i = 0; i < m_TextureTileManeger.m_vecTexture.size(); ++i)
{
// 作用区域示意图;
// 0 -- 64 -- 124
// 63 -- 125 -- 187
// 126 - 188 -- 250
// 189 -- 251 -- 313
// 计算三个高度作用边界,两个作用最低点和一个作用最大点
m_TextureTileManeger.m_vecTextureRegion[i]->m_iLowHeight = iLastEffectiveHeight + 1;
// 255是高度图的最大高度图
iLastEffectiveHeight += static_cast<GLint> ( 255/m_TextureTileManeger.m_vecTextureRegion.size() );
m_TextureTileManeger.m_vecTextureRegion[i]->m_iOptimalHeight = iLastEffectiveHeight;
m_TextureTileManeger.m_vecTextureRegion[i]->m_iHighHeight =
(iLastEffectiveHeight - m_TextureTileManeger.m_vecTextureRegion[i]->m_iLowHeight) + iLastEffectiveHeight;
}
// 记录地形纹理尺寸
m_iTerrainTextureSize = size;
// 为地形纹理分配内存
m_pTerrainData = new GLubyte[m_iTerrainTextureSize*m_iTerrainTextureSize*3];
// 高度图尺寸与地形纹理尺寸的映射比例
GLfloat fMapRatio = static_cast<GLfloat> (m_iHeightMapSize)/m_iTerrainTextureSize;
GLint x; // 循环索引变量
GLubyte ubRed, ubGreen, ubBlue; // 每个纹理砖瓦贡献的颜色值
GLfloat fTotalRed, fTotalGreen, fTotalBlue; // 总的纹理颜色值,使用GLfloat以提高精度
GLint iTexX, iTexZ; // 纹理坐标
GLfloat fBlend; // 保存每个纹理砖瓦颜色的混合百分比
// 创建地形纹理
for(GLint z = 0; z < m_iTerrainTextureSize; ++z)
{
for(x = 0; x < m_iTerrainTextureSize; ++x)
{
// 重新设置混合后的颜色值
fTotalRed = 0.0f;
fTotalGreen = 0.0f;
fTotalBlue = 0.0f;
// 循环遍历所有的纹理砖瓦提取其贡献的颜色值
for(i = 0; i < m_TextureTileManeger.m_vecTexture.size(); ++i)
{
// 保存纹理坐标
iTexX = x;
iTexZ = z;
// 得到地形纹理相对于当前索引砖瓦纹理的纹理坐标
GetTileTexCoord(m_TextureTileManeger.m_vecTexture[i], iTexX, iTexZ);
// 得到此纹理砖瓦坐标对应的纹理颜色值
m_TextureTileManeger.m_vecTexture[i]->GetPositionPixelColor(iTexX, iTexZ, ubRed, ubGreen, ubBlue);
// 得到当前纹理坐标的纹理颜色的混合百分比
fBlend = CalulateContributionPercent( static_cast<GLint> (i), InterpolateHeight(x, z, fMapRatio));
// 计算此纹理所贡献的各分量颜色值并加到总纹理的颜色值中
fTotalRed += ubRed * fBlend;
fTotalGreen += ubGreen * fBlend;
fTotalBlue += ubBlue * fBlend;
}
// 设置总纹理指定纹理坐标上的颜色值
m_pTerrainData[ (z*m_iTerrainTextureSize + x)*3 ] = static_cast<GLubyte> ( StandardizationValue(fTotalRed) );
m_pTerrainData[ (z*m_iTerrainTextureSize + x)*3 + 1 ] = static_cast<GLubyte> ( StandardizationValue(fTotalGreen) );
m_pTerrainData[ (z*m_iTerrainTextureSize + x)*3 + 2 ] = static_cast<GLubyte> ( StandardizationValue(fTotalBlue) );
}
}
// 生成地形纹理对象
glGenTextures(1, &m_uiTerrainTextureID);
glBindTexture(GL_TEXTURE_2D, m_uiTerrainTextureID);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, m_iTerrainTextureSize,
m_iTerrainTextureSize, 0, GL_RGB, GL_UNSIGNED_BYTE, m_pTerrainData);
return GL_TRUE;
}
//------------------------------------------------------------------------
// 函数名称:HeightMap::GenerateIlluminationMapAccordingHeightMap - public
// 描述:生成根据高度图生成照明图
// 参数:illuminationType - 生成的照明图的照明类型
// 返回:GL_TRUE - 成功生成照明图
// GL_FALSE - 生成照明图失败
//------------------------------------------------------------------------
GLboolean HeightMap::GenerateIlluminationMapAccordingHeightMap(IlluminationType illuminationType)
{
// 检测是否存在高度图
if (m_pHeightData == NULL || m_iHeightMapSize == 0)
{
// 错误信息:不存在高度图,无法生成照明图
return GL_FALSE;
}
// 检测是否已经存在照明图
if (m_pIlluminationData != NULL)
{
// 提示信息:已经存在照明图
return GL_FALSE;
}
// 检测参数指定的照明类型是否符合要求
if (illuminationType != BaseOnTerrainHeight && illuminationType != BaseOnSlopeIllumination)
{
// 错误信息:指定的照明类型是否符合要求
return GL_FALSE;
}
// 为照明图分配内存
m_pIlluminationData = new GLubyte[m_iHeightMapSize*m_iHeightMapSize];
// 记录照明类型
m_IlluminationType = illuminationType;
// 记录照明图尺寸,照明图应该与高度图尺寸相同
m_iIlluminationMapSize = m_iHeightMapSize;
// 根据基于的照明类型设置生成照明图
if (m_IlluminationType == BaseOnTerrainHeight)
{
for (GLint z = 0; z < m_iIlluminationMapSize; ++z)
{
for (GLint x = 0; x < m_iIlluminationMapSize; ++x)
{
SetBrightnessAtPoint( x, z, GetHeightAtPoint(x, z) );
}
}
}
else if (m_IlluminationType == BaseOnSlopeIllumination) // slope照明类型
{
GLfloat fShadeProportion; // 被照明的程度
for (GLint z = 0; z < m_iIlluminationMapSize; ++z)
{
for (GLint x = 0; x < m_iIlluminationMapSize; ++x)
{
// m_fLightSoftness可以起到间接调整关照光度的作用,
// m_fLightSoftness越大表示光照距地形表面较高,
// m_fLightSoftness越小表示光照距地形表面较低
if (z >= m_iDirectionZ && x >= m_iDirectionX)
{
fShadeProportion =
1.0f - ( GetHeightAtPoint(x - m_iDirectionX, z - m_iDirectionZ) - GetHeightAtPoint(x, z) )/m_fIlluminationSoftness;
}
else
{
fShadeProportion = 1.0f; // 避免边界情况
}
// 限制被照明程度到指定范围
if (fShadeProportion < m_fMinBrightness)
{
fShadeProportion = m_fMinBrightness;
}
if (fShadeProportion > m_fMaxBrightness)
{
fShadeProportion = m_fMaxBrightness;
}
// 设置此位置的被照明程度到照明图中
SetBrightnessAtPoint( x, z, static_cast<GLubyte> (fShadeProportion*255.0f) );
}
}
}
return GL_TRUE;
}
//---------------------------------------------------
// 函数名称:HeightMap::RenderHeightSmallMap - public
// 描述:将高度图小图
// 参数:windowWidth,windowHeight - 窗口尺寸
// 返回:None
//---------------------------------------------------
GLvoid HeightMap::RenderHeightSmallMap(GLint windowWidth, GLint windowHeight) const
{
// 检测此类对象中是否保存有高度图
if (m_pHeightData == NULL)
{
// 错误信息:不存在任何高度图
return;
}
glMatrixMode(GL_PROJECTION); // 设置操作矩阵为投影矩阵
glPushMatrix(); // 保存当前投影矩阵
glLoadIdentity(); // 载入单位矩阵
glOrtho(0, windowWidth, 0, windowHeight, -1, 1); // 设置正投影
glMatrixMode(GL_MODELVIEW); // 设置操作矩阵为模型视图矩阵
glPushMatrix(); // 保存模型视图矩阵
glLoadIdentity(); // 载入单位矩阵
// 不绑定任何纹理
glBindTexture(GL_TEXTURE_2D, NULL);
// 绘制高度图的小化图
glBegin(GL_POINTS);
for(GLint z = 0; z < m_iHeightMapSize; ++z)
{
for(GLint x = 0; x < m_iHeightMapSize; ++x)
{
glColor3ub(GetHeightAtPoint(x, z), GetHeightAtPoint(x, z), GetHeightAtPoint(x, z));
glVertex2i(x, windowHeight - z);
}
}
glEnd();
glPopMatrix(); // 恢复模型视图矩阵
glMatrixMode(GL_PROJECTION); // 设置操作矩阵为投影矩阵
glPopMatrix(); // 恢复当前投影矩阵
glMatrixMode(GL_MODELVIEW); // 设置操作矩阵为模型视图矩阵
}
//----------------------------------------------------------
// 函数名称:HeightMap::RenderIlluminationSmallMap - public
// 描述:将照明图小图
// 参数:windowWidth,windowHeight - 窗口尺寸
// 返回:None
//----------------------------------------------------------
GLvoid HeightMap::RenderIlluminationSmallMap(GLint windowWidth, GLint windowHeight) const
{
// 检测此类对象中是否保存有照明图
if (m_pIlluminationData == NULL)
{
// 错误信息:不存在任何照明图
return;
}
glMatrixMode(GL_PROJECTION); // 设置操作矩阵为投影矩阵
glPushMatrix(); // 保存当前投影矩阵
glLoadIdentity(); // 载入单位矩阵
glOrtho(0, windowWidth, 0, windowHeight, -1, 1); // 设置正投影
glMatrixMode(GL_MODELVIEW); // 设置操作矩阵为模型视图矩阵
glPushMatrix(); // 保存模型视图矩阵
glLoadIdentity(); // 载入单位矩阵
// 不绑定任何纹理
glBindTexture(GL_TEXTURE_2D, NULL);
// 绘制照明图的小化图
glBegin(GL_POINTS);
for(GLint z = 0; z < m_iIlluminationMapSize; ++z)
{
for(GLint x = 0; x < m_iIlluminationMapSize; ++x)
{
glColor3ub( m_pIlluminationData[m_iIlluminationMapSize*z + x],
m_pIlluminationData[m_iIlluminationMapSize*z + x], m_pIlluminationData[m_iIlluminationMapSize*z + x] );
glVertex2i(x, windowHeight - z);
}
}
glEnd();
glPopMatrix(); // 恢复模型视图矩阵
glMatrixMode(GL_PROJECTION); // 设置操作矩阵为投影矩阵
glPopMatrix(); // 恢复当前投影矩阵
glMatrixMode(GL_MODELVIEW); // 设置操作矩阵为模型视图矩阵
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -