ogrese地形数据信息 SETerrainData.h SETerrainData.cpp 源码以及注释

//*******************************************************************************
// 功能:存储地形判断射线相交的必须信息  
// ---------------
// 作者:马晓霏
//*******************************************************************************
#pragma once
#include <vector>
#include "OgreVector3.h"
#include "OgreAxisAlignedBox.h"
#include "OgreImage.h"
namespace OgreSE
{
class TerrainData
{
public:
	TerrainData(size_t width, size_t height, const Ogre::Vector3& scale = Ogre::Vector3(100,100,100));
	~TerrainData();

	
	// 功能:	得到世界坐标中 xz 点的法线值
	
	Ogre::Vector3 GetNormalAt(float x, float z) const;
	
	// 功能:	得到世界坐标中 xz 点的高度图值
	
	float GetRawHeightAt(float x, float z) const;
	
	// 功能:	计算绑定盒,结果保存到 pBox, 其他参数例如 32,64,64,96
	
	void ComputerBoundBox(Ogre::AxisAlignedBox* pBox, 
		size_t startX, size_t startZ, size_t endX, size_t endZ) const;
	
	// 功能:	得到绑定盒, 更新绑定盒
	
	Ogre::AxisAlignedBox& GetBoundBox(){return m_BoundBox;};
	
	// 功能:	得到高度图宽长
	
	size_t	GetWidth(){return m_nWidth;};
	size_t	GetHeight()	{return m_nHeight;};
	
	// 功能:	得到高度图
	
	const Ogre::Vector3& GetPosition(){return m_vPosition;};//返回当前地形的第一个节点 m_vPosition
	const Ogre::Vector3& GetScale(){return m_vScale;}; //得到地形的缩放率
	
	//-----------2D与3D之间转换---------------
	//
	// 功能:	计算给定的索引值在世界坐标中的位置
	//
	Ogre::Vector3 ConvertToWorld(int x, float yRaw, int z) const
	{
		return Ogre::Vector3(
			m_vPosition.x + m_vScale.x * x,
			m_vPosition.y + m_vScale.y * yRaw,
			m_vPosition.z + m_vScale.z * z);
	};
	float ConvertToWorldX(size_t x) const
	{
		return m_vPosition.x + m_vScale.x * x;
	}
	float ConvertToWorldZ(size_t z) const
	{
		return m_vPosition.z + m_vScale.z * z;
	}
	float ConvertToWorldY(float yRaw) const
	{
		return  m_vPosition.y + yRaw * m_vScale.y;
	}
	
	// 功能:	得到结点 xz 点的world坐标
	
	Ogre::Vector3 PixelToWorld(size_t x, size_t z) const
	{
		return ConvertToWorld(x, GetRawHeight(x,z), z);
	}
	
	// 功能:	得到高度图像素点对应的3D点的法线, 切线
	// 参数:	x,z,栅格点号
	// 返回值:	法线,切线
	
	Ogre::Vector3 GetPixelNormal(size_t x, size_t z) const;
	Ogre::Vector3 GetPixelTangent(size_t x, size_t z) const;

	
	// 功能:	得到xy点在世界坐标中的实际Y值
	
	float GetWorldHeight(size_t x, size_t z) const
	{
		assert(!IsEmpty() && IsValidPixel(x,z));
		return m_vPosition.y + m_vScale.y* GetRawHeight(x,z);
	}
	
	// 功能:	得到xy点在高度图中的高度值
	
	float GetRawHeight(size_t x, size_t z) const
	{
		assert(!IsEmpty() && IsValidPixel(x,z));
		return m_Heightmap[z*m_nWidth + x];
	}
	float& GetRawHeight(size_t x, size_t z)
	{
		assert(!IsEmpty() && IsValidPixel(x,z));
		return m_Heightmap[z*m_nWidth + x];
	}
	void SetRawHeight(size_t x, size_t z, float val)
	{
		assert(!IsEmpty() && IsValidPixel(x,z));
		m_Heightmap[z*m_nWidth + x] = val;
	}
	void  LoadHeightmapData(Ogre::DataStreamPtr &stream)
	{
		stream->read(m_Heightmap, m_nWidth*m_nHeight*sizeof(float));
	}
	void  SaveHeightmapData(std::ofstream &stream)
	{
		stream.write((char*)m_Heightmap, m_nWidth*m_nHeight*sizeof(float));
	}
	
	// 功能:	计算世界坐标中的xz在高度图中的位置
	
	size_t WorldToPixelX(float x) const
	{
		return Ogre::Math::IFloor((x - m_vPosition.x) * m_vInvScale.x + (float)0.5);
	}
	size_t WorldToPixelZ(float z) const
	{
		return Ogre::Math::IFloor((z - m_vPosition.z) * m_vInvScale.z + (float)0.5);
	}
	
