⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 terrain.cpp

📁 在程序中根据3D地形的高度图动态地生成光照图,其中已包含了3D地形混合纹理生成的代码,使用C++和OpenGL进行编写.
💻 CPP
📖 第 1 页 / 共 3 页
字号:
	// 取整后的高度值, 得到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 + -