	// 功能:	计算世界坐标中的xz的栅格号 m_vPosition.x:第一个栅格放在世界坐标中的位置
	
	size_t WorldToGridX(float x) const//从当前世界坐标来得到当前节点在地形栅格中的编号 
	{
		return Ogre::Math::IFloor((x - m_vPosition.x) * m_vInvScale.x);
	}
	size_t WorldToGridZ(float z) const
	{
		return Ogre::Math::IFloor((z - m_vPosition.z) * m_vInvScale.z);
	}

private:
	
	// 功能:	判断地形是否是空
	
	bool IsEmpty() const
	{
		return m_Heightmap == NULL;
	}
	
	// 功能:	给定xy点是否有效
	
	bool IsValidPixel(size_t x, size_t z) const  
	{
		return 0 <= x && x <    && 0 <= z && z < m_nHeight;
	}

private:
	// 设置数据
	size_t							m_nWidth;		// 高度图宽,(2^n)* m + 1
	size_t							m_nHeight;		// 高度图高,(2^n)* m + 1
	Ogre::Vector3					m_vScale;		// 缩放率:每个栅格的世界坐标单元尺寸
	Ogre::Vector3					m_vPosition;	// 第一个栅格放在世界坐标中的位置	
	float*							m_Heightmap;	// 保存每一点的高度, 有(m_nWidth * m_nHeight)个元素,保存在 *.Heightmap 中 高度数据存储在其中
	mutable Ogre::AxisAlignedBox	m_BoundBox;		// 边界盒
	Ogre::Vector3					m_vInvScale;	// 缩放率的倒数
};

}


//*******************************************************************************
// 功能:存储地形判断射线相交的必须信息
// ---------------
// 作者:马晓霏
//*******************************************************************************
#include "StdAfx.h"
#include "SETerrainData.h"

namespace OgreSE
{
//***************************************************************************************
// 构造 析构  //m_Heightmap用来存储地形的高度信息,设置地图的开始点,设置地图的外接盒
TerrainData::TerrainData(size_t width, size_t height, const Ogre::Vector3& scale)
: m_nWidth(width)//高度图宽
, m_nHeight(height) //高度图高
, m_vScale(scale) //缩放比率
, m_vInvScale(1/scale) //缩放比率的倒数
, m_Heightmap(NULL)//保存每一点的高度, 有(m_nWidth * m_nHeight)个元素,保存在 *.Heightmap 中 高度数据存储在其中
{
	m_Heightmap = new float[m_nWidth * height];//保存每一点的高度,有(m_nWidth * m_nHeight)个元素,保存在 *.Heightmap 中
	memset(m_Heightmap, 0, m_nWidth * height * sizeof(float));//初始化所有的高度为0
	--width; --height;
	//m_vPosition 第一个栅格放在世界坐标中的位置 注意一定要中心为 (0,0,0)
	m_vPosition = Ogre::Vector3(- m_vScale.x * (width>>1), 0, -m_vScale.z * (height>>1));	// 0,0为中点 m_vPosition=Vector3(-128,0,-128);
	//则 左上为(-128,0,-128) 右上 (128,0,-128) 右下 (-128,0,128) 右下 (128,0,128) center(0,0,0)
	//边界盒m_BoundBox
	m_BoundBox.setExtents(ConvertToWorld(0, 0, 0), ConvertToWorld(width, 0, height));
}

TerrainData::~TerrainData()
{
	SAFE_DELETE_ARRAY(m_Heightmap);
}
//用于计算地形的包围盒 
void TerrainData::ComputerBoundBox(Ogre::AxisAlignedBox* pBox, 
					  size_t startX, size_t startZ, size_t endX, size_t endZ)  const
{
	float minHeight = Ogre::Math::POS_INFINITY;	// 无穷大
	float maxHeight = Ogre::Math::NEG_INFINITY;	// 负无穷大

	// 找到该地形块 Y 最大和最小值
	for (size_t z = startZ; z <= endZ; ++z)
	{
		for (size_t x = startX; x <= endX; ++x)
		{
			float h = GetRawHeight(x,z);
			if (minHeight > h) minHeight = h;
			if (maxHeight < h) maxHeight = h;
		}
	}
	pBox->setExtents(ConvertToWorld(startX, minHeight, startZ), 
		ConvertToWorld(endX, maxHeight, endZ));
}

//***************************************************************************************
// 功能:	得到 heightmap xz 点的法线
Ogre::Vector3 TerrainData::GetPixelNormal(size_t x, size_t z) const
{
	/*
	x-1 x  x+1
z-1 +--+--+
	| /| /|
	|/ |/ |
z   +--+--+
	| /| /|
	|/ |/ |
z+1 +--+--+
	*/
	if (!IsValidPixel(x, z))
		return Ogre::Vector3::UNIT_Y;

	float h = GetRawHeight(x, z);
	Ogre::Vector3 corners[7];
	int count = 0;

#define V(i,j)	((void)(corners[count++] = Ogre::Vector3((i)*m_vScale.x, (GetRawHeight(x+(i),z+(j)) - h)*m_vScale.y, (j)*m_vScale.z)))
	if (x == 0)
	{
		if (z != m_nHeight - 1)
		{
			V( 0,+1);
		}
		V(+1, 0);
		if (z != 0)
		{
			V(+1,-1);
			V( 0,-1);
		}
	}
	else if (x == m_nWidth - 1)
	{
		if (z != 0)
		{
			V( 0,-1);
		}
		V(-1, 0);
		if (z != m_nHeight - 1)
		{
			V(-1,+1);
			V( 0,+1);
		}
	}
	else
	{
		if (z != 0)
		{
			V(+1, 0);
			V(+1,-1);
			V(0 ,-1);
		}
		V(-1, 0);
		if (z != m_nHeight - 1)
		{
			V(-1,+1);
			V( 0,+1);
			V(+1, 0);
		}
	}
#undef V

	assert(2 <= count && count <= sizeof(corners)/sizeof(*corners));

	Ogre::Vector3 sum(0, 0, 0);
	for (int i = 1; i < count; ++i)
	{
		Ogre::Vector3 n = corners[i-1].crossProduct(corners[i]);
		assert(n.y > 0);
		n.normalise();
		sum += n;
	}
	sum.normalise();

	return sum;
}
//***************************************************************************************
// 功能:	得到 高度图 xz 点的切线
Ogre::Vector3 TerrainData::GetPixelTangent(size_t x, size_t z) const
{
	Ogre::Vector3 v3Return;
	int flip = 1;
	Ogre::Vector3 here(x*m_vScale.x, GetRawHeight(x,z)*m_vScale.y, z*m_vScale.z);//得到当前节点的坐标here
	Ogre::Vector3 left;//当前节点左边的那个节点的坐标 left
	if (x == 0)//如果当前节点的左边没有节点了 即当前节点就是最左边节点 那么需要一个翻转
	{
		flip *= -1;
		left = Ogre::Vector3((x+1)*m_vScale.x, GetRawHeight(x+1,z)*m_vScale.y, z*m_vScale.z);//实际上是当前节点的右边坐标
	}
	else
		left = Ogre::Vector3((x-1)*m_vScale.x, GetRawHeight(x-1,z)*m_vScale.y, z*m_vScale.z);
	left -= here;//得到一个向量,是当前节点左边的坐标减去当前节点的坐标 ,就是切线
	v3Return = flip * left;
	v3Return.normalise();
	return v3Return;
}

//***************************************************************************************
// 功能:	得到世界坐标中 xz点的高度图值
float TerrainData::GetRawHeightAt(float x, float z) const
{
	// scale down
	x -= m_vPosition.x;
	z -= m_vPosition.z;
	x *= m_vInvScale.x;//得到在地形Terrain中的x和z坐标节点
	z *= m_vInvScale.z;

	// retrieve height from heightmap via bilinear interpolation
	size_t xi = (size_t) x, zi = (size_t) z;
	if (xi < 0) xi = 0;
	if (zi< 0) zi = 0;
	float xpct = x - xi, zpct = z - zi;
	if (xi >= m_nWidth-1)//如果当前节点在最右边那那一列,那么就要修改成为倒数第二列
	{
		xi = m_nWidth-2;
		xpct = 1.0f;
	}
	if (zi >= m_nHeight-1)//如果当前节点在最后边一行,那么修改成为倒数第二行
	{
		zi = m_nHeight-2;
		zpct = 1.0f;
	}

	// 内插
	float w0 = (1.0 - xpct) * (1.0 - zpct);
	float w1 = (1.0 - xpct) * zpct;
	float w2 = xpct * (1.0 - zpct);
	float w3 = xpct * zpct;
	return	w0 * GetRawHeight(xi, zi) + w1 * GetRawHeight(xi, zi+1) + 
			w2 * GetRawHeight(xi+1, zi) + w3 * GetRawHeight(xi+1, zi+1);
}

//***************************************************************************************
// 功能:	得到世界坐标中 xz 点的法线值,计算两个向量的叉积 
Ogre::Vector3 TerrainData::GetNormalAt(float x, float z) const
{
	Ogre::Vector3 here (x, ConvertToWorldY(GetRawHeightAt(x, z)), z);
	Ogre::Vector3 left (x-1, ConvertToWorldY(GetRawHeightAt(x-1, z)), z);
	Ogre::Vector3 down (x, ConvertToWorldY(GetRawHeightAt(x, z+1)), z+1);

	left = left - here;
	down = down - here;

	Ogre::Vector3 normal = left.crossProduct(down);//
	normal.normalise();
	return normal;
}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值